Ensure each playlist is unique by storing a record of previously used songs.
This commit is contained in:
parent
cb66d4dc2d
commit
f69e67de6f
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,3 +7,5 @@ dist/
|
||||
*.json
|
||||
archive/
|
||||
*.bplist
|
||||
covers/
|
||||
comfyui-output/
|
@ -1,97 +1,77 @@
|
||||
import json
|
||||
import os
|
||||
from saberlist.beatleaderAPI import BeatLeaderAPI
|
||||
from collections import defaultdict
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import logging
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s %(levelname)s: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
level=logging.DEBUG
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from collections import defaultdict
|
||||
from datetime import datetime
|
||||
|
||||
def build_difficulty_based_playlist(api, player_id):
|
||||
"""
|
||||
Builds a custom difficulty-based playlist for a given player and saves it as a bplist file.
|
||||
HISTORY_FILE = "playlist_history.json"
|
||||
|
||||
This function creates a playlist with the following structure:
|
||||
- 5 songs with difficulty 0 to 3 stars (Easy to Normal)
|
||||
- 5 songs with difficulty 4 to <6 stars (Hard to Expert)
|
||||
- 5 songs with difficulty 6 to <7 stars (Expert+)
|
||||
- 5 songs with difficulty 7+ stars (Expert++)
|
||||
def load_history():
|
||||
if os.path.exists(HISTORY_FILE):
|
||||
with open(HISTORY_FILE, 'r') as f:
|
||||
return json.load(f)
|
||||
return {}
|
||||
|
||||
For each difficulty range, it selects the 5 songs that were played longest ago,
|
||||
ensuring a mix of nostalgic tracks and skill-appropriate challenges.
|
||||
def save_history(history):
|
||||
with open(HISTORY_FILE, 'w') as f:
|
||||
json.dump(history, f, indent=2)
|
||||
|
||||
The function handles duplicate songs by keeping only the oldest play for each unique song
|
||||
within each difficulty group.
|
||||
|
||||
Parameters:
|
||||
api (BeatLeaderAPI): An instance of the BeatLeaderAPI class to fetch player scores.
|
||||
player_id (str): The unique identifier of the player.
|
||||
|
||||
Returns:
|
||||
tuple: A tuple containing two elements:
|
||||
- str: The file path of the created bplist file.
|
||||
- list: A list of score objects included in the playlist.
|
||||
|
||||
The created bplist file is saved in the current directory with a name format:
|
||||
"Custom Playlist - YYYY-MM-DD HH:MM:SS.bplist"
|
||||
|
||||
Note:
|
||||
- This function uses cached score data if available. To force a fresh API call,
|
||||
you may need to clear the cache or modify the api.get_player_scores() call.
|
||||
- The function assumes that the BeatLeaderAPI class has a create_bplist() method
|
||||
to generate the bplist file.
|
||||
"""
|
||||
|
||||
# Get all scores for the player
|
||||
def build_difficulty_based_playlist(api, player_id, history, playlist_name):
|
||||
scores_data = api.get_player_scores(player_id, use_cache=True)
|
||||
all_scores = scores_data['data']
|
||||
|
||||
# Sort scores by play time (oldest first)
|
||||
all_scores.sort(key=lambda x: x['timepost'])
|
||||
|
||||
# Group scores by difficulty
|
||||
difficulty_groups = defaultdict(list)
|
||||
for score in all_scores:
|
||||
stars = score['leaderboard']['difficulty']['stars']
|
||||
song_id = score['leaderboard']['song']['id']
|
||||
difficulty_name = score['leaderboard']['difficulty']['difficultyName']
|
||||
|
||||
if 0 <= stars <= 3:
|
||||
difficulty_groups[0].append(score)
|
||||
elif 4 <= stars < 6:
|
||||
difficulty_groups[1].append(score)
|
||||
elif 6 <= stars < 7:
|
||||
difficulty_groups[2].append(score)
|
||||
elif stars >= 7:
|
||||
difficulty_groups[3].append(score)
|
||||
# Check if this song:difficulty combination is in history
|
||||
if song_id not in history or difficulty_name not in history[song_id]:
|
||||
if 0 <= stars <= 3:
|
||||
difficulty_groups[0].append(score)
|
||||
elif 4 <= stars < 6:
|
||||
difficulty_groups[1].append(score)
|
||||
elif 6 <= stars < 7:
|
||||
difficulty_groups[2].append(score)
|
||||
elif stars >= 7:
|
||||
difficulty_groups[3].append(score)
|
||||
|
||||
# Build the playlist
|
||||
playlist_scores = []
|
||||
for difficulty, count in [(0, 5), (1, 5), (2, 5), (3, 5)]:
|
||||
# Remove duplicates (keep the oldest play for each unique song)
|
||||
unique_songs = {}
|
||||
for score in difficulty_groups[difficulty]:
|
||||
song_id = score['leaderboard']['song']['id']
|
||||
if song_id not in unique_songs or score['timepost'] < unique_songs[song_id]['timepost']:
|
||||
unique_songs[song_id] = score
|
||||
|
||||
# Add the oldest unique songs to the playlist
|
||||
playlist_scores.extend(sorted(unique_songs.values(), key=lambda x: x['timepost'])[:count])
|
||||
|
||||
# Create the bplist file
|
||||
playlist_title = f"Custom Playlist - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
|
||||
playlist_file = api.create_bplist(playlist_scores, playlist_title)
|
||||
# Update history
|
||||
for score in playlist_scores:
|
||||
song_id = score['leaderboard']['song']['id']
|
||||
difficulty_name = score['leaderboard']['difficulty']['difficultyName']
|
||||
if song_id not in history:
|
||||
history[song_id] = []
|
||||
history[song_id].append(difficulty_name)
|
||||
|
||||
playlist_file = api.create_bplist(playlist_scores, playlist_name)
|
||||
|
||||
return playlist_file, playlist_scores
|
||||
|
||||
def star_ladder():
|
||||
api = BeatLeaderAPI()
|
||||
player_id = '76561199407393962'
|
||||
playlist_file, playlist_scores = build_difficulty_based_playlist(api, player_id)
|
||||
|
||||
history = load_history()
|
||||
|
||||
# Generate a unique playlist name
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
playlist_name = f"star_ladder-{timestamp}"
|
||||
|
||||
playlist_file, playlist_scores = build_difficulty_based_playlist(api, player_id, history, playlist_name)
|
||||
save_history(history)
|
||||
|
||||
print(f"Playlist created: {playlist_file}")
|
||||
print("Playlist contents:")
|
||||
@ -99,3 +79,6 @@ def star_ladder():
|
||||
song = score['leaderboard']['song']
|
||||
difficulty = score['leaderboard']['difficulty']
|
||||
print(f"{i}. {song['name']} by {song['author']} (Mapper: {song['mapper']}) - {difficulty['stars']:.2f} stars - Last played: {datetime.fromtimestamp(score['timepost'])}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
star_ladder()
|
Loading…
x
Reference in New Issue
Block a user