From 8ba158564665875e3c213b6cf48f23d30345acc8 Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Sun, 5 Apr 2026 13:15:24 -0700 Subject: [PATCH] Paginate wishlist modal to prevent browser crash on large wishlists (5K+) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initial load fetches 200 tracks instead of all. "Load More" button at bottom shows (200 of 5,000) and loads next batch on click. Backend now returns total count alongside limited results for both album and singles categories. Rendering logic unchanged — just operates on smaller sets. --- web_server.py | 10 +++++++--- webui/static/script.js | 26 +++++++++++++++++++++++++- webui/static/style.css | 24 ++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/web_server.py b/web_server.py index 833c3080..8c6884c7 100644 --- a/web_server.py +++ b/web_server.py @@ -23189,12 +23189,16 @@ def get_wishlist_tracks(): if limit and len(filtered_tracks) >= limit: break - print(f"📊 Wishlist filter: {len(filtered_tracks)}/{len(sanitized_tracks)} tracks in '{category}' category (limit: {limit or 'none'})") - return jsonify({"tracks": filtered_tracks, "category": category}) + # Count total in category (quick scan — no heavy processing, just classification) + total_in_category = sum(1 for t in sanitized_tracks if _classify_wishlist_track(t) == category) + + print(f"📊 Wishlist filter: {len(filtered_tracks)}/{total_in_category} tracks in '{category}' category (limit: {limit or 'none'})") + return jsonify({"tracks": filtered_tracks, "category": category, "total": total_in_category}) # Apply limit to non-filtered results + total_count = len(sanitized_tracks) result_tracks = sanitized_tracks[:limit] if limit else sanitized_tracks - return jsonify({"tracks": result_tracks}) + return jsonify({"tracks": result_tracks, "total": total_count}) except Exception as e: print(f"Error getting wishlist tracks: {e}") return jsonify({"error": str(e)}), 500 diff --git a/webui/static/script.js b/webui/static/script.js index db86e2cf..56c5d5f5 100644 --- a/webui/static/script.js +++ b/webui/static/script.js @@ -13201,12 +13201,18 @@ async function selectWishlistCategory(category) { tracksList.innerHTML = '
Loading tracks...
'; - const response = await fetch(`/api/wishlist/tracks?category=${category}`); + const _wlPageSize = window._wlNextLimit || 200; + window._wlNextLimit = null; + const response = await fetch(`/api/wishlist/tracks?category=${category}&limit=${_wlPageSize}`); const data = await response.json(); if (!response.ok) throw new Error(data.error || 'Failed to fetch tracks'); const tracks = data.tracks || []; + const totalAvailable = data.total || tracks.length; + window._wlCategory = category; + window._wlOffset = tracks.length; + window._wlTotal = totalAvailable; if (tracks.length === 0) { tracksList.innerHTML = '
No tracks in this category
'; @@ -13333,6 +13339,10 @@ async function selectWishlistCategory(category) { albumsHTML += ''; tracksList.innerHTML = albumsHTML; + if (totalAvailable > tracks.length) { + tracksList.insertAdjacentHTML('beforeend', + ``); + } _attachWishlistDelegation(tracksList); } else { @@ -13393,6 +13403,10 @@ async function selectWishlistCategory(category) { }); tracksList.innerHTML = tracksHTML; + if (totalAvailable > tracks.length) { + tracksList.insertAdjacentHTML('beforeend', + ``); + } _attachWishlistDelegation(tracksList); } @@ -13402,6 +13416,16 @@ async function selectWishlistCategory(category) { } } +async function loadMoreWishlistTracks() { + const btn = document.querySelector('.wishlist-load-more-btn'); + if (btn) { btn.textContent = 'Loading...'; btn.disabled = true; } + // Increase page size and reload + window._wlOffset = (window._wlOffset || 200) + 200; + // Override the page size for this reload + window._wlNextLimit = window._wlOffset; + selectWishlistCategory(window._wlCategory); +} + function _attachWishlistDelegation(container) { // Single click handler for all wishlist album/track interactions container.addEventListener('click', (e) => { diff --git a/webui/static/style.css b/webui/static/style.css index c3e6e36d..bda61fca 100644 --- a/webui/static/style.css +++ b/webui/static/style.css @@ -16298,6 +16298,30 @@ body.helper-mode-active #dashboard-activity-feed:hover { padding: 8px 0; } +.wishlist-load-more-btn { + display: block; + width: 100%; + padding: 12px; + margin-top: 12px; + background: rgba(138, 43, 226, 0.1); + border: 1px solid rgba(138, 43, 226, 0.3); + color: rgba(255, 255, 255, 0.7); + border-radius: 8px; + cursor: pointer; + font-size: 13px; + transition: all 0.2s; +} + +.wishlist-load-more-btn:hover { + background: rgba(138, 43, 226, 0.2); + color: #fff; +} + +.wishlist-load-more-btn:disabled { + opacity: 0.5; + cursor: wait; +} + .wishlist-album-card { background: linear-gradient(135deg, rgba(26, 26, 26, 0.95) 0%, rgba(18, 18, 18, 0.98) 100%); border: 1px solid rgba(255, 255, 255, 0.08);