Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

guess-the-song

This repo features a fully working app that allows you to connect to room with your friends and play music trivia.

The very good documentation provided below describes communication contract between frontend app (Next.js) and backend server (Django). Very useful stuff, wasn't very fun to write.

Running dev environment

To run the whole shit in dev mode, use command provided below in the root directory.

docker compose -f dev.docker-compose.yml up --build

Dockerfiles and docker-compose for production will come in the future lol. They will also include redis and postgress because why not.

Containers can communicate with each other using:

http://backend:8000
ws://backend:8000

However, frontend requests come from browser, not from the container itself, so they should be just directed here:

http://localhost:8000
ws://localhost:8000

Running in prod

docker compose up -d
docker compose exec backend uv run python manage.py makemigrations game
docker compose exec backend uv run python manage.py migrate

HTTP Requests

All requests must include credentials: "include" so the browser sends the session cookie.

GET /spotify/login

Redirects the browser through the Spotify OAuth flow. After the user grants access, the backend creates a session and redirects to the frontend (FRONTEND_URL). On failure the frontend receives FRONTEND_URL/?auth_error=<reason>.

GET /spotify/profile

Returns the logged-in user's Spotify profile. Use this to check whether the user is authenticated — 401 means not logged in.

{
  "ok": true,
  "profile": {
    "id": "spotify_user_id",
    "display_name": "John Doe",
    "profile_image_url": "https://i.scdn.co/image/ab6775700000ee85example"
  }
}

GET /spotify/logout

Clears the session and deletes the user.

{
  "ok": true,
  "spotify_disconnected": true
}

GET /spotify/playlists

Returns a list of user's playlists.

{
  "ok": true, 
  "playlists": [
    {
      "id": "1dsvBXJqJ0yReZKc5bOqAS", 
      "name": "✨𝔟𝔢𝔰𝔱 𝔬𝔣 𝔱𝔥𝔢 𝔟𝔢𝔰𝔱✨", 
      "image_url": "https://image-cdn-fa.spotifycdn.com/image/ab67706c0000da842e428a59a6d4906dc2da460d"
    },
    {
      "id": "6vsFj5ydNbZYiNr4FHZAlV", 
      "name": "🌴 ɢʀօօօօօʋɛ", 
      "image_url": "https://image-cdn-ak.spotifycdn.com/image/ab67706c0000da84d183e7962c861b203b0f23b0"
    },
  ]
}

WS Communication

All websocket string messages should follow this format:

{
  "type": "namespace.event",
  "data": {}, // object containing additional fields depending on the message type
  "ok": true // required only in backend -> frontend messages
}

Non-string messages are chunks of audio stream.

Frontend -> Backend

room.join

Joins the room with code and nickname.

{"name": "nickname", "code": "abcd123"}
  • name must be between 3-20 letters, numbers + underscores.
  • code must consist of 6 letters.

room.create

Creates a new room, sets a playlist, amount of rounds and adds a user as a host.

{"name": "nickname", "playlist_id": "", "rounds" : 10}
  • name must be between 3-20 letters, numbers + underscores.
  • 1 <=rounds <= 20
  • playlistid must be a valid spotify playlist.

room.ready

Toggles the calling player's ready status. Broadcasts an updated room.updated state to all members.

{}

room.start

Starts the game for all players.

{}
  • user must be a host.

song.guess

Sends a guess.

{"guess": ""}
  • guess must be less that 100 characters.

Backend -> Frontend

room.updated

Returned to a client with current game state. The State object will have always have the same fields

{
  "state": {
    "code": "ABCDEF",
    "host_name": "alice",
    "members": ["alice", "bob", "charlie"],
    "ready_players": ["alice", "bob"],
    "scoreboard": {
      "alice": 15,
      "bob": 10,
      "charlie": 5
    },
    "playlist_name": "Top Hits 2025",
    "playlist_img": "https://i.scdn.co/image/ab67616d0000b273example",
    "started": true,
    "rounds": 5,
    "current_round": 2
  }
}

room.started

Returned to all clients after host sent room.start. The game will begin shortly after receiving this

song.correct

Returned to a client after host sent song.guess if the guess was correct. Contains info about amount of earned points and metadata of currently playing song to display.

{
  "points" : 233,
  "title": "Example Title",
  "artist": "Artist Name",
  "img": "https://i.scdn.co/image/ab67616d0000b273example"
}

song.incorrect

Returned to a client after host sent song.guess if the guess was incorrect.

round.started

Returned to all clients signifying beginning of the next round. Packets with music will be delivered shortly. Round clock timer can be started from this point (~30 seconds?).

round.ended

Returned to all clients signifying ending of the current round. Round end clock timer can be started from this point (~10 seconds?). Contains info about amount of earned points this round and metadata of the song that was playing this round to display.

{
  "points" : 0,
  "title": "Example Title",
  "artist": "Artist Name",
  "img": "https://i.scdn.co/image/ab67616d0000b273example"
}

room.ended

Returned to all clients when game ends. Returns the state like room.updated allowing to display final scores. Client will be disconnected by the server from the websocket in the next couple seconds.

{
  "state": {
    "code": "ABCDEF",
    "host_name": "alice",
    "members": ["alice", "bob", "charlie"],
    "scoreboard": {
      "alice": 15,
      "bob": 10,
      "charlie": 5
    },
    "playlist_name": "Top Hits 2025",
    "playlist_img": "https://i.scdn.co/image/ab67616d0000b273example",
    "started": true,
    "rounds": 5,
    "current_round": 2
  }
}

Error Convention

If error occurs, the ok field should be set to false. Error field should be added and set to object that follows this format:

"error": {
  "code": "ROOM_NOT_FOUND",
  "message": "Room does not exist"
}

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages