utils.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import os
  2. import xml.etree.ElementTree as ET
  3. import subprocess
  4. from dateutil import parser
  5. from django.conf import settings
  6. from .models import Developer, Game, GameSystem, Genre, Publisher
  7. import logging
  8. logger = logging.Logger(__name__)
  9. US_STRINGS = ["(u)", "(usa)", "(us)"]
  10. JP_STRINGS = ["(j)", "japan", "jp"]
  11. EU_STRINGS = ["(e)", "eur", "europe", "pal"]
  12. def update_media_root_for_import(file_path):
  13. """Given a file path, re-write it for our app MEDIA_ROOT"""
  14. split_path = file_path.split("/media/")
  15. return split_path[-1]
  16. def import_gamelist_file_to_db_for_system(game_system_slug, file_path=None):
  17. imported_games = []
  18. if not file_path:
  19. file_path = os.path.join(settings.ROMS_DIR, game_system_slug, "gamelist.xml")
  20. if not os.path.exists(file_path):
  21. logger.info(
  22. "File path for {game_system_slug} had no gamelist.xml file, run a scraper first!"
  23. )
  24. return
  25. gamelist = ET.parse(file_path)
  26. game_system = GameSystem.objects.filter(retropie_slug=game_system_slug).first()
  27. if not game_system:
  28. game_system = GameSystem.objects.create(
  29. name=game_system_slug, retropie_slug=game_system_slug
  30. )
  31. games = gamelist.findall("game")
  32. for game in games:
  33. name = game.find("name").text
  34. english_patched = "patched" in name.lower()
  35. undub = "undub" in name.lower()
  36. hack = "hack" in name.lower()
  37. region = None
  38. if any(us in name.lower() for us in US_STRINGS):
  39. region = Game.Region.US.name
  40. if any(jp in name.lower() for jp in JP_STRINGS):
  41. region = Game.Region.JP.name
  42. if any(eu in name.lower() for eu in EU_STRINGS):
  43. region = Game.Region.EU.name
  44. release_date_str = game.find("releasedate").text
  45. developer_str = game.find("developer").text
  46. publisher_str = game.find("publisher").text
  47. genres_str = game.find("genre").text
  48. rating_str = game.find("rating").text
  49. players_str = "1"
  50. if game.find("players"):
  51. players_str = game.find("players").text
  52. try:
  53. kid_game = game.find("kidgame").text == "true"
  54. except AttributeError:
  55. kid_game = False
  56. genre_list = []
  57. if genres_str:
  58. genre_str_list = genres_str.split(", ")
  59. for genre_str in genre_str_list:
  60. genre, _created = Genre.objects.get_or_create(name=genre_str)
  61. genre_list.append(genre)
  62. players = int(players_str) if players_str else 1
  63. rating = float(rating_str) if rating_str else None
  64. publisher = None
  65. if publisher_str:
  66. publisher, _created = Publisher.objects.get_or_create(name=publisher_str)
  67. developer = None
  68. if developer_str:
  69. developer, _created = Developer.objects.get_or_create(name=developer_str)
  70. release_date = parser.parse(release_date_str) if release_date_str else None
  71. description = game.find("desc").text
  72. screenshot_path = update_media_root_for_import(game.find("image").text)
  73. rom_path = update_media_root_for_import(game.find("path").text)
  74. video_path = update_media_root_for_import(game.find("video").text)
  75. marquee_path = update_media_root_for_import(game.find("marquee").text)
  76. obj, created = Game.objects.get_or_create(name=name)
  77. obj.game_system = game_system
  78. obj.developer = developer
  79. obj.publisher = publisher
  80. obj.players = players
  81. obj.description = description
  82. obj.release_date = release_date
  83. obj.rating = rating
  84. obj.genre.set(genre_list)
  85. obj.screenshot = screenshot_path
  86. obj.rom_file = rom_path
  87. obj.video = video_path
  88. obj.marquee = marquee_path
  89. obj.kid_game = kid_game
  90. obj.english_patched = english_patched
  91. obj.hack = hack
  92. obj.undub = undub
  93. obj.region = region
  94. obj.save()
  95. imported_games.append(game)
  96. return imported_games
  97. def export_gamelist_file_to_path_for_system(game_system_slug, file_path=None):
  98. exported_games = []
  99. game_system = GameSystem.objects.get(retropie_slug=game_system_slug)
  100. if not file_path:
  101. file_path = f"/tmp/{game_system_slug}-gamelist.xml"
  102. # file_path = os.path.join(settings.ROMS_DIR, game_system_slug, "gamelist.xml")
  103. root = ET.Element("gameList")
  104. tree = ET.ElementTree(root)
  105. tree.write(file_path)
  106. games = Game.objects.filter(game_system=game_system)
  107. for game in games:
  108. game_node = ET.SubElement(root, "game")
  109. genre_str = ", ".join(game.genre.all().values_list("name", flat=True))
  110. release_date_str = ""
  111. if game.release_date:
  112. release_date_str = game.release_date.strftime("%Y%m%dT00000")
  113. ET.SubElement(game_node, "path").text = (
  114. game.rom_file.path if game.rom_file else ""
  115. )
  116. ET.SubElement(game_node, "name").text = game.name
  117. ET.SubElement(game_node, "thumbnail").text = ""
  118. ET.SubElement(game_node, "image").text = (
  119. game.screenshot.path if game.screenshot else ""
  120. )
  121. ET.SubElement(game_node, "marquee").text = (
  122. game.marquee.path if game.marquee else ""
  123. )
  124. ET.SubElement(game_node, "video").text = game.video.path if game.video else ""
  125. ET.SubElement(game_node, "rating").text = str(game.rating)
  126. ET.SubElement(game_node, "desc").text = game.description
  127. ET.SubElement(game_node, "releasedate").text = release_date_str
  128. ET.SubElement(game_node, "developer").text = str(game.developer)
  129. ET.SubElement(game_node, "publisher").text = str(game.publisher)
  130. ET.SubElement(game_node, "genre").text = genre_str
  131. ET.SubElement(game_node, "players").text = str(game.players)
  132. if game.kid_game:
  133. ET.SubElement(game_node, "kidgame").text = "true"
  134. exported_games.append(game)
  135. tree = ET.ElementTree(root)
  136. tree.write(file_path, xml_declaration=True, encoding="utf-8")
  137. return exported_games, file_path
  138. def skyscrape_console(game_system_slug):
  139. scraper_config = settings.SCRAPER_CONFIG
  140. binary = scraper_config["bin_path"]
  141. site = scraper_config["site"]
  142. user = scraper_config["user"]
  143. password = scraper_config["pass"]
  144. threads = scraper_config["threads"]
  145. scrape_cmd = f"{binary} -s {site} -u {user}:{password} -t {threads} -f emulationstation -p {game_system_slug}"
  146. load_cmd = f"{binary} -f emulationstation -p {game_system_slug}"
  147. scrape_output = subprocess.run(
  148. [
  149. binary,
  150. "-s",
  151. "{site}",
  152. "-u",
  153. f"{user}:{password}",
  154. "-t",
  155. f"{threads}",
  156. "-f",
  157. "emulationstation",
  158. "-p",
  159. f"{game_system_slug}",
  160. ],
  161. capture_output=True,
  162. )
  163. load_output = subprocess.run(
  164. [
  165. binary,
  166. "-f",
  167. "emulationstation",
  168. "-p",
  169. f"{game_system_slug}",
  170. ],
  171. capture_output=True,
  172. )
  173. return scrape_output, load_output