Add Spotify integration with album streaming links

- Implement Spotify Web API integration for album streaming links
- Add extract_spotify_urls.py script for automated Spotify URL extraction
- Create spotify_urls_mapping.json with sample album mappings (20 albums)
- Update album cards to include both Wikipedia and Spotify links
- Add Spotify-branded styling with official green color and logo
- Implement smart fallback to Spotify search for unmapped albums
- Add responsive design for mobile with stacked link layout
- Update README with comprehensive feature documentation

Features:
• Each album now has "Listen on Spotify" link with Spotify icon
• Spotify links use official Spotify green branding
• Theme-aware styling adapts to dark/light themes
• Mobile-optimized layout with vertical link stacking
• Production-ready script for extracting all 500 album URLs

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Johan Lundberg 2025-07-02 00:36:58 +02:00
parent 5279d3bbba
commit a3bdd4b217
5 changed files with 340 additions and 14 deletions

View file

@ -5,6 +5,7 @@ let currentPage = 1;
const itemsPerPage = 50;
let isReversed = false;
let wikipediaUrlMappings = {};
let spotifyUrlMappings = {};
// DOM elements
const albumsGrid = document.getElementById('albumsGrid');
@ -22,6 +23,7 @@ const stats = document.getElementById('stats');
// Initialize the application
document.addEventListener('DOMContentLoaded', function() {
loadWikipediaMapping();
loadSpotifyMapping();
loadAlbumsData();
setupEventListeners();
loadTheme();
@ -40,6 +42,18 @@ async function loadWikipediaMapping() {
}
}
// Load Spotify URL mappings
async function loadSpotifyMapping() {
try {
const response = await fetch('spotify_urls_mapping.json');
if (response.ok) {
spotifyUrlMappings = await response.json();
}
} catch (err) {
console.warn('Could not load Spotify URL mappings:', err);
}
}
// Setup event listeners
function setupEventListeners() {
searchInput.addEventListener('input', debounce(handleSearch, 300));
@ -275,6 +289,12 @@ function createAlbumCard(album) {
<a href="${generateWikipediaUrl(album.Album, album.Artist)}" target="_blank" rel="noopener noreferrer" class="wikipedia-link">
View on Wikipedia
</a>
<a href="${generateSpotifyUrl(album.Album, album.Artist)}" target="_blank" rel="noopener noreferrer" class="spotify-link">
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" style="margin-right: 0.5rem;">
<path d="M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.66 0 12 0zm5.521 17.34c-.24.359-.66.48-1.021.24-2.82-1.74-6.36-2.101-10.561-1.141-.418.122-.84-.179-.959-.539-.12-.421.18-.78.54-.9 4.56-1.021 8.52-.6 11.64 1.32.42.18.479.659.361 1.02zm1.44-3.3c-.301.42-.841.6-1.262.3-3.239-1.98-8.159-2.58-11.939-1.38-.479.12-1.02-.12-1.14-.6-.12-.48.12-1.021.6-1.141C9.6 9.9 15 10.561 18.72 12.84c.361.181.54.78.241 1.2zm.12-3.36C15.24 8.4 8.82 8.16 5.16 9.301c-.6.179-1.2-.181-1.38-.721-.18-.601.18-1.2.72-1.381 4.26-1.26 11.28-1.02 15.721 1.621.539.3.719 1.02.42 1.56-.299.421-1.02.599-1.559.3z"/>
</svg>
Listen on Spotify
</a>
</div>
<button class="album-share" title="Share this album" data-rank="${album.Rank}">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@ -513,6 +533,22 @@ function generateWikipediaUrl(album, artist) {
return `https://en.wikipedia.org/wiki/${encodeURIComponent(albumUrl)}_(${encodeURIComponent(artistUrl)}_album)`;
}
function generateSpotifyUrl(album, artist) {
// Clean up album and artist names
const albumName = album.trim();
const artistName = artist.trim();
// Check if we have the exact Spotify URL from our mapping
if (spotifyUrlMappings[albumName]) {
return spotifyUrlMappings[albumName];
}
// If no mapping found, create a Spotify search URL
const searchQuery = `${albumName} ${artistName}`;
const encodedQuery = encodeURIComponent(searchQuery);
return `https://open.spotify.com/search/${encodedQuery}`;
}
function hideLoading() {
loading.style.display = 'none';
albumsGrid.style.display = 'grid';