DEV Community

Envoy49
Envoy49

Posted on

GO Spotify CLI

Image description

Source code: https://github.com/Envoy49/go-spotify-cli

💡Introduction to the Project

Ever since I started using Spotify, the idea of controlling it via the terminal has never left me. I also wanted to learn Go because I had heard many good things about it. Thus, the choice for my next project was obvious to me: building a Spotify CLI tool with Go.

📚Learning and Preparation

Initially, I dedicated about two months to learning the basics of Go. With my background in JavaScript, TypeScript, Python, and a bit of C#, picking up Go was relatively straightforward. Even though the error handling seemed somewhat unusual at first, I’ve since become comfortable with it. Then, it was time to begin the project development. Part of my preparation involved understanding the best practices for Go project folder structuring, as well as spending time reviewing various Go projects, packages, and libraries. I also focused on defining packages that would suit my needs.

🔐 Credential Storage and Authorisation Workflow

Spotify uses the OAuth 2.0 authorisation framework to grant access to apps that are trying to access data.

Following Spotify’s documentation, I quickly identified that my first steps should be to obtain a Client ID and ClientSecret, which are crucial for any connection with Spotify. So, I created an app on Spotify’s dashboard and secured those credentials.

The next step was to store these credentials somewhere. I decided to adopt the same approach the AWS CLI uses to store secrets, which is in the root folder of the user’s machine by creating a .go-spotify-cli folder with relevant file names. The first functionality I built for the app was to prompt the user to enter these secrets with instructions to follow.

The subsequent steps involved obtaining the access token using Client ID and Client Secret. To generate a token, Spotify requires the user to grant access through a browser; once access is granted, Spotify returns the certain code using a callback URL. Note: Callback URLs must be predefined in the app that was created on Spotify’s Developer Dashboard. Therefore, I wrote code to open a browser with the Spotify link and then wait for Spotify to invoke the callback URL to retrieve the specific code from the query parameters, which is then used to obtain a token. I also decided to store the tokens somewhere — you guessed it — in the same root folder on the user’s machine where the secrets are stored, within the .go-spotify-cli directory. Go offers convenient functionality from its standard library to access the user’s directory.

Each token generated by Spotify is only valid for one hour and is provided alongside a refresh token. The app uses the refresh token to obtain a new auth token if the original one has expired, thus avoiding the need to open a browser for a new token. Conveniently, Spotify also provides a timestamp indicating when the token will expire. The app utilises this timestamp to determine when to use the refresh token to generate a new auth token, which it then saves in the .go-spotify-cli folder. Therefore, each time a user executes any command, the program checks the validity of the token; if it has expired, the program retrieves a new one and saves it with an updated timestamp.

Spotify uses scopes to generate different tokens. I utilised three different scopes to generate three Bearer tokens to access various Spotify APIs needed for my app. Of course, there is much more to cover, but I wanted to concentrate on functionalities that I thought would be useful for me and others as well.

🛠️ Implementation of Core Functionalities

I managed to get basic functionality working relatively quickly. Play, Pause, Next, Previous commands were relatively easy to implement. Then I started working on the Search functionality, which required me to spend more time than I had spent on all the previous commands combined. The Search API is extensive and provides the ability to search for “Tracks,” “Artists,” “Albums,” “Playlists,” “Shows,” “Episodes,” and “Audiobooks.” I decided to focus only on Tracks and Episodes and to work on other options if my app gained enough popularity.

After getting the search functionality working, it was time for refactoring. I did extensive refactoring and cleaned up the code to prepare it for further extension and easier future development. Once the refactoring was complete, adding new commands became straightforward. For instance, implementing the new ‘saved’ command, which fetches all saved tracks and allows the user to play the selected track, took me only an hour.

One of my favourite APIs was the ability to control the device. At some point during the development process, I noticed that Spotify can’t play a track if no device is active. A quick search revealed that a Device API exists, allowing the activation of an inactive device. What it also allows is switching devices. How cool is that! So, by using the Device API, I could switch between my phone and computer and vice versa. I also used this API to give users the option to activate a device if, after using the Play command, Spotify throws an error saying that there is no active device.

🚀 Deployment and Distribution

The final steps involved deploying the app to ensure users could easily download it. This journey was particularly intriguing as I had envisioned distributing my CLI tool to both Mac and Windows users, despite never having deployed on Homebrew or Winget before.

🍏 Since I use a Mac, I opted for Homebrew to distribute my CLI. I created a Homebrew formula, which is necessary to direct Homebrew to the location of the app. I automated the process, enabling CI/CD to detect each new release in the main repository and subsequently update the Homebrew formula.

🪟 Similarly, for Windows users, I have leveraged Go's capability to build versatile binaries. Windows users can use Winget package manager to install Go Spotify CLI. Automation is in todo list.

🐧Linux users can also theoretically install the CLI using Homebrew. While I haven’t tested this on Linux, I would greatly appreciate any feedback from those who can try it out.

Steps for installation can be found here: https://github.com/Envoy49/go-spotify-cli

📝 TODOs:

1) A wealth of Spotify APIs are still available to enhance the app’s functionality. I’ve chosen to hold off on adding more features until the app achieves some level of popularity within the community. With numerous project ideas in the pipeline, I’ll leave this project as is for now and await feedback from users.

2) As you may have noticed from source code, the app currently lacks tests. My primary focus was on developing its core functionality, and given the constraints of balancing free time after work and family commitments, I have not prioritised writing tests at this stage.

If you find value in my work and would like to contribute, please consider supporting me on Buy Me A Coffee

https://www.buymeacoffee.com/envoy49

Top comments (0)