From 52558010e83a203dbc4c36e537468722a7c15874 Mon Sep 17 00:00:00 2001 From: "Troll (Hermes Agent)" Date: Wed, 5 Aug 2026 20:27:33 +0000 Subject: [PATCH] Add Live Queue slide to kiosk rotation - Added a third kiosk slide showing the active customer queue. - Customer names are derived from the local-part of their email address. - Statuses are mapped to friendly labels: pending -> Received prompt_ready / songs_uploaded -> Trollgorithm Recording in Studio revisions_requested -> Waiting for Customer Response awaiting_payment -> Payment Due - Completed/delivered statuses are not shown. - If the queue overflows, a note points customers to the status page. - Added queue-only mode (kiosk_cycle_seconds = 1) and updated the cycle logic to rotate QR -> pricing -> queue. - Updated /admin/settings help text for the new mode. Bumps version to 0.5.3. --- README.md | 2 +- VERSION | 2 +- app.py | 30 +++++++++- templates/admin/settings.html | 4 +- templates/kiosk.html | 110 +++++++++++++++++++++++++++++----- 5 files changed, 129 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 271c2fe..3d8c242 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Theme Song Booth -**Version:** `v0.5.2` +**Version:** `v0.5.3` A Flask web application for running a convention booth where visitors request a custom AI-generated theme song. Operators manage the queue from an admin dashboard, generate Suno prompts, upload MP3 previews, collect payment, and deliver final songs by email. diff --git a/VERSION b/VERSION index cb0c939..be14282 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.2 +0.5.3 diff --git a/app.py b/app.py index 4f15ff8..b83e57e 100644 --- a/app.py +++ b/app.py @@ -350,7 +350,10 @@ def get_kiosk_cycle_seconds(): def get_kiosk_mode(): - """Return 'cycle', 'qr', or 'prices' based on kiosk_cycle_seconds setting.""" + """ + Return 'qr', 'prices', 'queue', or 'cycle' based on kiosk_cycle_seconds setting. + -1 = QR only, 0 = prices only, 1 = queue only, 5+ = cycle through all three. + """ cfg = load_booth_settings() try: val = int(cfg.get('kiosk_cycle_seconds', 10)) @@ -360,6 +363,8 @@ def get_kiosk_mode(): return 'qr' if val == 0: return 'prices' + if val == 1: + return 'queue' return 'cycle' @@ -1017,12 +1022,35 @@ def kiosk(): mode = get_kiosk_mode() booth_open = get_booth_open() + # Build the public queue: only active statuses, mapped to friendly names, + # using the local-part of the email as the customer name. + KIOSK_STATUS_MAP = { + 'pending': 'Received', + 'prompt_ready': 'Trollgorithm Recording in Studio', + 'songs_uploaded': 'Trollgorithm Recording in Studio', + 'revisions_requested': 'Waiting for Customer Response', + 'awaiting_payment': 'Payment Due', + } + active_statuses = set(KIOSK_STATUS_MAP.keys()) + raw_queue = list_requests() + queue = [] + for r in raw_queue: + if r.get('status') in active_statuses: + email = r.get('email') or '' + name = email.split('@')[0] if '@' in email else email + queue.append({ + 'name': name or 'Guest', + 'status': KIOSK_STATUS_MAP[r['status']], + 'raw_status': r['status'], + }) + return render_template( 'kiosk.html', booth_open=booth_open, price_items=price_items, cycle_seconds=cycle_seconds, mode=mode, + queue=queue, refresh_seconds=30 ) diff --git a/templates/admin/settings.html b/templates/admin/settings.html index d70e3b2..2051b4c 100644 --- a/templates/admin/settings.html +++ b/templates/admin/settings.html @@ -272,12 +272,12 @@

Kiosk Display Mode

-

Set how the public /kiosk page cycles. Use -1 for QR only, 0 for pricing only, or 5+ seconds to cycle between them.

+

Set how the public /kiosk page cycles. Use -1 for QR only, 0 for pricing only, 1 for queue only, or 5+ seconds to cycle between QR, pricing, and queue.

-

Examples: -1 = QR only, 0 = pricing only, 10 = swap every 10 seconds.

+

Examples: -1 = QR only, 0 = pricing only, 1 = queue only, 10 = rotate QR → pricing → queue every 10 seconds.

diff --git a/templates/kiosk.html b/templates/kiosk.html index c125be4..b7f9d88 100644 --- a/templates/kiosk.html +++ b/templates/kiosk.html @@ -118,6 +118,53 @@ font-size:1.3rem; color:#9ca3af; } + .queue-card{ + background:rgba(31,41,55,.85); + border:1px solid rgba(96,165,250,.25); + border-radius:1.2rem; + padding:3vh 4vw; + box-shadow:0 15px 50px rgba(0,0,0,.35); + width:100%; + max-height:62vh; + display:flex; + flex-direction:column; + } + .queue-card h2{ + margin:0 0 2vh 0; + font-size:clamp(1.6rem,4vw,2.6rem); + color:#fbbf24; + } + .queue-list{ + list-style:none; + margin:0; + padding:0; + text-align:left; + overflow-y:auto; + flex:1; + } + .queue-list li{ + display:flex; + justify-content:space-between; + align-items:center; + border-bottom:1px solid rgba(147,197,253,.2); + padding:1.4vh 0; + font-size:clamp(1.2rem,2.8vw,1.7rem); + } + .queue-list li:last-child{border-bottom:none;} + .queue-list .customer{color:#e5e7eb;font-weight:600;} + .queue-list .status{font-weight:700;color:#60a5fa;text-align:right;} + .queue-empty{ + font-size:1.4rem; + color:#9ca3af; + text-align:center; + margin:auto 0; + } + .queue-note{ + font-size:1rem; + color:#9ca3af; + margin-top:1.5vh; + text-align:center; + } .footer{ font-size:1rem; color:#9ca3af; @@ -175,6 +222,25 @@ {% endif %} + {% elif mode == 'queue' %} +
+
+

Live Queue

+ {% if queue %} +
    + {% for item in queue %} +
  • + {{ item.name }} + {{ item.status }} +
  • + {% endfor %} +
+

If your request isn't shown, visit the request page and use the status link to check your place.

+ {% else %} +

No active requests right now. Be the first!

+ {% endif %} +
+
{% else %}

Scan to Order

@@ -198,6 +264,24 @@ {% endif %}
+ {% endif %} @@ -206,30 +290,28 @@
+