GuessTheSong is a project that was spawned by a course on Human-Computer Interaction done in University. From the ideation stage, we knew that we were going to continue working on this project, even after the course is over. Our course didn’t even require us to have a real backend. It was expected that we would return static data from a list, or possibly a Wizard of Oz experiment. However in the short week that we had in Uni to work on the project we worked on laying the foundation for future improvements by creating proper routing, a game manager, and a database.
I’ve split the article into 2 sections, first one introducing the game, second one talking more about the technology.
What is GuessTheSong
GuessTheSong is a free online browser-based multiplayer game, with multiple game modes. Where you can either compete against yourself or against others. The game runs on all devices with a web browser and is fun to play with your friends from home, or at a party.
How do you play GuessTheSong?
In GuessTheSong you can either play ‘Standard’ mode, or ‘Theme’ mode, I will explain the difference between the two below.
To start a game of GuessTheSong, one person needs to create a lobby, and then invite their friends by sharing the code. Once you can see everyone in the lobby, start the game.
The standard mode consists of you and your friend submitting your favorite song at the start of every round. Once everyone has submitted their song, the round will automatically start. When submitting a song it is a good idea to keep in mind whether your friends and/or family also know the song. People who submit songs that are able to be guessed by other people in the lobby actually receive some small bonus points to incentivize this mechanic.
In theme mode, you don’t need to submit any of your own songs. The creator of the lobby is able to choose a theme pack, examples include:
Each pack contains more than one hundred songs, meaning that two games of the same theme pack are never the same, and ensuring lots of fun repeatability.
The quickest way to invite others is by sharing with them your room code. We made this convenient by allowing for the copying of the URL with 1 button click. See image below!
A Game Round
Every round consists of a 5-second warmup countdown followed by 90 seconds of game time. When the round starts, the same song is played for everyone simultaneously. The way you can win is by guessing the name of the song correctly before the other people in the lobby. As time decreases, the number of points you can achieve that round also decreases. The maximum amount of points you can get in a round is 1000, whereas the minimum is 50.
GuessTheSong uses a hint system that tells users how many characters and words are in the title (see image). After 60 seconds, if the round is still being played a single character of the title becomes exposed. From that point onwards every 10 seconds a new character is exposed.
Guessing and Chatting
Guessing and chatting are done within the same window in GuessTheSong. GuessTheSong automatically knows when what you have written is a song guess, and when its a chat. It does this by making a comparison to the song being played, and if a certain threshold is hit, then it accepts your message as a guess.
If you make a correct guess, then the system will not broadcast your guess to others, however if you make an incorrect guess, then everyone will see it! If you are the one who submitted the song, then you won’t be able to guess the song’s title.
Submitting songs in standard mode
When submitting songs it is important to only submit the title of the song to stay consistent. If you add the song artist, then it can be subjective whether the artist is before the title or behind, etc. For consistency, it’s advised to only submit the song title.
Submitting song titles correctly is very important in GuessTheSong, as this is how the algorithm determines whether the other person’s guess is correct or not!
When searching for a song, a list of song titles is returned, the algorithm will try to clean up the title name by removing irrelevant information such as “lyrics” or “2020” etc. However, it’s not perfect. Upon clicking ‘select’, users are prompted a final time (4. on image below), whether the title is correct or not. If it’s not, users are able to manually change the title.
GuessTheSong has optional word censorship built-in, it is on by default. However, users can disable it by going to the settings.
We placed a lot of emphasis on communicating with the players what is currently happening in the game, to prevent any confusion. Throughout the game rounds you will find toast notifications keeping you up to date what is happening, for example when someone has submitted a song, or when someone has guessed a song.
We used Flask for our web server, we decided on this a little bit as an in-between, as my partner was familiar with Bottle and I was with Django. We agreed that Django might be overkill for a web-based multiplayer game. And we were interested in learning Flask, as it’s a lot more popular than Bottle is.
We’re using a PostgreSQL database, no elaborate reasoning, we were just both very comfortable with it, and we’ve never had any issues with it.
We decided to go with DigitalOcean for our hosting, we like them since they’re pretty fast and cheap. I also specifically really like that you can make shared projects, useful for SSH and billing.
Platform as a Service (PaaS)
This is something that is not necessarily required but it does make life a lot easier. We are using CapRover to help us with this. Caprover is kinda similar to Heroku if you have used that before. I’ve got an article covering how to set up a Django web server on Caprover if you are interested. Caprover is nice because it allows you to monitor your server’s resources easily as well as receive notification’s when sh*t hits the fan via email, Telegram, etc. Caprover also provides an easily accessible web GUI where you can easily see logs, setup automatic deployment via SSH (build on GitHub push -very nice), as well as updating system environmental variables from the browser.
Keeping track of users
Currently we do not have an elaborate login system. The way we are keeping track of users is by setting a cookie on their system which contains a unique id. This id is then being tracked in the database.
We’ve got 3 tables to keep track of the game.
- We’ve got a table to keep track of the rooms that currently exist and are being played, for each room we track some basic properties such as the PIN for the room (if applicable), whether the game has finished, the room name, and the room code.
- We’ve got another table to keep track of all the players, for each player we track their cookie id, their name, and some other information.
- Finally we need one more table to keep track of all the players in a given room.
to collect information about what type of lobby users we’re using WTForms, not that much to say apart from that it does the job perfectly!
Communicating with the page
To receive information from the form, its a simple GET request. After our server has received the request, our game engine spawns a new game object which basically contains all the information we need to play a game, such as current game state, amount of players in the game, the game turn, etc.
After the form has been received, the user is forwarded to a new Lobby page
To make new information appear on the screen without having to refresh the page we are using Flask-SocketIO WebSockets. Shout out to Miguel Grinberg as his blog, and his replies on StackOverflow helped us a lot. Essentially to do things with WebSockets you create a function on the frontend and on the backend, then let them communicate data, and based on the data that is sent you execute a behavior. WebSockets allow you to create specific ‘WebSocket’ rooms, which ensure that the only people who are able to receive your message are other people in that given room. We used the YouTube video below to get us started. I highly recommend it.
Once you’re inside the GuessTheSong game, essentially everything is done with WebSockets apart from the playing of the music. The chat and every other moving element on the screen are all being manipulated by WebSocket messages that are sent from the server. i.e., next turn, the user receives more points, the user makes a correct guess, a toast notification is triggered, etc.
To stream audio to each player we are using a library called HowlerJS, it allows you to send an audio stream to a user and play it on their device. Apart from that it also has other great functions like being able to add fade in and out, as well as being able to easily change the volume (with a HTML slider).
At the start of GuessTheSong we had some issues with HowlerJS, because some people have slower internet than others, they did not receive the song on time, leaving some of them with a 20 second delay. To fix this we made it sothat the song is preloaded on everyones device first. Once we can confirm that everyone has the song on their device, then we send the ‘start game’ signal.
Downloading / Storing audio
When users play the standard game mode, they are able to simply search the title of a song and are presented with a list of results, well actually these results come straight from YouTube. We started off by using the official Youtube API, but quickly noticed that its API Quota is so low that it is literally unusable. We found a quick fix however in Youtube-dl, a library that allows us to fetch search results as well as download songs.
Once a user searches for a song they are asked to select the correct video. from there we try to parse the YouTube Video title and make sure that it contains no unnessary words, such as the date, artist, “lyrics”, “karaoke” etc. We present our parsed version to the user, and ask them a second time whether it has been parsed correctly, as it’s not a perfect parser, allowing the user to manually edit the title if they so wish. Once the user makes their final modifications (if there is any), the data is sent back to the server, and their video is downloaded. (We have safety mechanisms to ensure files are not too big or long etc.) Once the video is downloaded, its converted to an .mp3 file and shortened to 90 seconds (length of a round). We do these post processing changes, as it saves bandwidth when sending the data back to all the users.
When users play the “Theme” game mode, we have a hardcoded pre-defined list of songs that they are able to try guess. These songs are already downloaded and stored on a volume, which is great as the user does not have to wait for any background downloading to occur.
We wanted to allow our users to add a little bit of their own personal touch. That’s why we added avatars. When looking online if there were any avatar generating libraries, I only saw overly advanced libraries that seemed like too much of a hassle for what it’s worth (given all the other things we also still had to add). Then it hit me, why not just use emoji’s, they are available on every platform and express what I want users to be able to express. The only issue was that there was no body attached to the emoticon. So I opened photoshop and quickly sketched one. Then used a Bootstrap 4 card as a layout, and centered the emoticon in that, with as background the body I made in photoshop. End result:
It’s always important when you are changing the environment, that the users know what is happening. To do this we are using JQuery Toast Notifications, it’s a good library, its free, looks good and just works. When the server sends a websocket message that a player has submitted a song or that a round has ended, these messages are also broadcasted to the screen using a Toast notification that times out after 5 seconds. So that the user knows what just happened.
Tying it all together
Once a lobby has been created by a user, they can share this lobby code with their friends and family. When a friend joins the lobby, we use WebSockets to update the lobby information.
Once a standard game is started, users are prompted to submit a song name. Here the user ping pong’s with the server which is running Youtube-dl until the user has selected their desired song, as well as the correct title.
The server knows how many people there are in the game, and waits until everyone has submitted a song correctly. For each person, once a song has been submitted it starts being downloaded to the server and processed, from which it will then be sent to the users.
Once everyone has submitted a song, the server sends a WebSocket message telling the game to start. The server will then send the first players song to everyone. Once everyone has downloaded the song, the server receives a message to start the turn.
Once the turn starts, the song should start playing for everyone at the same time. Users will start guessing songs in the ‘chat/guess window’, each guess is a WebSocket message, that the server reads, these messages contain the guess, as well as the user that sent them. Each guess is compared with the original title, and if a certain comparison threshold is passed then the guess is approved as being correct.
The server keeps track of time internally to make sure there is no cheating. based on how quickly a user guessed, a user is then awarded points.
Once either everyone has guessed, or 90 seconds have passed, a new turn is initiated and the next person’s song is played as before.
When there are no more turns left, then the round is over and players are required to submit a new song again. There are in total 3 rounds in the standard mode.
I hope this might have been informative to anyone that was wondering how a game like this might function. If you have any questions please leave them below, I would be happy to address them as well as update the article and add them there.