Git Product home page Git Product logo

spotification's Introduction

Spotification

As a Spotify user, I always keep up with new releases through the "Release Radar" playlist.

The way I normally use Release Radar is clicking in "Go to Album" to listen to the whole release (I like to listen to full albums) but to my frustration, most new releases are Singles =(

But, hey... I'm a programmer and Spotify has an API! Let's solve the problem! It's also an opportunity to apply some cool stuff like FP Scala, ZIO with Http4s, Refined and Newtypes, etc.

The "Release Radar (no singles)" use case is just the beginning; the possibilities are unlimited.

Project setup

First of all, it requires at least JDK 11.

To use the project, you need to register your application here. This will give you the CLIENT_ID and CLIENT_SECRET.

Then, on the Dashboard, you must configure your authorization REDIRECT_URI.

You will need the id of your "Release Radar" playlist. You can get it from the Spotify app itself in "Share > Copy Spotify URI" on the playlist page. it is the 3rd part (<1st>:<2nd>:<THE ID>)

For the "Release Radar No Singles", you must create the empty playlist yourself on Spotify app and get its ID like you did above.

Now that you have CLIENT_ID, CLIENT_SECRET and REDIRECT_URI, create a file called ".env" in the root of the project containing this variables (their values will be injected in the application.conf file). You can just copy the dotenv.template file, rename it and modify it.

Save Release Radar ID and Release Radar No Singles ID. You'll need them!

Running locally

With the environment variables in place, export them to make them available to sbt:

./load-dot-env.sh

Then run the application with the command:

sbt "~reStart" 

You can see if everything is ok accessing: http://localhost:8080/health

Docker

It's possible to run locally inside docker too. For this:

  • Build the image
./docker-build.sh
  • Run it
./docker-run.sh

The logs can be watched with the command:

./docker-logs.sh

To stop the app:

./docker-stop.sh

Features

Authorization

To be able to manipulate the playlists, the app must get authorization from Spotify. To do so, access http://localhost:8080/authorization/spotify and agree with the asked permissions. This will give you an access_token and a refresh_token.

Save the refresh_token somewhere, you'll need it to operate the app!

Filling the "Release Radar No Singles" playlist

Just execute the following command (of course you can use Postman or something like this):

curl -H "Authorization: Bearer <refresh_token>" -X PATCH "http://localhost:8080/playlists/release-radar-no-singles" -d '{"releaseRadarId": "???", "releaseRadarNoSinglesId": "???"}'

Then go to Spotify app and enjoy your brand new full albums! 🎢🎡

spotification's People

Contributors

programaker avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar

spotification's Issues

Give up "function-centric" design

Scala is not as good as Haskell or F# to work with stand-alone functions.

  • It is not as easy to compose them; ends up with lots of h(g(f(x))) which have a bad usability (reads and writes from right to left). Scala 2's type inference doesn't help much with point-free style either. Method chaining works better.
  • The design of the application looks different from Scala itself and the libs.
  • It's not very editor friendly; VSCode for instance doesn't index top-level definitions.
  • Lack of namespacing where the functions are called looks strange.
  • Functions-as-services are very granular; this has its advantages but in the end it's more work and the editors/ides won't help you finding the concrete functions of that type like they do with traits. Program dependencies, type aliases, R environment all become enormous because of this granularity.
  • It's different from everything in the community. You never see any devstar designing applications or libraries like this in Scala, not even the most FP fanatics. One of the core principles of Scala design is being Object-functional, so let it be, as long as the "Object" part is restricted to traits for services, ADTs for data (allowing them to have smart constructors and combinators) and objects as namespaces for the pure programs.

Bad request in token generation

This error started out-of-the-blue:

HTTP/1.1 500 Internal Server Error Headers(Content-Type: application/json, Content-Length: 107) 
body="{"error":"unexpected HTTP status: 400 Bad Request for request POST https://accounts.spotify.com/api/token"}"

Change the criteria of "Release radar (no singles)"

Singles like this one: https://open.spotify.com/album/4BdPaP1jstPSPn86T00lNF?si=RHBmQn9-SQiFi_zx4ieIag (more than 19 minutes of duration) could be on the Release radar (no singles) playlist. They are long enough to be listened like an album.

So, instead of checking for type == album, just accumulate the duration of the tracks until you reach a minimum duration (configurable).

  • Idea: this could be a separated feature; let the current one as it is and make a new one - "Release Radar (long enough albums)"

Anniversary playlist

Given a day (month-day), search among your followed artists for albums that where released on that day, get a track sample from it and add to a new playlist "Album anniversaries dd/MM" or something like that.

Avoid album's 1st and last tracks (intros and outros) when getting a sample.

Get a song's lyrics

Given a track, get its lyrics.
Spotify doesn't have this feature, so we will need to connect with another API

Implicits in the companion objects

The idea that putting "infrastructure" implicits in the domain types would break the layers and make the app core impure didn't hold very well.

In later projects, we saw that the concrete stuff never actually leaks into the domain and application. Maintaining is also easier because, when something changed, we didn't have to fix imports.

Possible bug in `/playlists/merged-playlist` endpoint

{
    "error": "unexpected HTTP status: 404 Not Found for request GET https://api.spotify.com/v1/playlists/37i9dQZF1DXe1eE6Gj3EKS/tracks?fields=items.track%28uri%2Calbum%28album_type%29%29%2Chref%2Cnext&limit=100&offset=0"
}

Update de Java 17

After the confusion with openjdk, we can use this image: bellsoft/liberica-openjre-alpine:17.0.1

Update to Scala 3

Scala 3 features will leverage design principles adopted in this app (i.e stand-alone functions, opaque types, type lambdas).

ZIO, Cats, Http4s, Circe already work πŸŽ‰

Newtypes lib can be replaced by built in opaque types.

Refined works, except for the macros (..refined.auto.*). Not a big deal, just need to rely more on refineU and value.

kind-projector plugin is no longer necessary, thanks to type lambdas.

wartremover doesn't work

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.