Add a help message and set up attributes for choosing a playlist strategy.
This commit is contained in:
parent
2d87cdd59e
commit
106c97ae41
@ -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"],
|
||||||
|
help="Specify the playlist generation strategy",
|
||||||
|
required=True)
|
||||||
|
|
||||||
|
if len(sys.argv) == 1:
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description="Generate a playlist based on player scores.")
|
|
||||||
parser.add_argument(
|
|
||||||
'--strategy',
|
|
||||||
type=str,
|
|
||||||
default='beatleader_oldscores',
|
|
||||||
choices=['scoresaber_oldscores', 'beatleader_oldscores'],
|
|
||||||
help='Strategy to use for building the playlist.'
|
|
||||||
)
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
return args.strategy
|
||||||
saberlist(strategy=args.strategy)
|
|
||||||
"""
|
|
Loading…
Reference in New Issue
Block a user