diff --git a/vrobbler/apps/boardgames/bgg.py b/vrobbler/apps/boardgames/bgg.py index d5aa843..10baea4 100644 --- a/vrobbler/apps/boardgames/bgg.py +++ b/vrobbler/apps/boardgames/bgg.py @@ -3,7 +3,9 @@ from typing import Optional import requests from bs4 import BeautifulSoup -SEARCH_ID_URL = "https://boardgamegeek.com/xmlapi/search?search={query}" +SEARCH_ID_URL = ( + "https://boardgamegeek.com/xmlapi/search?search={query}&exact=1" +) GAME_ID_URL = "https://boardgamegeek.com/xmlapi/boardgame/{id}" @@ -20,21 +22,41 @@ def take_first(thing: Optional[list]) -> str: return first -def get_id_from_bgg(title): - soup = "" +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") - return soup + + if soup: + result = soup.findAll("boardgame") + if not result: + return game_id + + game_id = result[0].get("objectid", None) + + return game_id -def get_game_by_id_from_bgg(game_id): +def lookup_boardgame_from_bgg(lookup_id: str) -> dict: soup = None game_dict = {} headers = {"User-Agent": "Vrobbler 0.11.12"} - url = GAME_ID_URL.format(id=game_id) + + title = "" + bgg_id = None + + try: + bgg_id = int(lookup_id) + except ValueError: + title = lookup_id + + 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") diff --git a/vrobbler/apps/boardgames/models.py b/vrobbler/apps/boardgames/models.py index 9fa50a4..5625bde 100644 --- a/vrobbler/apps/boardgames/models.py +++ b/vrobbler/apps/boardgames/models.py @@ -4,7 +4,7 @@ from typing import Optional from uuid import uuid4 import requests -from boardgames.bgg import get_game_by_id_from_bgg +from boardgames.bgg import lookup_boardgame_from_bgg from django.conf import settings from django.core.files.base import ContentFile from django.db import models @@ -69,6 +69,12 @@ class BoardGame(ScrobblableMixin): "boardgames:boardgame_detail", kwargs={"slug": self.uuid} ) + def primary_image_url(self) -> str: + url = "" + if self.cover: + url = self.cover.url + return url + def bggeek_link(self): link = "" if self.bggeek_id: @@ -111,12 +117,14 @@ class BoardGame(ScrobblableMixin): logger.debug("Loaded cover image from BGGeek") @classmethod - def find_or_create(cls, lookup_id: str) -> Optional["BoardGame"]: + def find_or_create( + cls, lookup_id: str, data: Optional[dict] = {} + ) -> Optional["BoardGame"]: """Given a Lookup ID (either BGG or BGA ID), return a board game object""" - data = {} boardgame = None - data = get_game_by_id_from_bgg(lookup_id) + if not data: + data = lookup_boardgame_from_bgg(lookup_id) if data: boardgame, created = cls.objects.get_or_create( diff --git a/vrobbler/apps/boardgames/urls.py b/vrobbler/apps/boardgames/urls.py new file mode 100644 index 0000000..acd1fcd --- /dev/null +++ b/vrobbler/apps/boardgames/urls.py @@ -0,0 +1,21 @@ +from django.urls import path +from boardgames import views + +app_name = "boardgames" + + +urlpatterns = [ + path( + "board-game/", views.BoardGameListView.as_view(), name="boardgame_list" + ), + path( + "board-game//", + views.BoardGameDetailView.as_view(), + name="boardgame_detail", + ), + path( + "board-game-publisher//", + views.BoardGamePublisherDetailView.as_view(), + name="publisher_detail", + ), +] diff --git a/vrobbler/apps/boardgames/views.py b/vrobbler/apps/boardgames/views.py new file mode 100644 index 0000000..ab02860 --- /dev/null +++ b/vrobbler/apps/boardgames/views.py @@ -0,0 +1,17 @@ +from django.views import generic +from boardgames.models import BoardGame, BoardGamePublisher + + +class BoardGameListView(generic.ListView): + model = BoardGame + paginate_by = 20 + + +class BoardGameDetailView(generic.DetailView): + model = BoardGame + slug_field = "uuid" + + +class BoardGamePublisherDetailView(generic.DetailView): + model = BoardGamePublisher + slug_field = "uuid" diff --git a/vrobbler/templates/boardgames/boardgame_detail.html b/vrobbler/templates/boardgames/boardgame_detail.html new file mode 100644 index 0000000..fccdbe1 --- /dev/null +++ b/vrobbler/templates/boardgames/boardgame_detail.html @@ -0,0 +1,82 @@ +{% extends "base_list.html" %} +{% load mathfilters %} +{% load static %} +{% load naturalduration %} + +{% block title %}{{object.title}}{% endblock %} + +{% block head_extra %} + +{% endblock %} + +{% block lists %} + +
+ {% if object.cover %} +
+ {% endif %} +
+ {% if object.description%} +

{{object.description|safe|linebreaks|truncatewords:160}}

+
+ {% endif %} +

+ +

+
+
+
+

{{object.scrobble_set.count}} scrobbles

+

{{object.scrobble_set.last.long_play_seconds|natural_duration}}{% if object.scrobble_set.last.long_play_complete %} and completed{% else %} spent playing{% endif %}

+

+ {% if object.scrobble_set.last.long_play_complete == True %} + Play again + {% else %} + Resume playing + {% endif %} +

+
+
+
+

Last scrobbles

+
+ + + + + + + + + + + {% for scrobble in object.scrobble_set.all|dictsortreversed:"timestamp" %} + + + + + + + {% endfor %} + +
DateCompletedDurationPlatforms
{{scrobble.timestamp}}{% if scrobble.long_play_complete == True %}Yes{% endif %}{% if scrobble.in_progress %}Now playing{% else %}{{scrobble.playback_position_seconds|natural_duration}}{% endif %}{% for platform in scrobble.video_game.platforms.all %}{{platform}}{% if not forloop.last %}, {% endif %}{% endfor %}
+
+
+
+{% endblock %} diff --git a/vrobbler/templates/boardgames/boardgame_list.html b/vrobbler/templates/boardgames/boardgame_list.html new file mode 100644 index 0000000..78a3047 --- /dev/null +++ b/vrobbler/templates/boardgames/boardgame_list.html @@ -0,0 +1,82 @@ +{% extends "base_list.html" %} +{% load urlreplace %} + +{% block title %}Albums{% endblock %} + +{% block lists %} + +
+

+ + {% if view == 'grid' %} + View as List + {% else %} + View as Grid + {% endif %} + +

+

+ + {% if page_obj.has_previous %} + prev + {% endif %} + + Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }} + + {% if page_obj.has_next %} + next + {% endif %} + +

