Add function to create playlists from ScoreSaber leaderboards.

This commit is contained in:
Brian Lee 2024-07-09 15:14:15 -07:00
parent 387a49438a
commit 4f8ec53033
3 changed files with 90 additions and 3 deletions

3
.gitignore vendored
View File

@ -5,4 +5,5 @@ __pycache__/
*.egg-info/
dist/
*.json
archive/
archive/
*.bplist

View File

@ -34,4 +34,5 @@ Homepage = "https://git.satstack.dev/blee/beatsaber-playlist-tool"
# https://setuptools.pypa.io/en/latest/userguide/entry_point.html
[project.scripts]
replay_ranked_ss = "saberlist.scoresaber:replay_ranked"
ranked_leaderboards_ss = "saberlist.scoresaber:ranked_leaderboards"
#replay_ranked_bl = "saberlist.beatleader:replay_ranked"

View File

@ -1,7 +1,7 @@
import json
import asyncio
from pyscoresaber import ScoreSaberAPI, ScoreSort
import requests
def filter_and_sort_scores_by_stars(scores, min_stars=0.1, max_stars=float('inf')):
# Exclude scores outside the specified star range
@ -10,6 +10,35 @@ def filter_and_sort_scores_by_stars(scores, min_stars=0.1, max_stars=float('inf'
sorted_scores = sorted(filtered_scores, key=lambda x: x.leaderboard.stars)
return sorted_scores
# TODO: combine with scores_to_playlist()
def leaderboards_to_playlist(leaderboards: list, playlist_title: str, playlist_author: str = "SaberList Tool") -> str:
playlist = {
"playlistTitle": playlist_title,
"playlistAuthor": playlist_author,
"songs": []
}
for leaderboard in leaderboards:
song_entry = {
"hash": leaderboard.song_hash,
"songName": leaderboard.song_name,
"difficulties": [
{
"name": leaderboard.difficulty.difficulty.name.lower(),
"characteristic": leaderboard.difficulty.game_mode.name.lower()
}
],
"levelAuthorName": leaderboard.level_author_name,
"songSubName": leaderboard.song_sub_name,
"songAuthorName": leaderboard.song_author_name
}
playlist["songs"].append(song_entry)
playlist_json = json.dumps(playlist, indent=4)
with open(f"{playlist_title}.bplist", 'w') as file:
file.write(playlist_json)
return playlist_json
def scores_to_playlist(scores, playlist_title, playlist_author = "SaberList Tool"):
playlist = {
"playlistTitle": playlist_title,
@ -33,7 +62,7 @@ def scores_to_playlist(scores, playlist_title, playlist_author = "SaberList Tool
playlist_json = json.dumps(playlist, indent=4)
with open(f"{playlist_title}.json", 'w') as file:
with open(f"{playlist_title}.bplist", 'w') as file:
file.write(playlist_json)
return playlist_json
@ -67,3 +96,59 @@ def replay_ranked():
asyncio.run(async_replay_ranked())
except Exception as e:
print(f"An error occurred: {e}")
def ranked_leaderboards():
default_min_stars = 6.0
min_stars = float(input(f"Enter the minimum starlevel to include on the playlist (Default: {default_min_stars}): ") or default_min_stars)
default_max_stars = min_stars + 0.10
max_stars = float(input(f"Enter the maximum starlevel to include on the playlist (Default: {default_max_stars}): ") or default_max_stars)
default_title = f"SS Leaderboard {min_stars}"
playlist_title = input(f"Enter the filename for the playlist (Default: {default_title}): ") or default_title
try:
leaderboards = asyncio.run(async_leaderboards(min_stars, max_stars))
except Exception as e:
print(f"An error occurred: {e}")
leaderboards_to_playlist(leaderboards, playlist_title)
async def async_leaderboards(min_stars: float, max_stars: float):
params = {
"category": 3, # sort by scores
"sort": 1, # sort ascending
"max_star": max_stars,
"min_star": min_stars,
"qualified": 0, # False
"ranked": 1 # True
}
scoresaber = ExtendedScoreSaberAPI()
await scoresaber.start()
all_leaderboards = []
try:
async for leaderboard_page in scoresaber.leaderboards_all(**params):
all_leaderboards.extend(leaderboard_page)
except Exception as e:
print(f"An error occurred: {e}")
finally:
await scoresaber.close()
return all_leaderboards
from math import ceil
from typing import AsyncIterable, List
from pyscoresaber.models import LeaderboardInfo
class ExtendedScoreSaberAPI(ScoreSaberAPI):
async def leaderboards_all(self, **params) -> AsyncIterable[List[LeaderboardInfo]]:
page = 1
max_page = -1
while page < max_page or max_page == -1:
try:
leaderboards = await self.leaderboards(**params, page=page)
if max_page == -1:
max_page = ceil(leaderboards.metadata.total / leaderboards.metadata.items_per_page)
yield leaderboards.leaderboards
page += 1
except Exception as e:
print(f"An error occurred while fetching page {page}: {e}")
break