123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- import csv
- import json
- import logging
- from typing import TYPE_CHECKING, Optional
- import requests
- from bs4 import BeautifulSoup
- from django.contrib.auth import get_user_model
- User = get_user_model()
- if TYPE_CHECKING:
- from scrobbles.models import Scrobble
- logger = logging.getLogger(__name__)
- SEARCH_ID_URL = (
- "https://boardgamegeek.com/xmlapi/search?search={query}&exact=1"
- )
- GAME_ID_URL = "https://boardgamegeek.com/xmlapi/boardgame/{id}"
- def take_first(thing: Optional[list]) -> str:
- first = ""
- try:
- first = thing[0]
- except IndexError:
- pass
- if first:
- try:
- first = first.get_text()
- except:
- pass
- return first
- def lookup_boardgame_id_from_bgg(title: str) -> Optional[int]:
- soup = None
- headers = {"User-Agent": "Vrobbler 0.11.12"}
- game_id = None
- url = SEARCH_ID_URL.format(query=title)
- r = requests.get(url, headers=headers)
- if r.status_code == 200:
- soup = BeautifulSoup(r.text, "xml")
- if soup:
- result = soup.findAll("boardgame")
- if not result:
- return game_id
- game_id = result[0].get("objectid", None)
- return game_id
- def lookup_boardgame_from_bgg(lookup_id: str) -> dict:
- soup = None
- game_dict = {}
- headers = {"User-Agent": "Vrobbler 0.11.12"}
- title = ""
- bgg_id = None
- try:
- bgg_id = int(lookup_id)
- logger.debug(f"Using BGG ID {bgg_id} to find board game")
- except ValueError:
- title = lookup_id
- logger.debug(f"Using title {title} to find board game")
- if not bgg_id:
- bgg_id = lookup_boardgame_id_from_bgg(title)
- url = GAME_ID_URL.format(id=bgg_id)
- r = requests.get(url, headers=headers)
- if r.status_code == 200:
- soup = BeautifulSoup(r.text, "xml")
- if soup:
- seconds_to_play = None
- minutes = take_first(soup.findAll("playingtime"))
- if minutes:
- seconds_to_play = int(minutes) * 60
- game_dict = {
- "bggeek_id": bgg_id,
- "title": take_first(soup.findAll("name", primary="true")),
- "description": take_first(soup.findAll("description")),
- "year_published": take_first(soup.findAll("yearpublished")),
- "publisher_name": take_first(soup.findAll("boardgamepublisher")),
- "cover_url": take_first(soup.findAll("image")),
- "min_players": take_first(soup.findAll("minplayers")),
- "max_players": take_first(soup.findAll("maxplayers")),
- "recommended_age": take_first(soup.findAll("age")),
- "run_time_seconds": seconds_to_play,
- }
- return game_dict
- def push_scrobble_to_bgg(scrobble: "Scrobble", user: User) -> Optional[bool]:
- bgg_username = user.profile.bgg_username
- bgg_password = user.profile.bgg_password
- if not bgg_username or bgg_password:
- return
- login_payload = {
- "credentials": {"username": bgg_username, "password": bgg_password}
- }
- headers = {"content-type": "application/json"}
- # TODO Look up past plays for scrobble.media_obj.bggeek_id, and make sure we haven't scrobbled this before
- with requests.Session() as s:
- p = s.post(
- "https://boardgamegeek.com/login/api/v1",
- data=json.dumps(login_payload),
- headers=headers,
- )
- players = []
- if scrobble.metadata:
- for player in scrobble.metadata.players:
- if player["user_id"]:
- player_user = User.objects.filter(
- id=player["user_id"]
- ).first()
- if player_user:
- if player_user.bgg_username:
- player["username"] = player_user.bgg_username
- else:
- player["name"] = player_user.username
- player["win"] = player.get("win")
- player["color"] = player.get("color")
- player["new"] = player.get("new")
- player["score"] = player.get("score")
- players.append(player)
- play_payload = {
- "playdate": scrobble.timestamp.date.strftime("%Y-%m-%d"),
- "length": scrobble.playback_position_seconds / 60,
- "comments": "Uploaded from Vrobbler",
- "location": scrobble.log.location or None,
- "objectid": scrobble.media_obj.bggeek_id,
- "quantity": "1",
- "action": "save",
- "players": players,
- "objecttype": "thing",
- "ajax": 1,
- }
|