views.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. import json
  2. import logging
  3. from datetime import datetime
  4. from celery import states
  5. from django.conf import settings
  6. from django.contrib.auth.decorators import login_required
  7. from django.contrib.auth.mixins import LoginRequiredMixin
  8. from django.core.cache import cache
  9. from django.db.models import Avg, Count, F
  10. from django.http import HttpResponse
  11. from django.views.generic import DetailView, ListView
  12. from django.views.generic.list import MultipleObjectMixin
  13. from django_celery_results.models import TaskResult
  14. from games.tasks import update_roms
  15. from .models import Developer, Game, GameCollection, GameSystem, Genre, Publisher
  16. logger = logging.Logger(__name__)
  17. IN_PROGRESS_STATES = [states.PENDING, states.STARTED, states.RETRY]
  18. class RecentGameList(LoginRequiredMixin, ListView):
  19. model = Game
  20. paginate_by = 12
  21. queryset = Game.objects.order_by("-created")[:64]
  22. def get_context_data(self, **kwargs):
  23. cached_game_id = cache.get("todays_game_id", None)
  24. if not cached_game_id:
  25. todays_game = (
  26. Game.objects.filter(rating__gte=0.7, featured_on__isnull=True)
  27. .order_by("?")
  28. .first()
  29. )
  30. cache.set("todays_game_id", todays_game.id, settings.FEATURED_GAME_DURATION)
  31. todays_game.featured_on = datetime.now()
  32. todays_game.save(update_fields=["featured_on"])
  33. else:
  34. todays_game = Game.objects.get(id=cached_game_id)
  35. return super(RecentGameList, self).get_context_data(
  36. todays_game=todays_game,
  37. **kwargs,
  38. )
  39. class LibraryGameList(ListView, LoginRequiredMixin):
  40. template_name = "games/game_library_list.html"
  41. model = Game
  42. paginate_by = 200
  43. def get_context_data(self, **kwargs):
  44. game_system_slug = self.request.GET.get("game_system")
  45. order_by = self.request.GET.get("order_by", "name")
  46. if order_by[0] == "-":
  47. order_by = order_by[1:]
  48. object_list = Game.objects.order_by(F(order_by).desc(nulls_last=True))
  49. else:
  50. object_list = Game.objects.order_by(F(order_by).asc(nulls_last=True))
  51. if game_system_slug:
  52. object_list = object_list.filter(
  53. game_system__retropie_slug=game_system_slug
  54. )
  55. context = super(LibraryGameList, self).get_context_data(
  56. object_list=object_list, **kwargs
  57. )
  58. return context
  59. class FilterableBaseListView(ListView, LoginRequiredMixin):
  60. def get_queryset(self, **kwargs):
  61. order_by = self.request.GET.get("order_by", "name")
  62. queryset = super().get_queryset(**kwargs)
  63. queryset = queryset.annotate(num_games=Count("game")).annotate(
  64. rating=Avg("game__rating")
  65. )
  66. if order_by[0] == "-":
  67. order_by = order_by[1:]
  68. queryset = queryset.order_by(F(order_by).desc(nulls_last=True))
  69. else:
  70. queryset = queryset.order_by(F(order_by).asc(nulls_last=True))
  71. return queryset
  72. class PublisherList(FilterableBaseListView):
  73. model = Publisher
  74. class DeveloperList(FilterableBaseListView):
  75. model = Developer
  76. class GenreList(FilterableBaseListView):
  77. model = Genre
  78. class GameDetail(DetailView, LoginRequiredMixin):
  79. model = Game
  80. class GamePlayDetail(DetailView, LoginRequiredMixin):
  81. template_name = "games/game_play_detail.html"
  82. model = Game
  83. class GameSystemList(ListView, LoginRequiredMixin):
  84. model = GameSystem
  85. class GameSystemDetail(DetailView, MultipleObjectMixin, LoginRequiredMixin):
  86. model = GameSystem
  87. paginate_by = 20
  88. def get_context_data(self, **kwargs):
  89. object_list = Game.objects.filter(game_system=self.get_object())
  90. context = super(GameSystemDetail, self).get_context_data(
  91. object_list=object_list, **kwargs
  92. )
  93. return context
  94. class GenreDetail(DetailView, MultipleObjectMixin, LoginRequiredMixin):
  95. model = Genre
  96. paginate_by = 20
  97. def get_context_data(self, **kwargs):
  98. object_list = Game.objects.filter(genre=self.get_object())
  99. context = super(GenreDetail, self).get_context_data(
  100. object_list=object_list, **kwargs
  101. )
  102. return context
  103. class PublisherDetail(DetailView, MultipleObjectMixin, LoginRequiredMixin):
  104. model = Publisher
  105. paginate_by = 20
  106. def get_context_data(self, **kwargs):
  107. object_list = Game.objects.filter(publisher=self.get_object())
  108. context = super(PublisherDetail, self).get_context_data(
  109. object_list=object_list, **kwargs
  110. )
  111. return context
  112. class DeveloperDetail(DetailView, MultipleObjectMixin, LoginRequiredMixin):
  113. model = Developer
  114. paginate_by = 20
  115. def get_context_data(self, **kwargs):
  116. object_list = Game.objects.filter(developer=self.get_object())
  117. context = super(DeveloperDetail, self).get_context_data(
  118. object_list=object_list, **kwargs
  119. )
  120. return context
  121. class GameCollectionList(ListView, LoginRequiredMixin):
  122. model = GameCollection
  123. class GameCollectionDetail(DetailView, LoginRequiredMixin):
  124. model = GameCollection
  125. def get_context_data(self, **kwargs):
  126. collection = self.get_object()
  127. order_by = self.request.GET.get("order_by", "release_date")
  128. object_list = collection.games.all()
  129. if order_by[0] == "-":
  130. order_by = order_by[1:]
  131. object_list = object_list.order_by(F(order_by).desc(nulls_last=True))
  132. else:
  133. object_list = object_list.order_by(F(order_by).asc(nulls_last=True))
  134. context = super(GameCollectionDetail, self).get_context_data(
  135. object_list=object_list, **kwargs
  136. )
  137. return context
  138. @login_required
  139. def trigger_rom_update(request):
  140. full_scan = request.GET.get("full_scan", False)
  141. if full_scan == "true":
  142. full_scan = True
  143. game_systems = request.GET.getlist("game_systems")
  144. if not game_systems:
  145. game_systems = list(settings.GAME_SYSTEM_DEFAULTS.keys())
  146. try:
  147. update_roms.delay(game_systems, full_scan=full_scan)
  148. except FileNotFoundError:
  149. return HttpResponse(
  150. json.dumps({"success": False, "msg": "Skyscraper is not installed"}),
  151. status=400,
  152. content_type="application/json",
  153. )
  154. return HttpResponse(
  155. json.dumps({"success": True, "msg": "Library scan started"}),
  156. status=200,
  157. content_type="application/json",
  158. )
  159. @login_required
  160. def library_update_status(request):
  161. update_task = TaskResult.objects.filter(
  162. task_name="games.tasks.update_roms",
  163. status__in=IN_PROGRESS_STATES,
  164. ).first()
  165. if not update_task:
  166. state = states.SUCCESS
  167. else:
  168. state = update_task.status
  169. return HttpResponse(
  170. json.dumps({"state": state}),
  171. status=200,
  172. content_type="application/json",
  173. )