+
+ + {% if view == 'grid' %} +
+ {% for game in object_list %} + {% if game.cover %} +
+
+
+ {% endif %} + {% endfor %} +
+ {% else %} +
+
+ + + + + + + + + + {% for game in object_list %} + + + + + + {% endfor %} + +
ScrobblesNamePublisher
{{game.scrobbles.count}}{{game}}{{game.publisher}}
+
+
+ {% endif %} + + +
+{% endblock %} diff --git a/vrobbler/urls.py b/vrobbler/urls.py index deff78e..cb853cd 100644 --- a/vrobbler/urls.py +++ b/vrobbler/urls.py @@ -9,6 +9,7 @@ from vrobbler.apps.books import urls as book_urls from vrobbler.apps.sports import urls as sports_urls from vrobbler.apps.podcasts import urls as podcast_urls from vrobbler.apps.videogames import urls as videogame_urls +from vrobbler.apps.boardgames import urls as boardgame_urls from vrobbler.apps.music.api.views import ( AlbumViewSet, ArtistViewSet, @@ -63,6 +64,7 @@ urlpatterns = [ path("", include(book_urls, namespace="books")), path("", include(video_urls, namespace="videos")), path("", include(videogame_urls, namespace="videogames")), + path("", include(boardgame_urls, namespace="boardgames")), path("", include(sports_urls, namespace="sports")), path("", include(podcast_urls, namespace="podcasts")), path("", include(scrobble_urls, namespace="scrobbles")),