{"slug": "download-most-played-beatmaps", "title": "download most played beatmaps", "summary": "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.", "body_md": "download_most_played.py\n\n      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.\n      \nLearn more about bidirectional Unicode characters\n\n \n    Show hidden characters\n\n\"\"\"\n\nRequires osu.py (https://github.com/sheppsu/osu.py)\n\nCan install via pip with \"pip install osu.py\"\n\nAlso 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.\"\n\n\"\"\"\n\nfrom osu import Client, UserBeatmapType\n\nimport requests\n\nimport os\n\nimport time\n\nCLIENT_ID = 0\n\nCLIENT_SECRET = \"****\"\n\nif CLIENT_ID == 0:\n\n    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.\")\n\n    quit()\n\nclient = Client.from_client_credentials(CLIENT_ID, CLIENT_SECRET, None)\n\ndef get_user():\n\n    user = input(\"User to fetch from (username): \").strip()\n\n    try:\n\n        user = client.get_user(user, key=\"username\")\n\n    except:\n\n        print(\"Unable to find a user by that name\")\n\n        return\n\n    return user\n\n \n\n \n\ndef get_limit():\n\n    while True:\n\n        try:\n\n            return int(input(\"Number of beatmaps to download: \").strip())\n\n        except ValueError:\n\n            print(\"Input a valid integer\")\n\n \n\n \n\ndef yield_beatmaps(user_id, limit):\n\n    cnt = 0\n\n    while limit-cnt > 0:\n\n        max_limit = min(50, limit-cnt)\n\n        for beatmap in client.get_user_beatmaps(user_id, UserBeatmapType.MOST_PLAYED, max_limit, cnt):\n\n            yield beatmap\n\n        cnt += max_limit\n\n \n\n \n\ndef download_beatmapset(beatmap):\n\n    attempts = 0\n\n    while True:\n\n        try:\n\n            resp = requests.get(f\"https://catboy.best/d/{beatmap.beatmapset.id}\")\n\n        except Exception as exc:\n\n            print(\"Failed to download: \", exc)\n\n            print(\"Retrying in a second...\")\n\n            time.sleep(1)\n\n            continue\n\n \n\n        map_string = f\"{beatmap.beatmapset.artist} - {beatmap.beatmapset.title} ({beatmap.beatmapset.id})\"\n\n        # returns 200, 404, or 500 according to docs\n\n        if resp.status_code == 200:\n\n            with open(f\"beatmap_downloads/{beatmap.beatmapset.id}.osz\", \"wb\") as f:\n\n                for chunk in resp.iter_content(4096):\n\n                    f.write(chunk)\n\n            print(f\"Downloaded {map_string}\")\n\n            break\n\n        elif resp.status_code == 404:\n\n            print(f\"Unable to find {map_string}\")\n\n        elif resp.status_code == 500:\n\n            print(f\"The api returned a server error for {map_string}\")\n\n        else:\n\n            print(f\"Failed to download {map_string} (HTTP {resp.status_code}\")\n\n \n\n        attempts += 1\n\n        if attempts == 3:\n\n            break\n\n \n\n        print(\"Trying again in a second...\")\n\n        time.sleep(1)\n\nif not os.path.isdir(\"beatmap_downloads\"):\n\n    os.mkdir(\"beatmap_downloads\")\n\nuser = get_user()\n\nlimit = get_limit()\n\nbeatmapsets_downloaded = []\n\nfor beatmap in yield_beatmaps(user.id, limit):\n\n    if beatmap.beatmapset.id in beatmapsets_downloaded:\n\n        continue\n\n    beatmapsets_downloaded.append(beatmap.beatmapset.id)\n\n \n\n    start = time.monotonic()\n\n    download_beatmapset(beatmap)\n\n    time.sleep(max(1 - (time.monotonic() - start), 0))  # stay under 1 request per second\n\n \n\nprint(\"Finished downloading!\")", "url": "https://wpnews.pro/news/download-most-played-beatmaps", "canonical_source": "https://gist.github.com/Sheppsu/920f7d751d696a1cd7b944ae90ea8786", "published_at": "2024-10-07 19:30:24+00:00", "updated_at": "2026-05-22 15:42:55.705744+00:00", "lang": "en", "topics": ["developer-tools", "open-source"], "entities": ["osu.py", "sheppsu", "osu"], "alternates": {"html": "https://wpnews.pro/news/download-most-played-beatmaps", "markdown": "https://wpnews.pro/news/download-most-played-beatmaps.md", "text": "https://wpnews.pro/news/download-most-played-beatmaps.txt", "jsonld": "https://wpnews.pro/news/download-most-played-beatmaps.jsonld"}}