05/09/2025

What It Took To Revive The Music Page

Categories: Tech, Reviews

I switched this site over to using the Zola SSG around May of this year because when I originally wrote the bulky-ass HTML files that used to be this site, I had a voice in the back of my head swearing that most people with a personal site were not, in fact, maintaining 4 different 500+line raw HTML files for their site. Feel free to look at my public Codeberg Repo here to see that monstrosity.

When I switched, my lack of knowledge of web development, already apparent, forced me to axe the music page that I had pieced together from JS tutorials and other pages. I liked it. It was the fanciest, most modern feeling part of the site because of the JS and animations and what not. It even had this awesome Apple Cover Flow-esque page for the albums that I love. So nostalgic. I had no idea how to begin to merge that into the new Zola structure of templates and markdown files. I honestly used to at one point believe that 'static' sites were sites with pure HTML/CSS, no Javascript. Funny, right?

Also Zola please update your documentation it's so bad I basically found more info asking around on Discord servers than in the docs.

Long intro, but that is all to say this post is to celebrate that I have managed to bring back the table view of the music page!

Before you keep reading, go take a peek at its beautiful simplicity!

Now you can come back, unimpressed, and have a laugh with me about all the random struggles I had and the "tech" behind how it works.

The front end is super simple, and is largely the same as the old version. The JavaScript loads a JSON file and uses the eventListener() to load that JSON data into the table using the HTML structure that is pre-defined. It was a great feeling to load the page and see all my row headers loaded and styled the way I remember. What sucked was staring at this blank table wondering why a hard refresh made the data pop up, but a normal refresh made it all disappear. This is where I will shout-out my friend, who is an actual software dev, for helping me figure out that the fetch() async clause that reads the JSON file needs to have an await in front so that the page waits for the JSON file to be fully loaded before displaying the front-end elements. I really don't get JS, so that was really nice of them to just jump on a call with me and live-troubleshoot in the middle of the workday.

So the HTMl for this page is the blueprint the JS renders the JSON data onto. It completely sidesteps Zola and Tera templates, even though I originally spent some 3-5 hours making a version that used Zola's load_data() function to read and display a csv with all my ratings. I moved away from that fairly quickly because with over 400 albums rated, there was no way this page would be usable without pagination or the ability to sort the columns. (I'm still working on figuring out the pagination by the way.)

So now you know I have some 400+ row spreadsheet (that maybe I need to turn into a proper database on my server at some point). The spreadsheet originally came from an 'Album A Day' group I was a part of in 2023. The group was ~15 people all listening to one album per day. The albums were also submitted by the members and we all took turns putting a new album 'on deck' and submitting our ratings for the album of that day. The sheet was hosted on Google Sheets, natural for collaborative work, and each person had a column to submit their score. The written reviews (if one wanted to submit one) were in the notes of each cell, so I had to find a google custom script to extract these notes into their own columns. After a little manual cleanup, I had a csv with the following fields for each album:

  • Artist
  • Album
  • Musicbrainz ID (MBID)
    • This was completely blank for all entries at this point, and not in the original Album a Day sheet.
  • Score
  • Review

I then wrote a Python script that reads the csv, cleans it, and then queries the Musicbrainz API to grab the missing info. I'm not sure if it would be useful to anyone else but just in case it now lives in its own repo project here. I think it's fairly neat, because if the artist+album query doesn't find a specific release/version you had in mind, it can be overriden with the MBID field on the CSV.

It's a slow script, as it has to wait 1 second between each query to respect the Musicbrainz API call limits. Maybe someone who knows the MB API better than me can figure out how to pass multiple album+artist pairs per API request. I haven't figured that out.

It also won't search a row if it already has all the columns filled in, meaning that adding new albums to the CSV won't cause the script to run longer and longer each time. One second per album with missing info. Maybe reasonable?

I will likely be trying to make improvements to it, and I'll try to be a good little dev and document them in the repo.

In the end, the script both populates the source csv with the found data, and generates a JSON that is more db-like for the JavaScript on the website.

So when I want to update the music page, I will first update the csv with any new entries, run the python script, then run 'Zola build' like usual to update the rest of the site. Then, as I do, I will drag the static files generated into neocities.

By the way, this last bit is another one of those "there must be a better way" moments, but I've not found some crystal-clear tutorial on how to automate the deplyment to neocities in some CI/CD way. Email me if you have one. I'm pretty useless.

So that's it, used the process flow and data analysis understanding I have from being a SQl data analyst in my day-to-day to code some useful python. Beyond that, lots of trial and error, and feverish googling of simpler and simpler reductions of the problem to piece together the final script.

I'll leave you with the ordered list of the "minimum viable product" iterative approach I took to arrive at the final version:

  1. MVP 1:
  • read csv to pandas df
  • query MB using artist+album
  • get MBID back into csv
  1. MVP 2:
  • If MBID exists in csv, use that for query instead
  1. MVP 3:
  • Get Zola to auto-read the JSON data
  1. MVP 4:
  • Display all csv data in sortable table on //music page
  • Note, this is now the python script+JS loading
  1. MVP 5:
  • If all columns except 'Review' are populated, skip that row.
  1. Future nice-to-haves:
  • "read more" cutoff for reviews column
  • grab csv from G sheets or server file
  • run with 'zola build' command (I don't know any Rust)
  • Paginate every 25 rows
  • Grid view with album arts!!!
  • Download button for CSV/JSON
image of writing in a notebook with similar text to the ordered list

_ _ _


Thoughts? Send me an email!
kagumail.uselessly535@passinbox.com
Feel free to remain anonymous and send it from a secure mailer!

Last Update: 09/05/2025
Banner image with A.C.A.B text Banner image with a cute cartoon frog Banner image with a meme about graphic design being my passion Banner image gif saying 'piracy now'! Banner image button alternating between 'free palestine' and 'from the river to the sea' Banner image button alternating between 'say no to Web3' and 'keep the web free' text Banner image button with the 88x31 logo, linking to a banner image repository