mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-16 08:23:28 -05:00
fix: keep recalbox and libretro entries on export
This commit is contained in:
1 parent
7cb2c21dd9
commit
ff5e5145fd
3 files changed
+150
-19
No files matched your search
@@ -115,18 +115,56 @@ class Exporter(BaseExporter):
|
||||
'<biosList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'
|
||||
' xsi:noNamespaceSchemaLocation="es_bios.xsd">',
|
||||
]
|
||||
# Recalbox's own file is the base, so an element our transcription
|
||||
# does not carry (added or renamed after a scrape) stays as written,
|
||||
# and its system order with it.
|
||||
theirs: list[tuple[str, str, list[dict[str, str]]]] = []
|
||||
original = originals.get(self.native_filename(), "")
|
||||
if original:
|
||||
try:
|
||||
root = parse_untrusted_xml(original, self.native_filename())
|
||||
except (ParseError, ValueError):
|
||||
root = None
|
||||
if root is not None:
|
||||
theirs = [
|
||||
(s.get("platform", ""), s.get("fullname", ""),
|
||||
[dict(b.attrib) for b in s.iter("bios")])
|
||||
for s in root.iter("system")
|
||||
]
|
||||
|
||||
for system in sorted(systems.values(), key=lambda s: s.native_id):
|
||||
ours: dict[str, tuple[NativeSystem, dict[str, str]]] = {}
|
||||
for system in systems.values():
|
||||
writable = [fe for fe in system.files if self.writable(fe)]
|
||||
if not writable:
|
||||
continue
|
||||
fullname = quoteattr(self.display_name(system))
|
||||
platform = quoteattr(system.native_id)
|
||||
lines.append(f" <system fullname={fullname} platform={platform}>")
|
||||
for fe in writable:
|
||||
lines.append(self._bios_element(fe, system.native_id))
|
||||
if writable:
|
||||
ours[system.native_id] = (system, {
|
||||
self._path(fe): self._bios_element(fe, system.native_id)
|
||||
for fe in writable
|
||||
})
|
||||
|
||||
def element(attrs: dict[str, str]) -> str:
|
||||
rendered = " ".join(f"{k}={quoteattr(v)}" for k, v in attrs.items())
|
||||
return f" <bios {rendered} />"
|
||||
|
||||
def emit(platform: str, fullname: str, body: list[str]) -> None:
|
||||
lines.append(
|
||||
f" <system fullname={quoteattr(fullname)} platform={quoteattr(platform)}>"
|
||||
)
|
||||
lines.extend(body)
|
||||
lines.append(" </system>")
|
||||
|
||||
for platform, fullname, bios in theirs:
|
||||
if platform not in ours:
|
||||
emit(platform, fullname, [element(attrs) for attrs in bios])
|
||||
continue
|
||||
system, elements = ours.pop(platform)
|
||||
body = [elements.pop(attrs.get("path", ""), None) or element(attrs)
|
||||
for attrs in bios]
|
||||
body.extend(elements.values())
|
||||
emit(platform, self.display_name(system), body)
|
||||
for platform in sorted(ours):
|
||||
system, elements = ours[platform]
|
||||
emit(platform, self.display_name(system), list(elements.values()))
|
||||
|
||||
lines.append("</biosList>")
|
||||
lines.append("")
|
||||
return {self.native_filename(): "\n".join(lines)}
|
||||
|
||||
@@ -36,6 +36,23 @@ def _quote(name: str, quoted: frozenset[str] = frozenset()) -> str:
|
||||
return f'"{name}"' if name in quoted or any(c in name for c in ' ()') else name
|
||||
|
||||
|
||||
_ROM_NAME = re.compile(r'^\trom \( name ("[^"]+"|\S+)')
|
||||
|
||||
|
||||
def _sections(original: str) -> list[tuple[str, list[str]]]:
|
||||
"""The system sections of a System.dat, each comment with its rom lines."""
|
||||
_, sep, body = original.partition("\ngame (")
|
||||
if not sep:
|
||||
return []
|
||||
sections: list[tuple[str, list[str]]] = []
|
||||
for line in body.splitlines():
|
||||
if line.startswith('\tcomment "') and line != '\tcomment "System"':
|
||||
sections.append((line[len('\tcomment "'):].rstrip('"'), []))
|
||||
elif line.startswith("\trom (") and sections:
|
||||
sections[-1][1].append(line)
|
||||
return sections
|
||||
|
||||
|
||||
class Exporter(BaseExporter):
|
||||
"""Write libretro's System.dat, corrected."""
|
||||
|
||||
@@ -118,16 +135,17 @@ class Exporter(BaseExporter):
|
||||
) -> dict[str, str]:
|
||||
lines = self._header(originals, scraped)
|
||||
lines.extend(["game (", '\tname "System"', '\tcomment "System"'])
|
||||
quoted = frozenset(_QUOTED_NAME.findall(originals.get(self.native_filename(), "")))
|
||||
original = originals.get(self.native_filename(), "")
|
||||
quoted = frozenset(_QUOTED_NAME.findall(original))
|
||||
|
||||
for system, files in sorted(
|
||||
self.exportable(systems), key=lambda pair: pair[0].native_id
|
||||
):
|
||||
rendered: list[str] = []
|
||||
ours: dict[str, dict[str, str]] = {}
|
||||
for system, files in self.exportable(systems):
|
||||
rendered: dict[str, str] = {}
|
||||
for fe in files:
|
||||
if not any(fe.hash(h) for h in ("crc32", "md5", "sha1")):
|
||||
continue
|
||||
parts = [f"name {_quote(self._rom_name(fe), quoted)}"]
|
||||
name = _quote(self._rom_name(fe), quoted)
|
||||
parts = [f"name {name}"]
|
||||
size = fe.size()
|
||||
if size:
|
||||
parts.append(f"size {size}")
|
||||
@@ -140,15 +158,29 @@ class Exporter(BaseExporter):
|
||||
sha1 = fe.hash("sha1")
|
||||
if sha1:
|
||||
parts.append(f"sha1 {sha1}")
|
||||
rendered.append(f"\trom ( {' '.join(parts)} )")
|
||||
rendered.setdefault(name, f"\trom ( {' '.join(parts)} )")
|
||||
if rendered:
|
||||
ours[system.native_id] = rendered
|
||||
|
||||
if not rendered:
|
||||
continue
|
||||
def section(comment: str, roms: list[str]) -> None:
|
||||
lines.append("")
|
||||
# libretro's comment is the system name as the DAT spells it,
|
||||
# "Atari - 400-800". Prettifying it drops the separator.
|
||||
lines.append(f'\tcomment "{system.native_id}"')
|
||||
lines.extend(rendered)
|
||||
lines.append(f'\tcomment "{comment}"')
|
||||
lines.extend(roms)
|
||||
|
||||
# libretro's own sections are the base: a rom line our transcription
|
||||
# does not carry (added or renamed after a scrape) stays as written.
|
||||
for comment, roms in _sections(original):
|
||||
rendered = ours.pop(comment, {})
|
||||
body = []
|
||||
for line in roms:
|
||||
match = _ROM_NAME.match(line)
|
||||
body.append(rendered.pop(match.group(1), line) if match else line)
|
||||
body.extend(rendered.values())
|
||||
section(comment, body)
|
||||
for comment in sorted(ours):
|
||||
section(comment, list(ours[comment].values()))
|
||||
|
||||
lines.append(")")
|
||||
lines.append("")
|
||||
|
||||
Reference in new issue
Block a user