Add rename functionality for recordings
- Added /rename/<filename> API endpoint - Accepts new_name in JSON body - Automatically appends .wav extension if missing - Uses secure_filename() for safety - Checks for existing files to prevent overwrites - Backs up renamed file to USB if backup enabled - Updated web interface (template v1.6.0) - Added "Rename" button to each recording - Added renameRecording() JavaScript function - Uses prompt dialog for name input - Pre-fills current name (without .wav extension) - Reloads page after successful rename This allows users to assign guest names to recordings for easier organization (e.g., "John_Smith.wav"). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -81,7 +81,7 @@ BACKUP_ON_WRITE = BACKUP_CONFIG.get('backup_on_write', True)
|
||||
WEB_PORT = SYS_CONFIG['web']['port']
|
||||
|
||||
# Template version - increment this when HTML template changes
|
||||
TEMPLATE_VERSION = "1.5.0" # Updated: Redesigned sound selection with dropdowns
|
||||
TEMPLATE_VERSION = "1.6.0" # Updated: Added rename functionality for recordings
|
||||
|
||||
# Flask app
|
||||
app = Flask(__name__)
|
||||
@@ -945,6 +945,40 @@ def delete_recording(filename):
|
||||
return jsonify({"success": True})
|
||||
return jsonify({"error": "File not found"}), 404
|
||||
|
||||
@app.route('/rename/<filename>', methods=['POST'])
|
||||
def rename_recording(filename):
|
||||
"""Rename a recording"""
|
||||
data = request.get_json()
|
||||
new_name = data.get('new_name', '').strip()
|
||||
|
||||
if not new_name:
|
||||
return jsonify({"error": "New name is required"}), 400
|
||||
|
||||
# Ensure .wav extension
|
||||
if not new_name.endswith('.wav'):
|
||||
new_name += '.wav'
|
||||
|
||||
# Sanitize filenames
|
||||
old_filepath = os.path.join(OUTPUT_DIR, secure_filename(filename))
|
||||
new_filepath = os.path.join(OUTPUT_DIR, secure_filename(new_name))
|
||||
|
||||
if not os.path.exists(old_filepath):
|
||||
return jsonify({"error": "File not found"}), 404
|
||||
|
||||
if os.path.exists(new_filepath):
|
||||
return jsonify({"error": "A file with that name already exists"}), 409
|
||||
|
||||
try:
|
||||
os.rename(old_filepath, new_filepath)
|
||||
|
||||
# Also backup renamed file if backup is enabled
|
||||
if SYS_CONFIG['backup']['enabled'] and SYS_CONFIG['backup']['backup_on_write']:
|
||||
backup_file_to_usb(new_filepath, 'recordings')
|
||||
|
||||
return jsonify({"success": True, "new_name": secure_filename(new_name)})
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
@app.route('/restore_default_sound', methods=['POST'])
|
||||
def restore_default_sound():
|
||||
"""Restore default dial tone"""
|
||||
@@ -1752,10 +1786,10 @@ def main():
|
||||
{% for recording in recordings %}
|
||||
<div class="recording-item" id="recording-{{ loop.index }}">
|
||||
<div class="recording-info">
|
||||
<h3>{{ recording.filename }}</h3>
|
||||
<h3 id="filename-{{ loop.index }}">{{ recording.filename }}</h3>
|
||||
<div class="recording-meta">
|
||||
📅 {{ recording.date }} |
|
||||
⏱️ {{ "%.1f"|format(recording.duration) }}s |
|
||||
📅 {{ recording.date }} |
|
||||
⏱️ {{ "%.1f"|format(recording.duration) }}s |
|
||||
💾 {{ "%.2f"|format(recording.size_mb) }} MB
|
||||
</div>
|
||||
</div>
|
||||
@@ -1766,6 +1800,9 @@ def main():
|
||||
<button class="btn btn-primary" onclick="downloadRecording('{{ recording.filename }}')">
|
||||
⬇️ Download
|
||||
</button>
|
||||
<button class="btn btn-secondary" onclick="renameRecording('{{ recording.filename }}', {{ loop.index }})">
|
||||
✏️ Rename
|
||||
</button>
|
||||
<button class="btn btn-danger" onclick="deleteRecording('{{ recording.filename }}', {{ loop.index }})">
|
||||
🗑️ Delete
|
||||
</button>
|
||||
@@ -1985,6 +2022,30 @@ def main():
|
||||
}
|
||||
}
|
||||
|
||||
function renameRecording(filename, index) {
|
||||
// Remove .wav extension for cleaner input
|
||||
const nameWithoutExt = filename.replace('.wav', '');
|
||||
const newName = prompt('Enter new name for recording:', nameWithoutExt);
|
||||
|
||||
if (newName && newName.trim() !== '' && newName !== nameWithoutExt) {
|
||||
fetch('/rename/' + filename, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ new_name: newName.trim() })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showAlert('Recording renamed! ✓', 'success');
|
||||
setTimeout(() => location.reload(), 1500);
|
||||
} else {
|
||||
showAlert('Error: ' + data.error, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => showAlert('Error: ' + error, 'error'));
|
||||
}
|
||||
}
|
||||
|
||||
function playAudio(type, filename) {
|
||||
const modal = document.getElementById('audio-modal');
|
||||
const player = document.getElementById('audio-player');
|
||||
|
||||
Reference in New Issue
Block a user