Billy Joel wrote "We Didn't Start the Fire" in 1989 as a rapid-fire list of 119 headlines from his own lifetime — the story goes that a 21-year-old friend of Sean Lennon's complained it was a terrible time to be 21, Joel pushed back with "didn't you hear of the Korean War or the Suez Canal Crisis," and the argument turned into a lyric. In 2023, Fall Out Boy released a cover-slash-update that swaps in 81 references covering 1990 to 2022 — the Berlin Wall to Anthony Fauci — over (mostly) the same melody.
Two versions of the same song, thirty-plus years apart, each one a compressed list of "things that happened." That's a dataset. So I built a small site that turns both songs into a chart you can play like a record: press play on either video, and a synced highlight tracks the current lyric against a shared timeline of the actual historical dates.
What it actually does
The page (index.html) is a single self-contained file: two embedded YouTube players (Billy Joel's original video and Fall Out Boy's), a Plotly chart, and a reference table underneath. Play either track and the current line's dot lights up on the chart and its row highlights in the table, in both directions — song position on one axis, real calendar date on the other. You can run both videos at once; each highlights independently in its own color.
There's also a small easter egg: jabronies.html, a mini version built from a clip of It's Always Sunny in Philadelphia's "The Gang" doing their own scrambled take on the song — same chart mechanic, different (much more chaotic) dataset.
The actual number the whole project turned out to hinge on
The stat block at the top of the page reports a Spearman rank correlation between each song's lyric order and real-world chronological order:
That's not a vibe, it's analyze_order.py computing rank correlation over both timeline JSONs. It's a nice one-number summary of something people already sensed listening to the two songs back to back: Joel is basically reciting a timeline, and Fall Out Boy's writers admittedly rearranged things for rhyme and flow rather than sequence (Pete Wentz has said as much in interviews cited in the project's own research notes). Charting it turns an anecdote into a measurable, citable difference between the two songs.
The pipeline: beats, Whisper, and a lot of manual correction
Under the hood this is three small pipelines chained together, and it took several passes to get right:
- Beat detection (
detect_beats.py) runslibrosaover both MP3s to get BPM and a beats-per-second array per song. Straightforward, worked cleanly. - Lyric-to-timestamp alignment is where most of the actual effort went, through three approaches before one stuck. First,
assign_times.pydistributed events proportionally across verse-line time windows from a plain transcript, using comma/"and" counts as a proxy for how many references a line packs in. That broke down because the Fall Out Boy auto-transcript flatly missed several references (Captain Planet, Arab Spring, Kurt Cobain) and mis-split others — it read "MySpace" as "Mars, Space" — which threw off the count and drifted the whole first verse.calibrate_times.pypatched that with manually-tuned anchor points. The version that actually stuck,whisper_align.py, runswhisper-timestamped(medium model) over each full MP3 for word-level timestamps, then walks each song's event list in order, fuzzy-matching each event's lyric to the next plausible Whisper word (exact match, then substring, then adifflibratio), and interpolates times for anything that doesn't match. Whisper output is cached per song so re-runs don't re-transcribe. - Historical event matching: the events (headline, date range, Wikipedia link, a note) are hand-researched and stored per-lyric in the timeline JSONs.
restore_bj_metadata.pyexists because an earlier version ofapply_timings.pyoverwrote that metadata with a thinner patch payload and lost it — fixed afterward by makingapply_timings.pymerge patches instead of replacing the array outright.split_events.pyis a one-off cleanup for two lyric lines that each secretly packed in two references ("Kanye West and Taylor Swift," "World Trade, second plane") and needed to become two separate chart points.
build_html.py then reads both finished timeline JSONs and renders the whole interactive page — chart, players, tables — as one static HTML file with no server needed.
Where it stands
Based on file timestamps, the bulk of this was built over a few sessions between May 10 and May 19 — beat detection and a plain first pass on day one, then most of the alignment debugging and the final index.html build clustered May 15–19. There are two screenshots in the project folder from May 19 that look like the finished state.
There's also a fairly detailed unbuilt design direction sitting in research/design-direction.md — a whole "kitchen TV" visual concept (CRT bezel around the chart, aging wallpaper keyed to the era, Storm Front red-and-black, Polaroid-style reference cards) that riffs on the 1989 music video's aesthetic. None of it has been implemented yet; the current page is still the plainer Plotly-chart-plus-video-player version — a "maybe next," not something that's live.
- This is a personal build with no public audience claims — just a project I made because the dataset was sitting right there in two songs.
- The jabronies easter egg (the It's Always Sunny version) is exactly that — an easter egg, not a separate release.