Explorar o código

Add update_roms command and game system list view

Colin Powell %!s(int64=3) %!d(string=hai) anos
pai
achega
bf3af2041a

+ 7 - 3
emus/settings.py

@@ -36,9 +36,9 @@ CELERY_DEFAULT_QUEUE = "emus"
 CELERY_TASK_ALWAYS_EAGER = os.getenv("EMUS_SKIP_CELERY", False)
 CELERY_BROKER_URL = os.getenv("EMUS_CELERY_BROKER_URL", "memory://localhost/")
 CELERY_RESULT_BACKEND = "django-db"
-CELERY_ACCEPT_CONTENT = ['application/json']
-CELERY_TASK_SERIALIZER = 'json'
-CELERY_RESULT_SERIALIZER = 'json'
+CELERY_ACCEPT_CONTENT = ["application/json"]
+CELERY_TASK_SERIALIZER = "json"
+CELERY_RESULT_SERIALIZER = "json"
 CELERY_TIMEZONE = os.getenv("EMUS_TIME_ZONE", "EST")
 CELERY_TASK_TRACK_STARTED = True
 
@@ -257,6 +257,10 @@ GAME_SYSTEM_DEFAULTS = {
         "name": "Colecovision",
         "retroarch_core": "bluemsx",
     },
+    "daphne": {
+        "name": "Daphne",
+        "retroarch_core": "daphne",
+    },
     "dreamcast": {
         "name": "Dreamcast",
         "color": "ED872D",

+ 22 - 0
games/management/commands/update_roms.py

@@ -0,0 +1,22 @@
+from django.core.management.base import BaseCommand, CommandError
+from django.conf import settings
+
+from games.tasks import update_roms
+
+
+class Command(BaseCommand):
+    help = "Scrape + import all games for all systems"
+
+    def add_arguments(self, parser):
+        parser.add_argument(
+            "--full-scan",
+            action="store_true",
+            help="Update all files, even ones we already know about",
+        )
+
+    def handle(self, *args, **options):
+        all_slugs = settings.GAME_SYSTEM_DEFAULTS.keys()
+        update_roms(all_slugs, full_scan=options["full_scan"])
+        self.stdout.write(
+            self.style.SUCCESS("Successfully scraped and imported roms")
+        )

+ 14 - 4
games/models.py

@@ -1,16 +1,18 @@
+import logging
 import os
-from shlex import quote
-
 from enum import Enum
+from shlex import quote
 
 from django.conf import settings
 from django.core.validators import MaxValueValidator, MinValueValidator
 from django.db import models
 from django.urls import reverse
-from django_extensions.db.models import TimeStampedModel
 from django_extensions.db.fields import AutoSlugField
+from django_extensions.db.models import TimeStampedModel
 from emus.utils import ChoiceEnum
 
+logger = logging.getLogger(__name__)
+
 
 def get_screenshot_upload_path(instance, filename):
     return f"{instance.game_system.retropie_slug}/screenshots/{filename}"
@@ -64,6 +66,7 @@ class StatisticsMixin(models.Model):
             return int(100 * avg)
         return 0
 
+
 class Genre(BaseModel, StatisticsMixin):
     def get_absolute_url(self):
         return reverse("games:genre_detail", args=[self.slug])
@@ -255,6 +258,10 @@ class Game(BaseModel):
         if not self.rom_file:
             return ""
         rom_file = quote(self.rom_file.path)
+        if not os.path.exists(self.retroarch_core_path):
+            logger.info(f"Missing libretro core file at {self.retroarch_core_path}")
+            return f"Libretro core not found at {self.retroarch_core_path}"
+
         return f"retroarch -L {self.retroarch_core_path} {rom_file} -v"
 
     def cmd(self, platform="linux"):
@@ -268,6 +275,7 @@ class Game(BaseModel):
             cmd = f"{emulator} --console --fullscreen --nogui {rom_file}"
         return cmd
 
+
 class GameCollection(BaseModel):
     games = models.ManyToManyField(Game)
     game_system = models.ForeignKey(
@@ -314,7 +322,9 @@ class GameCollection(BaseModel):
 
         file_path = f"/tmp/custom-{self.slug}.cfg"
         if not dryrun:
-            file_path = os.path.join(settings.COLLECTIONS_DIR, f"custom-{self.slug}.cfg")
+            file_path = os.path.join(
+                settings.COLLECTIONS_DIR, f"custom-{self.slug}.cfg"
+            )
 
         with open(file_path, "w") as outfile:
             for game in self.games.all():

+ 5 - 0
games/urls.py

@@ -30,6 +30,11 @@ urlpatterns = [
         views.DeveloperList.as_view(),
         name="developer_list",
     ),
+    path(
+        "game-system/",
+        views.GameSystemList.as_view(),
+        name="gamesystem_list",
+    ),
     path(
         "collection/",
         views.GameCollectionList.as_view(),

+ 7 - 2
games/views.py

@@ -40,7 +40,6 @@ class LibraryGameList(ListView, LoginRequiredMixin):
 
 
 class FilterableBaseListView(ListView, LoginRequiredMixin):
-
     def get_queryset(self, **kwargs):
         order_by = self.request.GET.get("order_by", "name")
         queryset = super().get_queryset(**kwargs)
@@ -77,6 +76,10 @@ class GamePlayDetail(DetailView, LoginRequiredMixin):
     model = Game
 
 
+class GameSystemList(ListView, LoginRequiredMixin):
+    model = GameSystem
+
+
 class GameSystemDetail(DetailView, MultipleObjectMixin, LoginRequiredMixin):
     model = GameSystem
     paginate_by = 20
@@ -143,5 +146,7 @@ class GameCollectionDetail(DetailView, LoginRequiredMixin):
         else:
             object_list = object_list.order_by(F(order_by).asc(nulls_last=True))
 
-        context = super(GameCollectionDetail, self).get_context_data(object_list=object_list, **kwargs)
+        context = super(GameCollectionDetail, self).get_context_data(
+            object_list=object_list, **kwargs
+        )
         return context

+ 2 - 1
templates/base.html

@@ -71,6 +71,7 @@
                 <li class="nav-item dropdown">
                     <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Systems</a>
                     <div class="dropdown-menu" aria-labelledby="navbarDropdown">
+                        <a class="dropdown-item" href="{% url "games:gamesystem_list" %}">All</a>
                         {% for system in game_systems %}
                         <a class="dropdown-item" href="{{system.get_absolute_url}}">{{system.name}} ({{system.game_set.count}})</a>
                         {% endfor %}
@@ -79,7 +80,7 @@
                 <li class="nav-item dropdown">
                     <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Collections</a>
                     <div class="dropdown-menu" aria-labelledby="navbarDropdown">
-			<a class="dropdown-item" href="{% url "games:gamecollection_list" %}">All</a>
+                        <a class="dropdown-item" href="{% url "games:gamecollection_list" %}">All</a>
                         {% for collection in game_collections %}
                         <a class="dropdown-item" href="{{collection.get_absolute_url}}">{{collection.name}} ({{collection.games.count}})</a>
                         {% endfor %}

+ 27 - 0
templates/games/gamesystem_list.html

@@ -0,0 +1,27 @@
+{% extends "base.html" %}
+{% block page_title %}{{object}}{% endblock %}
+
+{% block title %}{{object}}{% endblock %}
+
+{% block content %}
+    <table class="table table-bordered table">
+    <thead>
+        <tr>
+        <th scope="col">#</th>
+        <th scope="col">Name</th>
+        <th scope="col">Games</th>
+        <th scope="col">Rating</th>
+        </tr>
+    </thead>
+    <tbody>
+        {% for  object in object_list %}
+        <tr>
+        <th scope="row"><a href="{{object.get_absolute_url}}">{{object.id}}</a></th>
+        <td>{{object.name}}</td>
+        <td>{{object.game_set.count}}</td>
+        <td>{{object.rating_avg}}/100</td>
+        </tr>
+        {% endfor %}
+    </tbody>
+    </table>
+{% endblock %}