<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Ben A.</title>
    <description>The latest articles on Forem by Ben A. (@concourseben).</description>
    <link>https://forem.com/concourseben</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3433305%2F6b5e8202-b3bc-4dd8-a320-e7fa3ea5c6bc.png</url>
      <title>Forem: Ben A.</title>
      <link>https://forem.com/concourseben</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/concourseben"/>
    <language>en</language>
    <item>
      <title>RevenueSpot: A Reflection</title>
      <dc:creator>Ben A.</dc:creator>
      <pubDate>Mon, 20 Oct 2025 19:58:20 +0000</pubDate>
      <link>https://forem.com/concourseben/revenuespot-a-reflection-2i2m</link>
      <guid>https://forem.com/concourseben/revenuespot-a-reflection-2i2m</guid>
      <description>&lt;p&gt;RevenueSpot was an early project I worked on with the goal of learning a bit more about web scraping and how to use the Spotify API. I was also just genuinely curious about how much money each track on Spotify made. &lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;It was during the legendary Drake-Kendrick Lamar rap beef that a friend and I joked about how much more money these guys must be making off of this drama, what with people going to stream their music more. As these conversations often go, the topic of how much money they make came up and as musicians ourselves, how much money they must get per stream on Spotify. Given that Drake has songs with over 1 billion streams, I wanted to do the calculation.&lt;/p&gt;

&lt;p&gt;The long-held understanding has been that Spotify pays artists less than pennies per stream. According to this music site, some forums, and others, &lt;a href="https://dittomusic.com/en/blog/how-much-does-spotify-pay-per-stream" rel="noopener noreferrer"&gt;the estimation that each stream is equivalent to $0.00028 in revenue&lt;/a&gt;. Spotify &lt;a href="https://support.spotify.com/us/artists/article/understanding-spotify-royalties/" rel="noopener noreferrer"&gt;denies this (sort of)&lt;/a&gt;. Either way, I have always looked for an excuse to use the Spotify API. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fconcourse-codes.s3.us-east-1.amazonaws.com%2FRevenueSpot_Screenshot3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fconcourse-codes.s3.us-east-1.amazonaws.com%2FRevenueSpot_Screenshot3.png" alt="Drake Spotify screenshot" width="800" height="557"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial Build
&lt;/h2&gt;

&lt;p&gt;My first plan when building this out was to tap into the Spotify API to get play counts per track, then do some simple math to calculate the revenue. Strangely, the &lt;a href="https://developer.spotify.com/documentation/web-api/reference/get-track" rel="noopener noreferrer"&gt;Spotify API doesn't tell you this&lt;/a&gt;. I sort of understand this given how play counts must be stored as a hyper-dynamic value, especially for artists like Drake. There were also no third party tools online that offered this info. &lt;/p&gt;

&lt;p&gt;So, I whipped up a simple 'fetch track info' input element that grabbed whatever the Spotify API had to offer, and off I went into the wonderful world of web scraping. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fconcourse-codes.s3.us-east-1.amazonaws.com%2FRevenueSpot_Screenshot1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fconcourse-codes.s3.us-east-1.amazonaws.com%2FRevenueSpot_Screenshot1.png" alt="Drake Spotify screenshot" width="800" height="882"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Web Scraping
&lt;/h2&gt;

&lt;p&gt;Believe it or not, I actually have a non-insignificant amount of professional experience using web scraping. One of the first tasks I had upon my first job out of Uni was helping the company QA team develop some Python scripts to test for the new design implementations. &lt;br&gt;&lt;/p&gt;

&lt;p&gt;At that time, the directive was to use Java with Selenium. It was fairly straight forward in 2018, before React and SPAs took over more of the web. The problem was that it was quite cumbersome (as is Java in general). Each element required practically a full 80-character line of code to drill down into. Innovation was needed.&lt;/p&gt;

&lt;p&gt;One of the grand triumphs of my early career was making the decision to switch to Python and use BeautifulSoup instead to accomplish this task in front of me while also parameterizing the test suite for the QA team. They loved that. I loved that. Everyone was happy. &lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;p&gt;But now, years later, I was confronted with web scraping in the context of a new tech stack: a Node.js backend. Some research revealed that Puppeteer was the best library for this and off I went. &lt;/p&gt;

&lt;h2&gt;
  
  
  Success!
&lt;/h2&gt;

&lt;p&gt;From there, it was relatively straight forward. Getting the play count element on the web page was pretty simple, just a matter of finding the right unique combination of HTML elements to drill into. A bit of configuration research was needed but that's exactly where our new AI Copilot friends can excel in. Ez.&lt;/p&gt;

&lt;p&gt;The one tricky part was working around bot-tracking behaviors that browsers try to stomp out. I had to throw in some timeouts, tinker with the correct version of Chromium browser to use, and ensure I had the proper HTTP request configuration to prevent security measures from quickly shutting it down.&lt;/p&gt;

&lt;p&gt;Sure enough, I had my solution! It was a bit slow, but it worked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fconcourse-codes.s3.us-east-1.amazonaws.com%2FRevenueSpot_Screenshot2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fconcourse-codes.s3.us-east-1.amazonaws.com%2FRevenueSpot_Screenshot2.png" alt="Drake Spotify screenshot" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure!
&lt;/h2&gt;

&lt;p&gt;Well, not sure if it's totally fair to say "failure" but I did toss this project up quickly into an AWS EC2 instance so I could move on to new, cooler (shinier) ideas. &lt;/p&gt;

&lt;p&gt;The need for an EC2 instance was pressing as I needed a way for the scraper to boot up a headless chromium browser, let it run for anywhere between 15-90 seconds, and fetch the page data. I also just knew how to setup an EC2 instance from past experience.&lt;/p&gt;

&lt;p&gt;In my deployment research, Copilot had pointed towards an AWS Elastic Beanstalk configuration to help save with costs when the project wasn't in use. I recognized that that was the best solution, it wasn't even particularly much more complicated... I just hadn't used it before and didn't feel like spending the time to learn. (guilty as charged).&lt;/p&gt;

&lt;p&gt;This proved to be my downfall. What a surprise it was when I saw a $10 charge come across my credit card bill courtesy of AWS because of my RevenueSpot instance. I didn't budget for that!! &lt;/p&gt;

&lt;p&gt;The failure part becomes a bit clearer when I mention that I let that go on for a couple months without digging too deep as I had moved interest to new projects and life situations. I also thought that perhaps I had just gotten some random hits of people using it and that it would go down the next month since I wasn't sharing it anywhere really. &lt;/p&gt;

&lt;p&gt;I was wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The End
&lt;/h2&gt;

&lt;p&gt;It took a few months, but I finally have gotten around to shutting down the EC2 instance and the project as a whole. It's not a terribly useful tool, and I frankly don't feel that compelled or have enough free time to dig into how to make the deployment infra more cost efficient for this particular project. &lt;/p&gt;

&lt;p&gt;That said, I did record a nice little video of it in action which you can see above or below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;I might be able to speak on the lessons learned from the technical implementations, or the infrastrcuture struggles, or even just how Spotify is doing as little as they can to pay artists. But truthfully, I think the lesson learned was how to go about these impulsive little project ideas in a more thorough manner. &lt;/p&gt;

&lt;p&gt;Until next time,&lt;/p&gt;

&lt;p&gt;B&lt;/p&gt;

</description>
      <category>sideprojects</category>
      <category>showdev</category>
      <category>api</category>
      <category>learning</category>
    </item>
    <item>
      <title>TIL: Color Analysis</title>
      <dc:creator>Ben A.</dc:creator>
      <pubDate>Thu, 18 Sep 2025 19:29:51 +0000</pubDate>
      <link>https://forem.com/concourseben/til-color-analysis-1la7</link>
      <guid>https://forem.com/concourseben/til-color-analysis-1la7</guid>
      <description>&lt;p&gt;It's how these things go on teams, budgets, and companies large and small - you set out with one goal in mind and eventually lose sight due to the myriad of design, development &amp;amp; infrastructure decisions that come up in the meantime. &lt;/p&gt;

