{"id":107,"date":"2024-10-24T09:12:31","date_gmt":"2024-10-24T04:12:31","guid":{"rendered":"http:\/\/localblog.local\/?p=107"},"modified":"2026-06-19T23:26:52","modified_gmt":"2026-06-19T23:26:52","slug":"automated-updating-of-spotify-playlist-of-artists-with-upcoming-shows-draft","status":"publish","type":"post","link":"https:\/\/alanahryding.me\/blog\/programming\/automated-updating-of-spotify-playlist-of-artists-with-upcoming-shows-draft\/","title":{"rendered":"Automated updating of Spotify playlist of artists with upcoming shows"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Using the <a href=\"https:\/\/thecmf.com\/\">cmf.com&#8217;s<\/a> list of upcoming shows, I created a Python script\/class to crawl the list, find matches by band via Spotify&#8217;s API, and add songs to a playlist. It also updates a publicly available Google spreadsheet (in theory). I&#8217;m still improving it and working on a few things as I migrate and refactor code.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">See the <a href=\"https:\/\/open.spotify.com\/playlist\/6QuFno73ktEUXcNRvn6KiE?si=2db7772f038b4397\">playlist<\/a> and the <a href=\"https:\/\/docs.google.com\/spreadsheets\/d\/1T000vN0PjqGddB0EqgamyHP_JZTFZckomGRECsyU0MQ\/edit?usp=sharing\">spreadsheet<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"560\" src=\"https:\/\/alanahryding.me\/blog\/wp-content\/uploads\/2026\/06\/Screenshot-2024-11-13-at-22.11.30-1024x560.png\" alt=\"\" class=\"wp-image-348\" srcset=\"https:\/\/alanahryding.me\/blog\/wp-content\/uploads\/2026\/06\/Screenshot-2024-11-13-at-22.11.30-1024x560.png 1024w, https:\/\/alanahryding.me\/blog\/wp-content\/uploads\/2026\/06\/Screenshot-2024-11-13-at-22.11.30-300x164.png 300w, https:\/\/alanahryding.me\/blog\/wp-content\/uploads\/2026\/06\/Screenshot-2024-11-13-at-22.11.30-768x420.png 768w, https:\/\/alanahryding.me\/blog\/wp-content\/uploads\/2026\/06\/Screenshot-2024-11-13-at-22.11.30.png 1250w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"919\" height=\"166\" src=\"https:\/\/alanahryding.me\/blog\/wp-content\/uploads\/2026\/06\/Screenshot-2024-11-13-at-22.12.08.png\" alt=\"\" class=\"wp-image-350\" srcset=\"https:\/\/alanahryding.me\/blog\/wp-content\/uploads\/2026\/06\/Screenshot-2024-11-13-at-22.12.08.png 919w, https:\/\/alanahryding.me\/blog\/wp-content\/uploads\/2026\/06\/Screenshot-2024-11-13-at-22.12.08-300x54.png 300w, https:\/\/alanahryding.me\/blog\/wp-content\/uploads\/2026\/06\/Screenshot-2024-11-13-at-22.12.08-768x139.png 768w\" sizes=\"auto, (max-width: 919px) 100vw, 919px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"194\" src=\"https:\/\/alanahryding.me\/blog\/wp-content\/uploads\/2026\/06\/Screenshot-2024-11-14-at-23.23.33-1024x194.png\" alt=\"\" class=\"wp-image-317\" srcset=\"https:\/\/alanahryding.me\/blog\/wp-content\/uploads\/2026\/06\/Screenshot-2024-11-14-at-23.23.33-1024x194.png 1024w, https:\/\/alanahryding.me\/blog\/wp-content\/uploads\/2026\/06\/Screenshot-2024-11-14-at-23.23.33-300x57.png 300w, https:\/\/alanahryding.me\/blog\/wp-content\/uploads\/2026\/06\/Screenshot-2024-11-14-at-23.23.33-768x146.png 768w, https:\/\/alanahryding.me\/blog\/wp-content\/uploads\/2026\/06\/Screenshot-2024-11-14-at-23.23.33-1536x291.png 1536w, https:\/\/alanahryding.me\/blog\/wp-content\/uploads\/2026\/06\/Screenshot-2024-11-14-at-23.23.33-2048x388.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Note on recent Spotify Web API changes <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-dark-red-color\"><\/mark><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><mark>As of Dec. 2024, I will likely not be doing much more work on this as Spotify has made significant changes to the Web API as of late November 2024, unfortunately, and while this was just a project for fun, I was looking forward to playing around the the track features and audio analysis which I can no longer get. In fact, <a href=\"https:\/\/developer.spotify.com\/blog\/2024-11-27-changes-to-the-web-api\">a lot of things changed<\/a> that point to increased monetization efforts.<\/mark><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Spotify API used to return genres for albums very recently, and I found that even if an artist didn&#8217;t have genres, sometimes the albums would which would make the playlist more accurate; <em>however<\/em>, it&#8217;s showing deprecated as of December 2024. In fact, <a href=\"https:\/\/developer.spotify.com\/blog\/2024-11-27-changes-to-the-web-api\">a lot of things changed<\/a> that point to increased monetization efforts. Alas, we&#8217;ve all seen it.  Darn.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Any <span style=\"text-decoration: underline;\"><em>productionalized<\/em> <\/span>app that used the removed endpoints prior still have access, but new apps and any apps in dev mode do not.  As I have not productionalized my app (I run the update so I am the only user), my app is in dev mode. Darn. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We&#8217;ve come a long way since Echo Nest, the only reason I started using Spotify since they were acquired in 2014, which again, <a href=\"https:\/\/everynoise.com\/engenremap.html\">check out this website\/map<\/a> and <a href=\"https:\/\/furia.com\/\">blog<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Spotify API-related Tasks<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The API returns genres for some artists, and my matching &#8220;algorithm&#8221; if you can call it that isn&#8217;t very sophisticated right now, so adding an extra check for genre will help weed out stray songs. Though the <a href=\"https:\/\/developer.spotify.com\/documentation\/web-api\/reference\/get-recommendation-genres\">seed genres<\/a> list is more limited, the genres returned for artists seems to be more expansive.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, <a href=\"https:\/\/open.spotify.com\/artist\/76S65NHJHrNy4JTrXHP2BH?si=3cc68ebbdd094cf8\">Exodus<\/a> returns the below genres:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;\"death metal\", \"hard rock\", \"metal\", \"old school thrash\", \"speed metal\", \"thrash metal\"],<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The band <a href=\"https:\/\/open.spotify.com\/artist\/3v3VSKylQE69ztn5TUVlFE\">Nile<\/a> returns the below genres:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;\"brutal death metal\", \"death metal\", \"metal\", \"oriental metal\", \"south carolina metal\", \"technical death metal\", \"thrash metal\"]<\/code><\/pre>\n\n\n\n<p class=\"is-style-info has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-right:0;margin-bottom:0;margin-left:0;padding-top:var(--wp--preset--spacing--20);padding-right:0;padding-bottom:var(--wp--preset--spacing--20);padding-left:0\">As a note, the above is is copied and pasted from the JSON returned from the Spotify API artists endpoint. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Some others include&#8230;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"crossover thrash\", \"death metal\", \"denver metal\", \"metal\", \"speed metal\", \"thrash metal\"... \"horror punk\", \"industrial metal\"...\"finnish melodeath\", \"finnish metal\", \"folk metal\", \"melodic death metal\", \"metal\", \"nordic folk metal\", \"power metal\", \"symphonic metal\", \"viking metal\"...\"avant-garde metal\", \"swiss metal\"...\"chaotic hardcore\", \"chicago hardcore\", \"grindcore\", \"powerviolence\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Maybe you can guess from the genres above which ones belong to Weekend Nachos, Ensiferum, Wednesday 13, and Zeal &amp; Ardor.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">? Output Formatting<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">So far I&#8217;m just saving the (publicly) visible output to Google Sheets, but I am running the script via my own web app (Dockerized Flask, MySQL), and the output is friendlier but still needs tweaking.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Using the cmf.com&#8217;s list of upcoming shows, I created a Python script\/class to crawl the list, find matches by band via Spotify&#8217;s API, and add songs to a playlist. It also updates a publicly available Google spreadsheet (in theory). I&#8217;m still improving it and working on a few things as I migrate and refactor code. [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[9,14,17,22,24,27,31,36],"class_list":["post-107","post","type-post","status-publish","format-standard","hentry","category-programming","tag-api","tag-docker","tag-flask","tag-metal","tag-mysql","tag-oauth2","tag-python","tag-spotify"],"_links":{"self":[{"href":"https:\/\/alanahryding.me\/blog\/wp-json\/wp\/v2\/posts\/107","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/alanahryding.me\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/alanahryding.me\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/alanahryding.me\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/alanahryding.me\/blog\/wp-json\/wp\/v2\/comments?post=107"}],"version-history":[{"count":3,"href":"https:\/\/alanahryding.me\/blog\/wp-json\/wp\/v2\/posts\/107\/revisions"}],"predecessor-version":[{"id":394,"href":"https:\/\/alanahryding.me\/blog\/wp-json\/wp\/v2\/posts\/107\/revisions\/394"}],"wp:attachment":[{"href":"https:\/\/alanahryding.me\/blog\/wp-json\/wp\/v2\/media?parent=107"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/alanahryding.me\/blog\/wp-json\/wp\/v2\/categories?post=107"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/alanahryding.me\/blog\/wp-json\/wp\/v2\/tags?post=107"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}