Repository: lutris/lutris

Issue:
ValueError: not enough values to unpack (expected 2, got 1)
With the new RetroArch PR that went in I got this on the terminal, and Lutris won't start: https://paste.ubuntu.com/p/TqQzCvz56j/




Discussion:

Resolving patch:
diff --git a/lutris/runners/libretro.py b/lutris/runners/libretro.py
--- a/lutris/runners/libretro.py
+++ b/lutris/runners/libretro.py
@@ -1,120 +1,56 @@
 """libretro runner"""
 import os
+from zipfile import ZipFile
+
+import requests
+from operator import itemgetter
+
 from lutris.runners.runner import Runner
 from lutris.util.libretro import RetroConfig
 from lutris.util import system
 from lutris.util.log import logger
 from lutris import settings
 
+
+def get_default_config_path(path=""):
+    return os.path.join(settings.RUNNER_DIR, "retroarch", path)
+
+
 # List of supported libretro cores
 # First element is the human readable name for the core with the platform's short name
 # Second element is the core identifier
 # Third element is the platform's long name
-LIBRETRO_CORES = [
-    ("atari800 (Atari 800/5200)", "atari800", "Atari 800/5200"),
-    ("bsnes (Super Nintendo)", "bsnes", "Nintendo SNES"),
-    ("bsnes-hd beta (Super Nintendo)", "bsnes_hd_beta", "Nintendo SNES"),
-    ("BK (Elektronika BK-0010/BK-0011(M))", "bk", "Elektronika BK-0010/BK-0011"),
-    ("BlastEm (Sega Genesis)", "blastem", "Sega Genesis"),
-    ("blueMSX (MSX/MSX2/MSX2+)", "bluemsx", "MSX/MSX2/MSX2+"),
-    ("Caprice32 (Amstrad CPC)", "cap32", "Amstrad CPC"),
-    ("ChaiLove", "chailove", "ChaiLove"),
-    ("Citra (Nintendo 3DS)", "citra", "Nintendo 3DS"),
-    ("Citra Canary (Nintendo 3DS)", "citra_canary", "Nintendo 3DS"),
-    ("CrocoDS (Amstrad CPC)", "crocods", "Amstrad CPC"),
-    ("Daphne (Arcade)", "daphne", "Arcade"),
-    ("DesmuME (Nintendo DS)", "desmume", "Nintendo DS"),
-    ("Dinothawr (Game Engine)", "dinothawr", "Dinothawr"),
-    ("Dolphin (Nintendo Wii/Gamecube)", "dolphin", "Nintendo Wii/Gamecube"),
-    ("EightyOne (Sinclair ZX81)", "81", "Sinclair ZX81"),
-    ("FB Alpha (Arcade)", "fbalpha", "Arcade"),
-    ("FB Alpha (Capcom Play System 1)", "fbalpha2012_cps1", "Arcade"),
-    ("FB Alpha (Capcom Play System 2)", "fbalpha2012_cps2", "Arcade"),
-    ("FB Alpha (Capcom Play System 3)", "fbalpha2012_cps3", "Arcade"),
-    ("FB Alpha (SNK Neo Geo)", "fbalpha2012_neogeo", "Arcade"),
-    ("FBNeo (Arcade)", "fbneo", "Arcade"),
-    ("FCEUmm (Nintendo Entertainment System)", "fceumm", "Nintendo NES"),
-    ('Flycast (Sega Dreamcast)', 'flycast', 'Sega Dreamcast'),
-    ("fMSX (MSX/MSX2/MSX2+)", "fmsx", "MSX/MSX2/MSX2+"),
-    ("FreeJ2ME (J2ME)", "freej2me", "J2ME"),
-    ("Fuse (ZX Spectrum)", "fuse", "Sinclair ZX Spectrum"),
-    ("Gambatte (Game Boy Color)", "gambatte", "Nintendo Game Boy Color"),
-    ("Gearboy (Game Boy Color)", "gearboy", "Nintendo Game Boy Color"),
-    ("Gearsystem (Sega Master System/Gamegear)", "gearsystem", "Sega Master System/Gamegear"),
-    ("Genesis Plus GX (Sega Genesis)", "genesis_plus_gx", "Sega Genesis"),
-    ("Handy (Atari Lynx)", "handy", "Atari Lynx"),
-    ("Hatari (Atari ST/STE/TT/Falcon)", "hatari", "Atari ST/STE/TT/Falcon"),
-    ("HBMAME (Arcade)", "hbmame", "Arcade"),
-    ("higan accuracy(Super Nintendo)", "higan_sfc", "Nintendo SNES"),
-    ("higan balanced(Super Nintendo)", "higan_sfc_balanced", "Nintendo SNES"),
-    ("Kronos (Sega Saturn)", "kronos", "Sega Saturn"),
-    ("MAME (Arcade)", "mame", "Arcade"),
-    ("MAME 2003-Plus (Arcade)", "mame2003_plus", "Arcade"),
-    ("Mednafen GBA (Game Boy Advance)", "mednafen_gba", "Nintendo Game Boy Advance"),
-    ("Mednafen NGP (SNK Neo Geo Pocket)", "mednafen_ngp", "SNK Neo Geo Pocket"),
-    ("Mednafen PCE (TurboGrafx-16)", "mednafen_pce", "NEC PC Engine (TurboGrafx-16)"),
-    ("Mednafen PCE FAST (TurboGrafx-16)", "mednafen_pce_fast", "NEC PC Engine (TurboGrafx-16)"),
-    ("Mednafen PCFX (NEC PC-FX)", "mednafen_pcfx", "NEC PC-FX"),
-    ("Mednafen Saturn (Sega Saturn)", "mednafen_saturn", "Sega Saturn"),
-    ("Mednafen SGX (NEC PC Engine SuperGrafx)",
-     "mednafen_supergrafx",
-     "NEC PC Engine (SuperGrafx)"),
-    ("Mednafen WSWAN (Bandai WonderSwan)", "mednafen_wswan", "Bandai WonderSwan"),
-    ("Mednafen PSX (Sony Playstation)", "mednafen_psx", "Sony PlayStation"),
-    ("Mednafen PSX OpenGL (Sony Playstation)", "mednafen_psx_hw", "Sony PlayStation"),
-    ("Mesen (Nintendo Entertainment System)", "mesen", "Nintendo NES"),
-    ("Mesen-S (Super Nintendo)", "mesen-s", "Nintendo SNES"),
-    ("melonDS (Nintendo DS)", "melonds", "Nintendo DS"),
-    ("mGBA (Game Boy Advance)", "mgba", "Nintendo Game Boy Advance"),
-    ("Mupen64Plus (Nintendo 64)", "mupen64plus", "Nintendo N64"),
-    ("Nestopia (Nintendo Entertainment System)", "nestopia", "Nintendo NES"),
-    ("Neko Project 2 (NEC PC-98)", "nekop2", "NEC PC-98"),
-    ("Neko Project II kai (NEC PC-98)", "np2kai", "NEC PC-98"),
-    ("NeoCD (SNK Neo Geo CD)", "neocd", "SNK Neo Geo CD"),
-    ("O2EM (Magnavox Odyssey²)", "o2em", "Magnavox Odyssey²"),
-    ("Opera (3DO)", "opera", "3DO"),
-    ("ParaLLEl N64 (Nintendo 64)", "parallel_n64", "Nintendo N64"),
-    ("PCSX Rearmed (Sony Playstation)", "pcsx_rearmed", "Sony PlayStation"),
-    ("PicoDrive (Sega Genesis)", "picodrive", "Sega Genesis"),
-    ("Play! (Sony Playstation 2)", "play", "Sony PlayStation 2"),
-    ("Portable SHARP X68000 Emulator (SHARP X68000)", "px68k", "Sharp X68000"),
-    ("PPSSPP (PlayStation Portable)", "ppsspp", "Sony PlayStation Portable"),
-    ("ProSystem (Atari 7800)", "prosystem", "Atari 7800"),
-    ("QUASI88 (NEC PC-8801)", "quasi88", "NEC PC-8801"),
-    ("RACE (SNK Neo Geo Pocket)", "race", "SNK Neo Geo Pocket"),
-    ("RPG Maker 2000/2003 (EasyRPG)", "easyrpg", "RPG Maker 2000/2003 Game Engine"),
-    ("Snes9x (Super Nintendo)", "snes9x", "Nintendo SNES"),
-    ("Snes9x2010 (Super Nintendo)", "snes9x2010", "Nintendo SNES"),
-    ("Stella (Atari 2600)", "stella", "Atari 2600"),
-    ("Stella 2014 (Atari 2600)", "stella2014", "Atari 2600"),
-    ("smsplus (Sega - MS/GG)", "smsplus", "Sega MS/GG"),
-    ("Tic-80 (Tic-80)", "tic80", "TIC-80"),
-    ("Uzem (Uzebox)", "uzem", "Uzebox"),
-    ("VecX (Vectrex)", "vecx", "Vectrex"),
-    ("Yabause (Sega Saturn)", "yabause", "Sega Saturn"),
-    ("VBA Next (Game Boy Advance)", "vba_next", "Nintendo Game Boy Advance"),
-    ("VBA-M (Game Boy Advance)", "vbam", "Nintendo Game Boy Advance"),
-    ("Virtual Jaguar (Atari Jaguar)", "virtualjaguar", "Atari Jaguar"),
-    ("VICE (Commodore 128)", "vice_x128", "Commodore 128"),
-    ("VICE (Commodore CBM-II)", "vice_xcbm2", "Commodore CBM-II"),
-    ("VICE (Commodore Pet)", "vice_xpet", "Commodore Pet"),
-    ("VICE (Commodore 16/Plus/4)", "vice_xplus4", "Commodore 16/Plus/4"),
-    ("VICE (Commodore 64)", "vice_x64", "Commodore 64"),
-    ("VICE (Commodore 64)(Cycle-Exact)", "vice_x64sc", "Commodore 64"),
-    ("VICE (Commodore VIC-20)", "vice_xvic", "Commodore VIC-20"),
-    ("vitaQuake 2 (Quake 2)", "vitaquake2", "vitaQuake 2"),
-    ("vitaQuake 3 (Quake 3)", "vitaquake3", "vitaQuake 3"),
-]
+LIBRETRO_CORES = []
+runner_path = get_default_config_path()
+if os.path.exists(runner_path):
+    # Get core identifiers from info dir
+    info_path = get_default_config_path("info")
+    if not os.path.exists(info_path):
+        req = requests.get("http://buildbot.libretro.com/assets/frontend/info.zip", allow_redirects=True)
+        if req.status_code == requests.codes.ok:
+            open(get_default_config_path('info.zip'), 'wb').write(req.content)
+            with ZipFile(get_default_config_path('info.zip'), 'r') as info_zip:
+                info_zip.extractall(info_path)
+        else:
+            logger.error("Error retrieving libretro info archive from server: %s - %s", req.status_code)
+    # Parse info files to fetch display name and platform/system
+    if os.path.exists(info_path):
+        with os.scandir(info_path) as it:
+            for entry in it:
+                if entry.is_file():
+                    core_identifier = entry.name.replace("_libretro.info", "")
+                    core_config = RetroConfig(entry)
+                    if "categories" in core_config.keys() and "Emulator" in core_config["categories"]:
+                        core_label = core_config["display_name"] or ""
+                        core_system = core_config["systemname"] or ""
+                        LIBRETRO_CORES.append((core_label, core_identifier, core_system))
+            LIBRETRO_CORES.sort(key=itemgetter(0))
 
 
 def get_core_choices():
     return [(core[0], core[1]) for core in LIBRETRO_CORES]
 
 
