spotify-tui
spotify-tui copied to clipboard
Added feature to fetch song lyrics
Support for fetching song lyrics
I've been using this great tool for a while, and I was curious whether it would be possible to add a section that displays the lyrics of the song that's currently playing, so I decided to implement it: even if it's not one of the most important missing features listed on the readme, I thought that it would have been a pretty nice addition to improve the overall experience for many users like me.
Approach to the implementation
My main concerns and goals about the implementation of this feature were:
- First of all, not to damage in any way the current behaviour of the program: if a user doesn't want to use the lyrics function, the TUI needs to function in the exact same way as before. I made sure therefore that my code doesn't slow down any operation and can never panic. Every error is handled and results in a message saying "No lyrics were found for the current song".
- Secondly, not to introduce any overhead in the installation process: many lyrics APIs, like Genius or Musixmatch, require an authorization token. This means that during installation, a user would need to provide both the Spotify token and the token for the lyrics provider. To avoid this, I used the open source lyrics APIs provided by lyrics.ovh. The project is available here. In my opinion, since lyrics are not an essential feature, it was much better to use an archive not as complete as commercial ones, but that doesn't require authentication nor impose request limits.
Something to consider, and its solution.
Any API to fetch the lyrics is obviously not guaranteed to be available forever, and may interrupt its service at any time, just as Spotify could. Therefore, unless Spotify provides their personal API to fetch lyrics, this separation is unavoidable. What we can do to be prepared for any circumstance is to have an implementation that is easy to adapt and extend. Anything that is related or specific to the API we are currently using is contained in a single small function: to replace the api provider or just disable the lyrics service, it is only needed to modify that function.
How it works
The way to implement this that I found to be most cohesive and unobtrusive was to add a block just like the welcome, album or artist view, that integrates in the navigation_stack
. In this way, the shorcut (I opted for <ctrl+l>
) brings up the new lyrics window, that can be scrolled with the usual keys. Just like a playlist, album, or artist section, it stays in view until a new window is opened, or until q
is pressed to go back in the stack.
Final result
Lyrics found
Lyrics not found (in this case, it is an instrumental song)
Summary of the new code
In line with the principles defined previously, I did not change anything of the previously existing code. I am not an experienced Rust developer, but thanks to a perfectly robust and scalable implementation (for real, the quality of the code was amazing and very easy to understand and integrate!), I was able to add the new window by following the same exact patterns used for the other windows and sections, so basically I didn't write any new logic, I only extended what was already present.
What I added to project structure
- The only actual logic I added was in the function
send_lyrics_request
insidenetwork.rs
. Here, I send the http request, parse the received json, and return anOption<String>
with the fetched lyrics. This could have been done in a separate module kept in a separate file, but I thought that in this case, since it is only a single function, it is probably better to avoid introducing unnecessary complications. - The only external dependency I added was
ureq
, which was obviously needed to perform the http request. - I only added one file, which is
lyrics.rs
containing the handler for the lyrics component.
I hope you find this contribution useful, once again thanks a lot for bringing to life this great project. I sure had a lot of fun putting my hands on it! As i said, I am not very experienced with Rust, so I am definitely willing to put some time in to adjust the implementation in any way you think might be needed.
Giorgio
Hello @giorgioskij. Since Rigellute lacks the time to continue the project, @waeel444 made a soft-fork under github.com/spotify-tui/spotify-tui. Do you mind rebasing your PR against it so we can review it and try to merge it?