Add basic views for books and games
This commit is contained in:
@ -9,7 +9,8 @@ from scrobbles.admin import ScrobbleInline
|
||||
class AuthorAdmin(admin.ModelAdmin):
|
||||
date_hierarchy = "created"
|
||||
list_display = ("name", "openlibrary_id")
|
||||
ordering = ("name",)
|
||||
ordering = ("-created",)
|
||||
search_fields = ("name",)
|
||||
|
||||
|
||||
@admin.register(Book)
|
||||
@ -22,7 +23,8 @@ class BookAdmin(admin.ModelAdmin):
|
||||
"pages",
|
||||
"openlibrary_id",
|
||||
)
|
||||
ordering = ("title",)
|
||||
search_fields = ("name",)
|
||||
ordering = ("-created",)
|
||||
inlines = [
|
||||
ScrobbleInline,
|
||||
]
|
||||
|
||||
@ -61,19 +61,20 @@ def process_koreader_sqlite_file(sqlite_file_path, user_id):
|
||||
logger.debug(f"Found author {author}, created: {created}")
|
||||
|
||||
book, created = Book.objects.get_or_create(
|
||||
koreader_md5=book_row[KoReaderBookColumn.MD5.value]
|
||||
title=book_row[KoReaderBookColumn.TITLE.value]
|
||||
)
|
||||
|
||||
if created:
|
||||
book.title = book_row[KoReaderBookColumn.TITLE.value]
|
||||
book.pages = book_row[KoReaderBookColumn.PAGES.value]
|
||||
book.koreader_md5 = book_row[KoReaderBookColumn.MD5.value]
|
||||
book.koreader_id = int(book_row[KoReaderBookColumn.ID.value])
|
||||
book.koreader_authors = book_row[KoReaderBookColumn.AUTHORS.value]
|
||||
book.run_time_ticks = int(book_row[KoReaderBookColumn.PAGES.value])
|
||||
book.save(
|
||||
update_fields=[
|
||||
"title",
|
||||
"pages",
|
||||
"koreader_md5",
|
||||
"koreader_id",
|
||||
"koreader_authors",
|
||||
]
|
||||
|
||||
@ -30,7 +30,6 @@ class Book(ScrobblableMixin):
|
||||
|
||||
title = models.CharField(max_length=255)
|
||||
authors = models.ManyToManyField(Author)
|
||||
openlibrary_id = models.CharField(max_length=255, **BNULL)
|
||||
goodreads_id = models.CharField(max_length=255, **BNULL)
|
||||
koreader_id = models.IntegerField(**BNULL)
|
||||
koreader_authors = models.CharField(max_length=255, **BNULL)
|
||||
@ -39,6 +38,10 @@ class Book(ScrobblableMixin):
|
||||
pages = models.IntegerField(**BNULL)
|
||||
language = models.CharField(max_length=4, **BNULL)
|
||||
first_publish_year = models.IntegerField(**BNULL)
|
||||
author_name = models.CharField(max_length=255, **BNULL)
|
||||
author_openlibrary_id = models.CharField(max_length=255, **BNULL)
|
||||
openlibrary_id = models.CharField(max_length=255, **BNULL)
|
||||
cover = models.ImageField(upload_to="books/covers/", **BNULL)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.title} by {self.author}"
|
||||
@ -71,3 +74,11 @@ class Book(ScrobblableMixin):
|
||||
user = User.objects.get(id=user_id)
|
||||
last_scrobble = get_scrobbles_for_media(self, user).last()
|
||||
return int((last_scrobble.book_pages_read / self.pages) * 100)
|
||||
|
||||
@classmethod
|
||||
def find_or_create(cls, data_dict: dict) -> "Game":
|
||||
from books.utils import get_or_create_book
|
||||
|
||||
return get_or_create_book(
|
||||
data_dict.get("title"), data_dict.get("author")
|
||||
)
|
||||
|
||||
@ -6,6 +6,8 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
SEARCH_URL = "https://openlibrary.org/search.json?title={title}"
|
||||
ISBN_URL = "https://openlibrary.org/isbn/{isbn}.json"
|
||||
SEARCH_URL = "https://openlibrary.org/search.json?title={title}"
|
||||
COVER_URL = "https://covers.openlibrary.org/b/olid/{id}-L.jpg"
|
||||
|
||||
|
||||
def get_first(key: str, result: dict) -> str:
|
||||
@ -34,7 +36,7 @@ def lookup_book_from_openlibrary(title: str, author: str = None) -> dict:
|
||||
logger.warn(
|
||||
f"Lookup for {title} found top result with mismatched author"
|
||||
)
|
||||
|
||||
ol_id = top.get("cover_edition_key")
|
||||
return {
|
||||
"title": top.get("title"),
|
||||
"isbn": top.get("isbn")[0],
|
||||
@ -43,4 +45,6 @@ def lookup_book_from_openlibrary(title: str, author: str = None) -> dict:
|
||||
"author_openlibrary_id": get_first("author_key", top),
|
||||
"goodreads_id": get_first("id_goodreads", top),
|
||||
"first_publish_year": top.get("first_publish_year"),
|
||||
"pages": top.get("number_of_pages_median"),
|
||||
"cover_url": COVER_URL.format(id=ol_id),
|
||||
}
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
from django.core.files.base import ContentFile
|
||||
import requests
|
||||
from typing import Optional
|
||||
from books.openlibrary import lookup_book_from_openlibrary
|
||||
from books.models import Book
|
||||
|
||||
|
||||
def get_or_create_book(title: str, author: Optional[str] = None) -> Book:
|
||||
book_dict = lookup_book_from_openlibrary(title, author)
|
||||
|
||||
book, book_created = Book.objects.get_or_create(
|
||||
isbn=book_dict.get("isbn"),
|
||||
)
|
||||
|
||||
if book_created:
|
||||
cover_url = book_dict.pop("cover_url")
|
||||
|
||||
Book.objects.filter(pk=book.id).update(**book_dict)
|
||||
book.refresh_from_db()
|
||||
|
||||
r = requests.get(cover_url)
|
||||
if r.status_code == 200:
|
||||
fname = f"{book.title}_{book.uuid}.jpg"
|
||||
book.cover.save(fname, ContentFile(r.content), save=True)
|
||||
|
||||
book.fix_metadata()
|
||||
|
||||
return book
|
||||
|
||||
@ -20,7 +20,8 @@ class AlbumAdmin(admin.ModelAdmin):
|
||||
"theaudiodb_score",
|
||||
"theaudiodb_genre",
|
||||
)
|
||||
ordering = ("name",)
|
||||
ordering = ("-created",)
|
||||
search_fields = ("name",)
|
||||
filter_horizontal = [
|
||||
"artists",
|
||||
]
|
||||
@ -39,7 +40,8 @@ class ArtistAdmin(admin.ModelAdmin):
|
||||
"theaudiodb_mood",
|
||||
"theaudiodb_genre",
|
||||
)
|
||||
ordering = ("name",)
|
||||
search_fields = ("name",)
|
||||
ordering = ("-created",)
|
||||
|
||||
|
||||
@admin.register(Track)
|
||||
|
||||
@ -11,7 +11,15 @@ from scrobbles.models import (
|
||||
class ScrobbleInline(admin.TabularInline):
|
||||
model = Scrobble
|
||||
extra = 0
|
||||
raw_id_fields = ("video", "podcast_episode", "track")
|
||||
raw_id_fields = (
|
||||
"video",
|
||||
"podcast_episode",
|
||||
"track",
|
||||
"video_game",
|
||||
"book",
|
||||
"sport_event",
|
||||
"user",
|
||||
)
|
||||
exclude = ("source_id", "scrobble_log")
|
||||
|
||||
|
||||
@ -81,7 +89,11 @@ class ScrobbleAdmin(admin.ModelAdmin):
|
||||
"book",
|
||||
"video_game",
|
||||
)
|
||||
list_filter = ("is_paused", "in_progress", "source", "track__artist")
|
||||
list_filter = (
|
||||
"is_paused",
|
||||
"in_progress",
|
||||
"source",
|
||||
)
|
||||
ordering = ("-timestamp",)
|
||||
|
||||
def media_name(self, obj):
|
||||
|
||||
@ -1,2 +1,4 @@
|
||||
JELLYFIN_VIDEO_ITEM_TYPES = ["Episode", "Movie"]
|
||||
JELLYFIN_AUDIO_ITEM_TYPES = ["Audio"]
|
||||
|
||||
LONG_PLAY_MEDIA = ["VideoGame", "Book"]
|
||||
|
||||
@ -18,7 +18,7 @@ class ScrobbleForm(forms.Form):
|
||||
widget=forms.TextInput(
|
||||
attrs={
|
||||
"class": "form-control form-control-dark w-100",
|
||||
"placeholder": "Scrobble something (IMDB ID, String, TVDB ID ...)",
|
||||
"placeholder": "Scrobble something (ttIMDB, -v Video Game title, -b Book title, -s TheSportsDB ID)",
|
||||
"aria-label": "Scrobble something",
|
||||
}
|
||||
),
|
||||
|
||||
@ -20,6 +20,7 @@ from profiles.utils import (
|
||||
start_of_month,
|
||||
start_of_week,
|
||||
)
|
||||
from scrobbles.constants import LONG_PLAY_MEDIA
|
||||
from scrobbles.stats import build_charts
|
||||
from scrobbles.utils import check_scrobble_for_finish
|
||||
from sports.models import SportEvent
|
||||
@ -403,7 +404,7 @@ class Scrobble(TimeStampedModel):
|
||||
# Time keeping
|
||||
timestamp = models.DateTimeField(**BNULL)
|
||||
playback_position_ticks = models.PositiveBigIntegerField(**BNULL)
|
||||
playback_position = models.CharField(max_length=8, **BNULL)
|
||||
playback_position = models.CharField(max_length=10, **BNULL)
|
||||
|
||||
# Status indicators
|
||||
is_paused = models.BooleanField(default=False)
|
||||
@ -417,6 +418,7 @@ class Scrobble(TimeStampedModel):
|
||||
|
||||
# Fields for keeping track long content like books and games
|
||||
book_pages_read = models.IntegerField(**BNULL)
|
||||
video_game_minutes_played = models.IntegerField(**BNULL)
|
||||
long_play_complete = models.BooleanField(**BNULL)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
@ -468,6 +470,9 @@ class Scrobble(TimeStampedModel):
|
||||
@property
|
||||
def can_be_updated(self) -> bool:
|
||||
updatable = True
|
||||
if self.media_obj.__class__.__name__ in LONG_PLAY_MEDIA:
|
||||
logger.info(f"No - Long play media")
|
||||
updatable = False
|
||||
if self.percent_played > 100:
|
||||
logger.info(f"No - 100% played - {self.id} - {self.source}")
|
||||
updatable = False
|
||||
@ -589,6 +594,39 @@ class Scrobble(TimeStampedModel):
|
||||
self.in_progress = False
|
||||
self.save(update_fields=["in_progress"])
|
||||
logger.info(f"{self.id} - {self.source}")
|
||||
|
||||
class_name = self.media_obj.__class__.__name__
|
||||
if class_name in LONG_PLAY_MEDIA:
|
||||
logger.debug(
|
||||
"Syncing long play media playback time to elapsed time since start"
|
||||
)
|
||||
now = timezone.now()
|
||||
updated_playback = (now - self.timestamp).seconds / 60
|
||||
|
||||
media_filter = models.Q(video_game=self.video_game)
|
||||
if class_name == "Book":
|
||||
media_filter = models.Q(book=self.book)
|
||||
last_scrobble = Scrobble.objects.filter(
|
||||
media_filter,
|
||||
user_id=self.user,
|
||||
played_to_completion=True,
|
||||
long_play_complete=False,
|
||||
).last()
|
||||
self.video_game_minutes_played = (
|
||||
int(last_scrobble.playback_position) + updated_playback
|
||||
)
|
||||
|
||||
self.playback_position = int(updated_playback)
|
||||
self.played_to_completion = True
|
||||
self.save(
|
||||
update_fields=[
|
||||
"playback_position",
|
||||
"playback_position_ticks",
|
||||
"played_to_completion",
|
||||
"video_game_minutes_played",
|
||||
]
|
||||
)
|
||||
return
|
||||
check_scrobble_for_finish(self, force_finish)
|
||||
|
||||
def pause(self) -> None:
|
||||
|
||||
@ -16,6 +16,7 @@ from scrobbles.utils import convert_to_seconds, parse_mopidy_uri
|
||||
from sports.models import SportEvent
|
||||
from videos.models import Video
|
||||
from videogames.models import VideoGame
|
||||
from books.models import Book
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -206,19 +207,38 @@ def manual_scrobble_event(data_dict: dict, user_id: Optional[int]):
|
||||
def manual_scrobble_video_game(data_dict: dict, user_id: Optional[int]):
|
||||
game = VideoGame.find_or_create(data_dict)
|
||||
|
||||
last_scrobble = Scrobble.objects.filter(
|
||||
video_game=game, user_id=user_id, played_to_completion=True
|
||||
).last()
|
||||
|
||||
playback_position = 0
|
||||
if last_scrobble and not last_scrobble.playback_position:
|
||||
playback_position = last_scrobble.playback_position + (30 * 60)
|
||||
scrobble_dict = {
|
||||
"user_id": user_id,
|
||||
"timestamp": timezone.now(),
|
||||
"playback_position_ticks": playback_position * 1000,
|
||||
"playback_position": playback_position,
|
||||
"playback_position_ticks": None, # int(start_playback_position) * 1000,
|
||||
"playback_position": 0,
|
||||
"source": "Vrobbler",
|
||||
"long_play_complete": False,
|
||||
}
|
||||
|
||||
return Scrobble.create_or_update(game, user_id, scrobble_dict)
|
||||
|
||||
|
||||
def manual_scrobble_book(data_dict: dict, user_id: Optional[int]):
|
||||
book = Book.find_or_create(data_dict)
|
||||
|
||||
last_scrobble = Scrobble.objects.filter(
|
||||
book=book,
|
||||
user_id=user_id,
|
||||
played_to_completion=True,
|
||||
long_play_complete=False,
|
||||
).last()
|
||||
|
||||
start_playback_position = 0
|
||||
if last_scrobble:
|
||||
start_playback_position = last_scrobble.playback_position or 0
|
||||
scrobble_dict = {
|
||||
"user_id": user_id,
|
||||
"timestamp": timezone.now(),
|
||||
"playback_position_ticks": int(start_playback_position) * 1000,
|
||||
"playback_position": start_playback_position,
|
||||
"source": "Vrobbler",
|
||||
"long_play_complete": False,
|
||||
}
|
||||
|
||||
return Scrobble.create_or_update(book, user_id, scrobble_dict)
|
||||
|
||||
@ -44,6 +44,7 @@ from scrobbles.models import (
|
||||
from scrobbles.scrobblers import (
|
||||
jellyfin_scrobble_track,
|
||||
jellyfin_scrobble_video,
|
||||
manual_scrobble_book,
|
||||
manual_scrobble_event,
|
||||
manual_scrobble_video,
|
||||
manual_scrobble_video_game,
|
||||
@ -58,6 +59,7 @@ from scrobbles.tasks import (
|
||||
from sports.thesportsdb import lookup_event_from_thesportsdb
|
||||
from videos.imdb import lookup_video_from_imdb
|
||||
from videogames.howlongtobeat import lookup_game_from_hltb
|
||||
from vrobbler.apps.books.openlibrary import lookup_book_from_openlibrary
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -181,22 +183,29 @@ class ManualScrobbleView(FormView):
|
||||
|
||||
item_id = form.cleaned_data.get("item_id")
|
||||
data_dict = None
|
||||
if "tt" in item_id:
|
||||
data_dict = lookup_video_from_imdb(item_id)
|
||||
if data_dict:
|
||||
manual_scrobble_video(data_dict, self.request.user.id)
|
||||
|
||||
if not data_dict:
|
||||
if "-v" in item_id or not data_dict:
|
||||
logger.debug(f"Looking for video game with ID {item_id}")
|
||||
data_dict = lookup_game_from_hltb(item_id.replace("-v", ""))
|
||||
if data_dict:
|
||||
manual_scrobble_video_game(data_dict, self.request.user.id)
|
||||
|
||||
if "-b" in item_id and not data_dict:
|
||||
logger.debug(f"Looking for book with ID {item_id}")
|
||||
data_dict = lookup_book_from_openlibrary(item_id.replace("-b", ""))
|
||||
if data_dict:
|
||||
manual_scrobble_book(data_dict, self.request.user.id)
|
||||
|
||||
if "-s" in item_id and not data_dict:
|
||||
logger.debug(f"Looking for sport event with ID {item_id}")
|
||||
data_dict = lookup_event_from_thesportsdb(item_id)
|
||||
if data_dict:
|
||||
manual_scrobble_event(data_dict, self.request.user.id)
|
||||
|
||||
if not data_dict:
|
||||
logger.debug(f"Looking for video game with ID {item_id}")
|
||||
data_dict = lookup_game_from_hltb(item_id)
|
||||
if "tt" in item_id:
|
||||
data_dict = lookup_video_from_imdb(item_id)
|
||||
if data_dict:
|
||||
manual_scrobble_video_game(data_dict, self.request.user.id)
|
||||
manual_scrobble_video(data_dict, self.request.user.id)
|
||||
|
||||
return HttpResponseRedirect(reverse("vrobbler-home"))
|
||||
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from videogames.models import VideoGame, VideoGameCollection
|
||||
from videogames.models import VideoGame, VideoGamePlatform
|
||||
|
||||
from scrobbles.admin import ScrobbleInline
|
||||
|
||||
|
||||
@admin.register(VideoGameCollection)
|
||||
class VideoGameCollectionAdmin(admin.ModelAdmin):
|
||||
@admin.register(VideoGamePlatform)
|
||||
class VideoGamePlatformAdmin(admin.ModelAdmin):
|
||||
date_hierarchy = "created"
|
||||
list_display = (
|
||||
"name",
|
||||
@ -26,6 +26,10 @@ class GameAdmin(admin.ModelAdmin):
|
||||
"main_story_time",
|
||||
"release_year",
|
||||
)
|
||||
search_fields = (
|
||||
"title",
|
||||
"alternative_name",
|
||||
)
|
||||
ordering = ("-created",)
|
||||
inlines = [
|
||||
ScrobbleInline,
|
||||
|
||||
@ -36,6 +36,23 @@ def get_igdb_token() -> str:
|
||||
return results.get("access_token")
|
||||
|
||||
|
||||
def lookup_game_id_from_gdb(name: str) -> str:
|
||||
|
||||
headers = {
|
||||
"Authorization": f"Bearer {get_igdb_token()}",
|
||||
"Client-ID": IGDB_CLIENT_ID,
|
||||
}
|
||||
|
||||
body = f'fields name,game,published_at; search "{name}"; limit 20;'
|
||||
response = requests.post(SEARCH_URL, data=body, headers=headers)
|
||||
results = json.loads(response.content)
|
||||
if not results:
|
||||
logger.warn(f"Search of game on IGDB failed for name {name}")
|
||||
return ""
|
||||
|
||||
return results[0]["game"]
|
||||
|
||||
|
||||
def lookup_game_from_igdb(igdb_id: str) -> Dict:
|
||||
"""Given credsa and an IGDB game ID, lookup the game metadata and return it
|
||||
in a dictionary mapped to our internal game fields
|
||||
@ -45,7 +62,7 @@ def lookup_game_from_igdb(igdb_id: str) -> Dict:
|
||||
"Authorization": f"Bearer {get_igdb_token()}",
|
||||
"Client-ID": IGDB_CLIENT_ID,
|
||||
}
|
||||
fields = "id,name,alternative_names.*,release_dates.*,cover.*,screenshots.*,rating,rating_count"
|
||||
fields = "id,name,alternative_names.*,release_dates.*,cover.*,screenshots.*,rating,rating_count,summary"
|
||||
|
||||
game_dict = {}
|
||||
body = f"fields {fields}; where id = {igdb_id};"
|
||||
@ -87,6 +104,7 @@ def lookup_game_from_igdb(igdb_id: str) -> Dict:
|
||||
"rating": game.get("rating"),
|
||||
"rating_count": game.get("rating_count"),
|
||||
"release_date": release_date,
|
||||
"summary": game.get("summary"),
|
||||
}
|
||||
|
||||
return game_dict
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import logging
|
||||
from typing import Optional
|
||||
from uuid import uuid4
|
||||
|
||||
from django.conf import settings
|
||||
@ -8,6 +9,7 @@ from django.urls import reverse
|
||||
from django_extensions.db.models import TimeStampedModel
|
||||
from scrobbles.mixins import ScrobblableMixin
|
||||
from scrobbles.utils import get_scrobbles_for_media
|
||||
from videogames.igdb import lookup_game_id_from_gdb
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
BNULL = {"blank": True, "null": True}
|
||||
@ -72,6 +74,7 @@ class VideoGame(ScrobblableMixin):
|
||||
uuid = models.UUIDField(default=uuid4, editable=False, **BNULL)
|
||||
cover = models.ImageField(upload_to="games/covers/", **BNULL)
|
||||
screenshot = models.ImageField(upload_to="games/screenshots/", **BNULL)
|
||||
summary = models.TextField(**BNULL)
|
||||
hltb_cover = models.ImageField(upload_to="games/hltb_covers/", **BNULL)
|
||||
rating = models.FloatField(**BNULL)
|
||||
rating_count = models.IntegerField(**BNULL)
|
||||
@ -94,6 +97,14 @@ class VideoGame(ScrobblableMixin):
|
||||
def hltb_link(self):
|
||||
return f"https://howlongtobeat.com/game/{self.hltb_id}"
|
||||
|
||||
def igdb_link(self):
|
||||
slug = self.title.lower().replace(" ", "-")
|
||||
return f"https://igdb.com/games/{slug}"
|
||||
|
||||
def save(self, **kwargs):
|
||||
super().save(**kwargs)
|
||||
self.fix_metadata()
|
||||
|
||||
@property
|
||||
def seconds_for_completion(self) -> int:
|
||||
completion_time = self.run_time_ticks
|
||||
@ -112,10 +123,7 @@ class VideoGame(ScrobblableMixin):
|
||||
sec_played = last_scrobble.playback_position * 60
|
||||
return int(sec_played / self.run_time) * 100
|
||||
|
||||
def fix_metadata(
|
||||
self,
|
||||
force_update: bool = False,
|
||||
):
|
||||
def fix_metadata(self, force_update: bool = False):
|
||||
from videogames.utils import (
|
||||
get_or_create_videogame,
|
||||
load_game_data_from_igdb,
|
||||
@ -125,6 +133,9 @@ class VideoGame(ScrobblableMixin):
|
||||
get_or_create_videogame(str(self.hltb_id), force_update)
|
||||
|
||||
if self.igdb_id:
|
||||
# This almost never works without intervention
|
||||
# self.igdb_id = lookup_game_id_from_gdb(self.title)
|
||||
# self.save(update_fields=["igdb_id"])
|
||||
load_game_data_from_igdb(self.id)
|
||||
|
||||
if (not self.run_time_ticks or force_update) and self.main_story_time:
|
||||
|
||||
@ -5,10 +5,17 @@ app_name = "videogames"
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path("game/", views.VideoGameListView.as_view(), name="videogame_list"),
|
||||
path(
|
||||
"game/<slug:slug>/",
|
||||
"video-game/", views.VideoGameListView.as_view(), name="videogame_list"
|
||||
),
|
||||
path(
|
||||
"video-game/<slug:slug>/",
|
||||
views.VideoGameDetailView.as_view(),
|
||||
name="videogame_detail",
|
||||
),
|
||||
path(
|
||||
"video-game-platform/<slug:slug>/",
|
||||
views.VideoGamePlatformDetailView.as_view(),
|
||||
name="platform_detail",
|
||||
),
|
||||
]
|
||||
|
||||
@ -54,21 +54,25 @@ def get_or_create_videogame(
|
||||
return game
|
||||
|
||||
|
||||
def load_game_data_from_igdb(game_id: int) -> Optional[VideoGame]:
|
||||
def load_game_data_from_igdb(
|
||||
game_id: int, igdb_id: str = ""
|
||||
) -> Optional[VideoGame]:
|
||||
"""Look up game, if it doesn't exist, lookup data from igdb"""
|
||||
game = VideoGame.objects.filter(id=game_id).first()
|
||||
if not game:
|
||||
logger.warn(f"Video game with ID {game_id} not found")
|
||||
return
|
||||
|
||||
if not game.igdb_id:
|
||||
if not game.igdb_id and not igdb_id:
|
||||
logger.warn(f"Video game has no IGDB ID")
|
||||
return
|
||||
|
||||
logger.info(f"Looking up video game {game.igdb_id}")
|
||||
game_dict = lookup_game_from_igdb(game.igdb_id)
|
||||
igdb_id = game.igdb_id or igdb_id
|
||||
|
||||
logger.info(f"Looking up video game {igdb_id}")
|
||||
game_dict = lookup_game_from_igdb(igdb_id)
|
||||
if not game_dict:
|
||||
logger.warn(f"No game data found on IGDB for ID {game.igdb_id}")
|
||||
logger.warn(f"No game data found on IGDB for ID {igdb_id}")
|
||||
return
|
||||
|
||||
screenshot_url = game_dict.pop("screenshot_url")
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
from django.views import generic
|
||||
from videogames.models import VideoGame
|
||||
from videogames.models import VideoGame, VideoGamePlatform
|
||||
|
||||
|
||||
class VideoGameListView(generic.ListView):
|
||||
@ -10,3 +10,8 @@ class VideoGameListView(generic.ListView):
|
||||
class VideoGameDetailView(generic.DetailView):
|
||||
model = VideoGame
|
||||
slug_field = "uuid"
|
||||
|
||||
|
||||
class VideoGamePlatformDetailView(generic.DetailView):
|
||||
model = VideoGamePlatform
|
||||
slug_field = "uuid"
|
||||
|
||||
@ -307,11 +307,11 @@ LOGGING = {
|
||||
"loggers": {
|
||||
# Quiet down our console a little
|
||||
"django": {
|
||||
"handlers": ["console"],
|
||||
"handlers": ["null"],
|
||||
"propagate": True,
|
||||
},
|
||||
"django.db.backends": {"handlers": ["null"]},
|
||||
"django.server": {"handlers": ["console"]},
|
||||
"django.server": {"handlers": ["null"]},
|
||||
"pylast": {"handlers": ["null"], "propagate": False},
|
||||
"musicbrainzngs": {"handlers": ["null"], "propagate": False},
|
||||
"httpx": {"handlers": ["null"], "propagate": False},
|
||||
|
||||
@ -5,6 +5,7 @@ from rest_framework import routers
|
||||
import vrobbler.apps.scrobbles.views as scrobbles_views
|
||||
from vrobbler.apps.books.api.views import AuthorViewSet, BookViewSet
|
||||
from vrobbler.apps.music import urls as music_urls
|
||||
from vrobbler.apps.books import urls as book_urls
|
||||
from vrobbler.apps.sports import urls as sports_urls
|
||||
from vrobbler.apps.videogames import urls as videogame_urls
|
||||
from vrobbler.apps.music.api.views import (
|
||||
@ -58,6 +59,7 @@ urlpatterns = [
|
||||
path("admin/", admin.site.urls),
|
||||
path("accounts/", include("allauth.urls")),
|
||||
path("", include(music_urls, namespace="music")),
|
||||
path("", include(book_urls, namespace="books")),
|
||||
path("", include(video_urls, namespace="videos")),
|
||||
path("", include(videogame_urls, namespace="videogames")),
|
||||
path("", include(sports_urls, namespace="sports")),
|
||||
|
||||
Reference in New Issue
Block a user