Skip to content

React webapp that allows the user to input a Spotify playlist URL to dynamically populate a solar system based on the songs' metadata. Each planet varies in speed, color, size, texture, and rotational speed. Songs that are more popular produce larger planets for example.

Notifications You must be signed in to change notification settings

Space-ify/frontend-in-space

Repository files navigation

Spaceify

Currently Hosted here:

https://spaceify.jaydenpyles.dev/

You need to grab a spotify share URL to display songs on the app

Screenshot 2024-07-18 at 3 18 46 PM

Built in 24 hours - Auburn Hackathon 2024 Submission - Hackathon Theme: Space

React web app hosted on AWS EC2 that allows users to dynamically populate 3d rendering of playlists as a solar system. Song metadata determines factors of the planet like size, speed, and rotation. Users can click on planets to hear 30 second snippets of the song that planet represents. Employs computer vision to map album art palette to planet color gradient. Utilizes Docker to host the backend, frontend, and NGINX.

This repository is one of three. To see the others go to the "Space-ify" organization

Architechture

SpaceifyWorkflow

Tools Used:

  • React For rendering jsx elements and creating UI
  • Npm Package management and frontend server management
  • ReactThree.js Rendering and manipulating geometric objects in React
  • Docker Containerization of frontend, backend, and NGINX
  • SKLearn Machine learning appliation used to target prominent colors used to alter image data
  • AWS EC2 Cloud hosting of web applciation
  • GoDaddy Hosting for our domain
  • NGINX Reverse proxy manager to route traffice from port 80 to docker containers
  • MultiThreading Ran multiple threads for concurrent execution (downloading images is IO limited)
  • FastAPI Python api for querying spotify api and returning data to the frontend
  • Spotify We used their API to recieve meta data about playlists for planet manipulation

Loading Playlist

Loading

Planet Motion

PlanetSpin

Planet Selection (no audio in gif, but tracks are being played)

MusicSelect

Dynamic Input (100 songs)

100planets

Data Flow

  • Our frontend makes a fetch to the API
const res = await fetch(
        "http://localhost:8000/api/spotify/playlist",
        options
      );
  • Our API is hosted on a Uvicorn webserver, which accepts the HTTP request and routes it to the correct path to execute all of the logic to return the requested and modified data. the webserver plans to submit back a json object of the songs transformed into planet data.

  • First, we have to use our Spotify developer account to retrieve an authorization token that allows for access to the spotify API

    def generate_authorization_token(self) -> str:
        """ """
        url = "https://accounts.spotify.com/api/token"
        payload = {
            "grant_type": "client_credentials",
            "client_id": self.CLIENT_ID,
            "client_secret": self.CLIENT_SECRET,
        }
        headers = {"Content-Type": "application/x-www-form-urlencoded"}

        try:
            response = requests.post(url, data=payload, headers=headers)
            response.raise_for_status()  # Raise an exception if there's an HTTP error
            self.access_token = response.json().get("access_token")
            return self.access_token
        except requests.exceptions.RequestException as e:
            print(f"Error making request: {e}")
            return None
  • After we are authenticated, we can query Spotify and retrieve back the playlist data
@spotify_router.post("/api/spotify/playlist")
async def get_playlist(request: Request):
    spotify.auth.generate_authorization_token()

    res = await request.json()
    assert res.get("url")

    url = res.get("url")

    ID = re.search(r"/playlist/([^?]+)", url.get("query"))
    if ID:
        ID = ID.group(1)

    bearer_token = f"Bearer {spotify.auth.access_token}"
    headers = {"Authorization": bearer_token}

    playlist = Endpoints.PLAYLIST.value
    playlist = f"{playlist.PLAYLIST.value}/{ID}"

    res = requests.get(playlist, headers=headers)

    try:
        t = Transformer(res.json())
        return {"items": t.tracklist}
    except:
        return {"message": "Error parsing tracks."}
  • We then transform that data and map it to a planet, along with other transformations not shown
      track_as_dict = {
            "id": i,
            "size": size,
            "speed": speed,
            "name": name,
            "artists": artist_name,
            "textureMap": textureMap,
            "rotationSpeed": (random.randrange(15000, 25000) / 1000000),
            "offset": random.randint(0, 100),
            "xRadius": (i * 4) + 6,
            "is_explicit": is_explicit,
            "population": population,
            "preview": preview,
            "image_url": album_img,
            "album": album,
        }

Inspiration

We saw a project that procedurally generated a topographical map based on bit data from Spotify. Instead, we thought a song representing each celestial body would be more theme-driven.

We have a React frontend and a Python FastAPI backend. The frontend sends the playlist URL to the backend via fetch. Then the backend makes a call to Spotify API. The data is returned to the backend where the data is processed and organized into a planet data set with characteristics unique to the Spotify metadata. We use ReactThree.js to render 3d models in the react app. We hosted the microservices for our web app on AWS in an Ubuntu runner via Docker containers. NGINX was used to reverse proxy to route traffic from port 80 into our webapp container. We acquired a domain from GoDaddy to route to our public IP for the EC2 container.

About

React webapp that allows the user to input a Spotify playlist URL to dynamically populate a solar system based on the songs' metadata. Each planet varies in speed, color, size, texture, and rotational speed. Songs that are more popular produce larger planets for example.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published