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!")