|
@@ -2,12 +2,12 @@ from functools import cached_property
|
|
|
import logging
|
|
import logging
|
|
|
from dataclasses import dataclass
|
|
from dataclasses import dataclass
|
|
|
from datetime import datetime
|
|
from datetime import datetime
|
|
|
-from typing import Optional
|
|
|
|
|
|
|
+from typing import Optional, Any
|
|
|
from uuid import uuid4
|
|
from uuid import uuid4
|
|
|
|
|
|
|
|
from django import forms
|
|
from django import forms
|
|
|
import requests
|
|
import requests
|
|
|
-from boardgames.bgg import lookup_boardgame_from_bgg
|
|
|
|
|
|
|
+from boardgames.sources.bgg import lookup_boardgame_from_bgg
|
|
|
from django.conf import settings
|
|
from django.conf import settings
|
|
|
from django.core.files.base import ContentFile
|
|
from django.core.files.base import ContentFile
|
|
|
from django.db import models
|
|
from django.db import models
|
|
@@ -191,6 +191,10 @@ class BoardGame(ScrobblableMixin):
|
|
|
publisher = models.ForeignKey(
|
|
publisher = models.ForeignKey(
|
|
|
BoardGamePublisher, **BNULL, on_delete=models.DO_NOTHING
|
|
BoardGamePublisher, **BNULL, on_delete=models.DO_NOTHING
|
|
|
)
|
|
)
|
|
|
|
|
+ publishers = models.ManyToManyField(
|
|
|
|
|
+ BoardGamePublisher,
|
|
|
|
|
+ related_name="board_games",
|
|
|
|
|
+ )
|
|
|
designers = models.ManyToManyField(
|
|
designers = models.ManyToManyField(
|
|
|
BoardGameDesigner,
|
|
BoardGameDesigner,
|
|
|
related_name="board_games",
|
|
related_name="board_games",
|
|
@@ -224,6 +228,7 @@ class BoardGame(ScrobblableMixin):
|
|
|
options={"quality": 75},
|
|
options={"quality": 75},
|
|
|
)
|
|
)
|
|
|
rating = models.FloatField(**BNULL)
|
|
rating = models.FloatField(**BNULL)
|
|
|
|
|
+ bgg_rank = models.IntegerField(**BNULL)
|
|
|
max_players = models.PositiveSmallIntegerField(**BNULL)
|
|
max_players = models.PositiveSmallIntegerField(**BNULL)
|
|
|
min_players = models.PositiveSmallIntegerField(**BNULL)
|
|
min_players = models.PositiveSmallIntegerField(**BNULL)
|
|
|
published_date = models.DateField(**BNULL)
|
|
published_date = models.DateField(**BNULL)
|
|
@@ -301,29 +306,58 @@ class BoardGame(ScrobblableMixin):
|
|
|
|
|
|
|
|
# Go get cover image if the URL is present
|
|
# Go get cover image if the URL is present
|
|
|
if cover_url and not self.cover:
|
|
if cover_url and not self.cover:
|
|
|
- headers = {"User-Agent": "Vrobbler 0.11.12"}
|
|
|
|
|
- r = requests.get(cover_url, headers=headers)
|
|
|
|
|
- logger.debug(r.status_code)
|
|
|
|
|
- if r.status_code == 200:
|
|
|
|
|
- fname = f"{self.title}_cover_{self.uuid}.jpg"
|
|
|
|
|
- self.cover.save(fname, ContentFile(r.content), save=True)
|
|
|
|
|
- logger.debug("Loaded cover image from BGGeek")
|
|
|
|
|
|
|
+ self.save_image_from_url(cover_url)
|
|
|
|
|
+
|
|
|
|
|
+ def save_image_from_url(self, url):
|
|
|
|
|
+ headers = {"User-Agent": "Vrobbler 0.11.12"}
|
|
|
|
|
+ r = requests.get(url, headers=headers)
|
|
|
|
|
+ if r.status_code == 200:
|
|
|
|
|
+ fname = f"{self.title}_cover_{self.uuid}.jpg"
|
|
|
|
|
+ self.cover.save(fname, ContentFile(r.content), save=True)
|
|
|
|
|
|
|
|
@classmethod
|
|
@classmethod
|
|
|
def find_or_create(
|
|
def find_or_create(
|
|
|
- cls, lookup_id: str, data: Optional[dict] = {}
|
|
|
|
|
- ) -> Optional["BoardGame"]:
|
|
|
|
|
|
|
+ cls, lookup_id: str, data: dict[str, Any] = {}
|
|
|
|
|
+ ) -> "BoardGame":
|
|
|
"""Given a Lookup ID (either BGG or BGA ID), return a board game object"""
|
|
"""Given a Lookup ID (either BGG or BGA ID), return a board game object"""
|
|
|
- boardgame = cls.objects.filter(bggeek_id=lookup_id).first()
|
|
|
|
|
|
|
+ game = cls.objects.filter(bggeek_id=lookup_id).first()
|
|
|
|
|
|
|
|
- if not data or not boardgame:
|
|
|
|
|
- data = lookup_boardgame_from_bgg(lookup_id)
|
|
|
|
|
|
|
+ if game:
|
|
|
|
|
+ logger.info("Board game exists in database.", extra={"lookup_id": lookup_id, "data": data})
|
|
|
|
|
+ return game
|
|
|
|
|
|
|
|
- if data and not boardgame:
|
|
|
|
|
- boardgame, created = cls.objects.get_or_create(
|
|
|
|
|
- title=data["title"], bggeek_id=lookup_id
|
|
|
|
|
- )
|
|
|
|
|
- if created:
|
|
|
|
|
- boardgame.fix_metadata(data=data)
|
|
|
|
|
|
|
+ bgg_data = lookup_boardgame_from_bgg(data.get("name"))
|
|
|
|
|
+
|
|
|
|
|
+ mechanics = bgg_data.pop("mechanics", [])
|
|
|
|
|
+ designers = bgg_data.pop("designers", [])
|
|
|
|
|
+ categories = bgg_data.pop("categories", [])
|
|
|
|
|
+ publishers = bgg_data.pop("publishers", [])
|
|
|
|
|
+ cover_url = bgg_data.pop("cover_url")
|
|
|
|
|
+
|
|
|
|
|
+ game = cls.objects.create(
|
|
|
|
|
+ **bgg_data
|
|
|
|
|
+ )
|
|
|
|
|
|
|
|
- return boardgame
|
|
|
|
|
|
|
+ game.save_image_from_url(cover_url)
|
|
|
|
|
+ game.cooperative = data.get("cooperative", False)
|
|
|
|
|
+ game.highest_wins = data.get("highestWins", True)
|
|
|
|
|
+ game.no_points = data.get("noPoints", False)
|
|
|
|
|
+ game.uses_teams = data.get("useTeams", False)
|
|
|
|
|
+ game.bgstats_id = data.get("uuid", None)
|
|
|
|
|
+ game.save()
|
|
|
|
|
+
|
|
|
|
|
+ if designers:
|
|
|
|
|
+ for designer_name in designers:
|
|
|
|
|
+ designer, created = BoardGameDesigner.objects.get_or_create(
|
|
|
|
|
+ name=designer_name
|
|
|
|
|
+ )
|
|
|
|
|
+ game.designers.add(designer.id)
|
|
|
|
|
+
|
|
|
|
|
+ if publishers:
|
|
|
|
|
+ for name in publishers:
|
|
|
|
|
+ publisher, _ = BoardGamePublisher.objects.get_or_create(
|
|
|
|
|
+ name=name
|
|
|
|
|
+ )
|
|
|
|
|
+ game.publishers.add(publisher)
|
|
|
|
|
+
|
|
|
|
|
+ return game
|