From 0783e08fe92a8c8481e4db3bf247fe99affe6464 Mon Sep 17 00:00:00 2001 From: markmental Date: Mon, 2 Feb 2026 14:05:21 -0500 Subject: [PATCH] Added auth support and a helper script, targeting frankenphp --- .gitignore | 1 + auth.php | 50 +++++++ get_files.php | 5 +- index.php | 374 +++++++++++++++++++++++++++++++++++++++++++++++- login.php | 60 ++++++++ logout.php | 20 +++ serve_media.php | 5 +- start-server.sh | 144 +++++++++++++++++++ 8 files changed, 655 insertions(+), 4 deletions(-) create mode 100644 .gitignore create mode 100644 auth.php create mode 100644 login.php create mode 100644 logout.php create mode 100755 start-server.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env diff --git a/auth.php b/auth.php new file mode 100644 index 0000000..a0e73a1 --- /dev/null +++ b/auth.php @@ -0,0 +1,50 @@ + 0, + 'path' => '/', + 'domain' => '', + 'secure' => true, + 'httponly' => true, + 'samesite' => 'Lax', + ]); + + if (session_status() !== PHP_SESSION_ACTIVE) { + session_start(); + } +} + +/** + * Require a valid login. + * IMPORTANT: releases the session lock immediately to avoid deadlocks/timeouts. + */ +function require_auth(bool $json = true): void +{ + auth_session_start(); + + $ok = (isset($_SESSION['authed']) && $_SESSION['authed'] === true); + + // Release the session file lock ASAP. + // This prevents other requests from blocking on session_start(). + session_write_close(); + + if (!$ok) { + http_response_code(401); + + if ($json) { + header('Content-Type: application/json; charset=utf-8'); + echo json_encode(['error' => 'Unauthorized']); + } else { + header('Content-Type: text/plain; charset=utf-8'); + echo "Unauthorized"; + } + exit; + } +} + diff --git a/get_files.php b/get_files.php index b32acbe..9c998bc 100644 --- a/get_files.php +++ b/get_files.php @@ -2,8 +2,11 @@ /** * get_files.php - Recursively scans media directories and returns file structure as JSON */ - declare(strict_types=1); +require_once __DIR__ . '/auth.php'; +require_auth(true); + + header('Content-Type: application/json; charset=utf-8'); diff --git a/index.php b/index.php index 378d156..ca5dd62 100644 --- a/index.php +++ b/index.php @@ -342,6 +342,49 @@ font-weight: 600; } + .player-controls-row { + width: 100%; + display: flex; + align-items: center; + justify-content: center; + gap: 0.75rem; + margin-top: 1rem; + z-index: 1; + } + + .audio-track-label { + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.1em; + color: var(--text-secondary); + font-family: 'Orbitron', sans-serif; + } + + .audio-track-select { + background: var(--bg-tertiary); + border: 1px solid var(--border-color); + color: var(--text-primary); + padding: 0.55rem 0.75rem; + border-radius: 8px; + outline: none; + min-width: 220px; + font-family: 'Archivo', sans-serif; + } + + .audio-track-select:focus { + border-color: var(--accent-primary); + box-shadow: var(--shadow-glow); + } + + .audio-track-hint { + color: var(--text-secondary); + font-size: 0.8rem; + margin-top: 0.5rem; + z-index: 1; + text-align: center; + } + + .loading { display: inline-block; width: 20px; @@ -352,6 +395,119 @@ animation: spin 0.8s linear infinite; } + .overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.72); + backdrop-filter: blur(6px); + z-index: 9999; + display: flex; + align-items: center; + justify-content: center; + padding: 1.5rem; + } + + .login-card { + width: 100%; + max-width: 420px; + background: var(--bg-secondary); + border: 1px solid var(--border-color); + border-radius: 14px; + box-shadow: 0 10px 40px rgba(0,0,0,0.6); + padding: 1.75rem; + } + + .login-title { + font-family: 'Orbitron', sans-serif; + font-size: 1.4rem; + color: var(--accent-primary); + margin-bottom: 0.35rem; + } + + .login-subtitle { + color: var(--text-secondary); + font-size: 0.9rem; + margin-bottom: 1.25rem; + } + + .login-row { + display: flex; + flex-direction: column; + gap: 0.4rem; + margin-bottom: 0.9rem; + } + + .login-row label { + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.1em; + color: var(--text-secondary); + font-family: 'Orbitron', sans-serif; + } + + .login-row input { + background: var(--bg-tertiary); + border: 1px solid var(--border-color); + color: var(--text-primary); + padding: 0.75rem 0.85rem; + border-radius: 10px; + outline: none; + font-family: 'Archivo', sans-serif; + } + + .login-row input:focus { + border-color: var(--accent-primary); + box-shadow: var(--shadow-glow); + } + + .login-actions { + display: flex; + gap: 0.75rem; + margin-top: 1rem; + align-items: center; + justify-content: space-between; + } + + .btn { + cursor: pointer; + border: 1px solid var(--border-color); + border-radius: 10px; + padding: 0.75rem 1rem; + font-family: 'Orbitron', sans-serif; + letter-spacing: 0.05em; + text-transform: uppercase; + font-size: 0.85rem; + transition: all 0.2s ease; + background: var(--bg-tertiary); + color: var(--text-primary); + } + + .btn-primary { + background: linear-gradient(135deg, var(--accent-primary) 0%, var(--accent-secondary) 100%); + border-color: var(--accent-primary); + color: var(--bg-primary); + font-weight: 700; + box-shadow: var(--shadow-glow); + } + + .btn:hover { + transform: translateY(-1px); + } + + .login-error { + color: #ff6b6b; + margin-top: 0.75rem; + font-size: 0.9rem; + display: none; + } + + .topbar { + display: flex; + justify-content: flex-end; + margin-bottom: 1rem; + } + + @keyframes spin { to { transform: rotate(360deg); @@ -392,12 +548,22 @@
+
+ +
+
🎵

Select a file to start playing

+ + + + + +