-def get_default_config_path(path=""):
-    return os.path.join(settings.RUNNER_DIR, "retroarch", path)
-
-
 class libretro(Runner):
     human_name = "Libretro"
     description = "Multi system emulator"
diff --git a/lutris/runners/rpcs3.py b/lutris/runners/rpcs3.py
--- a/lutris/runners/rpcs3.py
+++ b/lutris/runners/rpcs3.py
@@ -1,4 +1,5 @@
 from lutris.runners.runner import Runner
+from lutris.util import system
 
 
 class rpcs3(Runner):
@@ -15,9 +16,26 @@ class rpcs3(Runner):
             "label": "Path to EBOOT.BIN",
         }
     ]
+    runner_options = [
+        {
+            "option": "nogui",
+            "type": "bool",
+            "label": "No GUI",
+            "default": False
+        }
+    ]
 
     # RPCS3 currently uses an AppImage, no need for the runtime.
     system_options_override = [{"option": "disable_runtime", "default": True}]
 
     def play(self):
-        return {"command": [self.get_executable(), self.game_config.get("main_file")]}
+        arguments = [self.get_executable()]
+
+        if self.runner_config.get("nogui"):
+            arguments.append("--no-gui")
+
+        eboot = self.game_config.get("main_file") or ""
+        if not system.path_exists(eboot):
+            return {"error": "FILE_NOT_FOUND", "file": eboot}
+        arguments.append(eboot)
+        return {"command": arguments}
diff --git a/lutris/util/libretro.py b/lutris/util/libretro.py
--- a/lutris/util/libretro.py
+++ b/lutris/util/libretro.py
@@ -18,12 +18,13 @@ def __init__(self, config_path):
                 line = line.strip()
                 if line == "" or line.startswith('#'):
                     continue
-                key, value = line.split("=", 1)
-                key = key.strip()
-                value = value.strip().strip('"')
-                if not key or not value:
-                    continue
-                self.config.append((key, value))
+                if '=' in line:
+                    key, value = line.split("=", 1)
+                    key = key.strip()
+                    value = value.strip().strip('"')
+                    if not key or not value:
+                        continue
+                    self.config.append((key, value))
 
     def save(self):
         with open(self.config_path, "w") as config_file:


Test patch: