Raspberry Pi 4

SpotifyGUI 2 – Touchscreen Controller for Spotify

SpotifyGUI 2

I am back with an update to SpotifyGUI! Since this thing has been working so well, it just sits on my desk and constantly updates with whatever I am playing, I have not had a need to update to much, other than to add more features! So… I ended up rewriting the entire app! The reason I did was because I felt like I was reaching the limitations what Python offers in visuals. Every new feature I thought about making for it I found myself thinking “Well, will Python be able to handle this?”

Python is a great language to do a lot of simple things really quickly, but consequently it makes implementing complex things that much harder, when compared to another language. I found that throughout development, especially towards the later stages of creating and designing the UI, I would think “Wow, it would be so much easier to do this in C.” or “This would be one line of JS…” This is what ultimately led me to rewriting the project. The language I chose was JavaScript, for many reasons, but mainly because of it’s ease of creating really nice looking UIs.

Don’t you worry though! Our best bud Python is still there under the hood! The new codebase consists of a Python back-end that handles the communication with the various APIs (Spotify, Lyrics, etc.), that then hands that information off to a JavaScript front-end that handles the task of making it pretty! And oh my is it better. I really liked the design that I had made with the Python-made GUI so I set out to just remake it with JS/CSS. Then, integrated it into the Linux distro for automatically running in a web app that is nice and neat to execute at startup, with it also being managed from the Python back-end.

Another big update is the display! I opted to go with this 10-inch OLED touchscreen that I feel better allows the elements the space they need! The upgrade from LCD w/ IPS panel to OLED makes the visually really pop out and gives an amazing vibrancy to the colors than the prior display! With the new space I definitely looking at ways to redesign the UI to make better use of the new real estate!

It’s a whole lot nicer. It’s snappier, it’s quicker. It’s responsiv-…er. It always for all of the multi-threaded capabilities of JavaScript with the reliability of Python. This includes and magnitude less amount of error-handling, and no longer being reliant on GTK.

While rewriting I also completed most of the goals I had set out to on the last post and more!

  • I reversed engineered the Spotify Canvaz API. It now downloads the short mini clips that are usually only available within the Spotify mobile apps and replaces the album art with the video on loop.
  • Refactored the background color picker. Now it picks a color that makes a lot more sense, including a gradient but only if it determines if it would be better than a single color. This is in contrast to the previous algorithm which would pick an average of the 5 more common occurring colors in the album art.

