|
@@ -1,12 +1,12 @@
|
|
|
import logging
|
|
|
import re
|
|
|
-from datetime import datetime
|
|
|
+from datetime import datetime, timedelta
|
|
|
from typing import Any, Optional
|
|
|
|
|
|
import pendulum
|
|
|
import pytz
|
|
|
from beers.models import Beer
|
|
|
-from boardgames.models import BoardGame
|
|
|
+from boardgames.models import BoardGame, BoardGameDesigner, BoardGameLocation
|
|
|
from books.models import Book
|
|
|
from bricksets.models import BrickSet
|
|
|
from dateutil.parser import parse
|
|
@@ -15,6 +15,7 @@ from locations.constants import LOCATION_PROVIDERS
|
|
|
from locations.models import GeoLocation
|
|
|
from music.constants import JELLYFIN_POST_KEYS, MOPIDY_POST_KEYS
|
|
|
from music.models import Track
|
|
|
+from people.models import Person
|
|
|
from podcasts.models import PodcastEpisode
|
|
|
from podcasts.utils import parse_mopidy_uri
|
|
|
from puzzles.models import Puzzle
|
|
@@ -28,10 +29,10 @@ from scrobbles.utils import convert_to_seconds, extract_domain
|
|
|
from sports.models import SportEvent
|
|
|
from sports.thesportsdb import lookup_event_from_thesportsdb
|
|
|
from tasks.models import Task
|
|
|
+from tasks.utils import get_title_from_labels
|
|
|
from videogames.howlongtobeat import lookup_game_from_hltb
|
|
|
from videogames.models import VideoGame
|
|
|
from videos.models import Video
|
|
|
-from tasks.utils import get_title_from_labels
|
|
|
from webpages.models import WebPage
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
@@ -311,26 +312,117 @@ def manual_scrobble_board_game(
|
|
|
return Scrobble.create_or_update(boardgame, user_id, scrobble_dict)
|
|
|
|
|
|
|
|
|
+def find_and_enrich_board_game_data(game_dict: dict) -> BoardGame | None:
|
|
|
+ """TODO Move this to a utility somewhere"""
|
|
|
+ game = BoardGame.find_or_create(game_dict.get("bggId"))
|
|
|
+
|
|
|
+ if game:
|
|
|
+ game.cooperative = game_dict.get("cooperative", False)
|
|
|
+ game.highest_wins = game_dict.get("highestWins", True)
|
|
|
+ game.no_points = game_dict.get("noPoints", False)
|
|
|
+ game.uses_teams = game_dict.get("useTeams", False)
|
|
|
+ if not game.rating:
|
|
|
+ game.rating = game_dict.get("rating") / 10
|
|
|
+ game.save()
|
|
|
+
|
|
|
+ if game_dict.get("designers"):
|
|
|
+ for designer_name in game_dict.get("designers", "").split(", "):
|
|
|
+ BoardGameDesigner.objects.get_or_create(name=designer_name)
|
|
|
+ return game
|
|
|
+
|
|
|
+
|
|
|
def email_scrobble_board_game(
|
|
|
bgstat_data: dict[str, Any], user_id: int
|
|
|
) -> Scrobble | None:
|
|
|
- game_dict: dict[str, Any] = bgstat_data.get("games", [])[0]
|
|
|
- if not game_dict.get("bggId", False):
|
|
|
+ player_dict = {}
|
|
|
+ for player in bgstat_data.get("players", []):
|
|
|
+ if player.get("isAnonymous"):
|
|
|
+ person, _created = Person.objects.get_or_create(name="Anonymous")
|
|
|
+ else:
|
|
|
+ person, _created = Person.objects.get_or_create(
|
|
|
+ bgstats_id=player.get("uuid")
|
|
|
+ )
|
|
|
+ if not person.name:
|
|
|
+ person.name = player.get("name", "")
|
|
|
+ person.save()
|
|
|
+ player_dict[player.get("id")] = person
|
|
|
+
|
|
|
+ game_list: list = bgstat_data.get("games", [])
|
|
|
+ if not game_list:
|
|
|
logger.info(
|
|
|
- "Data from BG Stats JSON had not BGG ID, not scrobbling",
|
|
|
+ "No game data from BG Stats, not scrobbling",
|
|
|
extra={"bgstat_data": bgstat_data},
|
|
|
)
|
|
|
return
|
|
|
|
|
|
- boardgame = BoardGame.find_or_create(game_dict.get("bggId"))
|
|
|
- # TODO Enrich data from our bgstats data?
|
|
|
- #
|
|
|
- # TODO Build up board game meta data from the rest of the data
|
|
|
- scrobble_dict = {}
|
|
|
- players_list: list[dict[str, Any]] = bgstat_data.get("players", [])
|
|
|
- location: dict[str, Any] = bgstat_data.get("locations", [])[0]
|
|
|
+ base_game = None
|
|
|
+ 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
|
|
|
+ elif game.get("isExpansion"):
|
|
|
+ expansions.append(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")
|
|
|
+ geoloc = GeoLocation.objects.filter(
|
|
|
+ title__icontains=location.name
|
|
|
+ ).first()
|
|
|
+ if geoloc:
|
|
|
+ location.geo_location = geoloc
|
|
|
+ location.save()
|
|
|
+ log_data["location_id"] = location.id
|
|
|
+
|
|
|
+ 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")
|
|
|
+
|
|
|
+ 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"),
|
|
|
+ }
|
|
|
+ )
|
|
|
|
|
|
- return Scrobble.create_or_update(boardgame, user_id, scrobble_dict)
|
|
|
+ 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,
|
|
|
+ }
|
|
|
+
|
|
|
+ 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()
|
|
|
+
|
|
|
+ return scrobble
|
|
|
|
|
|
|
|
|
def manual_scrobble_from_url(
|