cd /news/developer-tools/download-most-played-beatmaps · home topics developer-tools article
[ARTICLE · art-9368] src=gist.github.com ↗ pub= topic=developer-tools verified=true sentiment=· neutral

download most played beatmaps

This article provides a Python script that downloads a specified number of a user's most played beatmaps from the game osu! using the osu.py library and the osu API v2. The script requires the user to input their API client ID and secret, then prompts for a username and the number of beatmaps to download, saving them as .osz files in a local folder. It includes error handling and rate limiting to avoid exceeding one request per second.

read2 min views24 publishedOct 7, 2024

download_most_played.py

  This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.

Learn more about bidirectional Unicode characters

Show hidden characters

"""

Requires osu.py (https://github.com/sheppsu/osu.py) Can install via pip with "pip install osu.py"

Also must insert your osu api (v2) client id and client secret below where it says "CLIENT_ID" and "CLIENT_SECRET." You can get a client id and client secret via your settings on the osu website, at the bottom, where it says "OAuth."

"""

from osu import Client, UserBeatmapType

import requests

import os

import time

CLIENT_ID = 0

CLIENT_SECRET = "****"

if CLIENT_ID == 0:

    print("Edit the CLIENT_ID and CLIENT_SECRET variables before running the script. Read the docstring at the top of the file for more info.")

    quit()

client = Client.from_client_credentials(CLIENT_ID, CLIENT_SECRET, None)

def get_user():

    user = input("User to fetch from (username): ").strip()

    try:

        user = client.get_user(user, key="username")

    except:

        print("Unable to find a user by that name")

        return

    return user

 

 

def get_limit():

    while True:

        try:

            return int(input("Number of beatmaps to download: ").strip())

        except ValueError:

            print("Input a valid integer")

 

 

def yield_beatmaps(user_id, limit):

    cnt = 0

    while limit-cnt > 0:

        max_limit = min(50, limit-cnt)

        for beatmap in client.get_user_beatmaps(user_id, UserBeatmapType.MOST_PLAYED, max_limit, cnt):

            yield beatmap

        cnt += max_limit

 

 

def download_beatmapset(beatmap):

    attempts = 0

    while True:

        try:

            resp = requests.get(f"https://catboy.best/d/{beatmap.beatmapset.id}")

        except Exception as exc:

            print("Failed to download: ", exc)

            print("Retrying in a second...")

            time.sleep(1)

            continue

 

        map_string = f"{beatmap.beatmapset.artist} - {beatmap.beatmapset.title} ({beatmap.beatmapset.id})"


        if resp.status_code == 200:

            with open(f"beatmap_downloads/{beatmap.beatmapset.id}.osz", "wb") as f:

                for chunk in resp.iter_content(4096):

                    f.write(chunk)

            print(f"Downloaded {map_string}")

            break

        elif resp.status_code == 404:

            print(f"Unable to find {map_string}")

        elif resp.status_code == 500:

            print(f"The api returned a server error for {map_string}")

        else:

            print(f"Failed to download {map_string} (HTTP {resp.status_code}")

 

        attempts += 1

        if attempts == 3:

            break

 

        print("Trying again in a second...")

        time.sleep(1)

if not os.path.isdir("beatmap_downloads"):

    os.mkdir("beatmap_downloads")

user = get_user()

limit = get_limit()

beatmapsets_downloaded = []

for beatmap in yield_beatmaps(user.id, limit):

    if beatmap.beatmapset.id in beatmapsets_downloaded:

        continue

    beatmapsets_downloaded.append(beatmap.beatmapset.id)

 

    start = time.monotonic()

    download_beatmapset(beatmap)

    time.sleep(max(1 - (time.monotonic() - start), 0))  # stay under 1 request per second

 

print("Finished down!")
── more in #developer-tools 4 stories · sorted by recency
── more on @osu.py 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/download-most-played…] indexed:0 read:2min 2024-10-07 ·