&lt;p&gt;In this case, the team is just me, the budget is zero, and the project is a web app that's been roughly half-working for about three years. Meet "Synthesia". &lt;/p&gt;

&lt;p&gt;There's no buzzy tagline or product sign-up sheet - it's just a project to see how to make (my) music more &lt;em&gt;interactive&lt;/em&gt;. Users navigate to a page, are given a song, and asked to pick a color based on what they are feeling or hearing while listening. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6m2iz2t7rsn8p5tpjbi2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6m2iz2t7rsn8p5tpjbi2.png" alt=" " width="661" height="1000"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;an initial idea&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After getting lost in the weeds of trying to make this a product for some reason, today I finally got to the fun part of doing a bit of color analysis. &lt;/p&gt;

&lt;p&gt;At present, all tracks and their responses are saved to a supabase database with a 'colors' field existing as an array of hex code strings (i.e. ['fa012c', 'fffc43', 'c5e3a0', ...]). This has been the easiest to work with, easiest for users to understand, and a fairly quick solution. &lt;/p&gt;

&lt;p&gt;However, the world of color science goes &lt;em&gt;deep&lt;/em&gt;. I'm no Bob Ross, but even I understand how colors can typically be represented in values of &lt;strong&gt;hue&lt;/strong&gt;, &lt;strong&gt;saturation&lt;/strong&gt;, and &lt;strong&gt;lightness&lt;/strong&gt; (or 'light'). These basic values are rooted in core art principles and have existed long before computer screens made them common vernacular. They refer to the pure base color like red or blue (hue), the purity and intensity of that said color (saturation), and the amount of blackness or whiteness within that color (lightness). &lt;/p&gt;

&lt;p&gt;On computer applications from Photoshop to Figma to good ol' CSS, color can be defined by hex codes, hsl(), hsv(), and many more ways. &lt;/p&gt;

&lt;p&gt;So, the challenge was to figure out what interesting info I could glean from a set of hex codes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhebne6t41ucden667cg1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhebne6t41ucden667cg1.png" alt=" " width="800" height="95"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;about the extent i can take hex codes (or is it?)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For the sake of time and simplicity, I began with a simple and easy translation of my hex codes into hsl (hue, saturation, light) format using &lt;a href="https://gka.github.io/chroma.js/#installation" rel="noopener noreferrer"&gt;&lt;code&gt;chroma-js&lt;/code&gt;&lt;/a&gt;. This spat out a nice list of super long floating point numbers, but it gave me something to work with.&lt;/p&gt;

&lt;p&gt;Next, concatenated each of the respective values into their own arrays, used a simple &lt;code&gt;reduce()&lt;/code&gt; function to get a sum, and then extracted an average value for each. However, these were still just numerical values. In the online space, hue is interpreted as the degree at which the color sits on the color wheel while saturation and lightness are interpreted as percentages between 0% and 100%. A quick note that white, blacks, and grays will cause some wonkiness, so I took those out for now.&lt;/p&gt;

&lt;p&gt;Some simple math led me a few nice values, just a step away from deriving something neat. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0ek21ot74519fbugy7t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0ek21ot74519fbugy7t.png" alt=" " width="800" height="177"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, after a bit of finagling to figure out the correct syntax, I was able to define what is more-or-less the average color selected for this track!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqj0ktkv31l5wsdreiem.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqj0ktkv31l5wsdreiem.png" alt=" " width="800" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is hefty amount more that can be done to analyze just color values, but also an opportunity to do some statistical analysis to determine which tracks have an average color that follows closest to each of the individual selections. As you can see above, the derived color seems to be fairly reasonable. In the below track, however, the color appears to come out of nowhere.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu00lae9hx51couqbvspd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu00lae9hx51couqbvspd.png" alt=" " width="800" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've always been drawn to statistics and took a few courses at uni but have never really gone too far into the realm of possibilities. Perhaps this is a good opportunity to collaborate with some statistically-minded friends. &lt;/p&gt;

