From 4167c361a79b0c7bd168bf3eb9dd6ea83ef09360 Mon Sep 17 00:00:00 2001 From: Broque Thomas Date: Sun, 28 Sep 2025 19:51:29 -0700 Subject: [PATCH] beatport progress --- webui/index.html | 34 ++++ webui/static/script.js | 382 +++++++++++++++++++++++++++++++++++++++++ webui/static/style.css | 6 +- 3 files changed, 420 insertions(+), 2 deletions(-) diff --git a/webui/index.html b/webui/index.html index e1cc28a7..9ffb73f4 100644 --- a/webui/index.html +++ b/webui/index.html @@ -510,6 +510,40 @@ + + +
+

🎧 DJ Charts Collection

+

DJ curated chart collections

+ + +
+
+
+

Loading DJ chart collections...

+
+
+ +
+
+
+ + + diff --git a/webui/static/script.js b/webui/static/script.js index e0fed4e3..0559d418 100644 --- a/webui/static/script.js +++ b/webui/static/script.js @@ -9746,6 +9746,10 @@ function initializeSyncPage() { // Setup homepage chart handlers (following genre page pattern to prevent duplicates) setupHomepageChartTypeHandlers(); + // Load homepage chart collections automatically + loadDJChartsInline(); + loadFeaturedChartsInline(); + // Logic for Beatport breadcrumb back buttons const beatportBackButtons = document.querySelectorAll('.breadcrumb-back'); beatportBackButtons.forEach(button => { @@ -11588,6 +11592,384 @@ async function loadNewChartsInline(genreSlug, genreId, genreName) { } } +async function loadDJChartsInline() { + const chartsGrid = document.getElementById('dj-charts-grid'); + const loadingInline = document.getElementById('dj-charts-loading-inline'); + + if (!chartsGrid || !loadingInline) { + console.error('❌ DJ charts elements not found'); + return; + } + + // Show loading state + loadingInline.style.display = 'block'; + chartsGrid.style.display = 'none'; + chartsGrid.innerHTML = ''; + + try { + console.log('🔍 Loading DJ charts...'); + + // Fetch charts from the dj-charts-improved endpoint + const response = await fetch('/api/beatport/dj-charts-improved?limit=20'); + if (!response.ok) { + throw new Error(`Failed to fetch DJ charts: ${response.status}`); + } + + const data = await response.json(); + if (!data.success || !data.tracks || data.tracks.length === 0) { + // Show empty state + chartsGrid.innerHTML = ` +
+

No DJ Charts Available

+

No DJ curated charts found at the moment.

+
+ `; + loadingInline.style.display = 'none'; + chartsGrid.style.display = 'grid'; + return; + } + + // Create chart items using New Charts structure + const chartsHTML = data.tracks.map(chart => { + const chartName = chart.name || chart.title || 'Untitled Chart'; + const artistName = chart.artist || chart.curator || 'Various Artists'; + const chartUrl = chart.url || chart.chart_url || ''; + + return ` +
+
+
🎧
+
+
${chartName}
+

by ${artistName}

+
+
+
+ DJ curated chart collection +
+ +
+ `; + }).join(''); + + chartsGrid.innerHTML = chartsHTML; + + // Hide loading, show content + loadingInline.style.display = 'none'; + chartsGrid.style.display = 'grid'; + + // Setup click handlers for chart items + setupDJChartItemHandlers(); + + console.log(`✅ Loaded ${data.tracks.length} DJ charts`); + + } catch (error) { + console.error('❌ Error loading DJ charts:', error); + + // Show error state + chartsGrid.innerHTML = ` +
+

Error Loading DJ Charts

+

Unable to load DJ chart collections.

+
+ `; + + loadingInline.style.display = 'none'; + chartsGrid.style.display = 'grid'; + + showToast(`Error loading DJ charts: ${error.message}`, 'error'); + } +} + +async function loadFeaturedChartsInline() { + const chartsGrid = document.getElementById('featured-charts-grid'); + const loadingInline = document.getElementById('featured-charts-loading-inline'); + + if (!chartsGrid || !loadingInline) { + console.error('❌ Featured charts elements not found'); + return; + } + + // Show loading state + loadingInline.style.display = 'block'; + chartsGrid.style.display = 'none'; + chartsGrid.innerHTML = ''; + + try { + console.log('🔍 Loading Featured charts...'); + + // Fetch charts from the homepage/featured-charts endpoint + const response = await fetch('/api/beatport/homepage/featured-charts?limit=20'); + if (!response.ok) { + throw new Error(`Failed to fetch Featured charts: ${response.status}`); + } + + const data = await response.json(); + if (!data.success || !data.tracks || data.tracks.length === 0) { + // Show empty state + chartsGrid.innerHTML = ` +
+

No Featured Charts Available

+

No featured curated charts found at the moment.

+
+ `; + loadingInline.style.display = 'none'; + chartsGrid.style.display = 'grid'; + return; + } + + // Create chart items using New Charts structure + const chartsHTML = data.tracks.map(chart => { + const chartName = chart.name || chart.title || 'Untitled Chart'; + const artistName = chart.artist || chart.curator || 'Various Artists'; + const chartUrl = chart.url || chart.chart_url || ''; + + return ` +
+
+
+
+
${chartName}
+

by ${artistName}

+
+
+
+ Editor curated chart collection +
+ +
+ `; + }).join(''); + + chartsGrid.innerHTML = chartsHTML; + + // Hide loading, show content + loadingInline.style.display = 'none'; + chartsGrid.style.display = 'grid'; + + // Setup click handlers for chart items + setupFeaturedChartItemHandlers(); + + console.log(`✅ Loaded ${data.tracks.length} Featured charts`); + + } catch (error) { + console.error('❌ Error loading Featured charts:', error); + + // Show error state + chartsGrid.innerHTML = ` +
+

Error Loading Featured Charts

+

Unable to load featured chart collections.

+
+ `; + + loadingInline.style.display = 'none'; + chartsGrid.style.display = 'grid'; + + showToast(`Error loading Featured charts: ${error.message}`, 'error'); + } +} + +function setupDJChartItemHandlers() { + const chartItems = document.querySelectorAll('#dj-charts-grid .new-chart-item'); + + chartItems.forEach(item => { + item.addEventListener('click', async () => { + const chartName = item.dataset.chartName; + const chartUrl = item.dataset.chartUrl; + + console.log(`🎧 DJ Chart clicked: ${chartName}`); + + // Check if state already exists by name and type (follow same pattern as homepage Beatport cards) + const existingState = Object.values(beatportChartStates).find(state => + state.chart && state.chart.name === chartName && state.chart.chart_type === 'dj-chart' + ); + + if (existingState) { + console.log(`🔄 Found existing DJ chart state for ${chartName}, opening existing modal`); + handleBeatportCardClick(existingState.chart.hash); + return; + } + + try { + showToast(`Loading ${chartName}...`, 'info'); + + // Extract tracks from the DJ chart + const response = await fetch('/api/beatport/chart/extract', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + chart_url: chartUrl, + chart_name: chartName, + limit: 100 + }) + }); + + if (!response.ok) { + throw new Error(`Failed to extract chart tracks: ${response.status}`); + } + + const data = await response.json(); + if (data.success && data.tracks && data.tracks.length > 0) { + console.log(`✅ Extracted ${data.tracks.length} tracks from DJ chart: ${chartName}`); + + // Generate a unique hash for state management (following homepage pattern) + const chartHash = `dj_chart_${Date.now()}`; + + // Create chart data in the format expected by the state system + const chartData = { + hash: chartHash, + name: chartName, + chart_type: 'dj-chart', + track_count: data.tracks.length, + tracks: data.tracks.map(track => ({ + name: track.title || 'Unknown Title', + artists: [track.artist || 'Unknown Artist'], + album: chartName, + duration_ms: 0, + external_urls: { spotify: null }, + preview_url: null, + popularity: 0, + explicit: false, + track_number: track.position || 1, + disc_number: 1, + id: `dj_chart_${chartHash}_${track.position || Math.random()}`, + uri: null, + type: 'track', + is_local: false, + source: 'beatport_dj_chart' + })) + }; + + // Create state in beatportChartStates (follow same pattern as other Beatport cards) + beatportChartStates[chartHash] = { + chart: chartData, + phase: 'fresh', + cardElement: null, // Will be set when actual card is created + discovery_results: [], + discoveryProgress: 0 + }; + + // Use the same click handler as other Beatport cards + handleBeatportCardClick(chartHash); + + } else { + throw new Error('No tracks found in chart'); + } + + } catch (error) { + console.error('❌ Error extracting DJ chart tracks:', error); + showToast(`Error loading chart: ${error.message}`, 'error'); + } + }); + }); +} + +function setupFeaturedChartItemHandlers() { + const chartItems = document.querySelectorAll('#featured-charts-grid .new-chart-item'); + + chartItems.forEach(item => { + item.addEventListener('click', async () => { + const chartName = item.dataset.chartName; + const chartUrl = item.dataset.chartUrl; + + console.log(`⭐ Featured Chart clicked: ${chartName}`); + + // Check if state already exists by name and type (follow same pattern as homepage Beatport cards) + const existingState = Object.values(beatportChartStates).find(state => + state.chart && state.chart.name === chartName && state.chart.chart_type === 'featured-chart' + ); + + if (existingState) { + console.log(`🔄 Found existing Featured chart state for ${chartName}, opening existing modal`); + handleBeatportCardClick(existingState.chart.hash); + return; + } + + try { + showToast(`Loading ${chartName}...`, 'info'); + + // Extract tracks from the Featured chart + const response = await fetch('/api/beatport/chart/extract', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + chart_url: chartUrl, + chart_name: chartName, + limit: 100 + }) + }); + + if (!response.ok) { + throw new Error(`Failed to extract chart tracks: ${response.status}`); + } + + const data = await response.json(); + if (data.success && data.tracks && data.tracks.length > 0) { + console.log(`✅ Extracted ${data.tracks.length} tracks from Featured chart: ${chartName}`); + + // Generate a unique hash for state management (following homepage pattern) + const chartHash = `featured_chart_${Date.now()}`; + + // Create chart data in the format expected by the state system + const chartData = { + hash: chartHash, + name: chartName, + chart_type: 'featured-chart', + track_count: data.tracks.length, + tracks: data.tracks.map(track => ({ + name: track.title || 'Unknown Title', + artists: [track.artist || 'Unknown Artist'], + album: chartName, + duration_ms: 0, + external_urls: { spotify: null }, + preview_url: null, + popularity: 0, + explicit: false, + track_number: track.position || 1, + disc_number: 1, + id: `featured_chart_${chartHash}_${track.position || Math.random()}`, + uri: null, + type: 'track', + is_local: false, + source: 'beatport_featured_chart' + })) + }; + + // Create state in beatportChartStates (follow same pattern as other Beatport cards) + beatportChartStates[chartHash] = { + chart: chartData, + phase: 'fresh', + cardElement: null, // Will be set when actual card is created + discovery_results: [], + discoveryProgress: 0 + }; + + // Use the same click handler as other Beatport cards + handleBeatportCardClick(chartHash); + + } else { + throw new Error('No tracks found in chart'); + } + + } catch (error) { + console.error('❌ Error extracting Featured chart tracks:', error); + showToast(`Error loading chart: ${error.message}`, 'error'); + } + }); + }); +} + function setupNewChartItemHandlers(genreSlug, genreId, genreName) { const chartItems = document.querySelectorAll('#new-charts-grid .new-chart-item'); diff --git a/webui/static/style.css b/webui/static/style.css index 5d6e95bb..df8e4ab3 100644 --- a/webui/static/style.css +++ b/webui/static/style.css @@ -5180,9 +5180,11 @@ body { margin: 0; } -.new-charts-grid { +.new-charts-grid, +.dj-charts-grid, +.featured-charts-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + grid-template-columns: repeat(4, 1fr); gap: 16px; }