And more! Here are some new things implemented as well!

  • Transitions! Oh the wonders of CSS and JS. The app now has full and proper transitions for all elements. So when changing songs the text, controls, album art, and other elements fade out and the new ones fade in. The background fades into the new color. Lyrics fade between lines. It all looks really nice and modern.
  • Progress bar at the bottom keeps track of where in the song you are currently listening (with the progress color also having another determined color that contrasts with the background color.
  • Background gradient but only when it looks the best! The color picking algorithm is a whole lot better and it will determine if the album art has enough differing colors to make a good looking gradient, or if it should just stick to a single color background.

Wow. Lots of changes! Still more to go! I am happy were it is right now, but I will be updating it here and there because I have a new set of goals and ideas! So here goes:

  • Proper use of space. Empty space should be filled and elements should find their home in more general areas instead of at the edges.
  • Image modification. Admittedly, the image modification of the album art is easier in Python than it is in JS, which is why right now there are no rounding of corners and vibrancy changes to match the background like there is in the Python version before.
  • Sidebar menu to pick music, playlists, artists, etc. from recently played or Spotify main page.

Stay tuned! Lots of great things to come!

SpotifyGUI – Touchscreen Controller for Spotify

The last thing I would have thought a beautiful GUI could be made in was only one language: Python. One of the most diverse languages, Python is known to be the perfect tool in a developers arsenal for a wide variety of logistical tasks and projects. Being the most used scripting language in the world, as well as used by the biggest companies, Google, Facebook, Chase, Spotify, and that’s just to name a few. Python does a lot of things well, but one language you don’t reach for to make a GUI? The answer is also Python.

Now, while I could have made this in C to make it more native, JavaScript to make it prettier, or Java to give me a headache, I chose Python. Once I figure out why I did this I will update.

What I have made is a Python application that uses the Spotipy library (which is just a wrapper of the Spotify HTTP API) to facilitate an OAuth2 login to a Spotify account by opening a Spotify login screen, as well as hosting an HTTP server to recieve the localhost callback from the web browser to grab the authorization token provided by Spotify for the users account. This token is then stored locally and the proper steps as designed by Spotify are used to “refresh” that token with the user’s account information to generate new tokens without the need for a login each use.

The program then goes on to use the built-in “TKinter” Python library to create a scene and frames that are used to construct the GUI. TKinter is a really great library as it does not depend on a particular OS support and a GUI can be made that will operate on any platform (Windows, Mac OS, Linux, etc.), anywhere Python can be run.

Functions are defined to control each element of the GUI with all visuals being contrast-reversible. The program upon startup and after authentication, will go on to poll the Spotify API for the user’s currently playing information. Spotify provides this through there API in a JSON-formatted string which is parsed by the application to determine the key values that are needed for the program, such as the name of the device playback is currently on, the track title, the artist title, as well as the tracks length as well as the current track progress, so the progress bar can be drawn along the bottom of the display. After this information is displayed it waits for a change from either the on-screen controls, or another Spotify Connect device, as it will recognize and work with any other Spotify Connect device and keep up to date even when music playback is controlled elsewhere.

After this information is parsed, the program downloads the lyrics from a 3rd-party source (as Spotify nor their lyrics partner Musixmatch provide publicly available APIs), parses the data to separate at what second each line is being sung at any particular time. It then compares this information with the current position in the currently playing song and displays the line when it reaches the right time.

At the same time, multithreading is implemented to also download the album art of the current song from Spotify’s endpoint and display it, after some modifications. First, it runs the image through an algorithm to determine it’s “dominant” color. Now, I’ve bounced around re-designing this part a few times now, the rudimentary implementation being shrinking down the image to 1 pixel and having PIL determine what color that pixel should be, to what it is now which creates an entire color palate of the images, determining similar colors, then calculating the most used color from combining the similar colors… and I still think it has room for improvement The Pillow library is then used to draw circles on each corner, offset them, then crop the opposite out to white, which is then replaced with the color result of the aforementioned algorithm, this is what creates the curved edges of the album art. At the same time is also replaces the background of the entire screen with that same color. Then, that color is run through a luminance index to determine the perceived brightness of a particular color (which has also gone through many revisions), this then puts the color onto a brightness scale and recolors the UI elements either to black or white if it is past of the point where readability is impacted.

The screen will also detect if no music is playing and open a device selection screen which polls the Spotify API for all available devices by name on the user’s Spotify account and puts them in a list, where when a device is selected, playback starts on that device. After a predetermined amount of time of no playback the display will enter a limited sleep mode where the screen is dimmed, then later into a complete sleep mode where the display is off. Tapping the display will reactive the program and continue where it left off. Once playback starts the device selection screen is automatically closed and the now playing screen returns.

The device is fairly simple, a Raspberry Pi 4 wired to a capacitive touchscreen and connected via HDMI for picture. The Pi is running a lightweight Linux distro with no desktop environment or window manager installed, I also program the Python application to connect directly to the Linux system to start a purpose-built X server and bootstrap itself into it so there is no overhead. The result is a pretty speedy system that is very responsive and fully boots with Spotify connected in ~6s. Initially I was considering what hardware I was going to run this on and an Arduino-like device such as an ESP32 came to mind, however while this started as a small app with a small screen, the upgrades made along the way, driving the display and the amount of code that this project evolved to called for those ideas to be scraped, however I may make a version with less features later if I find I can reduce it’s footprint to become embedded. It now uses a 3:1 7.4 inch screen with a 3D printed case and stand to prop it up and is powered by one USB type-C cable and is completely self contained in the printed case.

The program also features a self-updater that reaches out to my server on each startup to look for a new build, downloads and installs the update before starting the bootstrapping process. I also created a single start install script written in both Bash and Batch for easy installation. The script reaches out to the update server but this time for a complete install, downloads all packages and assets (including required libraries), installs to the application directories for the respective OS, and creates and installs a Systemd/Init.d service on Linux or a Windows Service on Windows. The script has proper exception handling and sets the service up for bootup with a handler Python script that takes control of the display and does the aforementioned X server handling on startup.

The results are something I actually never expected when I first started this project on a tiny 1.4 inch, non-touch SPI display! It has grown and grown and there are still many features to add! There are so many more ideas I have to improve so I may update this post here with new features as I add them! To name a few:

  • Reverse engineer Spotify’s Canvaz API (which is obfuscated and not publicly available) to download short mini clips to each song and play this video in place of the album art.
  • Refactor background color to better choose a complementing color(s), after this is perfected, expand to multiple colors to render a gradient to better compliment the album art.
  • Groundwork already laid for a built-in voice assistant that will allow for hands-free control of playback.

There’s a lot to come and I am excited to continue working on it! Stayed tuned for more updates!