Add recording sorting with multiple options
Added comprehensive sorting functionality for recordings: Backend changes: - Updated get_recordings() to accept sort_by and sort_order parameters - Sort options: 'date', 'name', 'duration', 'size' - Sort order: 'asc' (ascending) or 'desc' (descending) - Added timestamp field to recordings for accurate date sorting - Default sort: by date, descending (newest first) Frontend changes (template v1.8.0): - Added sort controls above recordings list - Two dropdowns: sort field and sort direction - Visual styling with emojis for each option: 📅 Date - Sort by recording date/time 📝 Name - Sort alphabetically by filename ⏱️ Duration - Sort by recording length 💾 Size - Sort by file size ⬇️ Descending / ⬆️ Ascending - updateSort() JavaScript function reloads page with params - Preserves selected sort options via query params URL parameters: - ?sort=date&order=desc (default) - ?sort=name&order=asc (alphabetical A-Z) - ?sort=duration&order=desc (longest first) - ?sort=size&order=asc (smallest first) This makes it easy to find specific recordings or organize them by different criteria depending on what you need. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -151,7 +151,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.7.0" # Updated: Separate volume controls for greeting, button, and beep
|
||||
TEMPLATE_VERSION = "1.8.0" # Updated: Added recording sorting by date, name, duration, size
|
||||
|
||||
# Flask app
|
||||
app = Flask(__name__)
|
||||
@@ -834,7 +834,11 @@ phone = RotaryPhone()
|
||||
@app.route('/')
|
||||
def index():
|
||||
"""Main page"""
|
||||
recordings = get_recordings()
|
||||
# Get sort parameters from query string
|
||||
sort_by = request.args.get('sort', 'date')
|
||||
sort_order = request.args.get('order', 'desc')
|
||||
|
||||
recordings = get_recordings(sort_by=sort_by, sort_order=sort_order)
|
||||
greetings = get_greetings()
|
||||
status = phone.get_status()
|
||||
active_greeting = phone.config.get("active_greeting", "dialtone.wav")
|
||||
@@ -860,7 +864,9 @@ def index():
|
||||
volume_greeting=volume_greeting,
|
||||
volume_button=volume_button,
|
||||
volume_beep=volume_beep,
|
||||
greeting_delay=greeting_delay)
|
||||
greeting_delay=greeting_delay,
|
||||
sort_by=sort_by,
|
||||
sort_order=sort_order)
|
||||
|
||||
@app.route('/api/status')
|
||||
def api_status():
|
||||
@@ -1221,15 +1227,20 @@ def get_greetings():
|
||||
})
|
||||
return greetings
|
||||
|
||||
def get_recordings():
|
||||
"""Get list of all recordings with metadata"""
|
||||
def get_recordings(sort_by='date', sort_order='desc'):
|
||||
"""Get list of all recordings with metadata
|
||||
|
||||
Args:
|
||||
sort_by: Sort field - 'date', 'name', 'duration', or 'size'
|
||||
sort_order: Sort order - 'asc' or 'desc'
|
||||
"""
|
||||
recordings = []
|
||||
if os.path.exists(OUTPUT_DIR):
|
||||
for filename in sorted(os.listdir(OUTPUT_DIR), reverse=True):
|
||||
for filename in os.listdir(OUTPUT_DIR):
|
||||
if filename.endswith('.wav'):
|
||||
filepath = os.path.join(OUTPUT_DIR, filename)
|
||||
stat = os.stat(filepath)
|
||||
|
||||
|
||||
# Get duration from WAV file
|
||||
try:
|
||||
wf = wave.open(filepath, 'rb')
|
||||
@@ -1239,14 +1250,28 @@ def get_recordings():
|
||||
wf.close()
|
||||
except:
|
||||
duration = 0
|
||||
|
||||
|
||||
recordings.append({
|
||||
"filename": filename,
|
||||
"size": stat.st_size,
|
||||
"size_mb": stat.st_size / (1024 * 1024),
|
||||
"date": datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M:%S'),
|
||||
"timestamp": stat.st_mtime, # For sorting
|
||||
"duration": duration
|
||||
})
|
||||
|
||||
# Sort recordings based on parameters
|
||||
reverse = (sort_order == 'desc')
|
||||
|
||||
if sort_by == 'name':
|
||||
recordings.sort(key=lambda x: x['filename'].lower(), reverse=reverse)
|
||||
elif sort_by == 'duration':
|
||||
recordings.sort(key=lambda x: x['duration'], reverse=reverse)
|
||||
elif sort_by == 'size':
|
||||
recordings.sort(key=lambda x: x['size'], reverse=reverse)
|
||||
else: # default to date
|
||||
recordings.sort(key=lambda x: x['timestamp'], reverse=reverse)
|
||||
|
||||
return recordings
|
||||
|
||||
def get_local_ip():
|
||||
@@ -1995,6 +2020,23 @@ def main():
|
||||
</div>
|
||||
|
||||
{% if recordings %}
|
||||
<!-- Sort Controls -->
|
||||
<div style="margin-bottom: 20px; padding: 15px; background: #f9fafb; border-radius: 8px; border: 1px solid #e5e7eb;">
|
||||
<div style="display: flex; align-items: center; gap: 15px; flex-wrap: wrap;">
|
||||
<span style="font-weight: 600; color: #374151;">🔄 Sort by:</span>
|
||||
<select id="sort-by" onchange="updateSort()" style="padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; background: white; cursor: pointer; font-size: 0.95em;">
|
||||
<option value="date" {% if sort_by == 'date' %}selected{% endif %}>📅 Date</option>
|
||||
<option value="name" {% if sort_by == 'name' %}selected{% endif %}>📝 Name</option>
|
||||
<option value="duration" {% if sort_by == 'duration' %}selected{% endif %}>⏱️ Duration</option>
|
||||
<option value="size" {% if sort_by == 'size' %}selected{% endif %}>💾 Size</option>
|
||||
</select>
|
||||
<select id="sort-order" onchange="updateSort()" style="padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; background: white; cursor: pointer; font-size: 0.95em;">
|
||||
<option value="desc" {% if sort_order == 'desc' %}selected{% endif %}>⬇️ Descending</option>
|
||||
<option value="asc" {% if sort_order == 'asc' %}selected{% endif %}>⬆️ Ascending</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats">
|
||||
<div class="stat-box">
|
||||
<div class="stat-value">{{ recordings|length }}</div>
|
||||
@@ -2242,6 +2284,12 @@ def main():
|
||||
window.location.href = '/download_all';
|
||||
}
|
||||
|
||||
function updateSort() {
|
||||
const sortBy = document.getElementById('sort-by').value;
|
||||
const sortOrder = document.getElementById('sort-order').value;
|
||||
window.location.href = `/?sort=${sortBy}&order=${sortOrder}`;
|
||||
}
|
||||
|
||||
function deleteRecording(filename, index) {
|
||||
if (confirm('Delete this recording?')) {
|
||||
fetch('/delete/' + filename, { method: 'POST' })
|
||||
|
||||
Reference in New Issue
Block a user