[boardgames] Clean up email parser to work with many plays

This commit is contained in:
2025-07-03 00:34:51 -04:00
parent 1590ce5f18
commit 1fd325823b
5 changed files with 134 additions and 80 deletions

View File

@ -333,7 +333,15 @@ def find_and_enrich_board_game_data(game_dict: dict) -> BoardGame | None:
def email_scrobble_board_game(
bgstat_data: dict[str, Any], user_id: int
) -> Scrobble | None:
) -> list[Scrobble]:
game_list: list = bgstat_data.get("games", [])
if not game_list:
logger.info(
"No game data from BG Stats, not scrobbling",
extra={"bgstat_data": bgstat_data},
)
return []
player_dict = {}
for player in bgstat_data.get("players", []):
if player.get("isAnonymous"):
@ -347,82 +355,105 @@ def email_scrobble_board_game(
person.save()
player_dict[player.get("id")] = person
game_list: list = bgstat_data.get("games", [])
if not game_list:
logger.info(
"No game data from BG Stats, not scrobbling",
extra={"bgstat_data": bgstat_data},
)
return
base_game = None
expansions = []
base_games = {}
expansions = {}
log_data = {}
for game in game_list:
logger.info(f"Finding and enriching {game.get('name')}")
enriched_game = find_and_enrich_board_game_data(game)
if game.get("isBaseGame"):
base_game = enriched_game
base_games[game.get("id")] = enriched_game
elif game.get("isExpansion"):
expansions.append(enriched_game)
expansions[game.get("id")] = enriched_game
for expansion in expansions:
expansion.expansion_for_boardgame = base_game
expansion.save()
log_data["expansion_ids"] = [e.id for e in expansions]
location_dict: dict[str, Any] = bgstat_data.get("locations", [])[0]
location, _created = BoardGameLocation.objects.get_or_create(
bgstats_id=location_dict.get("uuid")
)
if not location.name:
location.name = location_dict.get("name")
locations = {}
for location_dict in bgstat_data.get("locations", []):
location, _created = BoardGameLocation.objects.get_or_create(
bgstats_id=location_dict.get("uuid")
)
update_fields = []
if not location.name:
location.name = location_dict.get("name")
update_fields.append("name")
geoloc = GeoLocation.objects.filter(
title__icontains=location.name
).first()
if geoloc:
location.geo_location = geoloc
location.save()
log_data["location_id"] = location.id
update_fields.append("geo_location")
if update_fields:
location.save(update_fields=update_fields)
play_dict = bgstat_data.get("plays", [])[0]
if play_dict.get("rounds", False):
log_data["rounds"] = play_dict.get("rounds")
if play_dict.get("board", False):
log_data["board"] = play_dict.get("board")
locations[location_dict.get("id")] = location
log_data["players"] = []
for score_dict in play_dict.get("playerScores", []):
log_data["players"].append(
{
"person_id": player_dict[score_dict.get("playerRefId")].id,
"new": score_dict.get("newPlayer"),
"win": score_dict.get("winner"),
"score": score_dict.get("score"),
"rank": score_dict.get("rank"),
"seat_order": score_dict.get("seatOrder"),
"role": score_dict.get("role"),
}
)
scrobbles_created = []
for play_dict in bgstat_data.get("plays", []):
log_data["expansion_ids"] = []
try:
base_game = base_games[play_dict.get("gameRefId")]
except KeyError:
try:
base_game = expansions[play_dict.get("gameRefId")]
except KeyError:
print(play_dict)
logger.info(
"Skipping scrobble of play, can't find game",
extra={"play_dict": play_dict},
)
continue
start = parse(play_dict.get("playDate"))
duration_seconds = play_dict.get("durationMin") * 60
stop = start + timedelta(seconds=duration_seconds)
scrobble_dict = {
"user_id": user_id,
"timestamp": start,
"playback_position_seconds": duration_seconds,
"source": "BG Stats",
"log": log_data,
}
for eplay in play_dict.get("expansionPlays", []):
expansion = expansions[eplay.get("gameRefId")]
expansion.expansion_for_boardgame = base_game
expansion.save()
log_data["expansion_ids"].append(expansion.id)
scrobble = Scrobble.create_or_update(base_game, user_id, scrobble_dict)
scrobble.stop_timestamp = stop
scrobble.in_progress = False
scrobble.played_to_completion = True
scrobble.save()
if play_dict.get("locationRefId", False):
log_data["location_id"] = locations[
play_dict.get("locationRefId")
].id
if play_dict.get("rounds", False):
log_data["rounds"] = play_dict.get("rounds")
if play_dict.get("board", False):
log_data["board"] = play_dict.get("board")
return scrobble
log_data["players"] = []
for score_dict in play_dict.get("playerScores", []):
log_data["players"].append(
{
"person_id": player_dict[score_dict.get("playerRefId")].id,
"new": score_dict.get("newPlayer"),
"win": score_dict.get("winner"),
"score": score_dict.get("score"),
"rank": score_dict.get("rank"),
"seat_order": score_dict.get("seatOrder"),
"role": score_dict.get("role"),
}
)
start = parse(play_dict.get("playDate"))
if play_dict.get("durationMin") > 0:
duration_seconds = play_dict.get("durationMin") * 60
else:
duration_seconds = base_game.run_time_seconds
stop = start + timedelta(seconds=duration_seconds)
scrobble_dict = {
"user_id": user_id,
"timestamp": start,
"playback_position_seconds": duration_seconds,
"source": "BG Stats",
"log": log_data,
}
print(scrobble_dict)
scrobble = Scrobble.create_or_update(base_game, user_id, scrobble_dict)
scrobble.stop_timestamp = stop
scrobble.in_progress = False
scrobble.played_to_completion = True
scrobble.save()
scrobbles_created.append(scrobble)
return scrobbles_created
def manual_scrobble_from_url(