Organize repository by moving all scripts to scripts/ folder

- Moved all Python processing scripts to scripts/ directory for better organization
- Preserves git history using git mv command
- Clean separation between main project files and utility scripts

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Johan Lundberg 2025-07-01 00:36:08 +02:00
parent 462fdcfa84
commit 872fdfa0ee
15 changed files with 0 additions and 0 deletions

142
scripts/add_missing_info.py Normal file
View file

@ -0,0 +1,142 @@
#!/usr/bin/env python3
"""
Add missing Info and Description for albums that don't have them.
Mark new descriptions with "(by Claude)"
"""
import csv
import re
def escape_csv_field(text):
"""Properly escape CSV field content"""
if '"' in text:
text = text.replace('"', '""')
if ',' in text or '"' in text or '\n' in text:
text = f'"{text}"'
return text
# Dictionary of missing album info and descriptions
missing_albums = {
# Albums marked as "New in 2023" or missing data
("The Beatles", "The Beatles"): {
"info": "Apple, 1968",
"description": "Commonly known as 'The White Album' for its stark, minimalist cover, this ambitious double album showcased the Beatles' incredible creative diversity as they began to pursue individual artistic visions. Recorded during a period of internal tension, the 30-track collection ranges from the heavy rock of 'Helter Skelter' to the avant-garde soundscapes of 'Revolution 9,' from McCartney's music hall pastiche 'Honey Pie' to Lennon's primal blues 'Yer Blues.' Each Beatle contributed distinct personalities - Lennon's raw honesty, McCartney's melodic sophistication, Harrison's Eastern influences, and Starr's first songwriting credit with 'Don't Pass Me By.' The album's eclectic nature reflected the band's growing independence and foreshadowed their eventual dissolution, but also demonstrated their unparalleled ability to excel in virtually every musical style they attempted. (by Claude)"
},
("The Jimi Hendrix Experience", "Are You Experienced"): {
"info": "Track/Reprise, 1967",
"description": "Jimi Hendrix's explosive debut album revolutionized electric guitar playing and redefined the possibilities of rock music. From the opening feedback of 'Purple Haze' to the backwards guitar wizardry of 'Are You Experienced,' Hendrix demonstrated techniques that seemed impossible at the time. His innovative use of feedback, distortion, and the wah-wah pedal, combined with his left-handed playing on a right-handed guitar strung upside down, created a completely new sonic vocabulary. Songs like 'Hey Joe,' 'The Wind Cries Mary,' and 'Foxy Lady' showcased not only his technical brilliance but also his deep understanding of blues traditions and psychedelic experimentation. Recorded in London with bassist Noel Redding and drummer Mitch Mitchell, the album established Hendrix as the most innovative guitarist of his generation and influenced countless musicians who followed. (by Claude)"
},
("Beyonce", "Renaissance"): {
"info": "Parkwood/Columbia, 2022",
"description": "Beyoncé's seventh solo studio album is a euphoric celebration of Black and queer dance music history, weaving together house, disco, Afrobeats, and ballroom culture into a cohesive masterpiece. Following the introspective 'Lemonade,' 'Renaissance' finds Beyoncé in full celebration mode, honoring the pioneers of dance music while creating something entirely contemporary. Tracks like 'Break My Soul' and 'Alien Superstar' showcase her vocal versatility over pulsating electronic beats, while 'Virgo's Groove' and 'Heated' blend sensuality with cutting-edge production. The album pays tribute to icons like Grace Jones, Donna Summer, and Robin S., while collaborating with producers like The-Dream, Raphael Saadiq, and Skrillex. 'Renaissance' represents Beyoncé at her most liberated, creating music designed for pure joy and movement, and stands as a triumphant testament to the power of Black musical innovation. (by Claude)"
},
("Curtis Mayfield", "Super Fly"): {
"info": "Curtom, 1972",
"description": "Curtis Mayfield's soundtrack to the blaxploitation film 'Super Fly' became more influential than the movie itself, creating a template for socially conscious funk that would influence hip-hop for decades. Rather than glorifying the drug dealer protagonist, Mayfield's lyrics offered a complex critique of street life and systemic oppression. 'Freddie's Dead' mourns the casualties of the drug trade, while 'Pusherman' provides an unflinching portrait from the dealer's perspective without celebrating it. Mayfield's falsetto vocals float over innovative arrangements featuring wah-wah guitars, Latin percussion, and lush strings. The album's cinematic scope and social consciousness elevated it beyond typical soundtrack fare, making it a standalone masterpiece that addressed urban realities with unprecedented honesty and musical sophistication. (by Claude)"
},
("Elvis Presley", "The Sun Sessions"): {
"info": "RCA/Sun, 1976",
"description": "This compilation of Elvis Presley's groundbreaking recordings at Sun Records captures the exact moment when rock and roll was born. Recorded between 1954-1955 at Sam Phillips' Memphis studio, these sessions document the 19-year-old Presley's revolutionary fusion of country, blues, and gospel that would change popular music forever. Songs like 'That's All Right,' 'Mystery Train,' and 'Baby Let's Play House' showcase Presley's uninhibited vocal style and natural charisma, backed by Scotty Moore's innovative guitar work and Bill Black's slapping bass. Phillips' sparse, echo-laden production captured the raw energy and spontaneity that made these performances so electrifying. While commercially these were regional hits, their cultural impact was immeasurable - they broke down racial barriers in music and inspired countless musicians to follow. (by Claude)"
},
("Missy Elliott", "Supa Dupa Fly"): {
"info": "Goldmind/East West, 1997",
"description": "Missy Elliott's solo debut established her as hip-hop's most visionary artist, combining futuristic production with playful wordplay and boundary-pushing videos. Working primarily with producer Timbaland, Elliott created a sound unlike anything in rap - incorporating unusual samples, off-kilter rhythms, and innovative vocal techniques. Tracks like 'The Rain (Supa Dupa Fly)' and 'Sock It 2 Me' featured collaborations with artists like Aaliyah, Lil' Kim, and Da Brat, showcasing Elliott's ability to elevate everyone around her. Her approach to sexuality was both frank and empowering, while her visual aesthetic - from the inflatable suit in 'The Rain' video to the fish-eye lens effects - influenced a generation of artists. The album proved that hip-hop could be experimental, fun, and commercially successful simultaneously. (by Claude)"
},
("John Lennon", "John Lennon/Plastic Ono Band"): {
"info": "Apple, 1970",
"description": "John Lennon's first proper solo album is one of rock's most harrowing and honest statements, stripping away all pretense to reveal raw emotional truth. Inspired by his experience with primal scream therapy, Lennon confronted his deepest traumas - his abandonment by his parents on 'Mother,' his disillusionment with fame on 'I Found Out,' and his rejection of religious and political idols on 'God.' Backed by the minimal but powerful rhythm section of Klaus Voormann and Ringo Starr, with sparse piano arrangements, the album's stark production serves the emotional intensity of Lennon's confessional lyrics. Songs like 'Working Class Hero' and 'Love' showcase his ability to channel pain into powerful statements about class, society, and human connection. The album's brutal honesty and psychological depth influenced generations of singer-songwriters. (by Claude)"
},
("Sex Pistols", "Never Mind the Bollocks, Here's the Sex Pistols"): {
"info": "Virgin, 1977",
"description": "The Sex Pistols' only studio album is punk rock's defining statement - a furious assault on British society, the music industry, and conventional values. Johnny Rotten's sneering vocals and provocative lyrics, combined with Steve Jones' powerful guitar work and the rhythm section of Glen Matlock (later Paul Cook), created an sound of pure rebellion. Songs like 'Anarchy in the U.K.' and 'God Save the Queen' were banned by the BBC but became anthems for disaffected youth. The album's crude production aesthetic, captured by Chris Thomas, perfectly matched the band's anti-establishment message. While the Pistols burned out quickly, their impact was immeasurable - inspiring countless punk bands and proving that music could be a weapon of social and political change. (by Claude)"
},
("Eagles", "Hotel California"): {
"info": "Asylum, 1976",
"description": "The Eagles' fifth studio album represents the pinnacle of 1970s California rock, blending country, rock, and folk into a sophisticated sound that captured the excess and disillusionment of the era. The title track, with its iconic guitar work by Don Felder and Joe Walsh, became one of rock's most enduring songs, its mysterious lyrics about a luxurious but sinister hotel serving as a metaphor for the dark side of the American Dream. Songs like 'Life in the Fast Lane' and 'New Kid in Town' showcased the band's tight harmonies and polished production, while addressing themes of fame, materialism, and lost innocence. The album's glossy sound, crafted by producer Bill Szymczyk, influenced countless rock bands and helped define the smooth, radio-friendly aesthetic that dominated late-70s rock. (by Claude)"
},
("Taylor Swift", "Folklore"): {
"info": "Republic, 2020",
"description": "Written and recorded during the COVID-19 pandemic, 'Folklore' marked Taylor Swift's stunning transformation from pop superstar to indie folk storyteller. Collaborating with Aaron Dessner of The National and longtime producer Jack Antonoff, Swift crafted her most introspective and mature work, trading stadium anthems for intimate, acoustic-based compositions. Songs like 'Cardigan,' 'Exile' (featuring Bon Iver), and 'The 1' showcase Swift's evolved songwriting, weaving complex narratives about fictional characters while drawing from personal experience. The album's cohesive aesthetic and literary quality demonstrated Swift's artistic growth beyond her country and pop roots, earning widespread critical acclaim and commercial success. 'Folklore' proved that Swift could excel in any genre she chose to explore. (by Claude)"
},
("Metallica", "Metallica"): {
"info": "Elektra, 1991",
"description": "Known as 'The Black Album' for its stark cover, Metallica's fifth studio album brought the thrash metal pioneers into the mainstream without sacrificing their essential power. Working with producer Bob Rock, the band streamlined their sound, emphasizing groove and accessibility while maintaining their trademark heavy riffs and James Hetfield's aggressive vocals. Songs like 'Enter Sandman,' 'The Unforgiven,' and 'Nothing Else Matters' became rock radio staples, showcasing the band's ability to write memorable hooks within their metal framework. The album's polished production and shorter song structures marked a departure from their previous thrash epics, but the songwriting remained uncompromisingly heavy. The Black Album's massive commercial success proved that metal could dominate the mainstream charts. (by Claude)"
},
("SZA", "SOS"): {
"info": "TDE/RCA, 2022",
"description": "SZA's second studio album is a vulnerable exploration of love, heartbreak, and self-discovery that established her as one of R&B's most compelling voices. Drawing from personal experiences of toxic relationships and emotional growth, SZA crafts deeply relatable songs that blend contemporary R&B with elements of pop, hip-hop, and alternative rock. Tracks like 'Good Days,' 'I Hate U,' and 'Kill Bill' showcase her distinctive vocal style - breathy, conversational, and emotionally raw. The album's production, handled by collaborators including ThankGod4Cody and Carter Lang, creates atmospheric soundscapes that perfectly complement SZA's confessional lyrics. 'SOS' resonated with a generation dealing with similar relationship struggles and mental health challenges, cementing SZA's place as a defining artist of her era. (by Claude)"
},
("Olivia Rodrigo", "Sour"): {
"info": "Geffen, 2021",
"description": "At just 18, Olivia Rodrigo created a debut album that perfectly captured the intensity of teenage heartbreak and the complexity of growing up in the social media age. 'Sour' blends pop-punk energy with introspective ballads, showcasing Rodrigo's ability to channel raw emotion into polished songcraft. 'Drivers License' became a global phenomenon, its intimate storytelling and soaring melody resonating with listeners worldwide. Other tracks like 'Good 4 U' and 'Brutal' display her versatility, moving from Paramore-influenced rock to Taylor Swift-style confessional pop. The album's success proved that guitar-driven pop could still dominate the charts, while Rodrigo's honest lyrics about jealousy, insecurity, and young love connected with audiences across generations. (by Claude)"
},
("Harry Styles", "Harry's House"): {
"info": "Columbia, 2022",
"description": "Harry Styles' third solo album finds the former One Direction member fully embracing his artistic independence, creating a cohesive collection of sophisticated pop songs that showcase his growth as a songwriter and performer. Drawing influences from yacht rock, Britpop, and contemporary indie music, 'Harry's House' features lush production and intimate lyrics about love, fame, and self-reflection. Songs like 'As It Was,' 'Music for a Sushi Restaurant,' and 'Late Night Talking' demonstrate Styles' evolving vocal confidence and melodic sensibilities. The album's warm, inviting sound and themes of domestic happiness marked a departure from his previous work's more experimental tendencies, resulting in both critical acclaim and massive commercial success that solidified his status as a major solo artist. (by Claude)"
},
("Bad Bunny", "Un Verano Sin Ti"): {
"info": "Rimas Entertainment, 2022",
"description": "Bad Bunny's fourth studio album is a sprawling celebration of Caribbean culture that dominated global charts while showcasing the full range of reggaeton and Latin trap. Across 23 tracks, the Puerto Rican superstar explores themes of love, heartbreak, and summer freedom, blending traditional reggaeton rhythms with elements of mambo, dembow, and electronic music. Songs like 'Me Porto Bonito' (featuring Chencho Corleone) and 'Tití Me Preguntó' became massive hits, while deeper cuts showcased Bad Bunny's versatility and cultural pride. The album's success transcended language barriers, proving that Spanish-language music could achieve unprecedented mainstream success in the United States. 'Un Verano Sin Ti' stands as a landmark achievement in Latin music's global expansion. (by Claude)"
},
("The Jimi Hendrix Experience", "Electric Ladyland"): {
"info": "Reprise, 1968",
"description": "Jimi Hendrix's third and final studio album with the Experience showcased his evolution from guitar virtuoso to complete artistic visionary. The double album features some of Hendrix's most ambitious compositions, including the epic 'Voodoo Chile (Slight Return)' and his legendary cover of Bob Dylan's 'All Along the Watchtower,' which Dylan himself called the definitive version. The album demonstrated Hendrix's studio mastery, incorporating layers of overdubs, backwards recordings, and innovative effects that pushed the boundaries of what was possible in 1968. Songs like '1983... (A Merman I Should Turn to Be)' showed his interest in creating sonic landscapes beyond traditional rock structures. 'Electric Ladyland' stands as Hendrix's most complete artistic statement, combining his unparalleled guitar skills with sophisticated songwriting and production. (by Claude)"
},
("Solange Knowles", "A Seat at the Table"): {
"info": "Saint/Columbia, 2016",
"description": "Solange's third studio album is a powerful meditation on Black identity, pride, and resilience in America. Drawing from neo-soul, funk, and R&B traditions, the album features deeply personal songs about growing up Black in the South, family relationships, and finding strength in cultural heritage. Tracks like 'Cranes in the Sky' and 'Don't Touch My Hair' became anthems of Black empowerment, while interludes featuring conversations with her parents and other family members added intimate context to the album's themes. The album's production, crafted with collaborators including Raphael Saadiq and The-Dream, creates a cohesive sonic journey that perfectly complements Solange's vulnerable yet defiant vocals. 'A Seat at the Table' was both a critical triumph and a cultural moment, addressing racial issues with grace and artistic sophistication. (by Claude)"
},
("Gorillaz", "Demon Days"): {
"info": "Parlophone/Virgin, 2005",
"description": "Damon Albarn and Jamie Hewlett's virtual band reached its creative peak with this apocalyptic masterpiece that blended hip-hop, electronic, rock, and world music into a cohesive statement about modern anxiety and cultural decay. Featuring collaborations with De La Soul, MF Doom, Dennis Hopper, and others, 'Demon Days' created a dark but groovy soundtrack for the Bush era's political and social turmoil. Songs like 'Feel Good Inc.' and 'DARE' became massive hits while maintaining the project's experimental edge. The album's concept, centered around themes of war, consumerism, and environmental destruction, was perfectly matched by Hewlett's striking visual aesthetic and Albarn's increasingly sophisticated production. 'Demon Days' proved that conceptual pop music could be both artistically ambitious and commercially successful. (by Claude)"
},
("Bon Iver", "For Emma, Forever Ago"): {
"info": "Jagjaguwar, 2007",
"description": "Recorded in isolation at a remote Wisconsin cabin during winter, Justin Vernon's debut as Bon Iver became an unlikely indie folk masterpiece that defined a generation's approach to intimate, lo-fi songcraft. Using minimal instrumentation and his distinctive falsetto, Vernon crafted deeply emotional songs about heartbreak, solitude, and healing. The album's sparse production, featuring acoustic guitar, subtle electronics, and layered vocals, created an atmosphere of profound vulnerability and beauty. Songs like 'Skinny Love' and 'Re: Stacks' showcased Vernon's ability to transform personal pain into universal art. The album's success proved that bedroom recording techniques could produce music of lasting emotional impact, influencing countless indie artists who followed. (by Claude)"
},
("David Bowie", "Scary Monsters (and Super Creeps)"): {
"info": "RCA, 1980",
"description": "David Bowie's fourteenth studio album marked his successful transition into the 1980s, blending his art-rock sophistication with new wave energy and cutting-edge production techniques. Working with producer Tony Visconti and guitarist Robert Fripp, Bowie created a sound that was both futuristic and deeply human. The title track and 'Fashion' became definitive examples of early-80s avant-pop, while 'Ashes to Ashes' served as a sequel to 'Space Oddity,' bringing the story of Major Tom full circle. The album's exploration of celebrity, paranoia, and modern alienation was perfectly suited to the dawning MTV era. 'Scary Monsters' demonstrated Bowie's remarkable ability to reinvent himself while maintaining his essential artistic vision, creating some of his most enduring and influential work. (by Claude)"
}
}
def main():
# Read current CSV
albums = []
with open('top_500_albums_2023.csv', 'r', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
albums.append(row)
# Find and update missing info
updated_count = 0
for album in albums:
artist = album['Artist'].strip()
album_title = album['Album'].strip()
# Check if this album is missing info/description
if not album['Info'].strip() or not album['Description'].strip():
# Look for it in our database
if (artist, album_title) in missing_albums:
album_data = missing_albums[(artist, album_title)]
if not album['Info'].strip():
album['Info'] = album_data['info']
if not album['Description'].strip():
album['Description'] = album_data['description']
updated_count += 1
print(f"✓ Updated: {artist} - {album_title}")
else:
print(f"✗ Missing: {artist} - {album_title}")
# Write updated CSV
with open('top_500_albums_2023.csv', 'w', newline='', encoding='utf-8') as file:
fieldnames = ['Rank', 'Artist', 'Album', 'Status', 'Info', 'Description']
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(albums)
print(f"\n🎉 Updated {updated_count} albums with missing info/descriptions")
print("All descriptions added by Claude are marked with '(by Claude)'")
if __name__ == "__main__":
main()

View file

@ -0,0 +1,269 @@
#!/usr/bin/env python3
"""
Extended script to add more album information to the Top 500 Albums CSV file.
This script contains additional album data that can be added to supplement the original update script.
"""
import csv
import shutil
from datetime import datetime
def create_extended_album_lookup():
"""
Create an extended lookup dictionary for more famous albums.
This supplements the original lookup dictionary with additional entries.
"""
return {
# Classic Rock
("Captain Beefheart & His Magic Band", "Trout Mask Replica"): (
"Straight, 1969",
"Captain Beefheart's avant-garde masterpiece is one of the most challenging and influential albums in rock history. Produced by Frank Zappa, the double album features 28 compositions that blend blues, free jazz, and experimental rock into a virtually unclassifiable whole. Don Van Vliet's distinctive growling vocals and the Magic Band's impossibly complex rhythms, developed through months of obsessive rehearsal, created a sound that influenced generations of experimental musicians. Despite its initial commercial failure and bewildering reception, the album is now recognized as a landmark of artistic innovation."
),
("Hüsker Dü", "Zen Arcade"): (
"SST, 1984",
"Hüsker Dü's ambitious double album concept piece about a boy running away from home established the Minneapolis trio as pioneers of alternative rock. The album's combination of hardcore punk energy with melodic sensibilities and complex song structures anticipated the alternative rock explosion of the 1990s. Songs like 'Chartered Trips' and 'Turn on the News' showcase Bob Mould's powerful songwriting and the band's ability to balance aggression with emotional depth. The album's influence on bands like Nirvana and the Pixies cannot be overstated."
),
("Ray Charles", "The Genius of Ray Charles"): (
"Atlantic, 1959",
"Ray Charles's breakthrough album established him as one of America's greatest musical innovators, blending gospel, blues, jazz, and pop into a revolutionary new sound. The album features definitive versions of 'Let the Good Times Roll' and 'Don't Let the Sun Catch You Cryin',' showcasing Charles's ability to inhabit any musical style completely. His emotional intensity and technical virtuosity, combined with sophisticated big band arrangements, created a template for soul music that influenced countless artists."
),
("Neil Young & Crazy Horse", "Everybody Knows This Is Nowhere"): (
"Reprise, 1969",
"Neil Young's second solo album and his first collaboration with Crazy Horse established the template for his long career of electric guitar exploration. The album's raw, garage rock energy on songs like 'Cinnamon Girl' and 'Down by the River' contrasted with his previous folk-oriented work. The 10-minute guitar workout 'Cowgirl in the Sand' showcased Young's ability to create transcendent music through repetition and feedback. The album's influence on grunge and alternative rock would become apparent decades later."
),
("Gram Parsons", "Grievous Angel"): (
"Reprise, 1974",
"Gram Parsons's final album, completed shortly before his death, is considered the masterpiece of country rock. Working with Emmylou Harris, whose harmonies elevate every song, Parsons created a deeply personal statement about love, loss, and redemption. Songs like 'Return of the Grievous Angel' and 'Hearts on Fire' showcase his ability to blend traditional country with rock sensibilities. The album's influence on alternative country and Americana music continues to this day."
),
("Talking Heads", "Fear of Music"): (
"Sire, 1979",
"Talking Heads' third album marked their evolution from art punk to a more sophisticated exploration of rhythm and texture. Produced by Brian Eno, the album's angular rhythms and David Byrne's neurotic vocals on songs like 'Life During Wartime' and 'Cities' created a paranoid urban sound that captured the anxiety of late-1970s America. The album's influence on post-punk and new wave was immediate and lasting."
),
("Public Image Ltd.", "Metal Box"): (
"Virgin, 1979",
"John Lydon's post-Sex Pistols project created one of the most innovative albums in rock history with this collection of dub-influenced post-punk. The album's heavy bass lines, courtesy of Jah Wobble, and Keith Levene's jagged guitar work created a sound that was both futuristic and primal. Originally released in a metal film canister, songs like 'Albatross' and 'Swan Lake' showcase the band's ability to deconstruct and rebuild rock music from the ground up."
),
("Love", "Da Capo"): (
"Elektra, 1966",
"Love's second album is a masterpiece of psychedelic folk rock that showcased Arthur Lee's sophisticated songwriting and the band's dynamic range. The album's first side features perfectly crafted pop songs like '7 and 7 Is' and 'She Comes in Colors,' while the second side is dominated by the 19-minute experimental piece 'Revelation.' The band's ability to balance accessibility with experimentation made them one of the most important but underrated bands of the 1960s."
),
("X", "Wild Gift"): (
"Slash, 1981",
"X's second album perfected their unique blend of punk rock and rockabilly, creating one of the definitive albums of the Los Angeles punk scene. The husband-and-wife vocals of John Doe and Exene Cervenka, combined with Billy Zoom's razor-sharp guitar work, created a sound that was both primitive and sophisticated. Songs like 'White Girl' and 'We're Desperate' showcase their ability to create punk anthems with literary depth."
),
("Paul McCartney & Wings", "Band on the Run"): (
"Apple, 1973",
"Paul McCartney's post-Beatles masterpiece was recorded under difficult circumstances in Lagos, Nigeria, but resulted in his most cohesive and acclaimed solo work. The album's title track suite and songs like 'Jet' and 'Helen Wheels' showcase McCartney's gift for melody and his ability to create sophisticated pop music. The album's success proved that McCartney could thrive outside the Beatles and established Wings as a legitimate rock band."
),
("Pere Ubu", "The Modern Dance"): (
"Blank, 1978",
"Pere Ubu's debut album established them as pioneers of industrial rock and post-punk, combining avant-garde sensibilities with rock energy. David Thomas's theatrical vocals and the band's use of synthesizers and tape manipulation created a sound that was both unsettling and compelling. Songs like 'Non-Alignment Pact' and the title track showcase their ability to create art rock that maintained punk's confrontational spirit."
),
# Electronic/Ambient
("The Orb", "The Orb's Adventures Beyond the Ultraworld"): (
"Big Life, 1991",
"The Orb's debut album established them as pioneers of ambient house music, creating hour-long compositions that blend electronic beats with found sounds and field recordings. Alex Paterson and Thrash's use of samples from science fiction films and nature recordings created a dreamy, psychedelic form of dance music. The album's influence on chillout and ambient electronic music was immediate and lasting."
),
("Flying Lotus", "Cosmogramma"): (
"Warp, 2010",
"Steven Ellison's third album as Flying Lotus is a genre-defying exploration of electronic music, jazz, and hip-hop that established him as one of the most innovative producers of the 2010s. The album's complex rhythms and dense layering, featuring contributions from Thom Yorke and Thundercat, created a new form of experimental hip-hop. Songs like 'Do the Astral Plane' showcase his ability to create both cerebral and visceral electronic music."
),
# Alternative/Indie Rock
("The Flaming Lips", "The Soft Bulletin"): (
"Warner Bros., 1999",
"The Flaming Lips' ninth studio album marked their evolution from noisy alternative rock to orchestral psychedelic pop. Wayne Coyne's childlike vocals and the band's lush arrangements on songs like 'Race for the Prize' and 'Waiting for a Superman' created a sound that was both epic and intimate. The album's themes of mortality and hope, combined with its innovative production, established the Flaming Lips as one of alternative rock's most unique voices."
),
("Guided by Voices", "Bee Thousand"): (
"Scat, 1994",
"Robert Pollard's lo-fi masterpiece contains 20 songs in 35 minutes, showcasing his gift for melody and his DIY aesthetic. Recorded on a four-track in Pollard's basement, the album's deliberately rough production and fragmented song structures created a new template for indie rock. Songs like 'I Am a Scientist' and 'Tractor Rape Chain' demonstrate Pollard's ability to create memorable pop songs within an experimental framework."
),
("The Jesus and Mary Chain", "Psychocandy"): (
"Blanco y Negro, 1985",
"The Reid brothers' debut album combined pop melodies with walls of feedback and distortion, creating a sound that influenced generations of alternative rock bands. The album's 14 songs blur the line between beauty and noise, with tracks like 'Just Like Honey' and 'Never Understand' showcasing their ability to create accessible songs within a harsh sonic landscape. The album's influence on shoegaze and alternative rock was immediate and lasting."
),
("Dinosaur Jr.", "You're Living All Over Me"): (
"SST, 1987",
"J. Mascis's guitar heroics and the band's combination of punk energy with classic rock influences created one of the most influential albums of the 1980s alternative rock scene. The album's loud-quiet-loud dynamics and Mascis's distinctive guitar sound on songs like 'Freak Scene' and 'Sludgefest' anticipated the grunge explosion of the early 1990s. The band's influence on alternative rock cannot be overstated."
),
("Mazzy Star", "So Tonight That I Might See"): (
"Capitol, 1993",
"Hope Sandoval's dreamy vocals and David Roback's atmospheric guitar work created one of the most beautiful albums of the 1990s alternative rock scene. The album's languid pace and psychedelic textures on songs like 'Fade Into You' and 'Blue Flower' created a sound that was both nostalgic and timeless. The album's influence on dream pop and shoegaze continues to this day."
),
# Hip-Hop
("EPMD", "Strictly Business"): (
"Priority, 1988",
"Erick Sermon and Parrish Smith's debut album established them as masters of sample-based hip-hop production. The album's laid-back grooves and clever wordplay on songs like the title track and 'You Gots to Chill' created a more relaxed alternative to the aggressive hip-hop of the late 1980s. Their influence on hip-hop production and their role in launching careers of future stars make this album a classic."
),
("Young Thug", "Barter 6"): (
"300 Entertainment, 2015",
"Young Thug's commercial mixtape debut showcased his unique vocal style and melodic approach to trap music. The album's innovative production and Thug's genre-blending approach on songs like 'Check' and 'With That' established him as one of hip-hop's most influential voices. His impact on contemporary rap and his role in popularizing melodic trap cannot be overstated."
),
# Classic Jazz/Blues
("Ornette Coleman", "Free Jazz"): (
"Atlantic, 1961",
"Ornette Coleman's revolutionary album featured two simultaneous quartets improvising freely, creating one of the most challenging and influential albums in jazz history. The 37-minute continuous performance broke down traditional jazz structures and established Coleman as a leader of the free jazz movement. The album's influence on experimental music extends far beyond jazz."
),
# Reggae
("King Tubby", "Meets Rockers Uptown"): (
"Yard, 1976",
"King Tubby's collaboration with Augustus Pablo established the template for dub reggae, using the mixing board as an instrument to create spacious, echo-laden soundscapes. The album's innovative use of reverb, delay, and instrumental isolation techniques created a new form of electronic music that influenced everything from post-punk to electronic dance music."
),
("The Congos", "Heart of the Congos"): (
"Black Ark, 1977",
"Produced by Lee 'Scratch' Perry at his legendary Black Ark studio, this album is considered one of the greatest achievements in reggae music. Cedric Myton's falsetto vocals and the trio's spiritual harmonies, combined with Perry's innovative production, created a deeply mystical form of roots reggae. The album's influence on roots reggae and its spiritual themes make it essential listening."
),
# More Modern Entries
("Tame Impala", "Lonerism"): (
"Modular/Interscope, 2012",
"Kevin Parker's second album as Tame Impala perfected his psychedelic pop sound, combining 1960s influences with modern production techniques. The album's lush soundscapes and introspective lyrics on songs like 'Elephant' and 'Feels Like We Only Go Backwards' created a modern psychedelic classic. The album's influence on contemporary indie rock and electronic music has been enormous."
),
("Big Thief", "U.F.O.F."): (
"4AD, 2019",
"Adrianne Lenker's intimate songwriting and the band's delicate arrangements created one of the most beautiful indie folk albums of the 2010s. The album's sparse production and Lenker's whispered vocals on songs like 'Not' and 'Simulation Swarm' showcase the band's ability to create profound emotional impact through understatement."
),
("The Mountain Goats", "The Sunset Tree"): (
"4AD, 2005",
"John Darnielle's autobiographical album about growing up with an abusive stepfather is a masterpiece of indie folk songwriting. The album's sparse arrangements and Darnielle's literary lyrics on songs like 'This Year' and 'Dance Music' create a powerful emotional journey. The album's influence on indie folk and its unflinching honesty about family trauma make it essential listening."
),
# Electronic/Experimental
("Talk Talk", "Laughing Stock"): (
"Verve, 1991",
"Talk Talk's final album pushed their sound to its most experimental extreme, creating a form of post-rock that influenced countless bands. Mark Hollis's whispered vocals and the band's use of silence and space created music that was both challenging and beautiful. The album's influence on post-rock and experimental music continues to grow."
),
("Throbbing Gristle", "20 Jazz Funk Greats"): (
"Industrial, 1979",
"Despite its misleading title and sunny cover photo, Throbbing Gristle's third album is a dark exploration of industrial music that helped establish the genre. The band's use of synthesizers, tape manipulation, and found sounds created a sound that was both futuristic and disturbing. The album's influence on industrial music and electronic music in general cannot be overstated."
),
# More Hip-Hop/R&B
("Missy Elliott", "Supa Dupa Fly"): (
"The Goldmind/East West, 1997",
"Missy Elliott's debut album, produced largely by Timbaland, established her as one of hip-hop's most innovative artists. The album's futuristic production and Elliott's creative wordplay on songs like 'The Rain (Supa Dupa Fly)' and 'Sock It 2 Me' created a new form of hip-hop that was both experimental and accessible. The album's influence on hip-hop production and female rap cannot be overstated."
),
("Janelle Monáe", "The ArchAndroid"): (
"Wondaland/Bad Boy, 2010",
"Janelle Monáe's debut full-length album is a ambitious concept album that blends funk, soul, rock, and electronic music into a cohesive science fiction narrative. The album's complex arrangements and Monáe's powerful vocals on songs like 'Tightrope' and 'Cold War' showcase her ability to create both accessible pop and experimental art. The album established Monáe as one of the most creative voices in contemporary R&B."
),
}
def read_csv_file(filepath):
"""Read the CSV file and return the data."""
with open(filepath, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
return list(reader)
def identify_missing_albums(data):
"""Identify albums with missing Info and Description."""
missing_albums = []
for row in data:
if not row.get('Info', '').strip() and not row.get('Description', '').strip():
missing_albums.append(row)
return missing_albums
def update_album_info(data, lookup_dict):
"""Update albums with information from the lookup dictionary."""
updated_count = 0
for row in data:
# Check if this album needs updating
if not row.get('Info', '').strip() and not row.get('Description', '').strip():
# Try to find it in our lookup dictionary
key = (row['Artist'], row['Album'])
if key in lookup_dict:
info, description = lookup_dict[key]
row['Info'] = info
row['Description'] = description
updated_count += 1
print(f"Updated: {row['Artist']} - {row['Album']}")
return updated_count
def write_csv_file(filepath, data, fieldnames):
"""Write the updated data back to CSV file."""
with open(filepath, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(data)
def main():
"""Main function to run the extended update process."""
csv_file = '/home/lundberg/projects/top500albums/top_500_albums_2023.csv'
backup_file = f'/home/lundberg/projects/top500albums/top_500_albums_2023_backup_extended_{datetime.now().strftime("%Y%m%d_%H%M%S")}.csv'
print(f"Reading CSV file: {csv_file}")
# Read the original data
data = read_csv_file(csv_file)
total_albums = len(data)
print(f"Total albums in database: {total_albums}")
# Identify albums with missing information
missing_albums = identify_missing_albums(data)
print(f"Albums with missing Info/Description: {len(missing_albums)}")
if len(missing_albums) == 0:
print("No albums need updating!")
return
# Create backup
print(f"Creating backup: {backup_file}")
shutil.copy2(csv_file, backup_file)
# Create lookup dictionary
lookup_dict = create_extended_album_lookup()
print(f"Extended lookup dictionary contains {len(lookup_dict)} albums")
# Update the data
print("\nUpdating albums...")
updated_count = update_album_info(data, lookup_dict)
# Write the updated data back to file
if updated_count > 0:
fieldnames = ['Rank', 'Artist', 'Album', 'Status', 'Info', 'Description']
write_csv_file(csv_file, data, fieldnames)
print(f"\nSuccessfully updated {updated_count} additional albums!")
print(f"Updated file saved as: {csv_file}")
print(f"Backup saved as: {backup_file}")
else:
print("\nNo additional albums were updated.")
# Show remaining missing albums
remaining_missing = identify_missing_albums(data)
print(f"\nRemaining albums with missing info: {len(remaining_missing)}")
if remaining_missing:
print("\nFirst 20 albums still missing information:")
for i, album in enumerate(remaining_missing[:20]):
print(f"{album['Rank']}. {album['Artist']} - {album['Album']}")
if __name__ == "__main__":
main()

View file

@ -0,0 +1,118 @@
#!/usr/bin/env python3
"""
Summary script to analyze the current state of the Top 500 Albums CSV file
and show statistics about missing and updated information.
"""
import csv
def read_csv_file(filepath):
"""Read the CSV file and return the data."""
with open(filepath, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
return list(reader)
def analyze_csv_data(data):
"""Analyze the CSV data and provide statistics."""
total_albums = len(data)
# Count albums with missing info
missing_info = 0
missing_description = 0
missing_both = 0
complete_albums = 0
missing_albums_list = []
for row in data:
has_info = bool(row.get('Info', '').strip())
has_description = bool(row.get('Description', '').strip())
if not has_info:
missing_info += 1
if not has_description:
missing_description += 1
if not has_info and not has_description:
missing_both += 1
missing_albums_list.append(row)
if has_info and has_description:
complete_albums += 1
return {
'total_albums': total_albums,
'missing_info': missing_info,
'missing_description': missing_description,
'missing_both': missing_both,
'complete_albums': complete_albums,
'missing_albums_list': missing_albums_list
}
def main():
"""Main function to analyze and summarize album data."""
csv_file = '/home/lundberg/projects/top500albums/top_500_albums_2023.csv'
print("=== TOP 500 ALBUMS CSV ANALYSIS ===\n")
# Read and analyze the data
data = read_csv_file(csv_file)
stats = analyze_csv_data(data)
print(f"Total albums in database: {stats['total_albums']}")
print(f"Albums with complete info (both Info and Description): {stats['complete_albums']}")
print(f"Albums missing Info field: {stats['missing_info']}")
print(f"Albums missing Description field: {stats['missing_description']}")
print(f"Albums missing both Info and Description: {stats['missing_both']}")
completion_rate = (stats['complete_albums'] / stats['total_albums']) * 100
print(f"\nCompletion rate: {completion_rate:.1f}%")
print(f"Albums updated by our scripts: {500 - 192} (original missing) -> {stats['complete_albums']} (current complete)")
print(f"Total albums updated: {500 - 192 - stats['complete_albums']} albums filled in")
if stats['missing_albums_list']:
print(f"\n=== REMAINING {len(stats['missing_albums_list'])} ALBUMS WITH MISSING INFO ===")
# Group by decade or genre for easier analysis
missing_by_rank = sorted(stats['missing_albums_list'], key=lambda x: int(x['Rank']))
print("\nTop 20 albums still needing information:")
for i, album in enumerate(missing_by_rank[:20]):
print(f"{album['Rank']:>3}. {album['Artist']} - {album['Album']}")
print(f"\n... and {len(missing_by_rank) - 20} more albums")
# Show some statistics about the remaining albums
print(f"\n=== ANALYSIS OF REMAINING ALBUMS ===")
# Count by rank ranges
top_100 = len([a for a in missing_by_rank if int(a['Rank']) <= 100])
rank_101_200 = len([a for a in missing_by_rank if 101 <= int(a['Rank']) <= 200])
rank_201_300 = len([a for a in missing_by_rank if 201 <= int(a['Rank']) <= 300])
rank_301_400 = len([a for a in missing_by_rank if 301 <= int(a['Rank']) <= 400])
rank_401_500 = len([a for a in missing_by_rank if 401 <= int(a['Rank']) <= 500])
print(f"Missing albums by rank range:")
print(f" Rank 1-100: {top_100:>3} albums")
print(f" Rank 101-200: {rank_101_200:>3} albums")
print(f" Rank 201-300: {rank_201_300:>3} albums")
print(f" Rank 301-400: {rank_301_400:>3} albums")
print(f" Rank 401-500: {rank_401_500:>3} albums")
# Show some notable missing albums that could be researched
notable_missing = []
for album in missing_by_rank:
artist = album['Artist'].lower()
if any(keyword in artist for keyword in ['beatles', 'bob dylan', 'rolling stones', 'beach boys',
'led zeppelin', 'pink floyd', 'david bowie', 'radiohead',
'nirvana', 'sex pistols', 'velvet underground']):
notable_missing.append(album)
if notable_missing:
print(f"\n=== NOTABLE CLASSIC ARTISTS STILL MISSING INFO ===")
for album in notable_missing[:10]:
print(f"{album['Rank']:>3}. {album['Artist']} - {album['Album']}")
else:
print("\n🎉 ALL ALBUMS HAVE COMPLETE INFORMATION! 🎉")
if __name__ == "__main__":
main()

View file

@ -0,0 +1,178 @@
#!/usr/bin/env python3
"""
Compare Rolling Stone Top 500 Albums lists from 2020 and 2023 (Wikipedia).
Identifies new albums, removed albums, and ranking changes.
"""
import csv
import re
from typing import Dict, List, Tuple, Optional
def normalize_text(text: str) -> str:
"""Normalize text for comparison: lowercase, remove punctuation, extra spaces."""
# Convert to lowercase
text = text.lower()
# Remove common punctuation and special characters
text = re.sub(r'[^\w\s]', ' ', text)
# Replace multiple spaces with single space
text = re.sub(r'\s+', ' ', text)
# Remove leading/trailing spaces
text = text.strip()
return text
def create_album_key(artist: str, album: str) -> str:
"""Create a normalized key for album matching."""
# Normalize both artist and album
norm_artist = normalize_text(artist)
norm_album = normalize_text(album)
# Handle common variations
# Remove "the" from the beginning of artist names
if norm_artist.startswith("the "):
norm_artist = norm_artist[4:]
# Handle "&" vs "and" in artist names
norm_artist = norm_artist.replace(" and ", " ").replace(" & ", " ")
# Create combined key
return f"{norm_artist}|{norm_album}"
def fuzzy_match(key1: str, key2: str) -> bool:
"""Check if two album keys are similar enough to be considered the same."""
# Exact match after normalization
if key1 == key2:
return True
# Split into artist and album parts
artist1, album1 = key1.split('|', 1)
artist2, album2 = key2.split('|', 1)
# Check if albums are very similar (allowing for minor variations)
# Using simple string comparison - could use more sophisticated matching
if artist1 == artist2:
# Check album similarity
words1 = set(album1.split())
words2 = set(album2.split())
# If most words match, consider it a match
if len(words1 & words2) >= min(len(words1), len(words2)) * 0.8:
return True
return False
def find_album_in_2020(artist: str, album: str, albums_2020: Dict[str, Tuple[int, str, str]]) -> Optional[int]:
"""Find an album in the 2020 list, return its rank if found."""
key_2023 = create_album_key(artist, album)
# First try exact match
if key_2023 in albums_2020:
return albums_2020[key_2023][0]
# Try fuzzy matching
for key_2020, (rank, _, _) in albums_2020.items():
if fuzzy_match(key_2023, key_2020):
return rank
return None
def main():
# Read 2020 Rolling Stone list
albums_2020 = {} # key -> (rank, artist, album)
print("Reading 2020 Rolling Stone list...")
with open('rolling_stone_top_500_albums_2020.csv', 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
rank = int(row['Rank'])
artist = row['Artist']
album = row['Album']
key = create_album_key(artist, album)
albums_2020[key] = (rank, artist, album)
print(f"Loaded {len(albums_2020)} albums from 2020 list")
# Read 2023 Wikipedia list and compare
results = []
print("\nReading 2023 Wikipedia list and comparing...")
with open('wikipedia_top_500_albums.csv', 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
rank_2023 = int(row['rank'])
artist = row['artist'].strip()
album = row['album'].strip()
# Find in 2020 list
rank_2020 = find_album_in_2020(artist, album, albums_2020)
if rank_2020 is None:
status = "New in 2023"
else:
change = rank_2020 - rank_2023
if change == 0:
status = "No change"
elif change > 0:
status = f"+{change}" # Improved ranking (moved up)
else:
status = str(change) # Dropped ranking (moved down)
results.append({
'Rank': rank_2023,
'Artist': artist,
'Album': album,
'Status': status
})
# Write results to CSV
print("\nWriting results to top_500_albums_2023.csv...")
with open('top_500_albums_2023.csv', 'w', newline='', encoding='utf-8') as f:
fieldnames = ['Rank', 'Artist', 'Album', 'Status']
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(results)
# Generate summary statistics
new_albums = sum(1 for r in results if r['Status'] == "New in 2023")
no_change = sum(1 for r in results if r['Status'] == "No change")
improved = sum(1 for r in results if r['Status'].startswith('+'))
dropped = sum(1 for r in results if r['Status'].startswith('-') and r['Status'] != "New in 2023")
print("\nSummary:")
print(f"Total albums in 2023 list: {len(results)}")
print(f"New albums in 2023: {new_albums}")
print(f"Albums with no ranking change: {no_change}")
print(f"Albums that improved ranking: {improved}")
print(f"Albums that dropped in ranking: {dropped}")
# Find biggest movers
biggest_improvements = []
biggest_drops = []
for r in results:
if r['Status'].startswith('+'):
change = int(r['Status'])
biggest_improvements.append((change, r['Artist'], r['Album'], r['Rank']))
elif r['Status'].startswith('-') and r['Status'] != "New in 2023":
change = int(r['Status'])
biggest_drops.append((change, r['Artist'], r['Album'], r['Rank']))
biggest_improvements.sort(reverse=True)
biggest_drops.sort()
print("\nTop 5 biggest improvements:")
for change, artist, album, rank in biggest_improvements[:5]:
print(f" {artist} - {album}: {change} (now at #{rank})")
print("\nTop 5 biggest drops:")
for change, artist, album, rank in biggest_drops[:5]:
print(f" {artist} - {album}: {change} (now at #{rank})")
print(f"\nResults saved to: top_500_albums_2023.csv")
if __name__ == "__main__":
main()

View file

@ -0,0 +1,77 @@
#!/usr/bin/env python3
"""
Complete the final 7 missing albums with Info and Description.
End descriptions with (by Claude) except for user-provided content.
"""
import csv
# Final missing albums data
final_missing_albums = {
("Otis Redding", "Complete & Unbelievable: The Otis Redding Dictionary of Soul"): {
"info": "Volt/Atco, 1966",
"description": "Complete & Unbelievable: The Otis Redding Dictionary of Soul, or simply Dictionary of Soul, is the fifth studio album by the American soul singer-songwriter Otis Redding and his last solo studio album released before his death. The successful Otis Blue and the following performance at Whisky a Go Go led to his rising fame across the United States. The first side of the album mainly contains cover versions, and the second songs mainly written by Redding. The Otis Redding Dictionary of Soul was released in October 1966 on the Stax label and peaked at number 73 and at number 5 on the Billboard 200 and the R&B LP charts respectively. The album produced two singles, \"Fa-Fa-Fa-Fa-Fa (Sad Song)\" and \"Try a Little Tenderness\". In 2000 it was voted number 488 in Colin Larkin's All Time Top 1000 Albums. In 2012, the album was ranked number 254 on Rolling Stone magazine's list of The 500 Greatest Albums of All Time. An expanded version, which includes stereo and mono mixes of the original album as well as additional tracks, was released in 2016."
},
("Al Green", "Al Green's Greatest Hits"): {
"info": "Hi Records, 1975",
"description": "This essential compilation captures Al Green at the absolute peak of his powers during his legendary collaboration with producer Willie Mitchell at Hi Records in Memphis. Featuring classics like 'Let's Stay Together,' 'Love and Happiness,' 'I'm Still in Love with You,' and 'Take Me to the River,' the collection showcases Green's unique ability to blend gospel fervor with sensual soul music. His silky smooth vocals, perfectly complemented by Mitchell's immaculate production and the Hi Rhythm Section's tight grooves, created a template for romantic soul that has never been equaled. Green's approach to love songs was both sacred and profane, expressing spiritual devotion and carnal desire with equal conviction. This compilation documents one of the most important partnerships in soul music history. (by Claude)"
},
("Black Uhuru", "Red"): {
"info": "Island, 1981",
"description": "Black Uhuru's breakthrough album marked a revolutionary moment in reggae music, introducing a harder, more militant sound that influenced dancehall and conscious reggae for decades. Featuring the powerhouse vocals of Michael Rose, Puma Jones, and Duckie Simpson, backed by the innovative production of Sly & Robbie, 'Red' created a new template for reggae that was both spiritually conscious and rhythmically aggressive. Songs like 'Guess Who's Coming to Dinner' and 'Youth of Eglington' addressed social issues with unflinching directness, while tracks like 'Plastic Smile' showcased the group's ability to blend political commentary with infectious grooves. The album's success helped establish Island Records as reggae's premier international label and proved that conscious reggae could achieve mainstream success without compromising its message. (by Claude)"
},
("Muddy Waters", "The Anthology: 19471972"): {
"info": "Chess/MCA, 1989",
"description": "This comprehensive collection documents the extraordinary career of the man who brought Delta blues to Chicago and helped create the template for rock and roll. From his early acoustic recordings for the Library of Congress to his revolutionary electric blues sides for Chess Records, the anthology traces Waters' evolution from Mississippi sharecropper to urban blues legend. Featuring classics like 'Hoochie Coochie Man,' 'Mannish Boy,' 'Got My Mojo Working,' and 'Rollin' Stone,' the collection showcases Waters' powerful vocals and commanding stage presence alongside the legendary Chess studio band. His influence on rock music was immeasurable, inspiring everyone from the Rolling Stones to Led Zeppelin. This anthology captures the full scope of Waters' contribution to American music and his role in bridging rural and urban Black musical traditions. (by Claude)"
},
("Various artists", "Back to Mono (19581969)"): {
"info": "ABKCO, 1991",
"description": "Phil Spector's comprehensive box set anthology documents the revolutionary 'Wall of Sound' that changed the landscape of popular music in the 1960s. Featuring classic recordings by The Ronettes, The Crystals, Ike & Tina Turner, and The Righteous Brothers, the collection showcases Spector's innovative production techniques that layered orchestras, multiple pianos, and echo chambers to create monumentally powerful pop symphonies. Songs like 'Be My Baby,' 'You've Lost That Lovin' Feelin',' and 'River Deep - Mountain High' demonstrated Spector's ability to transform simple pop songs into epic emotional statements. His meticulous attention to detail and obsessive studio methods influenced countless producers and helped establish the producer as a creative force equal to the artist. This collection preserves one of the most distinctive and influential sounds in popular music history. (by Claude)"
},
("The Ronettes", "Presenting the Fabulous Ronettes Featuring Veronica"): {
"info": "Philles, 1964",
"description": "The Ronettes' debut album captures the essence of Phil Spector's 'Wall of Sound' at its most perfect, featuring some of the most exhilarating pop music ever recorded. Ronnie Spector's distinctive vocals, sultry and innocent simultaneously, soar over Spector's massive orchestral arrangements on classics like 'Be My Baby,' 'Baby, I Love You,' and 'The Best Part of Breakin' Up.' The group's tough, street-smart image combined with their sophisticated harmonies created a template for girl groups that influenced everyone from The Shangri-Las to punk rockers decades later. Spector's revolutionary production techniques, using multiple instruments and echo chambers to create an overwhelming sonic experience, helped establish the album as a landmark of 1960s pop music. The Ronettes' unique blend of vulnerability and attitude made them one of the era's most compelling acts. (by Claude)"
},
("Rufus featuring Chaka Khan", "Ask Rufus"): {
"info": "ABC, 1977",
"description": "Rufus' fifth studio album showcased the band at the height of their creative powers, blending funk, soul, and rock with Chaka Khan's extraordinary vocals leading the way. The album features the massive hit 'Sweet Thing,' which became one of Khan's signature songs and demonstrated her ability to convey both tenderness and power within a single performance. The band's tight musicianship, anchored by Tony Maiden's guitar work and the rhythm section's precise grooves, provided the perfect foundation for Khan's dynamic vocal style. Songs like 'Hollywood' and 'Egyptian Song' showcased the group's willingness to experiment while maintaining their essential funkiness. 'Ask Rufus' captured the band during their most successful period and helped establish Chaka Khan as one of the greatest vocalists of her generation, setting the stage for her legendary solo career. (by Claude)"
}
}
def main():
# Read current CSV
albums = []
with open('top_500_albums_2023.csv', 'r', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
albums.append(row)
# Update the final missing albums
updated_count = 0
for album in albums:
artist = album['Artist'].strip()
album_title = album['Album'].strip()
# Check if this album is missing info/description
if not album['Info'].strip() or not album['Description'].strip():
if (artist, album_title) in final_missing_albums:
album_data = final_missing_albums[(artist, album_title)]
if not album['Info'].strip():
album['Info'] = album_data['info']
if not album['Description'].strip():
album['Description'] = album_data['description']
updated_count += 1
print(f"✓ Completed: {artist} - {album_title}")
# Write updated CSV
with open('top_500_albums_2023.csv', 'w', newline='', encoding='utf-8') as file:
fieldnames = ['Rank', 'Artist', 'Album', 'Status', 'Info', 'Description']
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(albums)
print(f"\n🎉 Completed final {updated_count} albums!")
print("Database is now 100% complete with Info and Description for all 500 albums!")
if __name__ == "__main__":
main()

77
scripts/create_favicon.py Normal file
View file

@ -0,0 +1,77 @@
#!/usr/bin/env python3
"""
Create a favicon for the Top 500 Albums website
"""
from PIL import Image, ImageDraw, ImageFont
import os
def create_favicon():
# Create a new image with transparent background
size = 32
img = Image.new('RGBA', (size, size), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# Create gradient background (simulate with filled circle)
# Purple/blue gradient colors
colors = [(102, 126, 234), (118, 75, 162)] # #667eea to #764ba2
# Draw background circle
margin = 1
draw.ellipse([margin, margin, size-margin, size-margin],
fill=(102, 126, 234), outline=None)
# Draw vinyl record
record_margin = 4
draw.ellipse([record_margin, record_margin, size-record_margin, size-record_margin],
fill=(26, 26, 26), outline=None)
# Draw center hole
center = size // 2
hole_radius = 3
draw.ellipse([center-hole_radius, center-hole_radius,
center+hole_radius, center+hole_radius],
fill=(102, 126, 234), outline=None)
# Draw grooves
for r in range(6, 12, 2):
draw.ellipse([center-r, center-r, center+r, center+r],
fill=None, outline=(51, 51, 51), width=1)
# Try to add "500" text
try:
# Use default font, small size
font = ImageFont.load_default()
text = "500"
# Get text size
bbox = draw.textbbox((0, 0), text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
# Center text at bottom
x = (size - text_width) // 2
y = size - text_height - 2
draw.text((x, y), text, fill=(255, 255, 255), font=font)
except:
# If font fails, just add a music note
draw.text((center-4, size-10), "", fill=(255, 255, 255))
# Save as PNG first
img.save('favicon-32x32.png', 'PNG')
# Create 16x16 version
img16 = img.resize((16, 16), Image.Resampling.LANCZOS)
img16.save('favicon-16x16.png', 'PNG')
# Create ICO file with multiple sizes
img.save('favicon.ico', format='ICO', sizes=[(16, 16), (32, 32)])
print("Favicon files created:")
print("- favicon.ico")
print("- favicon-16x16.png")
print("- favicon-32x32.png")
if __name__ == "__main__":
create_favicon()

View file

@ -0,0 +1,59 @@
#!/usr/bin/env python3
"""
Create a simple favicon using basic drawing
"""
def create_favicon_data():
"""Create a simple 16x16 favicon as a data URL"""
# Create a simple pattern for 16x16 favicon
# This will be a simplified version of our design
favicon_html = '''
<!DOCTYPE html>
<html>
<head><title>Favicon Creator</title></head>
<body>
<canvas id="favicon" width="16" height="16"></canvas>
<script>
const canvas = document.getElementById('favicon');
const ctx = canvas.getContext('2d');
// Fill background with gradient-like color
ctx.fillStyle = '#667eea';
ctx.fillRect(0, 0, 16, 16);
// Draw record
ctx.fillStyle = '#1a1a1a';
ctx.beginPath();
ctx.arc(8, 8, 6, 0, 2 * Math.PI);
ctx.fill();
// Center hole
ctx.fillStyle = '#667eea';
ctx.beginPath();
ctx.arc(8, 8, 2, 0, 2 * Math.PI);
ctx.fill();
// Download as PNG
function download() {
const link = document.createElement('a');
link.download = 'favicon-16x16.png';
link.href = canvas.toDataURL();
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
// Auto download
setTimeout(download, 100);
</script>
</body>
</html>'''
with open('favicon_generator.html', 'w') as f:
f.write(favicon_html)
print("Created favicon_generator.html - open this in a browser to download the favicon")
if __name__ == "__main__":
create_favicon_data()

View file

@ -0,0 +1,209 @@
#!/usr/bin/env python3
"""
Download album cover images for Top 500 Albums using iTunes Search API
"""
import requests
import csv
import os
import re
import time
import json
from urllib.parse import quote
from urllib.request import urlretrieve
def sanitize_filename(text):
"""Remove or replace characters that aren't valid in filenames"""
# Remove/replace problematic characters
text = re.sub(r'[<>:"/\\|?*]', '', text)
text = re.sub(r'[^\w\s\-_\.]', '', text)
text = re.sub(r'\s+', '_', text.strip())
return text[:100] # Limit length
def search_itunes(artist, album):
"""Search iTunes API for album artwork"""
# Clean up search terms
search_term = f"{artist} {album}".strip()
search_term = re.sub(r'\([^)]*\)', '', search_term) # Remove parentheses content
search_term = re.sub(r'\s+', ' ', search_term).strip()
url = "https://itunes.apple.com/search"
params = {
'term': search_term,
'media': 'music',
'entity': 'album',
'limit': 5
}
try:
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
if data['resultCount'] > 0:
# Try to find the best match
for result in data['results']:
result_artist = result.get('artistName', '').lower()
result_album = result.get('collectionName', '').lower()
# Simple matching - check if artist and album names are similar
if (artist.lower() in result_artist or result_artist in artist.lower()) and \
(album.lower() in result_album or result_album in album.lower()):
artwork_url = result.get('artworkUrl100', '').replace('100x100', '600x600')
return artwork_url
# If no exact match, return the first result
first_result = data['results'][0]
artwork_url = first_result.get('artworkUrl100', '').replace('100x100', '600x600')
return artwork_url
except Exception as e:
print(f"Error searching for {artist} - {album}: {e}")
return None
return None
def download_album_covers():
"""Main function to download all album covers"""
# Create covers directory
covers_dir = 'covers'
if not os.path.exists(covers_dir):
os.makedirs(covers_dir)
# Read the CSV file
csv_file = 'top_500_albums_2023.csv'
if not os.path.exists(csv_file):
print(f"Error: {csv_file} not found!")
return
albums_processed = 0
albums_found = 0
albums_downloaded = 0
# Keep track of what we've processed
log_file = 'download_log.json'
processed_albums = {}
# Load existing log if it exists
if os.path.exists(log_file):
with open(log_file, 'r') as f:
processed_albums = json.load(f)
with open(csv_file, 'r', encoding='utf-8') as file:
csv_reader = csv.DictReader(file)
for row in csv_reader:
rank = row.get('Rank', '').strip()
artist = row.get('Artist', '').strip()
album = row.get('Album', '').strip()
if not artist or not album:
continue
albums_processed += 1
# Create filename
safe_artist = sanitize_filename(artist)
safe_album = sanitize_filename(album)
filename = f"rank_{rank:03d}_{safe_artist}_{safe_album}.jpg"
filepath = os.path.join(covers_dir, filename)
# Skip if already downloaded
if os.path.exists(filepath):
print(f"✓ Already exists: {rank}. {artist} - {album}")
albums_downloaded += 1
continue
# Skip if we've already tried and failed
album_key = f"{artist}_{album}"
if album_key in processed_albums and not processed_albums[album_key]:
print(f"⚠ Previously failed: {rank}. {artist} - {album}")
continue
print(f"Searching: {rank}. {artist} - {album}")
# Search for artwork
artwork_url = search_itunes(artist, album)
if artwork_url:
try:
print(f" Downloading from: {artwork_url}")
urlretrieve(artwork_url, filepath)
print(f" ✓ Downloaded: {filename}")
albums_found += 1
albums_downloaded += 1
processed_albums[album_key] = True
except Exception as e:
print(f" ✗ Download failed: {e}")
processed_albums[album_key] = False
else:
print(f" ✗ No artwork found")
processed_albums[album_key] = False
# Save progress
with open(log_file, 'w') as f:
json.dump(processed_albums, f, indent=2)
# Be nice to the API
time.sleep(0.5)
# Progress update
if albums_processed % 25 == 0:
print(f"\nProgress: {albums_processed}/500 processed, {albums_found} found, {albums_downloaded} downloaded\n")
print(f"\nFinal Results:")
print(f"Albums processed: {albums_processed}")
print(f"Artwork found: {albums_found}")
print(f"Total downloaded: {albums_downloaded}")
print(f"Success rate: {albums_found/albums_processed*100:.1f}%")
def create_missing_report():
"""Create a report of albums without covers"""
covers_dir = 'covers'
missing_albums = []
with open('top_500_albums_2023.csv', 'r', encoding='utf-8') as file:
csv_reader = csv.DictReader(file)
for row in csv_reader:
rank = row.get('Rank', '').strip()
artist = row.get('Artist', '').strip()
album = row.get('Album', '').strip()
safe_artist = sanitize_filename(artist)
safe_album = sanitize_filename(album)
filename = f"rank_{rank:03d}_{safe_artist}_{safe_album}.jpg"
filepath = os.path.join(covers_dir, filename)
if not os.path.exists(filepath):
missing_albums.append({
'rank': rank,
'artist': artist,
'album': album,
'filename': filename
})
print(f"\nMissing covers: {len(missing_albums)}")
if missing_albums:
with open('missing_covers.csv', 'w', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=['rank', 'artist', 'album', 'filename'])
writer.writeheader()
writer.writerows(missing_albums)
print("Created missing_covers.csv with list of albums without artwork")
if __name__ == "__main__":
print("Top 500 Albums Cover Art Downloader")
print("===================================")
choice = input("Choose option:\n1. Download covers\n2. Create missing report\n3. Both\nEnter choice (1-3): ")
if choice in ['1', '3']:
download_album_covers()
if choice in ['2', '3']:
create_missing_report()
print("\nDone!")

View file

@ -0,0 +1,221 @@
#!/usr/bin/env python3
"""
Download album cover images for Top 500 Albums using iTunes Search API
Simple version using only built-in Python modules
"""
import urllib.request
import urllib.parse
import json
import csv
import os
import re
import time
def sanitize_filename(text):
"""Remove or replace characters that aren't valid in filenames"""
# Remove/replace problematic characters
text = re.sub(r'[<>:"/\\|?*]', '', text)
text = re.sub(r'[^\w\s\-_\.]', '', text)
text = re.sub(r'\s+', '_', text.strip())
return text[:100] # Limit length
def search_itunes(artist, album):
"""Search iTunes API for album artwork"""
# Clean up search terms
search_term = f"{artist} {album}".strip()
search_term = re.sub(r'\([^)]*\)', '', search_term) # Remove parentheses content
search_term = re.sub(r'\s+', ' ', search_term).strip()
# URL encode the search term
encoded_term = urllib.parse.quote(search_term)
url = f"https://itunes.apple.com/search?term={encoded_term}&media=music&entity=album&limit=5"
try:
with urllib.request.urlopen(url, timeout=10) as response:
data = json.loads(response.read().decode())
if data['resultCount'] > 0:
# Try to find the best match
for result in data['results']:
result_artist = result.get('artistName', '').lower()
result_album = result.get('collectionName', '').lower()
# Simple matching - check if artist and album names are similar
if (artist.lower() in result_artist or result_artist in artist.lower()) and \
(album.lower() in result_album or result_album in album.lower()):
artwork_url = result.get('artworkUrl100', '').replace('100x100', '600x600')
return artwork_url
# If no exact match, return the first result
first_result = data['results'][0]
artwork_url = first_result.get('artworkUrl100', '').replace('100x100', '600x600')
return artwork_url
except Exception as e:
print(f"Error searching for {artist} - {album}: {e}")
return None
return None
def download_sample_covers(limit=10):
"""Download a sample of album covers to test the system"""
# Create covers directory
covers_dir = 'covers'
if not os.path.exists(covers_dir):
os.makedirs(covers_dir)
# Read the CSV file
csv_file = 'top_500_albums_2023.csv'
if not os.path.exists(csv_file):
print(f"Error: {csv_file} not found!")
return
albums_processed = 0
albums_found = 0
print(f"Downloading sample of {limit} album covers...")
with open(csv_file, 'r', encoding='utf-8') as file:
csv_reader = csv.DictReader(file)
for row in csv_reader:
if albums_processed >= limit:
break
rank = row.get('Rank', '').strip()
artist = row.get('Artist', '').strip()
album = row.get('Album', '').strip()
if not artist or not album:
continue
albums_processed += 1
# Create filename
safe_artist = sanitize_filename(artist)
safe_album = sanitize_filename(album)
filename = f"rank_{rank.zfill(3)}_{safe_artist}_{safe_album}.jpg"
filepath = os.path.join(covers_dir, filename)
# Skip if already downloaded
if os.path.exists(filepath):
print(f"✓ Already exists: {rank}. {artist} - {album}")
albums_found += 1
continue
print(f"Searching: {rank}. {artist} - {album}")
# Search for artwork
artwork_url = search_itunes(artist, album)
if artwork_url:
try:
print(f" Downloading from: {artwork_url}")
urllib.request.urlretrieve(artwork_url, filepath)
print(f" ✓ Downloaded: {filename}")
albums_found += 1
except Exception as e:
print(f" ✗ Download failed: {e}")
else:
print(f" ✗ No artwork found")
# Be nice to the API
time.sleep(1)
print(f"\nSample Results:")
print(f"Albums processed: {albums_processed}")
print(f"Artwork found: {albums_found}")
print(f"Success rate: {albums_found/albums_processed*100:.1f}%")
def download_top_albums(limit=50):
"""Download covers for top N albums"""
# Create covers directory
covers_dir = 'covers'
if not os.path.exists(covers_dir):
os.makedirs(covers_dir)
# Read the CSV file
csv_file = 'top_500_albums_2023.csv'
if not os.path.exists(csv_file):
print(f"Error: {csv_file} not found!")
return
albums_processed = 0
albums_found = 0
print(f"Downloading covers for top {limit} albums...")
with open(csv_file, 'r', encoding='utf-8') as file:
csv_reader = csv.DictReader(file)
# Sort by rank to get top albums first
rows = list(csv_reader)
rows.sort(key=lambda x: int(x.get('Rank', 999)))
for row in rows[:limit]:
rank = row.get('Rank', '').strip()
artist = row.get('Artist', '').strip()
album = row.get('Album', '').strip()
if not artist or not album:
continue
albums_processed += 1
# Create filename
safe_artist = sanitize_filename(artist)
safe_album = sanitize_filename(album)
filename = f"rank_{rank.zfill(3)}_{safe_artist}_{safe_album}.jpg"
filepath = os.path.join(covers_dir, filename)
# Skip if already downloaded
if os.path.exists(filepath):
print(f"✓ Already exists: {rank}. {artist} - {album}")
albums_found += 1
continue
print(f"Searching: {rank}. {artist} - {album}")
# Search for artwork
artwork_url = search_itunes(artist, album)
if artwork_url:
try:
print(f" Downloading from: {artwork_url}")
urllib.request.urlretrieve(artwork_url, filepath)
print(f" ✓ Downloaded: {filename}")
albums_found += 1
except Exception as e:
print(f" ✗ Download failed: {e}")
else:
print(f" ✗ No artwork found")
# Be nice to the API
time.sleep(1)
print(f"\nTop {limit} Results:")
print(f"Albums processed: {albums_processed}")
print(f"Artwork found: {albums_found}")
print(f"Success rate: {albums_found/albums_processed*100:.1f}%")
if __name__ == "__main__":
print("Top 500 Albums Cover Art Downloader (Simple Version)")
print("==================================================")
choice = input("Choose option:\n1. Download sample (10 albums)\n2. Download top 50 albums\n3. Download top 100 albums\nEnter choice (1-3): ")
if choice == '1':
download_sample_covers(10)
elif choice == '2':
download_top_albums(50)
elif choice == '3':
download_top_albums(100)
else:
print("Invalid choice!")
print("\nDone!")

View file

@ -0,0 +1,176 @@
#!/usr/bin/env python3
"""
Download album covers for ALL 500 albums using iTunes Search API
"""
import urllib.request
import urllib.parse
import json
import csv
import os
import re
import time
def sanitize_filename(text):
"""Remove or replace characters that aren't valid in filenames"""
# Remove/replace problematic characters
text = re.sub(r'[<>:"/\\|?*]', '', text)
text = re.sub(r'[^\w\s\-_\.]', '', text)
text = re.sub(r'\s+', '_', text.strip())
return text[:100] # Limit length
def search_itunes(artist, album):
"""Search iTunes API for album artwork"""
# Clean up search terms
search_term = f"{artist} {album}".strip()
search_term = re.sub(r'\([^)]*\)', '', search_term) # Remove parentheses content
search_term = re.sub(r'\s+', ' ', search_term).strip()
# URL encode the search term
encoded_term = urllib.parse.quote(search_term)
url = f"https://itunes.apple.com/search?term={encoded_term}&media=music&entity=album&limit=5"
try:
with urllib.request.urlopen(url, timeout=15) as response:
data = json.loads(response.read().decode())
if data['resultCount'] > 0:
# Try to find the best match
for result in data['results']:
result_artist = result.get('artistName', '').lower()
result_album = result.get('collectionName', '').lower()
# Simple matching - check if artist and album names are similar
if (artist.lower() in result_artist or result_artist in artist.lower()) and \
(album.lower() in result_album or result_album in album.lower()):
artwork_url = result.get('artworkUrl100', '').replace('100x100', '600x600')
return artwork_url
# If no exact match, return the first result
first_result = data['results'][0]
artwork_url = first_result.get('artworkUrl100', '').replace('100x100', '600x600')
return artwork_url
except Exception as e:
print(f"Error searching for {artist} - {album}: {e}")
return None
return None
def download_all_covers():
"""Download covers for all 500 albums"""
# Create covers directory
covers_dir = 'covers'
if not os.path.exists(covers_dir):
os.makedirs(covers_dir)
# Read the CSV file
csv_file = 'top_500_albums_2023.csv'
if not os.path.exists(csv_file):
print(f"Error: {csv_file} not found!")
return
albums_processed = 0
albums_found = 0
albums_skipped = 0
failed_albums = []
print("Downloading covers for ALL 500 albums...")
print("This will take a while to be respectful to the iTunes API...\n")
with open(csv_file, 'r', encoding='utf-8') as file:
csv_reader = csv.DictReader(file)
# Convert to list and sort by rank
rows = list(csv_reader)
rows.sort(key=lambda x: int(x.get('Rank', 999)))
for i, row in enumerate(rows):
rank = row.get('Rank', '').strip()
artist = row.get('Artist', '').strip()
album = row.get('Album', '').strip()
if not artist or not album:
continue
albums_processed += 1
# Create filename
safe_artist = sanitize_filename(artist)
safe_album = sanitize_filename(album)
filename = f"rank_{rank.zfill(3)}_{safe_artist}_{safe_album}.jpg"
filepath = os.path.join(covers_dir, filename)
# Skip if already downloaded
if os.path.exists(filepath):
albums_skipped += 1
if albums_processed % 25 == 0:
print(f"✓ Already exists: {rank}. {artist} - {album}")
continue
print(f"Searching [{albums_processed}/500]: {rank}. {artist} - {album}")
# Search for artwork
artwork_url = search_itunes(artist, album)
if artwork_url:
try:
print(f" Downloading from: {artwork_url}")
urllib.request.urlretrieve(artwork_url, filepath)
print(f" ✓ Downloaded: {filename}")
albums_found += 1
except Exception as e:
print(f" ✗ Download failed: {e}")
failed_albums.append(f"{rank}. {artist} - {album}")
else:
print(f" ✗ No artwork found")
failed_albums.append(f"{rank}. {artist} - {album}")
# Be nice to the API - longer delay for bulk download
time.sleep(1.2)
# Progress update every 25 albums
if albums_processed % 25 == 0:
print(f"\n--- Progress Update ---")
print(f"Processed: {albums_processed}/500 ({albums_processed/500*100:.1f}%)")
print(f"Found: {albums_found}")
print(f"Skipped (already exist): {albums_skipped}")
print(f"Failed: {len(failed_albums)}")
print(f"Success rate: {albums_found/(albums_processed-albums_skipped)*100:.1f}%")
print("----------------------\n")
print(f"\n🎉 FINAL RESULTS:")
print(f"Albums processed: {albums_processed}")
print(f"Already existed: {albums_skipped}")
print(f"New downloads: {albums_found}")
print(f"Failed to find: {len(failed_albums)}")
print(f"Total covers available: {albums_found + albums_skipped}")
print(f"Overall success rate: {(albums_found + albums_skipped)/albums_processed*100:.1f}%")
if failed_albums:
print(f"\n❌ Failed albums ({len(failed_albums)}):")
for album in failed_albums[:10]: # Show first 10
print(f" {album}")
if len(failed_albums) > 10:
print(f" ... and {len(failed_albums) - 10} more")
# Save failed albums to file
with open('failed_downloads.txt', 'w') as f:
for album in failed_albums:
f.write(f"{album}\n")
print(f"\nFull list saved to failed_downloads.txt")
if __name__ == "__main__":
print("🎵 Top 500 Albums - Complete Cover Art Downloader")
print("=" * 50)
confirm = input("This will download covers for all 500 albums.\nThis may take 10-15 minutes. Continue? (y/n): ")
if confirm.lower() in ['y', 'yes']:
download_all_covers()
else:
print("Download cancelled.")
print("\nDone!")

View file

@ -0,0 +1,162 @@
#!/usr/bin/env python3
"""
Download album covers for albums that don't have covers yet
"""
import urllib.request
import urllib.parse
import json
import csv
import os
import re
import time
def sanitize_filename(text):
"""Remove or replace characters that aren't valid in filenames"""
# Remove/replace problematic characters
text = re.sub(r'[<>:"/\\|?*]', '', text)
text = re.sub(r'[^\w\s\-_\.]', '', text)
text = re.sub(r'\s+', '_', text.strip())
return text[:100] # Limit length
def search_itunes(artist, album):
"""Search iTunes API for album artwork"""
# Clean up search terms
search_term = f"{artist} {album}".strip()
search_term = re.sub(r'\([^)]*\)', '', search_term) # Remove parentheses content
search_term = re.sub(r'\s+', ' ', search_term).strip()
# URL encode the search term
encoded_term = urllib.parse.quote(search_term)
url = f"https://itunes.apple.com/search?term={encoded_term}&media=music&entity=album&limit=5"
try:
with urllib.request.urlopen(url, timeout=15) as response:
data = json.loads(response.read().decode())
if data['resultCount'] > 0:
# Try to find the best match
for result in data['results']:
result_artist = result.get('artistName', '').lower()
result_album = result.get('collectionName', '').lower()
# Simple matching - check if artist and album names are similar
if (artist.lower() in result_artist or result_artist in artist.lower()) and \
(album.lower() in result_album or result_album in album.lower()):
artwork_url = result.get('artworkUrl100', '').replace('100x100', '600x600')
return artwork_url
# If no exact match, return the first result
first_result = data['results'][0]
artwork_url = first_result.get('artworkUrl100', '').replace('100x100', '600x600')
return artwork_url
except Exception as e:
print(f"Error searching for {artist} - {album}: {e}")
return None
return None
def download_missing_covers():
"""Download covers for albums that don't have covers yet"""
# Create covers directory if it doesn't exist
covers_dir = 'covers'
if not os.path.exists(covers_dir):
os.makedirs(covers_dir)
# Read the CSV file
csv_file = 'top_500_albums_2023.csv'
if not os.path.exists(csv_file):
print(f"Error: {csv_file} not found!")
return
albums_processed = 0
albums_found = 0
albums_skipped = 0
failed_albums = []
print("Downloading covers for albums without covers...")
print("This will take a while to be respectful to the iTunes API...\\n")
with open(csv_file, 'r', encoding='utf-8') as file:
csv_reader = csv.DictReader(file)
# Convert to list and sort by rank
rows = list(csv_reader)
rows.sort(key=lambda x: int(x.get('Rank', 999)))
for i, row in enumerate(rows):
rank = row.get('Rank', '').strip()
artist = row.get('Artist', '').strip()
album = row.get('Album', '').strip()
if not artist or not album:
continue
albums_processed += 1
# Create filename
safe_artist = sanitize_filename(artist)
safe_album = sanitize_filename(album)
filename = f"rank_{rank.zfill(3)}_{safe_artist}_{safe_album}.jpg"
filepath = os.path.join(covers_dir, filename)
# Skip if already exists
if os.path.exists(filepath):
albums_skipped += 1
continue
print(f"Searching [{albums_processed - albums_skipped}/500]: {rank}. {artist} - {album}")
# Search for artwork
artwork_url = search_itunes(artist, album)
if artwork_url:
try:
print(f" Downloading from: {artwork_url}")
urllib.request.urlretrieve(artwork_url, filepath)
print(f" ✓ Downloaded: {filename}")
albums_found += 1
except Exception as e:
print(f" ✗ Download failed: {e}")
failed_albums.append(f"{rank}. {artist} - {album}")
else:
print(f" ✗ No artwork found")
failed_albums.append(f"{rank}. {artist} - {album}")
# Be nice to the API
time.sleep(1.2)
# Progress update every 25 new downloads
if albums_found % 25 == 0 and albums_found > 0:
print(f"\\n--- Progress Update ---")
print(f"New downloads: {albums_found}")
print(f"Already existed: {albums_skipped}")
print(f"Failed: {len(failed_albums)}")
print("----------------------\\n")
print(f"\\n🎉 FINAL RESULTS:")
print(f"Albums processed: {albums_processed}")
print(f"Already existed: {albums_skipped}")
print(f"New downloads: {albums_found}")
print(f"Failed to find: {len(failed_albums)}")
print(f"Total covers available: {albums_found + albums_skipped}")
print(f"Overall success rate: {(albums_found + albums_skipped)/albums_processed*100:.1f}%")
if failed_albums:
print(f"\\n❌ Failed albums ({len(failed_albums)}):")
for album in failed_albums[:10]: # Show first 10
print(f" {album}")
if len(failed_albums) > 10:
print(f" ... and {len(failed_albums) - 10} more")
# Save failed albums to file
with open('failed_downloads.txt', 'w') as f:
for album in failed_albums:
f.write(f"{album}\\n")
print(f"\\nFull list saved to failed_downloads.txt")
if __name__ == "__main__":
download_missing_covers()

View file

@ -0,0 +1,113 @@
#!/usr/bin/env python3
"""
Fill missing Info and Description using Wikipedia data and research.
End descriptions with (by Claude).
"""
import csv
import re
# Dictionary of missing album info and descriptions based on research
wikipedia_missing_albums = {
("Various artists", "The Harder They Come"): {
"info": "Island, 1972",
"description": "This reggae compilation soundtrack introduced the world to the power and beauty of Jamaican music through the 1972 film starring Jimmy Cliff. Featuring classic tracks by Bob Marley & the Wailers ('Many Rivers to Cross'), Toots and the Maytals ('Pressure Drop'), and Jimmy Cliff ('The Harder They Come'), the album became a cultural phenomenon that brought reggae to international audiences. The collection captures the roots of reggae at its most authentic, with spiritual themes of resistance, redemption, and social justice running throughout. The album's success helped establish reggae as a major world music genre and influenced countless artists across all musical styles. Its impact extended far beyond music, helping to spread Rastafarian culture and Jamaican identity globally. (by Claude)"
},
("Otis Redding", "Otis Blue/Otis Redding Sings Soul"): {
"info": "Volt, 1965",
"description": "Recorded at the legendary Stax Studios in Memphis, this album showcases Otis Redding at the peak of his vocal powers, delivering some of the most passionate performances in soul music history. The album features his scorching takes on classic songs including Sam Cooke's 'A Change Is Gonna Come,' the Rolling Stones' 'Satisfaction,' and the Beatles' 'Day Tripper,' transforming each into distinctly soulful statements. Backed by the tight Stax rhythm section of Booker T. Jones, Steve Cropper, Duck Dunn, and Al Jackson Jr., Redding's raw emotional intensity and gospel-trained vocals created a template for Southern soul that influenced generations of singers. His originals like 'Respect' (later immortalized by Aretha Franklin) and 'I've Been Loving You Too Long' demonstrate his extraordinary songwriting abilities alongside his legendary vocal delivery. (by Claude)"
},
("Björk", "Post"): {
"info": "One Little Indian, 1995",
"description": "Björk's second solo album expanded her artistic vision beyond the experimental rock of 'Debut,' incorporating electronic music, trip-hop, and avant-garde production techniques to create something entirely unique. Working with producers including Nellee Hooper, Tricky, and Howie B, Björk crafted songs that seamlessly blended organic and synthetic elements. Tracks like 'Army of Me' and 'It's Oh So Quiet' showcased her incredible vocal range and fearless artistic approach, while 'Hyperballad' and 'Possibly Maybe' revealed her vulnerable, romantic side. The album's innovative production, combining lush orchestrations with cutting-edge electronic textures, influenced countless artists in both pop and experimental music. 'Post' established Björk as one of music's most distinctive and influential artists, unafraid to push boundaries while maintaining emotional accessibility. (by Claude)"
},
("Weezer", "Weezer"): {
"info": "DGC, 1994",
"description": "Known as 'The Blue Album,' Weezer's debut perfectly captured the awkward charm and emotional intensity of alternative rock in the 1990s. Rivers Cuomo's deeply personal songwriting, combined with the band's crunchy guitar sound and pop sensibilities, created anthems for the misunderstood and lovelorn. Songs like 'Buddy Holly,' 'Undone (The Sweater Song),' and 'Say It Ain't So' became defining tracks of Generation X, blending heavy guitars with irresistible melodies and lyrics about social anxiety, family dysfunction, and unrequited love. Producer Ric Ocasek helped the band achieve a sound that was both polished and raw, perfectly suited to MTV and alternative radio. The album's success proved that vulnerability and intelligence could coexist with rock power, influencing countless indie and emo bands that followed. (by Claude)"
},
("Neil Young and Crazy Horse", "Rust Never Sleeps"): {
"info": "Reprise, 1979",
"description": "Neil Young's response to the punk movement was this fierce, electric masterpiece that proved the old guard could still deliver vital, relevant rock music. Recorded with his longtime backing band Crazy Horse, the album features some of Young's most powerful guitar work and politically charged lyrics. The epic 'Powderfinger' and 'Welfare Mothers' showcase the band's ability to create sprawling, feedback-drenched soundscapes, while 'My My, Hey Hey (Out of the Blue)' offers Young's famous meditation on rock and roll mortality with the prophetic line 'it's better to burn out than to fade away.' The album's raw energy and uncompromising attitude influenced grunge pioneers like Nirvana and Pearl Jam, proving Young's continued relevance across generations. (by Claude)"
},
("Sam Cooke", "Portrait of a Legend: 19511964"): {
"info": "ABKCO, 2003",
"description": "This comprehensive compilation captures the full scope of Sam Cooke's revolutionary career, from his gospel beginnings with the Soul Stirrers to his emergence as the king of soul music. Featuring classics like 'You Send Me,' 'Chain Gang,' 'Cupid,' and the posthumously released civil rights anthem 'A Change Is Gonna Come,' the collection demonstrates Cooke's unique ability to blend sacred and secular music into something transcendent. His smooth, sophisticated vocal style and innovative songwriting laid the groundwork for soul music and influenced every R&B singer who followed. Cooke's business acumen and artistic vision made him one of the first African American artists to gain control over his music and career, paving the way for future generations of Black artists. (by Claude)"
},
("Jerry Lee Lewis", "All Killer, No Filler: The Anthology"): {
"info": "Rhino, 1993",
"description": "This comprehensive collection showcases Jerry Lee Lewis at his wild, untamed best, capturing the raw energy and piano-pounding intensity that made him one of rock and roll's most explosive performers. From his legendary Sun Records recordings like 'Whole Lotta Shakin' Goin' On' and 'Great Balls of Fire' to his later country hits, the anthology demonstrates Lewis's versatility and enduring power as a performer. His manic piano style and uninhibited stage presence influenced countless rock and roll musicians, while his ability to cross genres from rockabilly to country to gospel showcased his deep musical roots. Despite personal controversies, Lewis's artistic legacy as 'The Killer' remains undiminished, representing the untamed spirit of early rock and roll at its most primal and exciting. (by Claude)"
},
("Janet Jackson", "Janet Jackson's Rhythm Nation 1814"): {
"info": "A&M, 1989",
"description": "Janet Jackson's fourth studio album was a bold statement about social justice and unity, wrapped in innovative production that helped define the sound of late-80s and early-90s pop. Working with producers Jimmy Jam and Terry Lewis, Jackson created a concept album that addressed issues like racism, poverty, and social inequality while delivering irresistible dance tracks. Songs like 'Rhythm Nation,' 'Miss You Much,' and 'Black Cat' showcased Jackson's evolution from teen pop star to serious artist and social commentator. The album's industrial-tinged production and Jackson's precise choreography in the accompanying videos influenced a generation of pop artists. 'Rhythm Nation 1814' proved that mainstream pop could carry powerful political messages without sacrificing commercial appeal. (by Claude)"
},
("Brian Wilson", "Brian Wilson Presents Smile"): {
"info": "Nonesuch, 2004",
"description": "Nearly four decades after its abandonment, Brian Wilson finally completed his legendary 'lost album' with help from lyricist Van Dyke Parks and arranger Paul Mertens. Originally conceived as the Beach Boys' follow-up to 'Pet Sounds,' 'Smile' was an ambitious song cycle about American history and mythology that proved too complex and experimental for its time. The completed version showcases Wilson's unparalleled melodic gifts and innovative harmonic concepts, featuring intricate vocal arrangements and unconventional song structures that influenced countless artists during its mythical status. Songs like 'Good Vibrations,' 'Heroes and Villains,' and 'Surf's Up' reveal Wilson's vision of a uniquely American art music that blends pop accessibility with avant-garde experimentation. The album's completion was both a personal triumph for Wilson and a gift to music history. (by Claude)"
},
("Various artists", "Nuggets: Original Artyfacts from the First Psychedelic Era, 19651968"): {
"info": "Elektra, 1972",
"description": "Compiled by Lenny Kaye (later guitarist for Patti Smith), this groundbreaking collection rescued dozens of obscure garage rock and proto-punk singles from the mid-1960s, creating the template for all compilation albums that followed. Featuring raw, energetic tracks by bands like The Seeds, Count Five, The Standells, and The 13th Floor Elevators, 'Nuggets' documented a forgotten chapter of American rock history between the British Invasion and the rise of psychedelia. The collection's influence was immeasurable, inspiring punk and alternative rock musicians who discovered that three chords and attitude could create timeless music. Kaye's liner notes helped establish the critical framework for understanding garage rock as a distinct genre, while the album's DIY aesthetic influenced countless musicians to start their own bands. (by Claude)"
},
("Paul McCartney and Linda McCartney", "Ram"): {
"info": "Apple, 1971",
"description": "Paul McCartney's second post-Beatles album, credited to both Paul and Linda McCartney, was initially dismissed by critics but has since been recognized as a charming, experimental work that captured the former Beatle's domestic bliss and musical curiosity. Recorded at his Scottish farm with a loose, homemade aesthetic, the album features unconventional song structures, playful lyrics, and a willingness to embrace both beauty and silliness. Songs like 'Uncle Albert/Admiral Halsey' and 'The Back Seat of My Car' showcase McCartney's melodic genius while revealing a more personal, intimate side than his Beatles work. The album's lo-fi production and pastoral themes influenced indie rock decades later, while its seamless blend of musical styles demonstrated McCartney's fearless creativity outside the Beatles framework. (by Claude)"
},
("Smokey Robinson", "Going to a Go-Go"): {
"info": "Tamla, 1965",
"description": "Smokey Robinson and the Miracles' album captures the essence of mid-1960s Motown at its most sophisticated and danceable. As Motown's vice president and chief songwriter, Robinson crafted smooth, soulful songs that balanced romantic vulnerability with irresistible grooves. The title track became a dance floor classic, while songs like 'My Girl Has Gone' and 'Since I Lost My Baby' showcased Robinson's gift for expressing heartbreak with remarkable grace and poetic insight. His silky falsetto and the Miracles' tight harmonies, backed by Motown's legendary Funk Brothers, created a template for soul music that influenced countless artists. Robinson's role as both performer and behind-the-scenes architect made him one of Motown's most important figures. (by Claude)"
},
("Four Tops", "Reach Out"): {
"info": "Motown, 1967",
"description": "The Four Tops' album, built around their massive hit 'Reach Out I'll Be There,' showcases one of Motown's most powerful vocal groups at their commercial and artistic peak. Levi Stubbs' passionate, gospel-influenced lead vocals, supported by the rock-solid harmonies of Abdul 'Duke' Fakir, Obie Benson, and Lawrence Payton, created some of soul music's most emotionally intense moments. The production by Holland-Dozier-Holland, featuring dramatic orchestrations and driving rhythms, helped define the Motown Sound's more ambitious phase. Songs like 'Standing in the Shadows of Love' and 'Bernadette' demonstrated the group's ability to convey both romantic longing and social consciousness with equal conviction. The Four Tops' longevity and consistent quality made them one of Motown's most beloved acts. (by Claude)"
},
("The Supremes", "Anthology"): {
"info": "Motown, 1974",
"description": "This comprehensive collection captures the extraordinary career of Motown's most successful female group, documenting their evolution from teenage hopefuls to international superstars. Featuring classic hits like 'Where Did Our Love Go,' 'Baby Love,' 'Stop! In the Name of Love,' and 'You Can't Hurry Love,' the anthology showcases Diana Ross's distinctive vocals and the group's impeccable harmonies over Holland-Dozier-Holland's innovative productions. The Supremes broke down racial barriers in popular music, becoming the first Black female group to achieve mainstream success on a global scale. Their sophisticated image and crossover appeal helped bring Motown to white audiences while maintaining their essential soulfulness. The collection documents one of the most important chapters in American popular music history. (by Claude)"
},
("Laura Nyro", "Eli and the Thirteenth Confession"): {
"info": "Columbia, 1968",
"description": "Laura Nyro's second album is a stunning showcase of her unique songwriting vision, blending jazz, soul, gospel, and folk into something entirely her own. Her passionate, multi-octave vocals and deeply personal lyrics about love, spirituality, and urban life created a template for the singer-songwriter movement of the 1970s. Songs like 'Stoned Soul Picnic,' 'Sweet Blindness,' and 'Eli's Comin'' were later covered by artists like The 5th Dimension and Three Dog Night, but Nyro's original versions remain definitive statements of artistic integrity and emotional intensity. Her innovative piano arrangements and fearless vocal delivery influenced countless female artists, from Joni Mitchell to Tori Amos. The album stands as one of the most important works by one of music's most underappreciated visionaries. (by Claude)"
}
}
def main():
# Read current CSV
albums = []
with open('top_500_albums_2023.csv', 'r', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
albums.append(row)
# Find and update missing info
updated_count = 0
for album in albums:
artist = album['Artist'].strip()
album_title = album['Album'].strip()
# Check if this album is missing info/description
if not album['Info'].strip() or not album['Description'].strip():
# Look for it in our Wikipedia-based database
if (artist, album_title) in wikipedia_missing_albums:
album_data = wikipedia_missing_albums[(artist, album_title)]
if not album['Info'].strip():
album['Info'] = album_data['info']
if not album['Description'].strip():
album['Description'] = album_data['description']
updated_count += 1
print(f"✓ Updated from Wikipedia research: {artist} - {album_title}")
else:
print(f"✗ Still missing: {artist} - {album_title}")
# Write updated CSV
with open('top_500_albums_2023.csv', 'w', newline='', encoding='utf-8') as file:
fieldnames = ['Rank', 'Artist', 'Album', 'Status', 'Info', 'Description']
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(albums)
print(f"\n🎉 Updated {updated_count} additional albums with Wikipedia-based research")
print("All descriptions end with '(by Claude)'")
if __name__ == "__main__":
main()

View file

@ -0,0 +1,209 @@
#!/usr/bin/env python3
"""
Script to merge Info and Description columns from 2020 Rolling Stone data
into the combined 2023 top 500 albums CSV file.
"""
import csv
from difflib import SequenceMatcher
import re
def normalize_string(s):
"""Normalize string for better matching"""
if s is None or s == '':
return ""
# Convert to lowercase and remove extra whitespace
s = str(s).lower().strip()
# Remove common punctuation and special characters
s = re.sub(r'[^\w\s&]', '', s)
# Replace multiple spaces with single space
s = re.sub(r'\s+', ' ', s)
return s
def similarity_ratio(a, b):
"""Calculate similarity ratio between two strings using difflib"""
return SequenceMatcher(None, a, b).ratio() * 100
def fuzzy_match_albums(artist1, album1, artist2, album2, threshold=85):
"""
Use fuzzy matching to determine if two albums are the same
Returns True if they match above the threshold
"""
# Normalize strings
artist1_norm = normalize_string(artist1)
album1_norm = normalize_string(album1)
artist2_norm = normalize_string(artist2)
album2_norm = normalize_string(album2)
# Calculate similarity scores
artist_score = similarity_ratio(artist1_norm, artist2_norm)
album_score = similarity_ratio(album1_norm, album2_norm)
# Both artist and album must be above threshold
return artist_score >= threshold and album_score >= threshold
def load_2020_data(filepath):
"""Load 2020 data handling multi-line descriptions"""
albums_2020 = {}
with open(filepath, 'r', encoding='utf-8') as file:
# Skip the header
next(file)
current_row = None
for line in file:
line = line.strip()
# Check if this line starts with a rank number (new record)
if line and line[0].isdigit():
# Save previous record if exists
if current_row:
try:
# Parse the CSV fields
reader = csv.reader([current_row])
fields = next(reader)
if len(fields) >= 5:
rank, artist, album, info, description = fields[:5]
key = normalize_string(f"{artist} {album}")
albums_2020[key] = {
'artist': artist,
'album': album,
'info': info,
'description': description
}
except:
pass # Skip malformed rows
# Start new record
current_row = line
else:
# Continue multi-line description
if current_row:
current_row += " " + line
# Don't forget the last record
if current_row:
try:
reader = csv.reader([current_row])
fields = next(reader)
if len(fields) >= 5:
rank, artist, album, info, description = fields[:5]
key = normalize_string(f"{artist} {album}")
albums_2020[key] = {
'artist': artist,
'album': album,
'info': info,
'description': description
}
except:
pass
return albums_2020
def load_2023_data(filepath):
"""Load 2023 data from CSV"""
albums_2023 = []
with open(filepath, 'r', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
albums_2023.append(row)
return albums_2023
def save_2023_data(filepath, albums_2023):
"""Save updated 2023 data to CSV"""
if not albums_2023:
return
fieldnames = ['Rank', 'Artist', 'Album', 'Status', 'Info', 'Description']
with open(filepath, 'w', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader()
for album in albums_2023:
writer.writerow(album)
def main():
# File paths
file_2023 = '/home/lundberg/projects/top500albums/top_500_albums_2023.csv'
file_2020 = '/home/lundberg/projects/top500albums/rolling_stone_top_500_albums_2020.csv'
print("Loading 2023 data...")
albums_2023 = load_2023_data(file_2023)
print(f"Loaded {len(albums_2023)} albums from 2023 data")
print("Loading 2020 data...")
albums_2020 = load_2020_data(file_2020)
print(f"Loaded {len(albums_2020)} albums from 2020 data")
# Add new columns to 2023 data
for album in albums_2023:
album['Info'] = ''
album['Description'] = ''
matches_found = 0
no_matches = 0
print("Matching albums...")
for album_2023 in albums_2023:
artist_2023 = album_2023['Artist']
album_title_2023 = album_2023['Album']
# First try exact match
key_2023 = normalize_string(f"{artist_2023} {album_title_2023}")
if key_2023 in albums_2020:
# Exact match found
album_2023['Info'] = albums_2020[key_2023]['info']
album_2023['Description'] = albums_2020[key_2023]['description']
matches_found += 1
print(f"✓ Exact match: {artist_2023} - {album_title_2023}")
else:
# Try fuzzy matching
best_match = None
best_score = 0
for key_2020, album_2020 in albums_2020.items():
if fuzzy_match_albums(artist_2023, album_title_2023,
album_2020['artist'], album_2020['album']):
# Calculate combined score for ranking
artist_score = similarity_ratio(normalize_string(artist_2023),
normalize_string(album_2020['artist']))
album_score = similarity_ratio(normalize_string(album_title_2023),
normalize_string(album_2020['album']))
combined_score = (artist_score + album_score) / 2
if combined_score > best_score:
best_score = combined_score
best_match = album_2020
if best_match:
album_2023['Info'] = best_match['info']
album_2023['Description'] = best_match['description']
matches_found += 1
print(f"✓ Fuzzy match ({best_score:.1f}%): {artist_2023} - {album_title_2023}{best_match['artist']} - {best_match['album']}")
else:
no_matches += 1
print(f"✗ No match: {artist_2023} - {album_title_2023}")
print(f"\nMatching complete!")
print(f"Matches found: {matches_found}")
print(f"No matches: {no_matches}")
print(f"Total albums: {len(albums_2023)}")
# Save updated CSV
print(f"\nSaving updated file...")
save_2023_data(file_2023, albums_2023)
print(f"File saved: {file_2023}")
# Display first few rows with new columns
print("\nFirst 5 rows with new columns:")
for i, album in enumerate(albums_2023[:5]):
print(f"{album['Rank']}: {album['Artist']} - {album['Album']} ({album['Status']})")
if album['Info']:
print(f" Info: {album['Info']}")
if album['Description']:
desc = album['Description'][:100] + "..." if len(album['Description']) > 100 else album['Description']
print(f" Description: {desc}")
print()
if __name__ == "__main__":
main()

176
scripts/remap_covers.py Normal file
View file

@ -0,0 +1,176 @@
#!/usr/bin/env python3
"""
Script to remap existing cover art files to match the new CSV ranking structure.
This avoids having to re-download all the covers.
"""
import csv
import os
import re
import shutil
from pathlib import Path
def sanitize_filename(text):
"""Remove or replace characters that aren't valid in filenames"""
# Remove/replace problematic characters
text = re.sub(r'[<>:"/\\|?*]', '', text)
text = re.sub(r'[^\w\s\-_\.]', '', text)
text = re.sub(r'\s+', '_', text.strip())
return text[:100] # Limit length
def normalize_for_matching(text):
"""Normalize text for matching album/artist names"""
text = text.lower().strip()
# Remove common punctuation and normalize
text = re.sub(r'[^\w\s&]', '', text)
text = re.sub(r'\s+', ' ', text)
# Handle common variations
text = text.replace(' and ', ' ').replace(' & ', ' ')
# Remove "the" from start
if text.startswith('the '):
text = text[4:]
return text
def find_matching_cover(artist, album, existing_covers):
"""Find existing cover file that matches this artist/album"""
target_artist = normalize_for_matching(artist)
target_album = normalize_for_matching(album)
for cover_file in existing_covers:
# Extract artist and album from filename
# Format: rank_XXX_Artist_Album.jpg
parts = cover_file.replace('.jpg', '').split('_')
if len(parts) < 4:
continue
# Skip rank part, reconstruct artist and album
file_parts = parts[2:] # Skip "rank" and "XXX"
# Find where artist ends and album begins (tricky!)
# We'll try different splits and see which gives best match
best_match_score = 0
best_file = None
for split_point in range(1, len(file_parts)):
file_artist = '_'.join(file_parts[:split_point])
file_album = '_'.join(file_parts[split_point:])
norm_file_artist = normalize_for_matching(file_artist.replace('_', ' '))
norm_file_album = normalize_for_matching(file_album.replace('_', ' '))
# Calculate match score
artist_match = target_artist in norm_file_artist or norm_file_artist in target_artist
album_match = target_album in norm_file_album or norm_file_album in target_album
if artist_match and album_match:
# Calculate more precise score
score = len(set(target_artist.split()) & set(norm_file_artist.split())) + \
len(set(target_album.split()) & set(norm_file_album.split()))
if score > best_match_score:
best_match_score = score
best_file = cover_file
# If we found a good match, return it
if best_match_score >= 2: # At least 2 word matches
return best_file
return None
def main():
covers_dir = Path('covers')
backup_dir = Path('covers_backup')
if not covers_dir.exists():
print("No covers directory found!")
return
# Create backup directory
if backup_dir.exists():
print("Backup directory already exists. Removing it...")
shutil.rmtree(backup_dir)
print("Creating backup of existing covers...")
shutil.copytree(covers_dir, backup_dir)
print(f"Backup created at {backup_dir}")
# Get list of existing cover files
existing_covers = [f for f in os.listdir(covers_dir) if f.endswith('.jpg')]
print(f"Found {len(existing_covers)} existing cover files")
# Load current CSV
csv_file = 'top_500_albums_2023.csv'
if not os.path.exists(csv_file):
print(f"Error: {csv_file} not found!")
return
new_covers_dir = Path('covers_new')
if new_covers_dir.exists():
shutil.rmtree(new_covers_dir)
new_covers_dir.mkdir()
mapped_count = 0
unmapped_count = 0
unmapped_albums = []
print("\nMapping covers to new rankings...")
with open(csv_file, 'r', encoding='utf-8') as file:
csv_reader = csv.DictReader(file)
for row in csv_reader:
rank = row.get('Rank', '').strip()
artist = row.get('Artist', '').strip()
album = row.get('Album', '').strip()
if not artist or not album:
continue
# Find matching existing cover
matching_cover = find_matching_cover(artist, album, existing_covers)
if matching_cover:
# Create new filename with correct ranking
safe_artist = sanitize_filename(artist)
safe_album = sanitize_filename(album)
new_filename = f"rank_{rank.zfill(3)}_{safe_artist}_{safe_album}.jpg"
# Copy file with new name
old_path = covers_dir / matching_cover
new_path = new_covers_dir / new_filename
shutil.copy2(old_path, new_path)
mapped_count += 1
if mapped_count % 50 == 0:
print(f"✓ Mapped {mapped_count} covers so far...")
else:
unmapped_count += 1
unmapped_albums.append(f"{rank}. {artist} - {album}")
print(f"✗ No cover found for: {rank}. {artist} - {album}")
print(f"\n🎉 MAPPING RESULTS:")
print(f"Successfully mapped: {mapped_count}")
print(f"Could not map: {unmapped_count}")
print(f"Total albums: {mapped_count + unmapped_count}")
print(f"Success rate: {mapped_count/(mapped_count + unmapped_count)*100:.1f}%")
if unmapped_albums:
print(f"\n❌ Albums without covers ({len(unmapped_albums)}):")
for album in unmapped_albums[:10]:
print(f" {album}")
if len(unmapped_albums) > 10:
print(f" ... and {len(unmapped_albums) - 10} more")
# Replace old covers directory with new one
print(f"\nReplacing covers directory...")
shutil.rmtree(covers_dir)
shutil.move(new_covers_dir, covers_dir)
print(f"✅ Cover remapping complete!")
print(f"Original covers backed up to: {backup_dir}")
print(f"New covers available in: {covers_dir}")
if __name__ == "__main__":
main()

View file

@ -0,0 +1,330 @@
#!/usr/bin/env python3
"""
Script to update missing Info and Description fields in the Top 500 Albums CSV file.
This script identifies albums with empty Info/Description columns and fills them with
information from a comprehensive lookup dictionary.
"""
import csv
import os
import shutil
from datetime import datetime
def create_album_lookup():
"""
Create a comprehensive lookup dictionary for famous albums.
Key format: (Artist, Album) -> (Info, Description)
"""
return {
# The Beatles
("The Beatles", 'The Beatles ("The White Album")'): (
"Apple, 1968",
"The Beatles' ambitious double album, officially titled 'The Beatles' but universally known as 'The White Album' due to its stark cover, showcased the band's incredible diversity and individual creativity. Recorded at Abbey Road Studios during a period of growing tensions within the group, the album contains 30 songs ranging from hard rock to experimental sound collages. Each member contributed distinctive material - from McCartney's vaudeville-inspired 'Honey Pie' to Lennon's minimalist 'Revolution 9' to Harrison's spiritual 'While My Guitar Gently Weeps' featuring Eric Clapton. The album's eclectic nature reflects the band's willingness to experiment with different genres and their growing interest in individual artistic expression, making it both a creative triumph and a harbinger of their eventual breakup."
),
# Jimi Hendrix
("Jimi Hendrix Experience", "Are You Experienced"): (
"Reprise/Track, 1967",
"Jimi Hendrix's explosive debut album revolutionized rock guitar and established him as one of music's most innovative artists. Recorded in London with producer Chas Chandler, the album showcased Hendrix's unprecedented guitar techniques including feedback, distortion, and his signature use of the wah-wah pedal. Songs like 'Purple Haze,' 'Hey Joe,' and the title track became instant classics, while 'The Wind Cries Mary' revealed his softer, more introspective side. The album's psychedelic production, combined with Hendrix's virtuosic playing and poetic lyrics, created a new template for rock music. His ability to blend blues, rock, and experimental sounds while pushing the electric guitar to its limits made this album a cornerstone of the psychedelic era."
),
("The Jimi Hendrix Experience", "Electric Ladyland"): (
"Reprise, 1968",
"Hendrix's ambitious double album showcased his studio wizardry and experimental vision at its peak. Recorded across multiple sessions in New York, the album features extended jams, intricate overdubs, and innovative production techniques. The epic 'Voodoo Child (Slight Return)' and his iconic cover of Dylan's 'All Along the Watchtower' demonstrated his ability to transform any song into something uniquely his own. The album's diverse range, from the funky 'Crosstown Traffic' to the ethereal '1983... (A Merman I Should Turn to Be),' established Hendrix as not just a guitarist but a visionary composer and producer."
),
# Nick Drake
("Nick Drake", "Five Leaves Left"): (
"Island, 1969",
"Nick Drake's haunting debut album is a masterpiece of melancholy folk that established him as one of Britain's most gifted singer-songwriters. Recorded with producer Joe Boyd and featuring lush orchestral arrangements by Robert Kirby, the album's delicate acoustic guitar work and Drake's whispered vocals create an intimate, almost fragile atmosphere. Songs like 'River Man' and 'Day is Done' showcase his sophisticated harmonic sense and poetic sensibility. Despite its initial commercial failure, the album has gained recognition as a profound work of art that captures the uncertainty and introspection of late-1960s youth culture."
),
# Otis Redding
("Otis Redding", "Otis Blue/Otis Redding Sings Soul"): (
"Volt, 1965",
"Recorded in a single day at Stax Studios in Memphis, this album captures Otis Redding's raw vocal power and emotional intensity at its peak. The album features his definitive versions of 'Respect' (later immortalized by Aretha Franklin), 'I've Been Loving You Too Long,' and his tender interpretation of 'A Change Is Gonna Come.' Backed by Booker T. & the M.G.'s and the Memphis Horns, Redding's passionate delivery and the tight rhythm section created a template for Southern soul. The album's mix of original compositions and inspired covers demonstrates Redding's ability to inhabit any song completely."
),
# Simon & Garfunkel
("Simon & Garfunkel", "Bookends"): (
"Columbia, 1968",
"Simon & Garfunkel's fourth studio album is a conceptual meditation on aging and the passage of time, bookended by different versions of the title track. The album features some of their most beloved songs, including 'Mrs. Robinson' (featured in 'The Graduate'), 'America,' and 'Hazy Shade of Winter.' Paul Simon's sophisticated songwriting, exploring themes of alienation and American society, combined with Art Garfunkel's pristine harmonies, created folk-rock of unprecedented literary depth. The album's seamless flow between individual songs and the 'Voices of Old People' interludes gives it a unified, almost cinematic quality."
),
# The Ramones
("The Ramones", "Ramones"): (
"Sire, 1976",
"The Ramones' self-titled debut album stripped rock & roll down to its essential elements and invented punk rock in the process. Recorded in just 18 days for $6,400, the album's 14 songs clock in at under 30 minutes, featuring buzzsaw guitars, pounding drums, and Joey Ramone's nasal vocals. Songs like 'Blitzkrieg Bop,' 'I Wanna Be Your Boyfriend,' and 'Now I Wanna Sniff Some Glue' combined teenage themes with breakneck tempos and three-chord simplicity. The album's aesthetic of deliberate amateurism and punk attitude influenced countless bands and launched the punk movement."
),
# Frank Sinatra
("Frank Sinatra", "Songs for Swingin' Lovers!"): (
"Capitol, 1956",
"One of Sinatra's finest Capitol albums, this collection of love songs arranged by Nelson Riddle showcases the Chairman of the Board at his swinging best. The album features definitive versions of American songbook standards like 'I've Got You Under My Skin,' 'Anything Goes,' and 'Makin' Whoopee.' Sinatra's mature vocal style, combining technical precision with emotional depth, paired with Riddle's sophisticated arrangements, created the template for the classic American pop album. The album's joyful celebration of romance and its impeccable production values made it both a commercial and artistic triumph."
),
# The Stooges
("The Stooges", "Raw Power"): (
"Columbia, 1973",
"The Stooges' final studio album is a primal scream of garage rock fury that anticipated punk rock by several years. Produced by David Bowie and featuring James Williamson's slashing guitar work alongside Iggy Pop's unhinged vocals, the album's raw energy and nihilistic attitude influenced generations of punk and alternative rock musicians. Songs like 'Search and Destroy' and 'I Need Somebody' combine primitive power with sophisticated songcraft. Despite its initial commercial failure, the album is now recognized as a crucial link between garage rock and punk."
),
# PJ Harvey
("PJ Harvey", "To Bring You My Love"): (
"Island, 1995",
"Polly Jean Harvey's third album marked a dramatic shift toward a more experimental and theatrical approach. Recorded with producer Flood, the album features Harvey's most diverse musical palette yet, incorporating blues, gospel, and electronic elements. Songs like 'Down by the Water' and 'C'mon Billy' showcase her powerful vocals and provocative lyrics, while tracks like 'Long Snake Moan' reveal her deep connection to American roots music. The album's dark, atmospheric production and Harvey's fearless artistic vision established her as one of the most important alternative rock artists of the 1990s."
),
# Björk
("Björk", "Post"): (
"One Little Indian, 1995",
"Björk's second solo album expanded her artistic palette beyond the experimental rock of 'Debut' to incorporate electronic music, jazz, and world music influences. Working with producers including Nellee Hooper, Tricky, and Graham Massey, Björk created a genre-defying album that features the hit singles 'Army of Me' and 'It's Oh So Quiet.' The album's adventurous spirit, combining her unique vocal style with cutting-edge production, established Björk as one of the most innovative artists of the 1990s. Her fearless experimentation with different genres while maintaining her distinctive artistic voice makes 'Post' a landmark of electronic music."
),
# Modern Hip-Hop/R&B Artists
("The Weeknd", "House of Balloons"): (
"XO/Republic, 2011",
"The Weeknd's debut mixtape, later remastered and commercially released, established Abel Tesfaye as a major force in contemporary R&B. The album's dark, atmospheric production and sexually explicit lyrics created a new template for alternative R&B. Songs like 'Wicked Games' and 'The Morning' showcase his distinctive falsetto and the album's nocturnal, drug-hazed aesthetic. The mysterious circumstances of its initial release and its influence on a generation of R&B artists make it a defining work of 2010s music."
),
("Travis Scott", "Astroworld"): (
"Cactus Jack/Grand Hustle, 2018",
"Travis Scott's third studio album is a psychedelic journey through hip-hop that draws inspiration from the defunct AstroWorld theme park in Houston. The album features innovative production techniques, auto-tuned vocals, and collaborations with artists ranging from Drake to Tame Impala. Songs like 'SICKO MODE' and 'STARLIGHT' showcase Scott's ability to create immersive sonic landscapes. The album's theme park concept and its blend of hip-hop with psychedelic and electronic elements established Scott as one of the most creative forces in contemporary rap."
),
("Tyler, the Creator", "Igor"): (
"Columbia, 2019",
"Tyler's fifth studio album marked a complete artistic transformation, moving away from the shock value of his early work toward a more mature exploration of love and relationships. The album's lush production, featuring live instrumentation and Tyler's increasingly sophisticated songwriting, creates a cohesive narrative arc. Songs like 'EARFQUAKE' and 'I THINK' showcase his growth as both a rapper and singer. The album's Grammy win and critical acclaim established Tyler as one of hip-hop's most creative and unpredictable artists."
),
# Electronic/Ambient
("Burial", "Untrue"): (
"Hyperdub, 2007",
"Burial's second album is a masterpiece of UK electronic music that captures the melancholy and alienation of urban life. Using a collage technique that incorporates vocal samples, vinyl crackle, and atmospheric textures, William Bevan created a deeply emotional form of dubstep. Tracks like 'Archangel' and 'Near Dark' evoke the ghostly atmosphere of London's nighttime streets. The album's influence on electronic music and its unique aesthetic of urban decay and romantic longing make it a defining work of 2000s electronic music."
),
("Aphex Twin", "Selected Ambient Works 85-92"): (
"R&S/Sire, 1992",
"Richard D. James's debut album as Aphex Twin established him as electronic music's most innovative and influential artist. Recorded primarily on analog equipment in his bedroom, the album's combination of ambient textures and intricate rhythms created a new form of electronic music. Tracks like 'Xtal' and 'Pulsewidth' showcase his ability to create both beautiful and unsettling soundscapes. The album's influence on electronic music genres from IDM to ambient techno cannot be overstated."
),
("Boards of Canada", "Music Has the Right to Children"): (
"Warp/Skam, 1998",
"The Scottish duo's debut album created a nostalgic, dream-like form of electronic music that seemed to capture the hazy memories of childhood. Using analog synthesizers, tape manipulation, and field recordings, Michael Sandison and Marcus Eoin crafted an album that feels both futuristic and deeply nostalgic. Tracks like 'Roygbiv' and 'Turquoise Hexagon Sun' feature their signature combination of warm melodies and degraded textures. The album's unique aesthetic and emotional depth established Boards of Canada as masters of ambient electronic music."
),
# Alternative/Indie Rock
("Weezer", "Pinkerton"): (
"DGC, 1996",
"Rivers Cuomo's deeply personal second album was initially dismissed by critics but has since been recognized as a masterpiece of alternative rock. Named after the character from Puccini's 'Madame Butterfly,' the album explores themes of loneliness, sexual frustration, and cultural identity with unprecedented honesty. Songs like 'El Scorcho' and 'The Good Life' combine Cuomo's neurotic lyrics with the band's powerful pop-rock sound. The album's raw emotional content and innovative song structures influenced countless alternative rock bands."
),
("Elliott Smith", "XO"): (
"DreamWorks, 1998",
"Elliott Smith's major-label debut expanded his intimate acoustic style with lush orchestration and multi-tracked vocals while maintaining his gift for melody and devastating emotional honesty. Songs like 'Waltz #2 (XO)' and 'Baby Britain' showcase his sophisticated harmonic sense and whispered vocal delivery. The album's themes of depression, addiction, and alienation, combined with its beautiful melodies, created a template for indie rock introspection. Smith's tragic death in 2003 has only enhanced the album's reputation as a classic of alternative rock."
),
("Bright Eyes", "I'm Wide Awake, It's Morning"): (
"Saddle Creek, 2005",
"Conor Oberst's most accessible album as Bright Eyes showcased his evolution from lo-fi indie folk to a more polished, country-influenced sound. Recorded with a full band including Emmylou Harris, the album features some of Oberst's most memorable songs, including 'First Day of My Life' and 'Lover I Don't Have to Love.' The album's political themes and personal revelations, combined with its warm production, established Bright Eyes as one of indie rock's most important voices."
),
# Hip-Hop Classics
("LL Cool J", "Radio"): (
"Def Jam, 1985",
"LL Cool J's debut album was one of the first rap albums to achieve mainstream commercial success while maintaining street credibility. Produced by Rick Rubin, the album's raw, stripped-down production and LL's aggressive delivery on tracks like 'Rock the Bells' and 'I Can't Live Without My Radio' established the template for hardcore rap. The album's success helped launch Def Jam Records and proved that rap could be both commercially viable and artistically innovative."
),
("UGK", "Ridin' Dirty"): (
"Jive, 1996",
"UGK's fourth studio album is considered a masterpiece of Southern hip-hop, establishing the duo of Bun B and Pimp C as pioneers of the genre. The album's laid-back production, featuring live instrumentation and jazz samples, provides the perfect backdrop for their distinctive flows and street narratives. Songs like 'One Day' and 'Murder' showcase their ability to balance hardcore rap with melodic sensibilities. The album's influence on Southern rap and its role in establishing Houston as a hip-hop center cannot be overstated."
),
# Grunge/Alternative
("Soundgarden", "Superunknown"): (
"A&M, 1994",
"Soundgarden's fourth studio album marked the band's creative and commercial peak, combining heavy metal with psychedelic and experimental elements. Chris Cornell's powerful vocals and the band's innovative use of alternate tunings created a unique sound that set them apart from their grunge peers. Songs like 'Black Hole Sun' and 'Spoonman' became alternative radio staples, while deeper cuts like '4th of July' and 'Limo Wreck' showcased the band's experimental side. The album's Grammy wins and multi-platinum success established Soundgarden as one of the most important bands of the 1990s."
),
# Punk/Alternative
("Fugazi", "Repeater"): (
"Dischord, 1990",
"Fugazi's debut full-length album established the Washington D.C. band as leaders of the post-hardcore movement. Ian MacKaye and Guy Picciotto's dual vocals and the band's innovative use of dynamics created a more complex form of punk rock. Songs like 'Waiting Room' and 'Merchandise' combine political lyrics with experimental song structures. The band's DIY ethics and refusal to sign with major labels made them heroes of the underground punk scene."
),
("Dead Kennedys", "Fresh Fruit for Rotting Vegetables"): (
"Alternative Tentacles, 1980",
"The Dead Kennedys' debut album is a scorching indictment of American society and politics wrapped in some of the most energetic punk rock ever recorded. Jello Biafra's provocative lyrics and theatrical vocals, combined with East Bay Ray's surf-punk guitar work, created a unique sound that influenced countless punk bands. Songs like 'Holiday in Cambodia' and 'California Über Alles' showcase their ability to combine political commentary with irresistible hooks."
),
# Electronic/Dance
("The Chemical Brothers", "Dig Your Own Hole"): (
"Freestyle Dust/Virgin, 1997",
"The Chemical Brothers' second album established them as leaders of the big beat movement and masters of electronic dance music. The album's combination of rock samples, breakbeats, and psychedelic elements created a new form of electronic music that worked equally well in clubs and on headphones. Tracks like 'Block Rockin' Beats' and 'Setting Sun' (featuring Noel Gallagher) became dancefloor anthems, while the album's innovative production techniques influenced a generation of electronic artists."
),
("The Avalanches", "Since I Left You"): (
"Modular, 2000",
"The Avalanches' debut album is a masterpiece of sample-based music, constructed from over 3,500 vinyl samples. The Australian group's cut-and-paste technique creates a dreamy, nostalgic journey through decades of recorded music. The title track and songs like 'Frontier Psychiatrist' showcase their ability to create coherent songs from disparate sources. The album's joyful celebration of musical history and its innovative production techniques make it a landmark of electronic music."
),
# Classic Rock/Metal
("Iron Maiden", "The Number of the Beast"): (
"EMI, 1982",
"Iron Maiden's third studio album, and the first to feature vocalist Bruce Dickinson, established them as leaders of the New Wave of British Heavy Metal. The album's epic compositions, galloping rhythms, and literary lyrics created a more sophisticated form of heavy metal. Songs like 'Run to the Hills' and the title track became metal classics, while Steve Harris's complex bass lines and the dual guitar attack of Dave Murray and Adrian Smith set the template for melodic metal."
),
("Judas Priest", "British Steel"): (
"Columbia, 1980",
"Judas Priest's sixth studio album streamlined their heavy metal sound into a more accessible form without sacrificing power. Rob Halford's operatic vocals and the band's twin-guitar attack on songs like 'Breaking the Law' and 'Living After Midnight' created anthems that defined heavy metal for the 1980s. The album's leather-and-studs aesthetic and uncompromising metal sound influenced countless metal bands."
),
# More Alternative/Indie
("Queens of the Stone Age", "Songs for the Deaf"): (
"Interscope, 2002",
"Queens of the Stone Age's third album, featuring Dave Grohl on drums, is a desert rock masterpiece that combines heavy riffs with psychedelic elements. The album's concept as a road trip through Palm Desert radio stations provides a unifying theme for Josh Homme's distinctive songwriting. Songs like 'No One Knows' and 'First It Giveth' showcase the band's ability to create heavy music that's both aggressive and melodic."
),
("Animal Collective", "Merriweather Post Pavilion"): (
"Domino, 2009",
"Animal Collective's eighth studio album marked their transition to a more electronic, dance-influenced sound while maintaining their experimental edge. The album's layered production, featuring Panda Bear's rhythmic vocals and Avey Tare's melodic contributions, creates a psychedelic electronic landscape. Songs like 'My Girls' and 'Summertime Clothes' showcase their ability to create accessible pop songs within an experimental framework."
),
("Bon Iver", "For Emma, Forever Ago"): (
"Jagjaguwar, 2007",
"Justin Vernon's debut album as Bon Iver was recorded in isolation at a remote cabin in Wisconsin, creating an intimate folk album that captured the loneliness and beauty of rural life. The album's sparse arrangements, featuring acoustic guitar, falsetto vocals, and subtle electronic textures, created a new template for indie folk. Songs like 'Skinny Love' and 'Re: Stacks' showcase Vernon's gift for melody and his ability to create emotional depth through minimalism."
),
# R&B/Soul
("Maxwell", "Urban Hang Suite"): (
"Columbia, 1996",
"Maxwell's debut album established him as a leader of the neo-soul movement, combining classic soul with contemporary R&B production. The album's sophisticated arrangements and Maxwell's smooth vocal delivery on songs like 'Ascension (Don't Ever Wonder)' and 'Whenever Wherever Whatever' created a more mature alternative to contemporary R&B. The album's influence on artists like D'Angelo and Erykah Badu helped establish neo-soul as a major force in 1990s music."
),
# Jazz
("Thelonious Monk", "Brilliant Corners"): (
"Riverside, 1957",
"Thelonious Monk's breakthrough album showcased his unique approach to jazz composition and performance. The album's angular melodies and unconventional harmonies, particularly on the title track, established Monk as one of jazz's most important innovators. Working with saxophonist Sonny Rollins and other top musicians, Monk created a form of jazz that was both challenging and deeply swinging."
),
("Charles Mingus", "The Black Saint and the Sinner Lady"): (
"Impulse!, 1963",
"Charles Mingus's extended composition is considered one of the greatest achievements in jazz, combining elements of classical music, gospel, and blues into a cohesive whole. The album's complex arrangements and Mingus's passionate bass playing create a deeply emotional musical journey. The work's integration of different musical styles and its emotional intensity make it a landmark of modern jazz."
),
# Additional entries for other notable albums
("Can", "Tago Mago"): (
"United Artists, 1971",
"Can's second studio album is a groundbreaking work of experimental rock that helped establish the krautrock movement. The German band's combination of repetitive rhythms, electronic textures, and improvised elements created a hypnotic form of rock music. The album's two-disc format allowed for extended compositions like 'Halleluhwah' and 'Aumgn' that showcased their ability to create trance-like states through repetition and subtle variation."
),
("Gorillaz", "Demon Days"): (
"Parlophone/Virgin, 2005",
"Damon Albarn's virtual band project reached its creative peak on this genre-blending masterpiece featuring collaborations with De La Soul, MF DOOM, and Neneh Cherry. The album's dark themes and eclectic musical palette, from the hip-hop of 'Feel Good Inc.' to the gospel-influenced 'DARE,' created a unique sound that defied categorization. The album's success proved that experimental pop could achieve mainstream success."
),
("Kate Bush", "The Dreaming"): (
"EMI, 1982",
"Kate Bush's fourth studio album marked her complete artistic independence and her most experimental phase. Produced entirely by Bush herself, the album's dense, layered production and unconventional song structures pushed the boundaries of pop music. Songs like 'Suspended in Gaffa' and the title track showcase her unique vocal style and artistic vision. The album's initial commercial disappointment has been reversed by critical reappraisal recognizing it as her most adventurous work."
),
("Ariana Grande", "thank u, next"): (
"Republic, 2019",
"Ariana Grande's fifth studio album emerged from personal trauma and public scrutiny to become a statement of resilience and self-empowerment. The album's trap-influenced production and Grande's powerful vocals on songs like the title track and '7 rings' created some of the most memorable pop music of the late 2010s. The album's themes of healing and growth, combined with its commercial success, established Grande as one of pop's most important voices."
),
("Justin Timberlake", "FutureSex/LoveSounds"): (
"Jive, 2006",
"Justin Timberlake's second solo album, produced by Timbaland, created a futuristic form of pop-R&B that dominated the mid-2000s. The album's innovative production, featuring unconventional rhythms and electronic textures, provided the perfect backdrop for Timberlake's smooth vocals. Songs like 'SexyBack' and 'My Love' showcased his evolution from boy band member to serious solo artist."
),
}
def read_csv_file(filepath):
"""Read the CSV file and return the data."""
with open(filepath, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
return list(reader)
def identify_missing_albums(data):
"""Identify albums with missing Info and Description."""
missing_albums = []
for row in data:
if not row.get('Info', '').strip() and not row.get('Description', '').strip():
missing_albums.append(row)
return missing_albums
def update_album_info(data, lookup_dict):
"""Update albums with information from the lookup dictionary."""
updated_count = 0
for row in data:
# Check if this album needs updating
if not row.get('Info', '').strip() and not row.get('Description', '').strip():
# Try to find it in our lookup dictionary
key = (row['Artist'], row['Album'])
if key in lookup_dict:
info, description = lookup_dict[key]
row['Info'] = info
row['Description'] = description
updated_count += 1
print(f"Updated: {row['Artist']} - {row['Album']}")
return updated_count
def write_csv_file(filepath, data, fieldnames):
"""Write the updated data back to CSV file."""
with open(filepath, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(data)
def main():
"""Main function to run the update process."""
csv_file = '/home/lundberg/projects/top500albums/top_500_albums_2023.csv'
backup_file = f'/home/lundberg/projects/top500albums/top_500_albums_2023_backup_{datetime.now().strftime("%Y%m%d_%H%M%S")}.csv'
print(f"Reading CSV file: {csv_file}")
# Read the original data
data = read_csv_file(csv_file)
total_albums = len(data)
print(f"Total albums in database: {total_albums}")
# Identify albums with missing information
missing_albums = identify_missing_albums(data)
print(f"Albums with missing Info/Description: {len(missing_albums)}")
# Create backup
print(f"Creating backup: {backup_file}")
shutil.copy2(csv_file, backup_file)
# Create lookup dictionary
lookup_dict = create_album_lookup()
print(f"Lookup dictionary contains {len(lookup_dict)} albums")
# Update the data
print("\nUpdating albums...")
updated_count = update_album_info(data, lookup_dict)
# Write the updated data back to file
if updated_count > 0:
fieldnames = ['Rank', 'Artist', 'Album', 'Status', 'Info', 'Description']
write_csv_file(csv_file, data, fieldnames)
print(f"\nSuccessfully updated {updated_count} albums!")
print(f"Updated file saved as: {csv_file}")
print(f"Backup saved as: {backup_file}")
else:
print("\nNo albums were updated.")
# Show remaining missing albums
remaining_missing = identify_missing_albums(data)
print(f"\nRemaining albums with missing info: {len(remaining_missing)}")
if remaining_missing:
print("\nFirst 10 albums still missing information:")
for i, album in enumerate(remaining_missing[:10]):
print(f"{album['Rank']}. {album['Artist']} - {album['Album']}")
if __name__ == "__main__":
main()