utils.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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. suffix = ""
  15. if file_path:
  16. suffix = file_path.split("/media/")[-1]
  17. return suffix
  18. def import_gamelist_file_to_db_for_system(
  19. game_system_slug, file_path=None, full_scan=False
  20. ):
  21. imported_games = []
  22. if not file_path:
  23. file_path = os.path.join(settings.ROMS_DIR, game_system_slug, "gamelist.xml")
  24. if not os.path.exists(file_path):
  25. logger.info(
  26. "File path for {game_system_slug} had no gamelist.xml file, run a scraper first!"
  27. )
  28. return
  29. gamelist = ET.parse(file_path)
  30. game_system = GameSystem.objects.filter(retropie_slug=game_system_slug).first()
  31. if not game_system:
  32. game_system = GameSystem.objects.create(
  33. name=game_system_slug, retropie_slug=game_system_slug
  34. )
  35. games = gamelist.findall("game")
  36. for game in games:
  37. name = game.find("name").text
  38. obj, created = Game.objects.get_or_create(name=name)
  39. if not created and not full_scan:
  40. logger.info(f"Found game {game} and not doing full scan, so skipping")
  41. continue
  42. english_patched = "patched" in name.lower()
  43. undub = "undub" in name.lower()
  44. hack = "hack" in name.lower()
  45. region = None
  46. if any(us in name.lower() for us in US_STRINGS):
  47. region = Game.Region.US.name
  48. if any(jp in name.lower() for jp in JP_STRINGS):
  49. region = Game.Region.JP.name
  50. if any(eu in name.lower() for eu in EU_STRINGS):
  51. region = Game.Region.EU.name
  52. release_date_str = game.find("releasedate").text
  53. developer_str = game.find("developer").text
  54. publisher_str = game.find("publisher").text
  55. genres_str = game.find("genre").text
  56. rating_str = game.find("rating").text
  57. players_str = "1"
  58. if game.find("players"):
  59. players_str = game.find("players").text
  60. try:
  61. kid_game = game.find("kidgame").text == "true"
  62. except AttributeError:
  63. kid_game = False
  64. genre_list = []
  65. if genres_str:
  66. genre_str_list = genres_str.split(", ")
  67. for genre_str in genre_str_list:
  68. genre, _created = Genre.objects.get_or_create(name=genre_str)
  69. genre_list.append(genre)
  70. players = int(players_str) if players_str else 1
  71. rating = float(rating_str) if rating_str else None
  72. publisher = None
  73. if publisher_str:
  74. publisher, _created = Publisher.objects.get_or_create(name=publisher_str)
  75. developer = None
  76. if developer_str:
  77. developer, _created = Developer.objects.get_or_create(name=developer_str)
  78. release_date = parser.parse(release_date_str) if release_date_str else None
  79. description = game.find("desc").text
  80. screenshot_path = update_media_root_for_import(game.find("image").text)
  81. rom_path = update_media_root_for_import(game.find("path").text)
  82. video_path_elem = game.find("video")
  83. video_path = ""
  84. if video_path_elem:
  85. video_path = update_media_root_for_import(video_path_elem.text)
  86. marquee_path = update_media_root_for_import(game.find("marquee").text)
  87. obj.game_system = game_system
  88. obj.developer = developer
  89. obj.publisher = publisher
  90. obj.players = players
  91. obj.description = description
  92. obj.release_date = release_date
  93. obj.rating = rating
  94. obj.genre.set(genre_list)
  95. obj.screenshot = screenshot_path
  96. obj.rom_file = rom_path
  97. obj.video = video_path
  98. obj.marquee = marquee_path
  99. obj.kid_game = kid_game
  100. obj.english_patched = english_patched
  101. obj.hack = hack
  102. obj.undub = undub
  103. obj.region = region
  104. obj.save()
  105. imported_games.append(game)
  106. return imported_games
  107. def export_gamelist_file_to_path_for_system(game_system_slug, file_path=None):
  108. exported_games = []
  109. game_system = GameSystem.objects.get(retropie_slug=game_system_slug)
  110. if not file_path:
  111. file_path = f"/tmp/{game_system_slug}-gamelist.xml"
  112. # file_path = os.path.join(settings.ROMS_DIR, game_system_slug, "gamelist.xml")
  113. root = ET.Element("gameList")
  114. tree = ET.ElementTree(root)
  115. tree.write(file_path)
  116. games = Game.objects.filter(game_system=game_system)
  117. for game in games:
  118. game_node = ET.SubElement(root, "game")
  119. genre_str = ", ".join(game.genre.all().values_list("name", flat=True))
  120. release_date_str = ""
  121. if game.release_date:
  122. release_date_str = game.release_date.strftime("%Y%m%dT00000")
  123. ET.SubElement(game_node, "path").text = (
  124. game.rom_file.path if game.rom_file else ""
  125. )
  126. ET.SubElement(game_node, "name").text = game.name
  127. ET.SubElement(game_node, "thumbnail").text = ""
  128. ET.SubElement(game_node, "image").text = (
  129. game.screenshot.path if game.screenshot else ""
  130. )
  131. ET.SubElement(game_node, "marquee").text = (
  132. game.marquee.path if game.marquee else ""
  133. )
  134. ET.SubElement(game_node, "video").text = game.video.path if game.video else ""
  135. ET.SubElement(game_node, "rating").text = str(game.rating)
  136. ET.SubElement(game_node, "desc").text = game.description
  137. ET.SubElement(game_node, "releasedate").text = release_date_str
  138. ET.SubElement(game_node, "developer").text = str(game.developer)
  139. ET.SubElement(game_node, "publisher").text = str(game.publisher)
  140. ET.SubElement(game_node, "genre").text = genre_str
  141. ET.SubElement(game_node, "players").text = str(game.players)
  142. if game.kid_game:
  143. ET.SubElement(game_node, "kidgame").text = "true"
  144. exported_games.append(game)
  145. tree = ET.ElementTree(root)
  146. tree.write(file_path, xml_declaration=True, encoding="utf-8")
  147. return exported_games, file_path
  148. def skyscrape_console(game_system_slug):
  149. scraper_config = settings.SCRAPER_CONFIG_FILE
  150. scraper_binary = settings.SCRAPER_BIN_PATH
  151. scraper_site = settings.SCRAPER_SITE
  152. # If the config file is relative, append our base dir
  153. print(f"Preparing to scrape game info for {game_system_slug}")
  154. if scraper_config[0] != "/":
  155. scraper_config = os.path.join(settings.BASE_DIR, scraper_config)
  156. if not os.path.exists(scraper_config):
  157. logger.info(f"Config file not found at {scraper_config}")
  158. print(f"Config file not found at {scraper_config}")
  159. return
  160. print(f"Using configuration file from {scraper_config}")
  161. # scrape_cmd = f"{binary} -c {config_file} -s {site} -u {user}:{password} -t {threads} -f emulationstation -p {game_system_slug}"
  162. # load_cmd = f"{binary} -f emulationstation -p {game_system_slug}"
  163. scrape_output = subprocess.run(
  164. [
  165. scraper_binary,
  166. "-c",
  167. f"{scraper_config}",
  168. "-s",
  169. f"{scraper_site}",
  170. "-p",
  171. f"{game_system_slug}",
  172. ],
  173. capture_output=True,
  174. )
  175. load_output = subprocess.run(
  176. [
  177. scraper_binary,
  178. "-c",
  179. f"{scraper_config}",
  180. "-f",
  181. "{scraper_site}",
  182. "-p",
  183. f"{game_system_slug}",
  184. ],
  185. capture_output=True,
  186. )
  187. print(scrape_output)
  188. print(load_output)
  189. return scrape_output, load_output