Compare commits

..

No commits in common. "dead6602f5664ceb9b6926ae5649e378773882bd" and "530451cfef58be58c7e157b1d90b39e702e1cf9b" have entirely different histories.

5 changed files with 3 additions and 34 deletions

View file

@ -1,6 +1,6 @@
# Theme Song Booth (MusicGPT Edition)
![Version](https://img.shields.io/badge/version-v0.9.2-blue)
![Version](https://img.shields.io/badge/version-v0.9.1-blue)
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 prompts via Hermes, queue generations through the MusicGPT API, and deliver final songs by email.
@ -78,7 +78,7 @@ The selected pronouns are stored in the `pronouns` column and included in confir
|------|------|---------|
| Login | `/admin/login` | Simple session-based login. Password comes from the `ADMIN_PASSWORD` environment variable. |
| Dashboard | `/admin` | Main queue. Filter by status and auto-refresh at a configurable interval. Includes a **Refresh MusicGPT Status** button to manually poll all in-flight tasks. |
| Request detail | `/admin/request/<id>` | Full control of one request: edit customer info, save prompt, copy Hermes callback, queue MusicGPT generation, poll a single MusicGPT task, view status/cost, view revision history, upload MP3 overrides, download individual Version A/B MP3s, send preview, record payment, deliver files (MP3/WAV/cover), add operator notes, cancel generation, and generate STEMS. |
| Request detail | `/admin/request/<id>` | Full control of one request: edit customer info, save prompt, copy Hermes callback, queue MusicGPT generation, poll a single MusicGPT task, view status/cost, view revision history, upload MP3 overrides, send preview, record payment, deliver files (MP3/WAV/cover), add operator notes, cancel generation, and generate STEMS. |
| Pricing | `/admin/pricing` | Configure fixed prices and up to 5 custom items. Also shows running MusicGPT cost totals in USD. |
| Sales | `/admin/sales` | Report of all delivered requests with customer details and Square payment references. |
| Settings | `/admin/settings` | Database health, backups, SMTP config, MP3 metadata defaults, revision limit, auto-refresh interval, kiosk mode, booth open/closed switch, Hermes API key management, MusicGPT webhook URL, album cover delivery toggle, automatic MusicGPT polling toggle, and system reset. |

View file

@ -1 +1 @@
0.9.2
0.9.1

18
app.py
View file

@ -922,24 +922,6 @@ def admin_download_stems(rid):
return send_file(buf, mimetype='application/zip', as_attachment=True, download_name=download_name)
@app.route('/admin/request/<int:rid>/download-song/<version>')
def admin_download_song(rid, version):
"""Download a single song MP3 (Version A or B) for a request."""
redir = require_admin()
if redir:
return redir
req = get_request_by_id(rid)
if not req:
abort(404)
if version not in ('a', 'b'):
abort(404)
path = req.get('song_a_path') if version == 'a' else req.get('song_b_path')
if not path or not Path(path).exists():
flash('Song file not found.', 'error')
return redirect(url_for('admin_request', rid=rid))
return send_file(path, as_attachment=True, download_name=Path(path).name)
# ---------------------------------------------------------------------------
# Admin routes
# ---------------------------------------------------------------------------

View file

@ -558,13 +558,6 @@
flex: 1;
}
.booth-page .song-download {
flex: 0 0 auto;
align-self: center;
font-size: 0.85rem;
padding: var(--space-1) var(--space-3);
}
.booth-page .file-select {
background: var(--bg-input);
border: 1px solid var(--border);

View file

@ -313,9 +313,6 @@
<span class="status-badge missing">Not ready</span>
{% endif %}
</label>
{% if req.song_a_path and file_exists(req.song_a_path) %}
<a href="{{ url_for('admin_download_song', rid=req.id, version='a') }}" class="button-link song-download">⬇ Download</a>
{% endif %}
</div>
<div class="song-row">
<input type="checkbox" id="delete_b" name="delete_song" value="b" {% if not (req.song_b_path and file_exists(req.song_b_path)) %}disabled{% endif %}>
@ -329,9 +326,6 @@
<span class="status-badge missing">Not ready</span>
{% endif %}
</label>
{% if req.song_b_path and file_exists(req.song_b_path) %}
<a href="{{ url_for('admin_download_song', rid=req.id, version='b') }}" class="button-link song-download">⬇ Download</a>
{% endif %}
</div>
<div class="actions">
<button type="submit" class="button-danger" onclick="return confirm('Delete selected song files? This will reset the request to Prompt Ready.')">Delete Selected Songs</button>