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);