My biggest project to this day is Mino. A from scratch written JavaScript Beatmap Mirror that has everything someone could ask for. It even became the name for a company i’m a part of!
But how did i even get the idea?
Well, simply said: i was tired that everyone else sucked.
You had mirrors like Chimu, Beatconnect or Kitsu that all came with major drawbacks.
- Chimu was in maintenance
- Beatconnect was horrendously slow and had no public api
- Kitsu was new and unreliable to stay running
One day i was annoyed and thought: what the hell, why not just make my own? How hard can it be?
So i made some sketching for what i’d need to do.
Step 1 - The database
I was lucky to be so far involved with Kitsu, that i had access to the structure they used. I followed the structure and therefore landed on using mysql as my database to store the metadata.
Step 2 - The API
Step 2.1 Metadata
Getting the metadata via crawling was the next step so i can populate the database. It was relatively easy back then using the osu! api v1 by using an api key. It did limit me to 60 requests/min though.
Step 2.2 Beatmaps (.osz files)
Now the tricky part was getting the actual .osz files to store and serve when requested. After a lot of digging, i found out that the osu! api v2 does in fact have an endpoint for downloads! check notes
oh wait it’s locked behind a client scope… sigh great.
After some more digging i got the necessary resources to emulate the lazer client which i won’t disclose exactly how and got the necessary scope to make the request.
Step 2.3 Beatmaps (.osu files)
This was fairly easy because .osu files are served via a different api that is public. Requesting https://osu.ppy.sh/osu/:id would give me the .osu file for the difficulty which is all i needed.
Step 3 - Implementation
Now i got everything i needed to have the most basic mirror that has metadata and files that are cached once requested. I did a very quick implementation and tested it out on my own osu! server Horizon since that was the initial trigger of why i got mad in the first place.
Things looked fine and things loaded slow at the beginning and when cached immediately loaded, which at the time, was a win in my book.
I then wanted to figure out how to do beatmap searching inside the client so that’s what i worked on next.
After some request catching inside the server’s console i made a quick mockup inside my own API doing your typical full text search shenanigans. Once finished, i did some testing and it worked great! I got the songs i was looking for and the filters were working fine.
I got so excited about how “fast” things were running, that i recorded a video and asked RealistikDash (a virtual collegue of mine) to check it out.
He got back to me soon after, and asked me if he could test it on his own server aswell. I told him that i don’t have a public endpoint yet, since it was in development and not made for usage outside of my server but that i’ll get on it. So i took a random domain i still had laying around; catboy.best and slapped my service onto it naming it Mino.
Of course having a quick laughter about it, he also informed me that the search did not work for him and we went investigating. And there it hit us, Cheesegull.
CheesegullRipple’s formatting for beatmaps used in most osu! private server instances made back in 2016
Step 4 - Cheesegull
To satisfy the standard for Cheesegull i did some rewriting of the API and let me tell you, Cheesegull definetly had it’s deserved place! But now it’s just a pain in the ass since api v2 exists and literally everyone still adopts Cheesegull as the standard in their server (what’s up with that anyways?)
After doing those changes i got back to my RealistikDash and he gave me the green light that everything worked as expected. He also suggested to make it a public thing since it went really fast and people could use it considering the asfore above mentioned and i thought sure what’s the worst that could happen?
Well, the “worst” that happened is that it actually gained attraction from other server owners and developers. And of course when something is booming in the backend the first question asked by a user is “when frontend?”
Step 5 - Frontend
I’m not a frontend genius, by any means. I used some bootstrap and wrote some silly little thing in like 2 days worth of time that featured:
Homepage
- A landing page where you can see the crawler’s progress and what data has been recently added.
Search
- A search page to search for beatmaps! (wow)
About
- A quick overview of what this project actually is, who contributed to it and a discord server to join.
Of course not forgetting about an E-Mail for DMCA complains. (still haven’t received one now that i think about it)
Time flies and all of a sudden in the span of a month, most people have switched to my mirror. Well great now i’m stuck with the domain catboy.best for this because i didn’t think this would actually take off.
In the meantime i made a switch from my database going from mysql to meilisearch. A search database designed for specifically that and have not switched off from since and also marked Version 2. (besides this weird mongo phase i had for a month but psscht we don’t talk about it here)
Fixes & Optimizations
Of course, with the growing amount of users, there were bugs bound to be discovered and optimizations to be made for a more stable Mino. It’s not some small 4 fun project anymore but instead developers decided to actually use it as a dependancy so i had to use the advantage. Another month passes by, Chimu gets out of maintenance. Once a giant lost 50% of it’s users, Kitsu rebrands and rewrites their backend but lost 80% of their users due to prior complications. All of those users got to me, but now it’s more intense because Mino has to perform well to stay on top. I also got some concerning amount of negativity back from a certain developer that shall not be named who wasn’t happy with my mirror’s existence.
Quick Rundown of what else happened
Since the project is 3 years old at the time of the writing (September 19th, 2025), i’ll spare you the boring details (since i can’t remember most of them anyways)
Webosu - May 2022
- Mino became the main mirror for the web ported version of osu! webosu!
bancho.py - June 2022
- Mino also became the standard in cmyui’s bancho.py (formerly gulag) repository. Go check it out if you’re interested in making an osu server for yourself.
Team-Up with Philsty - July 2022
- Since 2022 i’ve been working closely with Phil. He was so kind and provided a big part of Mino’s infrastructure and taught me to think about things that i haven’t paid much attention to before. He also works with me on Advance!
Geolocation - October 2022
- We setup multiple server (one in the US and one in Europe) and gave it automatic geolocation so each user has the smoothest experience.
CI/CD - April 2023
- With the work of Phil, pushing changes to servers (yes, at that point it was servers) was automated and worked like a charm.
Version 3 - September 2023
- Mino officially rolled out Version 3 with the new versioning system (i’ve done a billion rewrites and called them by major versions before)
- Therefore i landed from Version 7 to Version 3.3.6
- Major bug fixes that affected stability and performance
- Introduced the fastest latency making it the top contender since
- Huge consistency upgrades
Version 4 - March 2024
- Mino officially rolled out Version 4 making great changes to internal structure.
- Database optimizations
- Performance improvements on certain routes
- Minor Bug fixes
Frontend Rewrite - July 2024
- Refining my frontend skills, i decided to give it another go
- No bootstrap, but tailwind
- Cleaner and more modern UI
- It’s still bad, but at least it looks nicer and displays the pure backend performance.
Version 5 (The TypeScript update) - June 2025
- Rewritten Mino in TypeScript using Bun
- Increasing performance on bucket requests
- Increasing general performance across all routes using Bun’s http module
- Pain and suffering figuring out Bun’s http module and Zig
The Future - Pending
- Since this is fairly recent, you’ll be able to know about it on another blog post. Stay tuned!
Last Words
Thanks for listening to this yap fest of a blog post. This is my very first, so i hope you were able to not only endure but also enjoy it as much as i did writing this.
Special Thanks
- RealistikDash
- Philsty
- cmyui
- lenforiee
- tsunyoku