فهرست منبع

Add board game urls and views

Colin Powell 2 سال پیش
والد
کامیت
fc927c72d1

+ 28 - 6
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")

+ 12 - 4
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(

+ 21 - 0
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/<slug:slug>/",
+        views.BoardGameDetailView.as_view(),
+        name="boardgame_detail",
+    ),
+    path(
+        "board-game-publisher/<slug:slug>/",
+        views.BoardGamePublisherDetailView.as_view(),
+        name="publisher_detail",
+    ),
+]

+ 17 - 0
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"

+ 82 - 0
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 %}
+<style>
+    .cover img {
+        width: 250px;
+    }
+
+    .cover {
+        float: left;
+        width: 252px;
+        padding: 0;
+    }
+
+    .summary {
+        float: left;
+        width: 600px;
+        margin-left: 10px;
+    }
+</style>
+{% endblock %}
+
+{% block lists %}
+
+<div class="row">
+    {% if object.cover %}
+    <div class="cover"><img src="{{object.cover.url}}" /></div>
+    {% endif %}
+    <div class="summary">
+        {% if object.description%}
+        <p>{{object.description|safe|linebreaks|truncatewords:160}}</p>
+        <hr />
+        {% endif %}
+        <p style="float:right;">
+            <a href="{{object.bggeek_link}}"><img src="{% static "images/bgg-logo.png" %}" width=35></a>
+        </p>
+    </div>
+</div>
+<div class="row">
+    <p>{{object.scrobble_set.count}} scrobbles</p>
+    <p>{{object.scrobble_set.last.long_play_seconds|natural_duration}}{% if object.scrobble_set.last.long_play_complete %} and completed{% else %} spent playing{% endif %}</p>
+    <p>
+        {% if object.scrobble_set.last.long_play_complete == True %}
+        <a href="">Play again</a>
+        {% else %}
+        <a href="{{object.get_start_url}}">Resume playing</a>
+        {% endif %}
+    </p>
+</div>
+<div class="row">
+    <div class="col-md">
+        <h3>Last scrobbles</h3>
+        <div class="table-responsive">
+            <table class="table table-striped table-sm">
+                <thead>
+                    <tr>
+                        <th scope="col">Date</th>
+                        <th scope="col">Completed</th>
+                        <th scope="col">Duration</th>
+                        <th scope="col">Platforms</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {% for scrobble in object.scrobble_set.all|dictsortreversed:"timestamp" %}
+                    <tr>
+                        <td>{{scrobble.timestamp}}</td>
+                        <td>{% if scrobble.long_play_complete == True %}Yes{% endif %}</td>
+                        <td>{% if scrobble.in_progress %}Now playing{% else %}{{scrobble.playback_position_seconds|natural_duration}}{% endif %}</td>
+                        <td>{% for platform in scrobble.video_game.platforms.all %}<a href="{{platform.get_absolute_url}}">{{platform}}</a>{% if not forloop.last %}, {% endif %}{% endfor %}</td>
+                    </tr>
+                    {% endfor %}
+                </tbody>
+            </table>
+        </div>
+    </div>
+</div>
+{% endblock %}

+ 82 - 0
vrobbler/templates/boardgames/boardgame_list.html

@@ -0,0 +1,82 @@
+{% extends "base_list.html" %}
+{% load urlreplace %}
+
+{% block title %}Albums{% endblock %}
+
+{% block lists %}
+
+<div class="row">
+    <p class="view">
+        <span class="view-links">
+            {% if view == 'grid' %}
+            View as <a href="?{% urlreplace view='list' %}">List</a>
+            {% else %}
+            View as <a href="?{% urlreplace view='grid' %}">Grid</a>
+            {% endif %}
+        </span>
+    </p>
+    <p class="pagination">
+        <span class="page-links">
+            {% if page_obj.has_previous %}
+            <a href="?{% urlreplace page=page_obj.previous_page_number %}">prev</a>
+            {% endif %}
+            <span class="page-current">
+                Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
+            </span>
+            {% if page_obj.has_next %}
+            <a href="?{% urlreplace page=page_obj.next_page_number %}">next</a>
+            {% endif %}
+        </span>
+    </p>
+    <hr />
+
+    {% if view == 'grid' %}
+    <div>
+        {% for game in object_list %}
+        {% if game.cover %}
+        <dl style="width: 130px; float: left; margin-right:10px;">
+            <dd><img src="{{game.cover.url}}" width=120 height=120 /></dd>
+        </dl>
+        {% endif %}
+        {% endfor %}
+    </div>
+    {% else %}
+    <div class="col-md">
+        <div class="table-responsive">
+            <table class="table table-striped table-sm">
+                <thead>
+                    <tr>
+                        <th scope="col">Scrobbles</th>
+                        <th scope="col">Name</th>
+                        <th scope="col">Publisher</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {% for game in object_list %}
+                    <tr>
+                        <td>{{game.scrobbles.count}}</td>
+                        <td><a href="{{game.get_absolute_url}}">{{game}}</a></td>
+                        <td><a href="{{game.publisher.get_absolute_url}}">{{game.publisher}}</a></td>
+                    </tr>
+                    {% endfor %}
+                </tbody>
+            </table>
+        </div>
+    </div>
+    {% endif %}
+
+    <div class="pagination" style="margin-bottom:50px;">
+        <span class="page-links">
+            {% if page_obj.has_previous %}
+            <a href="?{% urlreplace page=page_obj.previous_page_number %}">prev</a>
+            {% endif %}
+            <span class="page-current">
+                Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
+            </span>
+            {% if page_obj.has_next %}
+            <a href="?{% urlreplace page=page_obj.next_page_number %}">next</a>
+            {% endif %}
+        </span>
+    </div>
+</div>
+{% endblock %}

+ 2 - 0
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")),