153 lines
4.5 KiB
Python
153 lines
4.5 KiB
Python
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,
|
|
}
|