Album of the Week
- Project link: Album of the Week
- Source code: Github
A few months ago I made a little site for hosting an ‘Album of the Week’. It basically does 2 things: display an album of the week and accept user submissions. Check it out using the link above, and feel free to submit an album!
Technical Details
One major design decision behind this was to keep client side JS to a minimum. Requests made to and responses from the backend are all hypertext – no JSON in sight. This made some things a little tricky (namely, form options), but I’m pretty proud with how it turned out.
The site is essentially just a Flask server with three endpoints: /
, /search
, and /submit
.
The index route /
builds a super lightweight page with the album cover art,
basic info, and a search box. Typing in the search box triggers an HTMX query to
/search
with the partially typed title after a half second of inactivity.
Clicking the submit button (>) triggers the /submit
request.
/search
When the /search
route is triggered, the backend server takes the entered text in the
input field and creates a query for the last.fm API album search. The API returns
the N most likely matches, /search
returns the first 5 albums formatted as “TITLE (ARTIST)”.
The list that is returned presents itself as a dropdown under the search bar. The user is able to click on one of the options to have it fill in the search bar. This is the only piece of custom javascript I wrote for the site – I wasn’t able to find a nice type-in dropdown solution without a bit of scripting.
/submit
/submit
accepts the entry from the text box and adds it to the list of upcoming albums. It
attempts to parse the input in the format “TITLE (ARTIST)”, if no parenthesis are present it
will leave the artist field blank. The list of upcoming titles is just a flat JSON file with
each entry containing the album title, artist, date of submission, and a hashed IP address.
Album Selection
Besides the web server, there’s another python script that is running every week to
select the next album. Every Sunday, a cronjob triggers the python file gen_next.py
,
which takes the list of upcoming albums and selects the next most relevant one.
It attempts to find an album submission from an IP address not in the most recent 3 addresses. If
unsuccessful, it keeps removing IP addresses until it finds and album. If no valid albums are found,
it quits. Once finding an album, it agains queries the last.fm API for album information,
matching the first result with the artist provided by /submit
(In case there are multiple albums
with the same name). It also saves the release year provided by the API and the cover art.
Using the MusicBrainz ID field in the image (if present), the script will query Cover Art Archive to see if a higher-resolution image is present. Last.fm only provides up to 300x300 pixels; the Album of the Week website displays at a higher resolution than that. If provided, great. If not, no worries – last.fm gave us an image to use.
The current album file (also a flat JSON file) is overwritten with the new information and the new album art is saved.
A note on storage
I intentionally did not use a database with this project. Setting up a sql server or even file would have taken much longer than writing to a flat file. Sure, it doesn’t scale well. But it doesn’t need to! I don’t think more than 2 people are using this right now. For the purposes of this project, the flat files are all I need.
What did I learn?
This is my first time experimenting with HTMX. I like it quite a bit and I’m excited to use it in future web projects. I prefer this and the performance mindset over some overly complicated tool like React (for the purposes of the website being built). All this needs is a little HTML, CSS, JS, and a little backend code. Nice and easy!
It’s a little silly but the thing I’m most proud of with the website is the little dotted line between the album art / info and the submission box. When viewed on a wide screen (monitor, laptop) the two elements are on two sides of the screen and the dotted line is vertical. When the screen is resized (or viewed on a phone), the two sections flex on top of each other and the line turns vertical. All CSS! When the pixel width is larger than the flex break point, the submission section displays a left border. When smaller, a top border. It really is a little thing but finally figuring it out was such a great moment.
Services / Tools Used
-C