Last active
August 29, 2021 09:40
-
-
Save Miss-Inputs/e8f44d7e5b8315e88fe0ed09b48a2c81 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import os | |
import glob | |
from urllib.request import urlopen | |
from urllib.error import HTTPError, URLError | |
from xml.etree import ElementTree | |
source_path = '/home/megan/351ELEC' | |
es_config_path = os.path.join(source_path, 'packages', 'ui', '351elec-emulationstation', 'config') | |
es_systems_path = os.path.join(es_config_path, 'es_systems.cfg') | |
es_systems = ElementTree.parse(es_systems_path) | |
#This feels like the wrong way to get the locally "built" core info directory, but the version can change… | |
try: | |
core_info_directory = glob.glob(os.path.join(source_path, 'build.351ELEC-RG351P.aarch64', 'core-info-*'))[0] | |
except IndexError: | |
core_info_directory = None | |
variant_systems = { | |
#We probably expect all the emulators for these to be the same | |
#'arcade': ['cps1', 'cps2', 'cps3', 'neogeo'], #maybe not though | |
'gb': ['gbh'], | |
'gbc': ['gbch'], | |
'gba': ['gbah'], | |
'gamegear': ['ggh'], | |
'megacd': ['segacd'], | |
'megadrive': ['megadrive-japan', 'genesis', 'genh'], | |
'nes': ['famicom', 'nesh'], | |
'pcengine': ['tg16'], | |
'pcenginecd': ['tg16cd'], | |
'psp': ['pspminis'], | |
'snes': ['snesh', 'sfc'], | |
} | |
subset_systems = { | |
#Where x: y; we expect all emulators for y to also emulate x, but there could reasonably be an emulator for x which doesn't do y | |
'nes': ['fds'], | |
'snes': ['snesmsu1', 'satellaview'], | |
'pcengine': ['supergrafx', 'pcenginecd'], | |
'tg16': ['tg16cd'], | |
'megadrive': ['megacd', 'sega32x'], | |
'odyssey2': ['videopac'], #maybe this is an okay assumption to make? | |
#Maybe amiga > amigacd32? | |
#amstradcpc > gx4000 but that ended up not being a thing | |
'gb': ['gbc'], | |
'ngp': ['ngpc'], | |
'wonderswan': ['wonderswancolor'], | |
} | |
systems = {system.findtext('name'): system for system in es_systems.findall('system')} | |
def get_emulators(system_name): | |
emulators_tag = systems[system_name].find('emulators') | |
if emulators_tag is None: | |
#This isn't a concern, tools/screenshots etc has no emulators defined | |
return {} | |
return {emulator.attrib['name']: [core.text for core in emulator.find('cores').findall('core')] for emulator in emulators_tag.findall('emulator')} | |
def get_emulator_set(system_name): | |
return {emulator_name + '/' + core for emulator_name, emulators in get_emulators(system_name).items() for core in emulators} | |
def parse_core_info(core_info): | |
d = {} | |
for line in core_info.splitlines(): | |
line = line.strip() | |
if not line: | |
continue | |
if line.startswith('#'): | |
continue | |
if ' = ' not in line: | |
print('wat', line) | |
continue | |
k, v = line.split(' = ', 1) | |
d[k] = v | |
return d | |
def get_core_info(core_name): | |
info_name = core_name + '_libretro.info' | |
core_info_path = os.path.join(core_info_directory, info_name) | |
if core_info_directory: | |
try: | |
with open(core_info_path, 'rt') as core_info: | |
return parse_core_info(core_info.read()) | |
except FileNotFoundError: | |
print(core_name, 'does not have an info file in the local build, maybe it is new') | |
url = 'http://raw.githubusercontent.com/libretro/libretro-core-info/master/' + info_name.replace('beetle_', 'mednafen_') #Going to be renamed upstream later I guess | |
try: | |
with urlopen(url) as response: | |
data = response.read().decode('utf-8') | |
with open(core_info_path, 'wt') as core_info: | |
core_info.write(data) | |
return parse_core_info(data) | |
except (HTTPError, URLError): | |
print('Warning!', core_name, 'does not have an info file remotely') | |
return None | |
def get_core_extensions(core_name): | |
core_info = get_core_info(core_name) | |
if not core_info: | |
return set() | |
supported_extensions = core_info.get('supported_extensions') | |
if not supported_extensions: | |
return set() | |
return set(supported_extensions.strip('"').split('|')) | |
def get_system_extensions(system): | |
return set(ext.lstrip('.').lower() for ext in system.findtext('extension').strip().split(' ')) | |
def check_emus_are_same(): | |
for base_variant_system, variants in variant_systems.items(): | |
base_emulators = get_emulator_set(base_variant_system) | |
base_extensions = get_system_extensions(systems[base_variant_system]) | |
for variant in variants: | |
variant_emulators = get_emulator_set(variant) | |
for base_only_emulator in base_emulators - variant_emulators: | |
print(base_only_emulator, 'exists in', base_variant_system, 'but not', variant) | |
for variant_only_emulator in variant_emulators - base_emulators: | |
print(variant_only_emulator, 'exists in', variant, 'but not', base_variant_system) | |
variant_extensions = get_system_extensions(systems[variant]) | |
base_only_extensions = base_extensions - variant_extensions | |
if base_only_extensions: | |
print(base_variant_system, 'has extensions that', variant, 'does not have (maybe intended):', base_only_extensions) | |
variant_only_extensions = variant_extensions - base_extensions | |
if variant_only_extensions: | |
print(variant, 'has extensions that', base_variant_system, 'does not have (maybe intended):', variant_only_extensions) | |
for base_subset_system, subsets in subset_systems.items(): | |
base_emulators = get_emulator_set(base_subset_system) | |
for subset in subsets: | |
subset_emulators = get_emulator_set(subset) | |
for subset_only_emulator in subset_emulators - base_emulators: | |
print(subset_only_emulator, 'exists in', subset, 'but not', base_subset_system) | |
def check_libretro_cores(): | |
core_extensions = {} | |
defined_exts_for_systems_using_core = {} | |
for system_name, system in systems.items(): | |
emulators = get_emulators(system_name) | |
if not emulators: | |
continue | |
cores = emulators.get('libretro', emulators.get('retroarch')) | |
if not cores: | |
continue | |
for core in cores: | |
if core not in core_extensions: | |
core_extensions[core] = get_core_extensions(core) | |
if core not in defined_exts_for_systems_using_core: | |
defined_exts_for_systems_using_core[core] = [] | |
defined_exts_for_systems_using_core[core] += list(get_system_extensions(system)) | |
print(core_extensions['fceumm']) | |
for system_name, system in systems.items(): | |
emulators = get_emulators(system_name) | |
retroarch_cores = emulators.get('libretro') #This is going to be changed to 'retroarch' in the not too distant future I think | |
retrorun_cores = emulators.get('retrorun') | |
if retroarch_cores is not None: | |
if retrorun_cores is not None: | |
for retrorun_only in set(retrorun_cores) - set(retroarch_cores): | |
print(system_name, 'has', retrorun_only, 'core for retrorun but not RetroArch') | |
for retroarch_only in set(retroarch_cores) - set(retrorun_cores): | |
print(system_name, 'has', retroarch_only, 'core for RetroArch but not retrorun, but retrorun is used for this system') #Maybe that is allowed? | |
if system_name not in ('doom', 'scummvm', 'ecwolf'): | |
defined_extensions = get_system_extensions(system) | |
system_core_extensions = {core: core_extensions[core] for core in retroarch_cores} | |
all_core_extensions = set(ext for core_exts in system_core_extensions.values() for ext in core_exts) | |
if not (set(emulators) - {'libretro', 'retroarch', 'retrorun'}): | |
#Don't try and figure out any weird extensions if there are any standalone emulators, since we don't know the extensions of standalone emulators | |
defined_junk_extensions = (defined_extensions - {'7z', 'zip'}) - all_core_extensions | |
if defined_junk_extensions: | |
print(system_name, 'has extensions defined which are not listed as supported for any of the cores:', defined_junk_extensions) | |
if system_name not in [v for vv in variant_systems.values() for v in vv]: | |
for core_name in retroarch_cores: | |
if not core_name.startswith(('fbneo', 'fbalpha', 'mame')): | |
#Hmm I'm tired and looking at this code like a week later, does it make sense or should it be using defined_extensions | |
extra_extensions = core_extensions[core_name] - set(defined_exts_for_systems_using_core[core_name]) | |
if extra_extensions: | |
print('May not be an issue but', core_name, 'seems to support', extra_extensions, 'not defined for', system_name) | |
check_emus_are_same() | |
check_libretro_cores() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment