From c279f2e4fa330636ff87f22e96f2872a69f249a4 Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Sun, 1 Mar 2026 22:52:27 -0800 Subject: [PATCH] Design retag layout --- database/music_database.py | 15 ++ web_server.py | 23 ++ webui/index.html | 13 +- webui/static/mobile.css | 44 ++++ webui/static/script.js | 174 ++++++++++++++- webui/static/style.css | 418 +++++++++++++++++++++++++++++-------- 6 files changed, 589 insertions(+), 98 deletions(-) diff --git a/database/music_database.py b/database/music_database.py index c166f0c4..ef2dadda 100644 --- a/database/music_database.py +++ b/database/music_database.py @@ -5311,6 +5311,21 @@ class MusicDatabase: logger.error(f"Error deleting retag group: {e}") return False + def delete_all_retag_groups(self) -> int: + """Delete all retag groups and tracks. Returns count deleted.""" + try: + conn = self._get_connection() + cursor = conn.cursor() + cursor.execute("SELECT COUNT(*) FROM retag_groups") + count = cursor.fetchone()[0] + cursor.execute("DELETE FROM retag_tracks") + cursor.execute("DELETE FROM retag_groups") + conn.commit() + return count + except Exception as e: + logger.error(f"Error clearing all retag groups: {e}") + return 0 + # Thread-safe singleton pattern for database access _database_instances: Dict[int, MusicDatabase] = {} # Thread ID -> Database instance _database_lock = threading.Lock() diff --git a/web_server.py b/web_server.py index 719a5d49..62b762f8 100644 --- a/web_server.py +++ b/web_server.py @@ -14211,6 +14211,29 @@ def delete_retag_group(group_id): else: return jsonify({"success": False, "error": "Group not found"}), 404 +@app.route('/api/retag/groups/delete-batch', methods=['POST']) +def delete_retag_groups_batch(): + """Delete multiple retag groups at once.""" + from database.music_database import get_database + data = request.get_json() or {} + group_ids = data.get('group_ids', []) + if not group_ids: + return jsonify({"success": False, "error": "No group IDs provided"}), 400 + db = get_database() + removed = 0 + for gid in group_ids: + if db.delete_retag_group(int(gid)): + removed += 1 + return jsonify({"success": True, "removed": removed}) + +@app.route('/api/retag/groups/clear-all', methods=['POST']) +def clear_all_retag_groups(): + """Delete all retag groups.""" + from database.music_database import get_database + db = get_database() + count = db.delete_all_retag_groups() + return jsonify({"success": True, "removed": count}) + # =============================== # == DOWNLOAD MISSING TRACKS == # =============================== diff --git a/webui/index.html b/webui/index.html index b7468c6c..bad8ea61 100644 --- a/webui/index.html +++ b/webui/index.html @@ -4250,8 +4250,17 @@
-

Retag Tool

- +
+

Retag Tool

+
+
+ + +
+
+
Loading downloads...
diff --git a/webui/static/mobile.css b/webui/static/mobile.css index 330f5fd8..dcfe8471 100644 --- a/webui/static/mobile.css +++ b/webui/static/mobile.css @@ -1442,6 +1442,50 @@ padding: 0 16px; } + /* Retag modal on mobile — fullscreen */ + .retag-modal-container { + max-width: 100vw; + width: 100vw; + max-height: 100vh; + border-radius: 0; + } + + .retag-modal-header { + padding: 16px; + flex-wrap: wrap; + gap: 8px; + } + + .retag-modal-body { + padding: 16px; + } + + .retag-batch-bar { + margin: 0 16px 12px; + } + + .retag-group-header { + padding: 12px; + gap: 10px; + } + + .retag-group-image, + .retag-group-image-placeholder { + width: 44px; + height: 44px; + } + + .retag-group-album { + font-size: 13px; + } + + .retag-search-container { + max-width: 100vw; + width: 100vw; + max-height: 100vh; + border-radius: 0; + } + /* Watchlist live activity - stack on mobile */ #watchlist-live-activity { flex-direction: column; diff --git a/webui/static/script.js b/webui/static/script.js index c697d6cd..e4dc8610 100644 --- a/webui/static/script.js +++ b/webui/static/script.js @@ -14503,6 +14503,12 @@ async function openRetagModal() { modal.style.display = 'flex'; document.body.style.overflow = 'hidden'; + // Reset batch bar and clear-all button + const batchBar = document.getElementById('retag-batch-bar'); + if (batchBar) batchBar.style.display = 'none'; + const clearBtn = document.getElementById('retag-clear-all-btn'); + if (clearBtn) { clearBtn.textContent = 'Clear All'; clearBtn.dataset.confirming = ''; clearBtn.style.background = ''; } + const body = document.getElementById('retag-modal-body'); body.innerHTML = '
Loading downloads...
'; @@ -14511,8 +14517,10 @@ async function openRetagModal() { const data = await response.json(); if (!data.success || !data.groups || data.groups.length === 0) { body.innerHTML = '

No downloads recorded yet. Downloads will appear here after completing album or single downloads.

'; + if (clearBtn) clearBtn.style.display = 'none'; return; } + if (clearBtn) clearBtn.style.display = ''; renderRetagGroups(data.groups, body); } catch (e) { body.innerHTML = '

Failed to load downloads.

'; @@ -14551,13 +14559,19 @@ function renderRetagGroups(groups, container) { html += `
+ ${imgHtml}
${escapeHtml(group.album_name || 'Unknown')} ${typeLabel}${releaseDate ? ' \u00b7 ' + releaseDate : ''} \u00b7 ${trackCount} track${trackCount !== 1 ? 's' : ''}
- +
+ +