beatport progress
This commit is contained in:
parent
5e73b53a0f
commit
69c8622588
5 changed files with 771 additions and 0 deletions
|
|
@ -1403,6 +1403,263 @@ class BeatportUnifiedScraper:
|
||||||
print(f"Error extracting track data: {e}")
|
print(f"Error extracting track data: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def scrape_homepage_top10_releases(self) -> List[Dict]:
|
||||||
|
"""Scrape Top 10 Releases from homepage - FIXED VERSION"""
|
||||||
|
print("\n💿 FIXED: Scraping Top 10 Releases from homepage...")
|
||||||
|
|
||||||
|
soup = self.get_page(self.base_url)
|
||||||
|
if not soup:
|
||||||
|
print(" ❌ Could not get homepage")
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Extract Top 10 Releases items - EXACT same as test script
|
||||||
|
top10_releases_items = soup.select('[data-testid="top-10-releases-item"]')
|
||||||
|
print(f" FOUND {len(top10_releases_items)} Top 10 Releases items")
|
||||||
|
|
||||||
|
if len(top10_releases_items) == 0:
|
||||||
|
print(" ❌ No items found - trying alternatives")
|
||||||
|
return []
|
||||||
|
|
||||||
|
releases = []
|
||||||
|
for i, item in enumerate(top10_releases_items, 1):
|
||||||
|
try:
|
||||||
|
# Use the SAME function name as the test script
|
||||||
|
release_data = self.extract_release_from_item_FIXED(item, i)
|
||||||
|
if release_data:
|
||||||
|
releases.append(release_data)
|
||||||
|
print(f" ✅ {i}. {release_data['artist']} - {release_data['title']}")
|
||||||
|
else:
|
||||||
|
print(f" ❌ {i}. No data extracted")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ❌ Error extracting release {i}: {e}")
|
||||||
|
|
||||||
|
print(f"✅ FINAL: Extracted {len(releases)} Top 10 Releases")
|
||||||
|
return releases
|
||||||
|
|
||||||
|
def extract_release_from_item_FIXED(self, item, rank):
|
||||||
|
"""Extract release data from a list item - EXACT COPY FROM WORKING TEST SCRIPT"""
|
||||||
|
try:
|
||||||
|
# Get the release URL
|
||||||
|
link_elem = item.select_one('a[href*="/release/"]')
|
||||||
|
release_url = ""
|
||||||
|
if link_elem and link_elem.get('href'):
|
||||||
|
release_url = f"https://www.beatport.com{link_elem.get('href')}"
|
||||||
|
|
||||||
|
# Extract release title
|
||||||
|
title = "Unknown Title"
|
||||||
|
# Try multiple selectors for title
|
||||||
|
title_selectors = [
|
||||||
|
'[class*="ItemName"]',
|
||||||
|
'[class*="ReleaseName"]',
|
||||||
|
'[class*="release-name"]',
|
||||||
|
'[class*="TrackName"]',
|
||||||
|
'[class*="track-name"]',
|
||||||
|
'a[href*="/release/"]',
|
||||||
|
'h3', 'h4', 'h5',
|
||||||
|
'[class*="title"]',
|
||||||
|
'[class*="Title"]'
|
||||||
|
]
|
||||||
|
|
||||||
|
for selector in title_selectors:
|
||||||
|
title_elem = item.select_one(selector)
|
||||||
|
if title_elem:
|
||||||
|
title = title_elem.get_text(strip=True)
|
||||||
|
if title and title != "Unknown Title" and len(title) > 2:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Extract artist name - try multiple approaches
|
||||||
|
artist = "Unknown Artist"
|
||||||
|
artist_selectors = [
|
||||||
|
'[class*="Artists"]',
|
||||||
|
'[class*="artist"]',
|
||||||
|
'[class*="Artist"]',
|
||||||
|
'[class*="ItemArtist"]',
|
||||||
|
'a[href*="/artist/"]',
|
||||||
|
'[class*="by"]',
|
||||||
|
'[class*="By"]'
|
||||||
|
]
|
||||||
|
|
||||||
|
for selector in artist_selectors:
|
||||||
|
artist_elem = item.select_one(selector)
|
||||||
|
if artist_elem:
|
||||||
|
artist = artist_elem.get_text(strip=True)
|
||||||
|
if artist and artist != "Unknown Artist" and len(artist) > 1:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Extract label name - try multiple approaches
|
||||||
|
label = "Unknown Label"
|
||||||
|
label_selectors = [
|
||||||
|
'[class*="Label"]',
|
||||||
|
'[class*="label"]',
|
||||||
|
'[class*="ItemLabel"]',
|
||||||
|
'a[href*="/label/"]',
|
||||||
|
'[class*="imprint"]',
|
||||||
|
'[class*="Imprint"]'
|
||||||
|
]
|
||||||
|
|
||||||
|
for selector in label_selectors:
|
||||||
|
label_elem = item.select_one(selector)
|
||||||
|
if label_elem:
|
||||||
|
label = label_elem.get_text(strip=True)
|
||||||
|
if label and label != "Unknown Label" and len(label) > 2:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Extract image URL - this is important for releases
|
||||||
|
image_url = ""
|
||||||
|
image_selectors = [
|
||||||
|
'img[src]',
|
||||||
|
'img[data-src]',
|
||||||
|
'img[data-lazy]',
|
||||||
|
'[style*="background-image"]',
|
||||||
|
'picture img',
|
||||||
|
'.artwork img',
|
||||||
|
'[class*="artwork"] img',
|
||||||
|
'[class*="Artwork"] img',
|
||||||
|
'[class*="image"] img',
|
||||||
|
'[class*="Image"] img'
|
||||||
|
]
|
||||||
|
|
||||||
|
for selector in image_selectors:
|
||||||
|
img_elem = item.select_one(selector)
|
||||||
|
if img_elem:
|
||||||
|
# Try different image source attributes
|
||||||
|
img_src = (img_elem.get('src') or
|
||||||
|
img_elem.get('data-src') or
|
||||||
|
img_elem.get('data-lazy') or
|
||||||
|
img_elem.get('data-original'))
|
||||||
|
|
||||||
|
if img_src and img_src.startswith(('http', '//')):
|
||||||
|
image_url = img_src
|
||||||
|
break
|
||||||
|
elif img_src and img_src.startswith('/'):
|
||||||
|
image_url = f"https://www.beatport.com{img_src}"
|
||||||
|
break
|
||||||
|
|
||||||
|
return {
|
||||||
|
"rank": rank,
|
||||||
|
"title": title,
|
||||||
|
"artist": artist,
|
||||||
|
"label": label,
|
||||||
|
"url": release_url,
|
||||||
|
"image_url": image_url,
|
||||||
|
"list_name": "Top 10 Releases"
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error extracting release data: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def extract_release_from_top10_item(self, item, rank):
|
||||||
|
"""Extract release data from a top 10 releases item"""
|
||||||
|
try:
|
||||||
|
# Get the release URL
|
||||||
|
link_elem = item.select_one('a[href*="/release/"]')
|
||||||
|
release_url = ""
|
||||||
|
if link_elem and link_elem.get('href'):
|
||||||
|
release_url = f"https://www.beatport.com{link_elem.get('href')}"
|
||||||
|
|
||||||
|
# Extract release title
|
||||||
|
title = "Unknown Title"
|
||||||
|
title_selectors = [
|
||||||
|
'[class*="ItemName"]',
|
||||||
|
'[class*="ReleaseName"]',
|
||||||
|
'[class*="release-name"]',
|
||||||
|
'[class*="TrackName"]',
|
||||||
|
'[class*="track-name"]',
|
||||||
|
'a[href*="/release/"]',
|
||||||
|
'h3', 'h4', 'h5',
|
||||||
|
'[class*="title"]',
|
||||||
|
'[class*="Title"]'
|
||||||
|
]
|
||||||
|
|
||||||
|
for selector in title_selectors:
|
||||||
|
title_elem = item.select_one(selector)
|
||||||
|
if title_elem:
|
||||||
|
title = title_elem.get_text(strip=True)
|
||||||
|
if title and title != "Unknown Title" and len(title) > 2:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Extract artist name
|
||||||
|
artist = "Unknown Artist"
|
||||||
|
artist_selectors = [
|
||||||
|
'[class*="Artists"]',
|
||||||
|
'[class*="artist"]',
|
||||||
|
'[class*="Artist"]',
|
||||||
|
'[class*="ItemArtist"]',
|
||||||
|
'a[href*="/artist/"]',
|
||||||
|
'[class*="by"]',
|
||||||
|
'[class*="By"]'
|
||||||
|
]
|
||||||
|
|
||||||
|
for selector in artist_selectors:
|
||||||
|
artist_elem = item.select_one(selector)
|
||||||
|
if artist_elem:
|
||||||
|
artist = artist_elem.get_text(strip=True)
|
||||||
|
if artist and artist != "Unknown Artist" and len(artist) > 1:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Extract label name
|
||||||
|
label = "Unknown Label"
|
||||||
|
label_selectors = [
|
||||||
|
'[class*="Label"]',
|
||||||
|
'[class*="label"]',
|
||||||
|
'[class*="ItemLabel"]',
|
||||||
|
'a[href*="/label/"]',
|
||||||
|
'[class*="imprint"]',
|
||||||
|
'[class*="Imprint"]'
|
||||||
|
]
|
||||||
|
|
||||||
|
for selector in label_selectors:
|
||||||
|
label_elem = item.select_one(selector)
|
||||||
|
if label_elem:
|
||||||
|
label = label_elem.get_text(strip=True)
|
||||||
|
if label and label != "Unknown Label" and len(label) > 2:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Extract image URL - important for releases
|
||||||
|
image_url = ""
|
||||||
|
image_selectors = [
|
||||||
|
'img[src]',
|
||||||
|
'img[data-src]',
|
||||||
|
'img[data-lazy]',
|
||||||
|
'[style*="background-image"]',
|
||||||
|
'picture img',
|
||||||
|
'.artwork img',
|
||||||
|
'[class*="artwork"] img',
|
||||||
|
'[class*="Artwork"] img',
|
||||||
|
'[class*="image"] img',
|
||||||
|
'[class*="Image"] img'
|
||||||
|
]
|
||||||
|
|
||||||
|
for selector in image_selectors:
|
||||||
|
img_elem = item.select_one(selector)
|
||||||
|
if img_elem:
|
||||||
|
img_src = (img_elem.get('src') or
|
||||||
|
img_elem.get('data-src') or
|
||||||
|
img_elem.get('data-lazy') or
|
||||||
|
img_elem.get('data-original'))
|
||||||
|
|
||||||
|
if img_src and img_src.startswith(('http', '//')):
|
||||||
|
image_url = img_src
|
||||||
|
break
|
||||||
|
elif img_src and img_src.startswith('/'):
|
||||||
|
image_url = f"https://www.beatport.com{img_src}"
|
||||||
|
break
|
||||||
|
|
||||||
|
return {
|
||||||
|
"rank": rank,
|
||||||
|
"title": title,
|
||||||
|
"artist": artist,
|
||||||
|
"label": label,
|
||||||
|
"url": release_url,
|
||||||
|
"image_url": image_url,
|
||||||
|
"list_name": "Top 10 Releases"
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error extracting release data: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
def scrape_new_on_beatport_hero(self, limit: int = 10) -> List[Dict]:
|
def scrape_new_on_beatport_hero(self, limit: int = 10) -> List[Dict]:
|
||||||
"""Scrape the 'New on Beatport' hero slideshow from homepage"""
|
"""Scrape the 'New on Beatport' hero slideshow from homepage"""
|
||||||
print("\n🎯 Scraping 'New on Beatport' hero slideshow...")
|
print("\n🎯 Scraping 'New on Beatport' hero slideshow...")
|
||||||
|
|
|
||||||
|
|
@ -13262,6 +13262,44 @@ def get_beatport_homepage_top10_lists():
|
||||||
"hype_count": 0
|
"hype_count": 0
|
||||||
}), 500
|
}), 500
|
||||||
|
|
||||||
|
@app.route('/api/beatport/homepage/top-10-releases-cards', methods=['GET'])
|
||||||
|
def get_beatport_homepage_top10_releases_cards():
|
||||||
|
"""Get Beatport Top 10 Releases CARDS from homepage (not individual tracks)"""
|
||||||
|
try:
|
||||||
|
logger.info("💿 API request for Beatport homepage Top 10 Releases CARDS")
|
||||||
|
|
||||||
|
# Initialize the Beatport scraper
|
||||||
|
scraper = BeatportUnifiedScraper()
|
||||||
|
|
||||||
|
# Get top 10 releases from homepage
|
||||||
|
top10_releases = scraper.scrape_homepage_top10_releases()
|
||||||
|
|
||||||
|
logger.info(f"✅ API extracted {len(top10_releases)} Top 10 Release Cards")
|
||||||
|
|
||||||
|
# Debug: Log first release if any
|
||||||
|
if top10_releases:
|
||||||
|
logger.info(f"First release: {top10_releases[0].get('title', 'No title')} by {top10_releases[0].get('artist', 'No artist')}")
|
||||||
|
else:
|
||||||
|
logger.warning("❌ No releases found by scraper")
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"releases": top10_releases,
|
||||||
|
"releases_count": len(top10_releases),
|
||||||
|
"source": "beatport_homepage_top10_releases_cards"
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Error getting Beatport homepage Top 10 Releases cards: {e}")
|
||||||
|
import traceback
|
||||||
|
logger.error(f"Full traceback: {traceback.format_exc()}")
|
||||||
|
return jsonify({
|
||||||
|
"success": False,
|
||||||
|
"error": str(e),
|
||||||
|
"releases": [],
|
||||||
|
"releases_count": 0
|
||||||
|
}), 500
|
||||||
|
|
||||||
@app.route('/api/beatport/homepage/featured-charts', methods=['GET'])
|
@app.route('/api/beatport/homepage/featured-charts', methods=['GET'])
|
||||||
def get_beatport_homepage_featured_charts():
|
def get_beatport_homepage_featured_charts():
|
||||||
"""Get Beatport Featured Charts from homepage section"""
|
"""Get Beatport Featured Charts from homepage section"""
|
||||||
|
|
|
||||||
|
|
@ -850,6 +850,26 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Top 10 Releases Section -->
|
||||||
|
<div class="beatport-releases-top10-section">
|
||||||
|
<div class="beatport-releases-top10-header">
|
||||||
|
<h2 class="beatport-releases-top10-title">💿 Top 10 Releases</h2>
|
||||||
|
<p class="beatport-releases-top10-subtitle">Most popular albums and EPs on Beatport</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="beatport-releases-top10-container">
|
||||||
|
<div class="beatport-releases-top10-list" id="beatport-releases-top10-list">
|
||||||
|
<!-- Loading placeholder -->
|
||||||
|
<div class="beatport-releases-top10-loading">
|
||||||
|
<div class="beatport-releases-top10-loading-content">
|
||||||
|
<h4>💿 Loading Top 10 Releases...</h4>
|
||||||
|
<p>Fetching trending albums and EPs</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- New Releases Grid Slideshow Section -->
|
<!-- New Releases Grid Slideshow Section -->
|
||||||
<div class="beatport-releases-section">
|
<div class="beatport-releases-section">
|
||||||
<div class="beatport-releases-header">
|
<div class="beatport-releases-header">
|
||||||
|
|
|
||||||
|
|
@ -9735,6 +9735,7 @@ function initializeSyncPage() {
|
||||||
if (tabId === 'rebuild') {
|
if (tabId === 'rebuild') {
|
||||||
initializeBeatportRebuildSlider();
|
initializeBeatportRebuildSlider();
|
||||||
loadBeatportTop10Lists();
|
loadBeatportTop10Lists();
|
||||||
|
loadBeatportTop10Releases();
|
||||||
initializeBeatportReleasesSlider();
|
initializeBeatportReleasesSlider();
|
||||||
initializeBeatportHypePicksSlider();
|
initializeBeatportHypePicksSlider();
|
||||||
initializeBeatportChartsSlider();
|
initializeBeatportChartsSlider();
|
||||||
|
|
@ -19844,3 +19845,79 @@ function showTop10ListsError(errorMessage) {
|
||||||
if (beatportContainer) beatportContainer.innerHTML = errorHtml;
|
if (beatportContainer) beatportContainer.innerHTML = errorHtml;
|
||||||
if (hypeContainer) hypeContainer.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 response = await fetch('/api/beatport/homepage/top-10-releases-cards');
|
||||||
|
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) {
|
||||||
|
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 = `
|
||||||
|
<div class="beatport-releases-top10-tracks">
|
||||||
|
`;
|
||||||
|
|
||||||
|
releases.forEach((release, index) => {
|
||||||
|
releasesHtml += `
|
||||||
|
<div class="beatport-releases-top10-card" data-url="${release.url || '#'}">
|
||||||
|
<div class="beatport-releases-top10-card-rank">${release.rank || index + 1}</div>
|
||||||
|
<div class="beatport-releases-top10-card-artwork">
|
||||||
|
${release.image_url ?
|
||||||
|
`<img src="${release.image_url}" alt="${release.title}" loading="lazy">` :
|
||||||
|
'<div class="beatport-releases-top10-card-placeholder">💿</div>'
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="beatport-releases-top10-card-info">
|
||||||
|
<h4 class="beatport-releases-top10-card-title">${release.title || 'Unknown Title'}</h4>
|
||||||
|
<p class="beatport-releases-top10-card-artist">${release.artist || 'Unknown Artist'}</p>
|
||||||
|
<p class="beatport-releases-top10-card-label">${release.label || 'Unknown Label'}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
|
||||||
|
releasesHtml += '</div>';
|
||||||
|
container.innerHTML = releasesHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show error message for top 10 releases
|
||||||
|
*/
|
||||||
|
function showTop10ReleasesError(errorMessage) {
|
||||||
|
const container = document.getElementById('beatport-releases-top10-list');
|
||||||
|
|
||||||
|
const errorHtml = `
|
||||||
|
<div class="beatport-releases-top10-error">
|
||||||
|
<h3>❌ Error Loading Releases</h3>
|
||||||
|
<p>${errorMessage}</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
if (container) container.innerHTML = errorHtml;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12506,6 +12506,384 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =======================================
|
||||||
|
BEATPORT TOP 10 RELEASES SECTION
|
||||||
|
======================================= */
|
||||||
|
|
||||||
|
.beatport-releases-top10-section {
|
||||||
|
margin-top: 40px;
|
||||||
|
padding: 0 30px;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-title {
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #ffffff;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-subtitle {
|
||||||
|
font-size: 16px;
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Single column container for releases */
|
||||||
|
.beatport-releases-top10-container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* List styling with unique design */
|
||||||
|
.beatport-releases-top10-list {
|
||||||
|
background: linear-gradient(135deg,
|
||||||
|
rgba(20, 20, 20, 0.95),
|
||||||
|
rgba(35, 35, 35, 0.9));
|
||||||
|
border-radius: 24px;
|
||||||
|
padding: 40px;
|
||||||
|
backdrop-filter: blur(25px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
box-shadow:
|
||||||
|
0 25px 50px rgba(0, 0, 0, 0.6),
|
||||||
|
0 0 25px rgba(138, 43, 226, 0.1),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.15);
|
||||||
|
border-left: 4px solid #8a2be2;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Track containers with grid layout for releases */
|
||||||
|
.beatport-releases-top10-tracks {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Individual release cards - unique design with images */
|
||||||
|
.beatport-releases-top10-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: linear-gradient(135deg,
|
||||||
|
rgba(30, 30, 30, 0.9),
|
||||||
|
rgba(45, 45, 45, 0.85));
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
backdrop-filter: blur(15px);
|
||||||
|
transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
|
||||||
|
min-height: 120px;
|
||||||
|
max-height: 120px;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hover animations for release cards */
|
||||||
|
.beatport-releases-top10-card:hover {
|
||||||
|
background: linear-gradient(135deg,
|
||||||
|
rgba(138, 43, 226, 0.15),
|
||||||
|
rgba(45, 45, 45, 0.95));
|
||||||
|
border-color: rgba(138, 43, 226, 0.4);
|
||||||
|
transform: translateY(-5px) scale(1.02);
|
||||||
|
box-shadow:
|
||||||
|
0 20px 40px rgba(0, 0, 0, 0.6),
|
||||||
|
0 0 30px rgba(138, 43, 226, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release rank number */
|
||||||
|
.beatport-releases-top10-card-rank {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 900;
|
||||||
|
color: #8a2be2;
|
||||||
|
min-width: 40px;
|
||||||
|
text-align: center;
|
||||||
|
margin-right: 20px;
|
||||||
|
text-shadow: 0 3px 8px rgba(138, 43, 226, 0.4);
|
||||||
|
background: linear-gradient(135deg, rgba(138, 43, 226, 0.15), rgba(138, 43, 226, 0.08));
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 12px 0;
|
||||||
|
border: 2px solid rgba(138, 43, 226, 0.3);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release artwork - larger since these have images */
|
||||||
|
.beatport-releases-top10-card-artwork {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
border-radius: 16px;
|
||||||
|
margin-right: 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.5);
|
||||||
|
border: 3px solid rgba(255, 255, 255, 0.15);
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card-artwork img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
transition: transform 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card:hover .beatport-releases-top10-card-artwork img {
|
||||||
|
transform: scale(1.2) rotate(2deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Artwork placeholder for releases */
|
||||||
|
.beatport-releases-top10-card-placeholder {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28px;
|
||||||
|
background: linear-gradient(135deg, rgba(138, 43, 226, 0.2), rgba(80, 80, 80, 0.8));
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release info */
|
||||||
|
.beatport-releases-top10-card-info {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #ffffff;
|
||||||
|
line-height: 1.3;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.9);
|
||||||
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card-artist {
|
||||||
|
font-size: 15px;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
font-weight: 600;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card-label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(138, 43, 226, 0.95);
|
||||||
|
font-weight: 700;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.8px;
|
||||||
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading states for releases */
|
||||||
|
.beatport-releases-top10-loading {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 200px;
|
||||||
|
background: linear-gradient(135deg,
|
||||||
|
rgba(20, 20, 20, 0.7),
|
||||||
|
rgba(30, 30, 30, 0.5));
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-loading-content {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-loading-content h4 {
|
||||||
|
font-size: 20px;
|
||||||
|
color: #ffffff;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-loading-content p {
|
||||||
|
font-size: 15px;
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Error states for releases */
|
||||||
|
.beatport-releases-top10-error {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 200px;
|
||||||
|
background: linear-gradient(135deg,
|
||||||
|
rgba(255, 51, 51, 0.12),
|
||||||
|
rgba(45, 45, 45, 0.9));
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 1px solid rgba(255, 51, 51, 0.25);
|
||||||
|
text-align: center;
|
||||||
|
padding: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-error h3 {
|
||||||
|
color: #ff3366;
|
||||||
|
font-size: 20px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-error p {
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
font-size: 15px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive Design for Top 10 Releases */
|
||||||
|
@media (max-width: 1300px) {
|
||||||
|
.beatport-releases-top10-card-title {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card-artist {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card-label {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card-rank {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.beatport-releases-top10-tracks {
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-list {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card {
|
||||||
|
min-height: 110px;
|
||||||
|
max-height: 110px;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card-artwork {
|
||||||
|
width: 70px;
|
||||||
|
height: 70px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.beatport-releases-top10-tracks {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-section {
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-title {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card {
|
||||||
|
min-height: 100px;
|
||||||
|
max-height: 100px;
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card-artwork {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card-rank {
|
||||||
|
font-size: 18px;
|
||||||
|
min-width: 35px;
|
||||||
|
margin-right: 16px;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.beatport-releases-top10-section {
|
||||||
|
padding: 0 15px;
|
||||||
|
margin-top: 30px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-header {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-list {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-title {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card {
|
||||||
|
min-height: 90px;
|
||||||
|
max-height: 90px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card-artwork {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card-rank {
|
||||||
|
font-size: 16px;
|
||||||
|
min-width: 30px;
|
||||||
|
margin-right: 12px;
|
||||||
|
padding: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card-title {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card-artist {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beatport-releases-top10-card-label {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ================================
|
/* ================================
|
||||||
BEATPORT NEW RELEASES SECTION
|
BEATPORT NEW RELEASES SECTION
|
||||||
================================ */
|
================================ */
|
||||||
|
|
@ -13863,6 +14241,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.beatport-dj-creator {
|
.beatport-dj-creator {
|
||||||
|
display: none;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: rgba(255, 255, 255, 0.9);
|
color: rgba(255, 255, 255, 0.9);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue