`;
sliderTrack.insertAdjacentHTML('beforeend', slideHtml);
console.log(`π₯ Created slide ${slideIndex + 1}/${slides.length} with ${slideReleases.length} releases`);
// Create indicator
const indicatorHtml = ``;
indicatorsContainer.insertAdjacentHTML('beforeend', indicatorHtml);
});
// Add click handlers to track cards
setupBeatportHypePickCardHandlers();
}
/**
* Create a hype pick card HTML (for release cards, same as new releases)
*/
function createBeatportHypePickCard(release) {
const artworkUrl = release.image_url || '';
const bgStyle = artworkUrl ? `style="--card-bg-image: url('${artworkUrl}')"` : '';
return `
${artworkUrl ? `` : ''}
${release.title || 'Unknown Title'}
${release.artist || 'Unknown Artist'}
${release.label || 'Hype Pick'}
`;
}
/**
* Setup navigation for hype picks slider (same pattern as releases)
*/
function setupBeatportHypePicksSliderNavigation() {
const prevBtn = document.getElementById('beatport-hype-picks-prev-btn');
const nextBtn = document.getElementById('beatport-hype-picks-next-btn');
if (prevBtn) {
// Clone button to remove all existing event listeners
const newPrevBtn = prevBtn.cloneNode(true);
prevBtn.parentNode.replaceChild(newPrevBtn, prevBtn);
newPrevBtn.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
console.log('Previous hype picks button clicked, current slide:', beatportHypePicksSliderState.currentSlide);
goToBeatportHypePicksSlide(beatportHypePicksSliderState.currentSlide - 1);
resetBeatportHypePicksSliderAutoPlay();
});
}
if (nextBtn) {
// Clone button to remove all existing event listeners
const newNextBtn = nextBtn.cloneNode(true);
nextBtn.parentNode.replaceChild(newNextBtn, nextBtn);
newNextBtn.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
console.log('Next hype picks button clicked, current slide:', beatportHypePicksSliderState.currentSlide);
goToBeatportHypePicksSlide(beatportHypePicksSliderState.currentSlide + 1);
resetBeatportHypePicksSliderAutoPlay();
});
}
}
/**
* Setup indicators for hype picks slider
*/
function setupBeatportHypePicksSliderIndicators() {
const indicators = document.querySelectorAll('.beatport-hype-picks-indicator');
indicators.forEach((indicator, index) => {
indicator.addEventListener('click', () => {
goToBeatportHypePicksSlide(index);
resetBeatportHypePicksSliderAutoPlay();
});
});
}
/**
* Navigate to specific slide
*/
function goToBeatportHypePicksSlide(slideIndex) {
console.log('goToBeatportHypePicksSlide called with:', slideIndex, 'current:', beatportHypePicksSliderState.currentSlide);
// Handle wrap around
if (slideIndex < 0) {
slideIndex = beatportHypePicksSliderState.totalSlides - 1;
} else if (slideIndex >= beatportHypePicksSliderState.totalSlides) {
slideIndex = 0;
}
// Update current slide
beatportHypePicksSliderState.currentSlide = slideIndex;
// Update slides
const slides = document.querySelectorAll('.beatport-hype-picks-slide');
slides.forEach((slide, index) => {
slide.classList.remove('active', 'prev', 'next');
if (index === slideIndex) {
slide.classList.add('active');
} else if (index < slideIndex) {
slide.classList.add('prev');
} else {
slide.classList.add('next');
}
});
// Update indicators
const indicators = document.querySelectorAll('.beatport-hype-picks-indicator');
indicators.forEach((indicator, index) => {
indicator.classList.toggle('active', index === slideIndex);
});
console.log('Slide updated to:', beatportHypePicksSliderState.currentSlide);
}
/**
* Start auto-play for hype picks slider
*/
function startBeatportHypePicksSliderAutoPlay() {
if (beatportHypePicksSliderState.autoPlayInterval) {
clearInterval(beatportHypePicksSliderState.autoPlayInterval);
}
beatportHypePicksSliderState.autoPlayInterval = setInterval(() => {
goToBeatportHypePicksSlide(beatportHypePicksSliderState.currentSlide + 1);
}, beatportHypePicksSliderState.autoPlayDelay);
console.log('π₯ Hype picks slider autoplay started');
}
/**
* Reset auto-play for hype picks slider
*/
function resetBeatportHypePicksSliderAutoPlay() {
startBeatportHypePicksSliderAutoPlay();
}
/**
* Setup hover pause for hype picks slider
*/
function setupBeatportHypePicksSliderHoverPause() {
const sliderContainer = document.querySelector('.beatport-hype-picks-slider-container');
if (sliderContainer) {
sliderContainer.addEventListener('mouseenter', () => {
if (beatportHypePicksSliderState.autoPlayInterval) {
clearInterval(beatportHypePicksSliderState.autoPlayInterval);
}
});
sliderContainer.addEventListener('mouseleave', () => {
startBeatportHypePicksSliderAutoPlay();
});
}
}
/**
* Setup click handlers for hype pick cards
*/
function setupBeatportHypePickCardHandlers() {
const cards = document.querySelectorAll('.beatport-hype-pick-card:not(.beatport-hype-pick-placeholder)');
cards.forEach(card => {
const releaseUrl = card.getAttribute('data-url');
if (releaseUrl && releaseUrl !== '#' && releaseUrl !== '') {
// Extract release data from the card elements
const titleElement = card.querySelector('.beatport-hype-pick-title');
const artistElement = card.querySelector('.beatport-hype-pick-artist');
const labelElement = card.querySelector('.beatport-hype-pick-label');
const imageElement = card.querySelector('.beatport-hype-pick-artwork img');
const releaseData = {
url: releaseUrl,
title: titleElement ? titleElement.textContent.trim() : 'Unknown Title',
artist: artistElement ? artistElement.textContent.trim() : 'Unknown Artist',
label: labelElement ? labelElement.textContent.trim() : 'Unknown Label',
image_url: imageElement ? imageElement.src : ''
};
card.addEventListener('click', () => handleBeatportReleaseCardClick(card, releaseData));
card.style.cursor = 'pointer';
}
});
}
/**
* Show error state for hype picks slider
*/
function showBeatportHypePicksError(errorMessage) {
const sliderTrack = document.getElementById('beatport-hype-picks-slider-track');
if (sliderTrack) {
sliderTrack.innerHTML = `
β Error Loading Hype Picks
${errorMessage}
`;
}
}
/**
* Clean up hype picks slider when switching away
*/
function cleanupBeatportHypePicksSlider() {
if (beatportHypePicksSliderState.autoPlayInterval) {
clearInterval(beatportHypePicksSliderState.autoPlayInterval);
beatportHypePicksSliderState.autoPlayInterval = null;
}
}
// ===================================
// BEATPORT FEATURED CHARTS SLIDER
// ===================================
// State management for featured charts slider (copied from releases slider)
let beatportChartsSliderState = {
currentSlide: 0,
totalSlides: 0,
autoPlayInterval: null,
autoPlayDelay: 10000, // Slightly longer auto-play for charts
isInitialized: false
};
/**
* Initialize the beatport featured charts slider functionality (based on releases slider)
*/
function initializeBeatportChartsSlider() {
console.log('π₯ Initializing beatport featured charts slider...');
const slider = document.getElementById('beatport-charts-slider');
if (!slider) {
console.warn('Beatport charts slider not found');
return;
}
// Prevent double initialization
if (slider.dataset.initialized === 'true') {
console.log('Charts slider already initialized');
return;
}
const sliderTrack = document.getElementById('beatport-charts-slider-track');
const indicatorsContainer = document.getElementById('beatport-charts-slider-indicators');
if (!sliderTrack || !indicatorsContainer) {
console.warn('Charts slider elements not found');
return;
}
// Load data and initialize
loadBeatportFeaturedCharts().then(success => {
if (success) {
setupBeatportChartsSliderNavigation();
setupBeatportChartsSliderIndicators();
setupBeatportChartsSliderHoverPause();
startBeatportChartsSliderAutoPlay();
slider.dataset.initialized = 'true';
beatportChartsSliderState.isInitialized = true;
console.log('β Featured charts slider initialized successfully');
}
});
}
/**
* Load featured charts data from API
*/
async function loadBeatportFeaturedCharts() {
try {
console.log('π Loading featured charts data...');
const signal = getBeatportContentSignal();
const response = await fetch('/api/beatport/featured-charts', signal ? { signal } : undefined);
const data = await response.json();
if (data.success && data.charts && data.charts.length > 0) {
console.log(`π Loaded ${data.charts.length} featured charts`);
createBeatportChartsSlides(data.charts);
return true;
} else {
console.warn('No featured charts data available');
return false;
}
} catch (error) {
if (error && error.name === 'AbortError') return false;
console.error('β Error loading featured charts:', error);
return false;
}
}
/**
* Create chart slides with grid layout (copied from releases slider)
*/
function createBeatportChartsSlides(charts) {
const sliderTrack = document.getElementById('beatport-charts-slider-track');
const indicatorsContainer = document.getElementById('beatport-charts-slider-indicators');
if (!sliderTrack || !indicatorsContainer) {
console.error('Charts slider elements not found');
return;
}
const cardsPerSlide = 10; // 5x2 grid
const totalSlides = Math.ceil(charts.length / cardsPerSlide);
// Clear existing content
sliderTrack.innerHTML = '';
indicatorsContainer.innerHTML = '';
// Update state
beatportChartsSliderState.totalSlides = totalSlides;
beatportChartsSliderState.currentSlide = 0;
console.log(`π― Creating ${totalSlides} chart slides with ${cardsPerSlide} cards each`);
// Generate slides HTML
for (let slideIndex = 0; slideIndex < totalSlides; slideIndex++) {
const startIndex = slideIndex * cardsPerSlide;
const endIndex = Math.min(startIndex + cardsPerSlide, charts.length);
const slideCharts = charts.slice(startIndex, endIndex);
// Create grid HTML for this slide
const gridHtml = slideCharts.map(chart => {
const bgImageStyle = chart.image ? `--chart-bg-image: url('${chart.image}')` : '';
return `
${chart.name || 'Unknown Chart'}
${chart.creator || 'Unknown Creator'}
`;
}).join('');
// Create slide HTML
const slideHtml = `
${gridHtml}
`;
sliderTrack.innerHTML += slideHtml;
// Create indicator
const indicatorHtml = ``;
indicatorsContainer.innerHTML += indicatorHtml;
}
console.log(`β Created ${totalSlides} chart slides`);
// Add click handlers for individual chart discovery (matching chart pattern)
const chartCards = sliderTrack.querySelectorAll('.beatport-chart-card[data-url]');
chartCards.forEach((card) => {
const chartUrl = card.getAttribute('data-url');
if (chartUrl && chartUrl !== '') {
// Find the corresponding chart data
const chartData = charts.find(chart => chart.url === chartUrl);
if (chartData) {
card.addEventListener('click', () => handleBeatportChartCardClick(card, chartData));
card.style.cursor = 'pointer';
}
}
});
}
/**
* Set up navigation functionality (copied from releases slider with button cloning)
*/
function setupBeatportChartsSliderNavigation() {
const prevBtn = document.getElementById('beatport-charts-prev-btn');
const nextBtn = document.getElementById('beatport-charts-next-btn');
if (prevBtn) {
// Clone button to remove all existing event listeners
const newPrevBtn = prevBtn.cloneNode(true);
prevBtn.parentNode.replaceChild(newPrevBtn, prevBtn);
newPrevBtn.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
console.log('Previous charts button clicked, current slide:', beatportChartsSliderState.currentSlide);
goToBeatportChartsSlide(beatportChartsSliderState.currentSlide - 1);
resetBeatportChartsSliderAutoPlay();
});
}
if (nextBtn) {
// Clone button to remove all existing event listeners
const newNextBtn = nextBtn.cloneNode(true);
nextBtn.parentNode.replaceChild(newNextBtn, nextBtn);
newNextBtn.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
console.log('Next charts button clicked, current slide:', beatportChartsSliderState.currentSlide);
goToBeatportChartsSlide(beatportChartsSliderState.currentSlide + 1);
resetBeatportChartsSliderAutoPlay();
});
}
}
/**
* Set up indicator functionality (copied from releases slider)
*/
function setupBeatportChartsSliderIndicators() {
const indicators = document.querySelectorAll('.beatport-charts-indicator');
indicators.forEach((indicator, index) => {
indicator.addEventListener('click', () => {
goToBeatportChartsSlide(index);
resetBeatportChartsSliderAutoPlay();
});
});
}
/**
* Navigate to a specific slide (copied from releases slider)
*/
function goToBeatportChartsSlide(slideIndex) {
console.log('goToBeatportChartsSlide called with:', slideIndex, 'current:', beatportChartsSliderState.currentSlide);
// Wrap around if out of bounds
if (slideIndex < 0) {
slideIndex = beatportChartsSliderState.totalSlides - 1;
} else if (slideIndex >= beatportChartsSliderState.totalSlides) {
slideIndex = 0;
}
console.log('After wrapping, slideIndex:', slideIndex);
// Update current slide
beatportChartsSliderState.currentSlide = slideIndex;
// Update slide visibility
const slides = document.querySelectorAll('.beatport-charts-slide');
slides.forEach((slide, index) => {
slide.classList.remove('active', 'prev', 'next');
if (index === slideIndex) {
slide.classList.add('active');
} else if (index < slideIndex) {
slide.classList.add('prev');
} else {
slide.classList.add('next');
}
});
// Update indicators
const indicators = document.querySelectorAll('.beatport-charts-indicator');
indicators.forEach((indicator, index) => {
indicator.classList.toggle('active', index === slideIndex);
});
console.log('Charts slide updated to:', beatportChartsSliderState.currentSlide);
}
/**
* Start auto-play functionality (copied from releases slider)
*/
function startBeatportChartsSliderAutoPlay() {
if (beatportChartsSliderState.autoPlayInterval) {
clearInterval(beatportChartsSliderState.autoPlayInterval);
}
beatportChartsSliderState.autoPlayInterval = setInterval(() => {
goToBeatportChartsSlide(beatportChartsSliderState.currentSlide + 1);
}, beatportChartsSliderState.autoPlayDelay);
}
/**
* Reset auto-play timer (copied from releases slider)
*/
function resetBeatportChartsSliderAutoPlay() {
startBeatportChartsSliderAutoPlay();
}
/**
* Set up hover pause functionality (copied from releases slider)
*/
function setupBeatportChartsSliderHoverPause() {
const sliderContainer = document.querySelector('.beatport-charts-slider-container');
if (sliderContainer) {
sliderContainer.addEventListener('mouseenter', () => {
if (beatportChartsSliderState.autoPlayInterval) {
clearInterval(beatportChartsSliderState.autoPlayInterval);
beatportChartsSliderState.autoPlayInterval = null;
}
});
sliderContainer.addEventListener('mouseleave', () => {
startBeatportChartsSliderAutoPlay();
});
}
}
/**
* Clean up charts slider when switching away (copied from releases slider)
*/
function cleanupBeatportChartsSlider() {
if (beatportChartsSliderState.autoPlayInterval) {
clearInterval(beatportChartsSliderState.autoPlayInterval);
beatportChartsSliderState.autoPlayInterval = null;
}
}
// ===================================
// BEATPORT DJ CHARTS SLIDER
// ===================================
// State management for DJ charts slider (3 cards per slide)
let beatportDJSliderState = {
currentSlide: 0,
totalSlides: 0,
autoPlayInterval: null,
autoPlayDelay: 12000, // Longer auto-play for DJ charts
isInitialized: false
};
/**
* Initialize the beatport DJ charts slider functionality (based on charts slider)
*/
function initializeBeatportDJSlider() {
console.log('π§ Initializing beatport DJ charts slider...');
const slider = document.getElementById('beatport-dj-slider');
if (!slider) {
console.warn('Beatport DJ slider not found');
return;
}
// Prevent double initialization
if (slider.dataset.initialized === 'true') {
console.log('DJ slider already initialized');
return;
}
const sliderTrack = document.getElementById('beatport-dj-slider-track');
const indicatorsContainer = document.getElementById('beatport-dj-slider-indicators');
if (!sliderTrack || !indicatorsContainer) {
console.warn('DJ slider elements not found');
return;
}
// Load data and initialize
loadBeatportDJCharts().then(success => {
if (success) {
setupBeatportDJSliderNavigation();
setupBeatportDJSliderIndicators();
setupBeatportDJSliderHoverPause();
startBeatportDJSliderAutoPlay();
slider.dataset.initialized = 'true';
beatportDJSliderState.isInitialized = true;
console.log('β DJ charts slider initialized successfully');
}
});
}
/**
* Load DJ charts data from API
*/
async function loadBeatportDJCharts() {
try {
console.log('π§ Loading DJ charts data...');
const signal = getBeatportContentSignal();
const response = await fetch('/api/beatport/dj-charts', signal ? { signal } : undefined);
const data = await response.json();
if (data.success && data.charts && data.charts.length > 0) {
console.log(`π Loaded ${data.charts.length} DJ charts`);
createBeatportDJSlides(data.charts);
return true;
} else {
console.warn('No DJ charts data available');
return false;
}
} catch (error) {
if (error && error.name === 'AbortError') return false;
console.error('β Error loading DJ charts:', error);
return false;
}
}
/**
* Create DJ chart slides with 3 cards per slide layout
*/
function createBeatportDJSlides(charts) {
const sliderTrack = document.getElementById('beatport-dj-slider-track');
const indicatorsContainer = document.getElementById('beatport-dj-slider-indicators');
if (!sliderTrack || !indicatorsContainer) {
console.error('DJ slider elements not found');
return;
}
const cardsPerSlide = 3; // 3 cards per slide for DJ charts
const totalSlides = Math.ceil(charts.length / cardsPerSlide);
// Clear existing content
sliderTrack.innerHTML = '';
indicatorsContainer.innerHTML = '';
// Update state
beatportDJSliderState.totalSlides = totalSlides;
beatportDJSliderState.currentSlide = 0;
console.log(`π― Creating ${totalSlides} DJ chart slides with ${cardsPerSlide} cards each`);
// Generate slides HTML
for (let slideIndex = 0; slideIndex < totalSlides; slideIndex++) {
const startIndex = slideIndex * cardsPerSlide;
const endIndex = Math.min(startIndex + cardsPerSlide, charts.length);
const slideCharts = charts.slice(startIndex, endIndex);
// Create grid HTML for this slide
const gridHtml = slideCharts.map(chart => {
const bgImageStyle = chart.image ? `--dj-bg-image: url('${chart.image}')` : '';
return `
${chart.name || 'Unknown Chart'}
${chart.creator || 'Unknown Creator'}
`;
}).join('');
// Create slide HTML
const slideHtml = `
${gridHtml}
`;
sliderTrack.innerHTML += slideHtml;
// Create indicator
const indicatorHtml = ``;
indicatorsContainer.innerHTML += indicatorHtml;
}
console.log(`β Created ${totalSlides} DJ chart slides`);
// Add click handlers for individual DJ chart discovery (matching chart pattern)
const djChartCards = sliderTrack.querySelectorAll('.beatport-dj-card[data-url]');
djChartCards.forEach((card) => {
const chartUrl = card.getAttribute('data-url');
if (chartUrl && chartUrl !== '') {
// Find the corresponding chart data
const chartData = charts.find(chart => chart.url === chartUrl);
if (chartData) {
card.addEventListener('click', () => handleBeatportDJChartCardClick(card, chartData));
card.style.cursor = 'pointer';
}
}
});
}
/**
* Set up navigation functionality (copied from charts slider with button cloning)
*/
function setupBeatportDJSliderNavigation() {
const prevBtn = document.getElementById('beatport-dj-prev-btn');
const nextBtn = document.getElementById('beatport-dj-next-btn');
if (prevBtn) {
// Clone button to remove all existing event listeners
const newPrevBtn = prevBtn.cloneNode(true);
prevBtn.parentNode.replaceChild(newPrevBtn, prevBtn);
newPrevBtn.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
console.log('Previous DJ button clicked, current slide:', beatportDJSliderState.currentSlide);
goToBeatportDJSlide(beatportDJSliderState.currentSlide - 1);
resetBeatportDJSliderAutoPlay();
});
}
if (nextBtn) {
// Clone button to remove all existing event listeners
const newNextBtn = nextBtn.cloneNode(true);
nextBtn.parentNode.replaceChild(newNextBtn, nextBtn);
newNextBtn.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
console.log('Next DJ button clicked, current slide:', beatportDJSliderState.currentSlide);
goToBeatportDJSlide(beatportDJSliderState.currentSlide + 1);
resetBeatportDJSliderAutoPlay();
});
}
}
/**
* Set up indicator functionality (copied from charts slider)
*/
function setupBeatportDJSliderIndicators() {
const indicators = document.querySelectorAll('.beatport-dj-indicator');
indicators.forEach((indicator, index) => {
indicator.addEventListener('click', () => {
goToBeatportDJSlide(index);
resetBeatportDJSliderAutoPlay();
});
});
}
/**
* Navigate to a specific slide (copied from charts slider)
*/
function goToBeatportDJSlide(slideIndex) {
console.log('goToBeatportDJSlide called with:', slideIndex, 'current:', beatportDJSliderState.currentSlide);
// Wrap around if out of bounds
if (slideIndex < 0) {
slideIndex = beatportDJSliderState.totalSlides - 1;
} else if (slideIndex >= beatportDJSliderState.totalSlides) {
slideIndex = 0;
}
console.log('After wrapping, slideIndex:', slideIndex);
// Update current slide
beatportDJSliderState.currentSlide = slideIndex;
// Update slide visibility
const slides = document.querySelectorAll('.beatport-dj-slide');
slides.forEach((slide, index) => {
slide.classList.remove('active', 'prev', 'next');
if (index === slideIndex) {
slide.classList.add('active');
} else if (index < slideIndex) {
slide.classList.add('prev');
} else {
slide.classList.add('next');
}
});
// Update indicators
const indicators = document.querySelectorAll('.beatport-dj-indicator');
indicators.forEach((indicator, index) => {
indicator.classList.toggle('active', index === slideIndex);
});
console.log('DJ slide updated to:', beatportDJSliderState.currentSlide);
}
/**
* Start auto-play functionality (copied from charts slider)
*/
function startBeatportDJSliderAutoPlay() {
if (beatportDJSliderState.autoPlayInterval) {
clearInterval(beatportDJSliderState.autoPlayInterval);
}
beatportDJSliderState.autoPlayInterval = setInterval(() => {
goToBeatportDJSlide(beatportDJSliderState.currentSlide + 1);
}, beatportDJSliderState.autoPlayDelay);
}
/**
* Reset auto-play timer (copied from charts slider)
*/
function resetBeatportDJSliderAutoPlay() {
startBeatportDJSliderAutoPlay();
}
/**
* Set up hover pause functionality (copied from charts slider)
*/
function setupBeatportDJSliderHoverPause() {
const sliderContainer = document.querySelector('.beatport-dj-slider-container');
if (sliderContainer) {
sliderContainer.addEventListener('mouseenter', () => {
if (beatportDJSliderState.autoPlayInterval) {
clearInterval(beatportDJSliderState.autoPlayInterval);
beatportDJSliderState.autoPlayInterval = null;
}
});
sliderContainer.addEventListener('mouseleave', () => {
startBeatportDJSliderAutoPlay();
});
}
}
/**
* Clean up DJ slider when switching away (copied from charts slider)
*/
function cleanupBeatportDJSlider() {
if (beatportDJSliderState.autoPlayInterval) {
clearInterval(beatportDJSliderState.autoPlayInterval);
beatportDJSliderState.autoPlayInterval = null;
}
}
/**
* Load top 10 lists data from API and populate both lists
*/
async function loadBeatportTop10Lists() {
try {
console.log('π Loading top 10 lists data...');
const signal = getBeatportContentSignal();
const response = await fetch('/api/beatport/homepage/top-10-lists', signal ? { signal } : undefined);
const data = await response.json();
if (data.success) {
console.log(`π΅ Loaded ${data.beatport_count} Beatport Top 10 + ${data.hype_count} Hype Top 10 tracks`);
// Populate both lists
populateBeatportTop10List(data.beatport_top10);
populateHypeTop10List(data.hype_top10);
return true;
} else {
console.error('Failed to load top 10 lists:', data.error);
showTop10ListsError(data.error || 'No data available');
return false;
}
} catch (error) {
if (error && error.name === 'AbortError') return false;
console.error('Error loading top 10 lists:', error);
showTop10ListsError('Failed to load top 10 lists');
return false;
}
}
/**
* Clean track/artist text for proper spacing
*/
function cleanTrackText(text) {
if (!text) return text;
// Fix common spacing issues
text = text.replace(/([a-z$!@#%&*])([A-Z])/g, '$1 $2'); // Add space between lowercase/symbols and uppercase
text = text.replace(/([a-zA-Z]),([a-zA-Z])/g, '$1, $2'); // Add space after comma
text = text.replace(/([a-zA-Z])(Mix|Remix|Extended|Version)\b/g, '$1 $2'); // Fix mix types
text = text.replace(/\s+/g, ' '); // Collapse multiple spaces
text = text.trim();
return text;
}
/**
* Populate Beatport Top 10 list with data
*/
function populateBeatportTop10List(tracks) {
const container = document.getElementById('beatport-top10-list');
if (!container || !tracks || tracks.length === 0) return;
// Generate HTML for the tracks
let tracksHtml = `
π΅ Beatport Top 10
Most popular tracks on Beatport
`;
tracks.forEach((track, index) => {
// Clean the text data before injection
const cleanTitle = cleanTrackText(track.title || 'Unknown Title');
const cleanArtist = cleanTrackText(track.artist || 'Unknown Artist');
const cleanLabel = cleanTrackText(track.label || 'Unknown Label');
tracksHtml += `
${track.rank || index + 1}
${track.artwork_url ?
`` :
'
π΅
'
}
${cleanTitle}
${cleanArtist}
${cleanLabel}
`;
});
tracksHtml += '
';
container.innerHTML = tracksHtml;
}
/**
* Populate Hype Top 10 list with data
*/
function populateHypeTop10List(tracks) {
const container = document.getElementById('beatport-hype10-list');
if (!container || !tracks || tracks.length === 0) return;
// Generate HTML for the tracks
let tracksHtml = `
π₯ Hype Top 10
Editor's trending picks
`;
tracks.forEach((track, index) => {
// Clean the text data before injection
const cleanTitle = cleanTrackText(track.title || 'Unknown Title');
const cleanArtist = cleanTrackText(track.artist || 'Unknown Artist');
const cleanLabel = cleanTrackText(track.label || 'Unknown Label');
tracksHtml += `
${track.rank || index + 1}
${track.artwork_url ?
`` :
'
π₯
'
}
${cleanTitle}
${cleanArtist}
${cleanLabel}
`;
});
tracksHtml += '
';
container.innerHTML = tracksHtml;
}
/**
* Show error message for top 10 lists
*/
function showTop10ListsError(errorMessage) {
const beatportContainer = document.getElementById('beatport-top10-list');
const hypeContainer = document.getElementById('beatport-hype10-list');
const errorHtml = `
β Error Loading Data
${errorMessage}
`;
if (beatportContainer) beatportContainer.innerHTML = errorHtml;
if (hypeContainer) hypeContainer.innerHTML = errorHtml;
}
/**
* Load top 10 releases data from API and populate the list
*/
async function loadBeatportTop10Releases() {
try {
console.log('πΏ Loading top 10 releases data...');
const signal = getBeatportContentSignal();
const response = await fetch('/api/beatport/homepage/top-10-releases-cards', signal ? { signal } : undefined);
const data = await response.json();
if (data.success) {
console.log(`πΏ Loaded ${data.releases_count} Top 10 Releases`);
populateBeatportTop10Releases(data.releases);
return true;
} else {
console.error('Failed to load top 10 releases:', data.error);
showTop10ReleasesError(data.error || 'No data available');
return false;
}
} catch (error) {
if (error && error.name === 'AbortError') return false;
console.error('Error loading top 10 releases:', error);
showTop10ReleasesError('Failed to load top 10 releases');
return false;
}
}
/**
* Populate Top 10 Releases list with data
*/
function populateBeatportTop10Releases(releases) {
const container = document.getElementById('beatport-releases-top10-list');
if (!container || !releases || releases.length === 0) return;
// Generate HTML for the releases
let releasesHtml = `
`;
}
function addGenreHeroReleaseClickHandlers(releases) {
// Clear any existing intervals first
if (window.genreHeroSliderState && window.genreHeroSliderState.autoPlayInterval) {
clearInterval(window.genreHeroSliderState.autoPlayInterval);
console.log('π§Ή Cleared previous genre hero auto-play interval');
}
// CRITICAL: Clear ALL possible conflicting intervals
if (typeof beatportRebuildSliderState !== 'undefined' && beatportRebuildSliderState.autoPlayInterval) {
clearInterval(beatportRebuildSliderState.autoPlayInterval);
console.log('π Cleared main rebuild slider auto-play interval');
}
// Initialize global slider state for genre hero slider
window.genreHeroSliderState = {
currentSlide: 0,
totalSlides: releases.length,
autoPlayInterval: null
};
console.log(`π Initializing genre hero slider with ${releases.length} slides`);
// Set up navigation button handlers
const prevBtn = document.getElementById('genre-hero-prev-btn');
const nextBtn = document.getElementById('genre-hero-next-btn');
if (prevBtn) {
prevBtn.addEventListener('click', () => {
window.genreHeroSliderState.currentSlide = window.genreHeroSliderState.currentSlide > 0
? window.genreHeroSliderState.currentSlide - 1
: window.genreHeroSliderState.totalSlides - 1;
updateGenreHeroSlide(window.genreHeroSliderState.currentSlide);
console.log(`β¬ οΈ Previous: Moving to slide ${window.genreHeroSliderState.currentSlide}`);
});
}
if (nextBtn) {
nextBtn.addEventListener('click', () => {
window.genreHeroSliderState.currentSlide = (window.genreHeroSliderState.currentSlide + 1) % window.genreHeroSliderState.totalSlides;
updateGenreHeroSlide(window.genreHeroSliderState.currentSlide);
console.log(`β‘οΈ Next: Moving to slide ${window.genreHeroSliderState.currentSlide}`);
});
}
// Set up indicator handlers
const indicators = document.querySelectorAll('#genre-hero-slider .beatport-rebuild-indicator');
indicators.forEach((indicator, index) => {
indicator.addEventListener('click', () => {
window.genreHeroSliderState.currentSlide = index;
updateGenreHeroSlide(index);
console.log(`π― Indicator: Jumping to slide ${index}`);
});
});
// Set up individual slide click handlers (like the main hero slider)
const slides = document.querySelectorAll('#genre-hero-slider .beatport-rebuild-slide[data-url]');
console.log(`π Found ${slides.length} slides to set up click handlers for`);
slides.forEach((slide, index) => {
const releaseUrl = slide.getAttribute('data-url');
if (releaseUrl && releaseUrl !== '#' && releaseUrl !== '') {
const release = releases[index];
if (release) {
// Ensure we use the absolute URL and match the expected data structure
const releaseData = {
url: releaseUrl, // This is already the absolute URL from data-url
title: release.title || 'Unknown Title',
artist: release.artists_string || 'Unknown Artist', // handleBeatportReleaseCardClick expects 'artist'
label: release.label || 'Unknown Label',
image_url: release.image_url || '',
// Include all original data for completeness
artists_string: release.artists_string,
type: release.type,
source: release.source,
badges: release.badges || []
};
slide.addEventListener('click', async (event) => {
// Prevent navigation button clicks from triggering this
if (event.target.closest('.beatport-rebuild-nav-btn') ||
event.target.closest('.beatport-rebuild-indicator')) {
return;
}
console.log(`π΅ Genre hero slide clicked: ${releaseData.title} by ${releaseData.artist}`);
// Use the exact same functionality as the main hero slider
await handleBeatportReleaseCardClick(slide, releaseData);
});
slide.style.cursor = 'pointer';
}
}
});
// Ensure first slide is active BEFORE starting auto-play
updateGenreHeroSlide(0);
// Delay auto-play start to let DOM settle
setTimeout(() => {
startGenreHeroSliderAutoPlay();
}, 100);
// Pause on hover
const sliderContainer = document.querySelector('#genre-hero-slider');
if (sliderContainer) {
sliderContainer.addEventListener('mouseenter', () => {
if (window.genreHeroSliderState.autoPlayInterval) {
clearInterval(window.genreHeroSliderState.autoPlayInterval);
console.log('βΈοΈ Paused auto-play on hover');
}
});
sliderContainer.addEventListener('mouseleave', () => {
// Delay restart to avoid rapid state changes
setTimeout(() => {
startGenreHeroSliderAutoPlay();
}, 100);
console.log('βΆοΈ Resumed auto-play after hover');
});
}
console.log(`β Set up slider functionality for ${releases.length} genre hero releases`);
}
function updateGenreHeroSlide(slideIndex) {
if (!window.genreHeroSliderState) {
console.error('β Genre hero slider state not initialized');
return;
}
// First update the state
window.genreHeroSliderState.currentSlide = slideIndex;
// Update slide visibility - use the exact same logic as main slider
const slides = document.querySelectorAll('#genre-hero-slider .beatport-rebuild-slide');
console.log(`π Updating slide to index ${slideIndex}, found ${slides.length} slides`);
if (slideIndex >= slides.length || slideIndex < 0) {
console.error(`β Invalid slide index ${slideIndex}, max is ${slides.length - 1}`);
return;
}
slides.forEach((slide, index) => {
slide.classList.remove('active', 'prev', 'next');
if (index === slideIndex) {
slide.classList.add('active');
console.log(`β Activated slide ${index}: ${slide.getAttribute('data-slide')} - Title: ${slide.querySelector('.beatport-rebuild-track-title')?.textContent}`);
} else if (index < slideIndex) {
slide.classList.add('prev');
} else {
slide.classList.add('next');
}
});
// Update indicators
const indicators = document.querySelectorAll('#genre-hero-slider .beatport-rebuild-indicator');
indicators.forEach((indicator, index) => {
indicator.classList.toggle('active', index === slideIndex);
});
console.log(`Genre slide updated to: ${window.genreHeroSliderState.currentSlide}`);
}
function startGenreHeroSliderAutoPlay() {
if (!window.genreHeroSliderState) {
console.error('β Cannot start auto-play: Genre hero slider state not initialized');
return;
}
// Clear any existing intervals first
if (window.genreHeroSliderState.autoPlayInterval) {
clearInterval(window.genreHeroSliderState.autoPlayInterval);
console.log('π§Ή Cleared existing auto-play interval');
}
window.genreHeroSliderState.autoPlayInterval = setInterval(() => {
if (!window.genreHeroSliderState) {
console.error('β Auto-play fired but state is gone, clearing interval');
clearInterval(window.genreHeroSliderState.autoPlayInterval);
return;
}
const currentSlide = window.genreHeroSliderState.currentSlide;
const totalSlides = window.genreHeroSliderState.totalSlides;
const nextSlide = (currentSlide + 1) % totalSlides;
console.log(`β° Auto-play: Current=${currentSlide}, Total=${totalSlides}, Next=${nextSlide}`);
// Validate the next slide index
if (nextSlide >= 0 && nextSlide < totalSlides) {
updateGenreHeroSlide(nextSlide);
} else {
console.error(`β Invalid nextSlide calculated: ${nextSlide}, resetting to 0`);
updateGenreHeroSlide(0);
}
}, 5000); // 5 second intervals like the main slider
console.log(`βΆοΈ Started auto-play for genre hero slider (${window.genreHeroSliderState.totalSlides} slides)`);
}
/**
* Load Top 10 lists for a specific genre (Beatport + Hype)
*/
async function loadGenreTop10Lists(genreSlug, genreId, genreName) {
console.log(`π΅ Loading Top 10 lists for ${genreName}...`);
const container = document.getElementById('genre-top10-lists-container');
if (!container) {
console.error('β Genre Top 10 lists container not found');
return;
}
try {
const response = await fetch(`/api/beatport/genre/${genreSlug}/${genreId}/top-10-lists`);
const data = await response.json();
if (!data.success) {
throw new Error(data.error || 'Failed to load Top 10 lists');
}
console.log(`β Loaded ${data.beatport_count} Beatport + ${data.hype_count} Hype Top 10 tracks for ${genreName}`);
// Generate HTML using exact same structure as main page (but unique IDs)
const top10ListsHTML = createGenreTop10ListsHTML(data, genreName);
container.innerHTML = top10ListsHTML;
// Add container-level click handlers exactly like main page
addGenreTop10ClickHandlers();
console.log(`β Successfully populated genre Top 10 lists for ${genreName}`);
} catch (error) {
console.error(`β Error loading Top 10 lists for ${genreName}:`, error);
// Show error state
container.innerHTML = `
β Error Loading Top 10 Lists
Could not load Top 10 tracks for ${genreName}
${error.message}
`;
}
}
/**
* Create HTML for genre Top 10 lists (exact structure as main page, unique IDs)
*/
function createGenreTop10ListsHTML(data, genreName) {
const { beatport_top10, hype_top10, has_hype_section } = data;
// Use exact same structure as main page but with genre-specific IDs
let html = `
π ${genreName} Top 10 Lists
Current trending ${genreName.toLowerCase()} tracks
π΅ Beatport Top 10
Most popular ${genreName.toLowerCase()} tracks
`;
// Add Beatport Top 10 tracks (same classes as main page)
beatport_top10.forEach((track, index) => {
const cleanTitle = cleanTrackText(track.title || 'Unknown Title');
const cleanArtist = cleanTrackText(track.artist || 'Unknown Artist');
const cleanLabel = cleanTrackText(track.label || 'Unknown Label');
html += `
${track.rank || index + 1}
${track.artwork_url ?
`` :
'
π΅
'
}
${cleanTitle}
${cleanArtist}
${cleanLabel}
`;
});
html += `
`;
// Add Hype Top 10 section (same classes, unique ID)
if (has_hype_section && hype_top10.length > 0) {
html += `