Add download all recordings as ZIP feature
- Add /download_all endpoint to create in-memory ZIP archive - Include zipfile and io imports for ZIP creation - Add "Download All as ZIP" button in web interface (only shows when recordings exist) - ZIP filename includes timestamp: wedding_recordings_YYYYMMDD_HHMMSS.zip - Only includes .wav files from recordings directory - Update API documentation in README.md - Document feature in CLAUDE.md Allows users to quickly backup all guest recordings in a single download. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,8 @@ import json
|
||||
import sys
|
||||
import zlib
|
||||
import shutil
|
||||
import zipfile
|
||||
import io
|
||||
|
||||
# Load configuration
|
||||
def load_system_config():
|
||||
@@ -798,6 +800,42 @@ def download_recording(filename):
|
||||
return send_file(filepath, as_attachment=True)
|
||||
return "File not found", 404
|
||||
|
||||
@app.route('/download_all')
|
||||
def download_all_recordings():
|
||||
"""Download all recordings as a ZIP file"""
|
||||
if not os.path.exists(OUTPUT_DIR):
|
||||
return "No recordings found", 404
|
||||
|
||||
# Get all recording files
|
||||
recordings = [f for f in os.listdir(OUTPUT_DIR)
|
||||
if f.endswith('.wav') and os.path.isfile(os.path.join(OUTPUT_DIR, f))]
|
||||
|
||||
if not recordings:
|
||||
return "No recordings found", 404
|
||||
|
||||
# Create ZIP file in memory
|
||||
memory_file = io.BytesIO()
|
||||
|
||||
with zipfile.ZipFile(memory_file, 'w', zipfile.ZIP_DEFLATED) as zf:
|
||||
for filename in recordings:
|
||||
filepath = os.path.join(OUTPUT_DIR, filename)
|
||||
# Add file to ZIP with just the filename (no path)
|
||||
zf.write(filepath, arcname=filename)
|
||||
|
||||
# Seek to beginning of file
|
||||
memory_file.seek(0)
|
||||
|
||||
# Generate filename with timestamp
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
zip_filename = f"wedding_recordings_{timestamp}.zip"
|
||||
|
||||
return send_file(
|
||||
memory_file,
|
||||
mimetype='application/zip',
|
||||
as_attachment=True,
|
||||
download_name=zip_filename
|
||||
)
|
||||
|
||||
@app.route('/delete/<filename>', methods=['POST'])
|
||||
def delete_recording(filename):
|
||||
"""Delete a recording"""
|
||||
@@ -1499,8 +1537,15 @@ def main():
|
||||
|
||||
<!-- Recordings Card -->
|
||||
<div class="card">
|
||||
<h2>🎙️ Recordings</h2>
|
||||
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
|
||||
<h2 style="margin: 0;">🎙️ Recordings</h2>
|
||||
{% if recordings %}
|
||||
<button class="btn btn-primary" onclick="downloadAllRecordings()" style="font-size: 0.9em;">
|
||||
📦 Download All as ZIP
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if recordings %}
|
||||
<div class="stats">
|
||||
<div class="stat-box">
|
||||
@@ -1715,7 +1760,11 @@ def main():
|
||||
function downloadRecording(filename) {
|
||||
window.location.href = '/download/' + filename;
|
||||
}
|
||||
|
||||
|
||||
function downloadAllRecordings() {
|
||||
window.location.href = '/download_all';
|
||||
}
|
||||
|
||||
function deleteRecording(filename, index) {
|
||||
if (confirm('Delete this recording?')) {
|
||||
fetch('/delete/' + filename, { method: 'POST' })
|
||||
|
||||
Reference in New Issue
Block a user