Add a help message and set up attributes for choosing a playlist strategy.

This commit is contained in:
Brian Lee 2024-10-04 22:27:49 -07:00
parent 2d87cdd59e
commit 106c97ae41

View File

@ -1,5 +1,7 @@
import argparse
import json import json
import os import os
import sys
import logging import logging
from collections import defaultdict from collections import defaultdict
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
@ -94,9 +96,105 @@ def normalize_difficulty_name(difficulty_name):
# Return the mapped value or the original name if there is no mapping # Return the mapped value or the original name if there is no mapping
return difficulty_names.get(difficulty_name, difficulty_name) return difficulty_names.get(difficulty_name, difficulty_name)
def playlist_strategy_scoresaber_oldscores(
api: ScoreSaberAPI,
song_count: int = 20 # Total number of songs to select
) -> List[Dict[str, Any]]:
"""Build and format a list of songs based on old scores from ScoreSaber, avoiding reusing the same song+difficulty."""
player_id = prompt_for_player_id()
history = load_history()
history.setdefault('scoresaber_oldscores', {})
scores_data = api.get_player_scores(player_id, use_cache=True)
all_scores = scores_data.get('playerScores', [])
if not all_scores:
logging.warning(f"No scores found for player ID {player_id}.")
return []
logging.debug(f"Found {len(all_scores)} scores for player ID {player_id}.")
# Sort scores by timeSet in ascending order (oldest first)
all_scores.sort(key=lambda x: x['score'].get('timeSet', ''))
playlist_data = []
current_time = datetime.now(timezone.utc)
for score in all_scores:
leaderboard = score.get('leaderboard', {})
song_id = leaderboard.get('songHash')
difficulty_raw = leaderboard.get('difficulty', {}).get('difficultyRaw', '')
if not song_id or not difficulty_raw:
logging.debug(f"Skipping score due to missing song_id or difficulty_raw: {score}")
continue # Skip if essential data is missing
# Calculate time ago
time_set_str = score['score'].get('timeSet')
if not time_set_str:
logging.debug(f"Skipping score due to missing timeSet: {score}")
continue # Skip if time_set is missing
try:
time_set = datetime.fromisoformat(time_set_str.replace('Z', '+00:00'))
except ValueError as e:
logging.error(f"Invalid time format for score ID {score['score'].get('id')}: {e}")
continue
time_difference = current_time - time_set
time_ago = format_time_ago(time_difference)
# Normalize the difficulty name
difficulty = normalize_difficulty_name(difficulty_raw)
game_mode = leaderboard.get('difficulty', {}).get('gameMode', 'Standard')
if 'Standard' in game_mode:
game_mode = 'Standard'
# Check history to avoid reusing song+difficulty
if song_id in history['scoresaber_oldscores'] and difficulty in history['scoresaber_oldscores'][song_id]:
logging.debug(f"Skipping song {song_id} with difficulty {difficulty} as it's in history.")
continue # Skip if already used
# Format the song data as expected by PlaylistBuilder
song_dict = {
'hash': song_id,
'songName': leaderboard.get('songName', 'Unknown'),
'difficulties': [
{
'name': difficulty,
'characteristic': game_mode
}
]
}
# Add the song to the playlist
playlist_data.append(song_dict)
logging.debug(f"Selected song for playlist: {song_dict['songName']} ({difficulty})")
# Log the song addition
mapper = "Unknown" # Mapper information can be added if available
logging.info(f"Song added: {song_dict['songName']} ({difficulty}), mapped by {mapper}. Last played {time_ago} ago.")
# Check if the desired number of songs has been reached
if len(playlist_data) >= song_count:
logging.debug(f"Reached the desired song count: {song_count}.")
break
# Log if no songs were added
if not playlist_data:
logging.info("No new songs found to add to the playlist based on history.")
else:
logging.info(f"Total songs added to playlist: {len(playlist_data)}")
# Update history to avoid reusing the same song+difficulty
for song in playlist_data:
song_id = song['hash']
difficulty_name = song['difficulties'][0]['name']
history['scoresaber_oldscores'].setdefault(song_id, []).append(difficulty_name)
save_history(history)
return playlist_data
def playlist_strategy_beatleader_oldscores( def playlist_strategy_beatleader_oldscores(
api: BeatLeaderAPI, api: BeatLeaderAPI,
song_count: int = 40 song_count: int = 20
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
""" """
Build and format a list of songs based on old scores from BeatLeader, Build and format a list of songs based on old scores from BeatLeader,
@ -186,12 +284,13 @@ def playlist_strategy_beatleader_oldscores(
return playlist_data return playlist_data
def saberlist(strategy='beatleader_oldscores') -> None: def saberlist() -> None:
""" """
Generate a playlist of songs from a range of difficulties, all with scores previously set a long time ago. Generate a playlist of songs from a range of difficulties, all with scores previously set a long time ago.
The range of difficulties ensures that the first few songs are good for warming up. The range of difficulties ensures that the first few songs are good for warming up.
Avoids reusing the same song+difficulty in a playlist based on history. Avoids reusing the same song+difficulty in a playlist based on history.
""" """
strategy = get_strategy()
if strategy == 'scoresaber_oldscores': if strategy == 'scoresaber_oldscores':
api = ScoreSaberAPI(cache_expiry_days=CACHE_EXPIRY_DAYS) api = ScoreSaberAPI(cache_expiry_days=CACHE_EXPIRY_DAYS)
elif strategy == 'beatleader_oldscores': elif strategy == 'beatleader_oldscores':
@ -206,7 +305,7 @@ def saberlist(strategy='beatleader_oldscores') -> None:
if strategy == 'scoresaber_oldscores': if strategy == 'scoresaber_oldscores':
playlist_data = playlist_strategy_scoresaber_oldscores(api) playlist_data = playlist_strategy_scoresaber_oldscores(api)
elif strategy == 'beatleader_oldscores': elif strategy == 'beatleader_oldscores':
playlist_data = playlist_strategy_beatleader_oldscores(api, song_count=40) playlist_data = playlist_strategy_beatleader_oldscores(api)
if not playlist_data: if not playlist_data:
logging.info("No new scores found to add to the playlist.") logging.info("No new scores found to add to the playlist.")
@ -218,19 +317,16 @@ def saberlist(strategy='beatleader_oldscores') -> None:
playlist_author="SaberList Tool" playlist_author="SaberList Tool"
) )
""" def get_strategy():
if __name__ == "__main__": parser = argparse.ArgumentParser(description="Generate Beat Saber playlists")
import argparse parser.add_argument("-s", "--strategy",
choices=["scoresaber_oldscores", "beatleader_oldscores"],
parser = argparse.ArgumentParser(description="Generate a playlist based on player scores.") help="Specify the playlist generation strategy",
parser.add_argument( required=True)
'--strategy',
type=str, if len(sys.argv) == 1:
default='beatleader_oldscores', parser.print_help()
choices=['scoresaber_oldscores', 'beatleader_oldscores'], sys.exit(1)
help='Strategy to use for building the playlist.'
)
args = parser.parse_args() args = parser.parse_args()
return args.strategy
saberlist(strategy=args.strategy)
"""