&lt;p&gt;In the next TIL iteration about this project, I hope to share a bit more on the technical considerations I made behind how to perform this computational analysis within my codestack.&lt;/p&gt;

&lt;p&gt;For now, farewell.&lt;/p&gt;

&lt;p&gt;-B&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Turning Your "Braindumps" Into Trackable Tasks</title>
      <dc:creator>Ben A.</dc:creator>
      <pubDate>Wed, 13 Aug 2025 20:09:40 +0000</pubDate>
      <link>https://forem.com/concourseben/turning-your-braindumps-into-trackable-tasks-4bf5</link>
      <guid>https://forem.com/concourseben/turning-your-braindumps-into-trackable-tasks-4bf5</guid>
      <description>&lt;p&gt;*&lt;em&gt;Do you spend more time organizing your to-do list than actually doing tasks? *&lt;/em&gt;&lt;br&gt;
Do you often forget about important tasks?&lt;br&gt;
Are you constantly recreating to-do lists to remember?&lt;/p&gt;

&lt;p&gt;Well, then 🧠braindump💩 is for you! &lt;/p&gt;

&lt;p&gt;👉🔗 &lt;a href="https://brain.concourse.codes/" rel="noopener noreferrer"&gt;https://brain.concourse.codes/&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Whoa, whoa! Let's hold up a quick sec. I'll admit: this is definitely an MVP version and is also one of my first times working on a side project app that is seeing the light of day. I've been working on this project for several months now but have been struggling with knowing when to call it "MVP", but today I've decided that it's good enough.&lt;/p&gt;

&lt;p&gt;Built using Next.js, React, my first try using TailwindCSS, and built on top of Supabase (I'm cheap), this project has mostly been built by hand as an learning opportunity. GitHub Copilot has helped me throughout, but I've been trying to improve my foundational skills here first and foremost. It also means that there may be some rough edges.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0ge6yjgx5xetstjmpt1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0ge6yjgx5xetstjmpt1.png" alt=" " width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The premise of the app is simple - if you ever find it helpful to just raw-dump all your thoughts of to-do lists, tasks, thoughts, ideas, and random tidbits, then the goal of this app is to turn that raw list into tasks that can be categorized and prioritized. In this sense, it's no different than your run-of-the-mill task tracking application except that instead of inputting new tasks each time, you are dropping all your thoughts into a blank textbox.&lt;/p&gt;

&lt;p&gt;Everyone has their own preferences but as someone with ADHD, I sometimes find any amount of pre-built structure around my braindumps to be cumbersome &amp;amp; distracting. Sometimes I don't want to fiddle with the neat (&amp;amp; helpful) features of to-do apps, I just want to drop everything in then sort it out later. The simplicity here is why most braindumps take place on paper - which I still find helpful. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuwt1qce7eagfp8ylbvoq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuwt1qce7eagfp8ylbvoq.png" alt=" " width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The eventual goal is to build a scoring system around the tasks such that the app will tell you when a certain item has appeared a number of times without being completed. Perhaps it should be moved to the backlog if it isn't important, or maybe you ought to just get it finished. &lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;p&gt;This post is a bit sporadic &amp;amp; incomplete; I've just had enough of this "half-finished" state and wanted to do something to mark it as an official "MVP". Thus, keeping this writing within 10 minutes so I can focus on the actual work - have at it. &lt;/p&gt;

&lt;p&gt;Giving myself a pat on the back and hoping for more good things to come!&lt;/p&gt;

&lt;p&gt;✌️ Peace!&lt;/p&gt;

&lt;p&gt;-Ben &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>nextjs</category>
      <category>react</category>
    </item>
  </channel>
</rss>
