282 lines
8.7 KiB
Python
282 lines
8.7 KiB
Python
import glob
|
|
import os
|
|
import pickle
|
|
import re
|
|
import subprocess
|
|
from xml.sax.saxutils import unescape
|
|
import zipfile
|
|
|
|
from lxml import etree
|
|
|
|
|
|
class MessROM(object):
|
|
''' One Mame Software List ROM '''
|
|
|
|
def __init__(self):
|
|
self.name = ''
|
|
self.cloneof = None
|
|
self.description = ''
|
|
self.year = ''
|
|
self.manufacturer = ''
|
|
self.category = ''
|
|
|
|
def __str__(self):
|
|
return self.description
|
|
# return '["%s", "%s", "%s", "%s", "%s" "%s", "%s"]' % (
|
|
# self.name, self.cloneof, self.description, self.year,
|
|
# self.manufacturer, self.status, self.category)
|
|
|
|
def __repr__(self):
|
|
return '%s("%s", "%s", "%s", "%s", "%s", "%s")' % (
|
|
self.__class__.__name__, self.name, self.cloneof, self.description,
|
|
self.year, self.manufacturer, self.category)
|
|
|
|
|
|
class MessROMs(object):
|
|
''' A Collection of MAME Software List Roms '''
|
|
|
|
def __init__(self, data_dir, cfg):
|
|
self.all_roms = []
|
|
self.roms = []
|
|
self.categories = []
|
|
self.all_categories = []
|
|
self.catdict = {}
|
|
self.len = 0
|
|
self.data_dir = data_dir
|
|
self.cfg = cfg
|
|
self.emulator_dir = os.path.split(cfg['EXE'])[0]
|
|
|
|
self.parse()
|
|
self.filter()
|
|
|
|
self.snapdir = os.path.join(self.emulator_dir, 'snap')
|
|
if os.path.isfile(os.path.join(self.snapdir, 'snap.zip')):
|
|
self.snapfile = zipfile.ZipFile(
|
|
os.path.join(self.snapdir, "snap.zip"))
|
|
else:
|
|
self.snapfile = None
|
|
self.snapdir = os.path.join(self.snapdir, 'snap')
|
|
|
|
infofn = os.path.join(self.emulator_dir, 'messinfo.dat')
|
|
if not os.path.isfile(infofn):
|
|
self.info = None
|
|
else:
|
|
with open(infofn, 'rt', encoding='latin1') as f:
|
|
self.info = f.read()
|
|
|
|
historyfn = os.path.join(self.emulator_dir, 'history.dat')
|
|
if not os.path.isfile(historyfn):
|
|
self.history = None
|
|
else:
|
|
with open(historyfn, 'rt', encoding='utf-8') as f:
|
|
self.history = f.read()
|
|
|
|
def __len__(self):
|
|
return self.len
|
|
|
|
def __getitem__(self, item):
|
|
return self.roms[item]
|
|
|
|
def filter(self):
|
|
self.roms = []
|
|
|
|
for rom in self.all_roms:
|
|
if self.cfg["Category"] == "All Games" or self.cfg["Category"] == rom.category:
|
|
if self.cfg["ShowClones"] or rom.cloneof is None:
|
|
self.roms.append(rom)
|
|
|
|
if self.cfg["Sort"] == "Name Asc":
|
|
self.roms.sort(key=lambda x: x.description.lower(), reverse=False)
|
|
elif self.cfg["Sort"] == "Name Dec":
|
|
self.roms.sort(key=lambda x: x.description.lower(), reverse=True)
|
|
elif self.cfg["Sort"] == "Year Asc":
|
|
self.roms.sort(key=lambda x: x.year.lower(), reverse=False)
|
|
elif self.cfg["Sort"] == "Year Dec":
|
|
self.roms.sort(key=lambda x: x.year.lower(), reverse=True)
|
|
|
|
self.len = len(self.roms)
|
|
|
|
self.categories = self.all_categories
|
|
|
|
def parse(self):
|
|
""" Parse xml """
|
|
|
|
mess_version = self.get_mess_version()
|
|
datfile = os.path.join(self.data_dir, 'mess.dat')
|
|
|
|
if self.cfg['Version'] != mess_version:
|
|
self.cfg['Version'] = mess_version
|
|
|
|
if os.path.isfile(datfile):
|
|
os.unlink(datfile)
|
|
|
|
if os.path.isfile(datfile):
|
|
with open(datfile, 'rb') as i:
|
|
temp_mess_version = pickle.load(i)
|
|
|
|
if temp_mess_version == mess_version:
|
|
self.all_categories = pickle.load(i)
|
|
self.all_roms = pickle.load(i)
|
|
return True
|
|
else:
|
|
os.unlink(datfile)
|
|
|
|
self.all_categories = []
|
|
self.catdict = {}
|
|
|
|
files = glob.glob(os.path.join(self.emulator_dir, "hash", '*.xml'))
|
|
for file in files:
|
|
with open(file, 'rt', encoding='utf-8') as f:
|
|
line = None
|
|
while True:
|
|
line = f.readline().strip()
|
|
if line.startswith('<softwarelist name'):
|
|
break
|
|
self.all_categories.append(
|
|
unescape(line[line.find('ion=') + 5:-2]))
|
|
self.catdict[self.all_categories[-1]] = file
|
|
self.catdict[file] = self.all_categories[-1]
|
|
# TODO: Fix me for emulator names
|
|
# <softwarelist name="n64" description="Nintendo 64 cartridges">
|
|
self.all_categories.sort()
|
|
|
|
# pylint: disable=no-member
|
|
for xmlfile in files:
|
|
tree = etree.parse(xmlfile)
|
|
|
|
rom = None
|
|
for child in tree.getiterator():
|
|
if child.tag == 'software':
|
|
if rom:
|
|
rom.category = self.catdict[xmlfile]
|
|
self.all_roms.append(rom)
|
|
rom = None
|
|
if 'supported' not in child.attrib or child.attrib['supported'] != 'no':
|
|
rom = MessROM()
|
|
rom.name = child.attrib['name']
|
|
else:
|
|
rom = None
|
|
if rom and 'cloneof' in child.attrib:
|
|
rom.cloneof = child.attrib['cloneof']
|
|
elif rom and child.tag == 'description':
|
|
rom.description = child.text
|
|
elif rom and child.tag == 'year':
|
|
rom.year = child.text
|
|
elif rom and child.tag == 'publisher':
|
|
rom.manufacturer = child.text
|
|
|
|
if rom:
|
|
rom.category = self.catdict[xmlfile]
|
|
self.all_roms.append(rom)
|
|
|
|
self.all_categories.insert(0, 'All Games')
|
|
self.all_categories.append('Unknown')
|
|
|
|
with open(datfile, 'wb') as output:
|
|
pickle.dump(mess_version, output)
|
|
pickle.dump(self.all_categories, output)
|
|
pickle.dump(self.all_roms, output)
|
|
|
|
return True
|
|
|
|
def get_mess_version(self):
|
|
mamerun = subprocess.run(
|
|
[self.cfg['EXE'], '-?'], stdout=subprocess.PIPE)
|
|
output = mamerun.stdout.decode('utf-8')
|
|
output = output[output.find('v'):]
|
|
output = output[:output.find(' ')]
|
|
|
|
return output
|
|
|
|
def get_snap(self, rom, type_of_image): # pylint : disable=R0912
|
|
data = None
|
|
image_file = None
|
|
image_dir = None
|
|
|
|
if type_of_image == 'snap':
|
|
image_dir = self.snapdir
|
|
image_file = self.snapfile
|
|
|
|
if image_file:
|
|
try:
|
|
data = image_file.read(rom.name + ".png")
|
|
except:
|
|
try:
|
|
data = image_file.read(rom.cloneof + '.png')
|
|
except:
|
|
data = None
|
|
elif image_dir:
|
|
fn = os.path.join(image_dir, rom.name + '.png')
|
|
if os.path.isfile(fn):
|
|
with open(fn, 'rb') as f:
|
|
data = f.read()
|
|
elif rom.cloneof:
|
|
fn = os.path.join(image_dir, rom.cloneof + '.png')
|
|
if os.path.isfile(fn):
|
|
with open(fn, 'rb') as f:
|
|
data = f.read()
|
|
else:
|
|
data = None
|
|
else:
|
|
data = None
|
|
else:
|
|
data = None
|
|
|
|
return data
|
|
|
|
def get_info(self, rom):
|
|
if not self.info:
|
|
return
|
|
|
|
search = re.search("\\$info=%s" % rom.name, self.info)
|
|
|
|
if not search:
|
|
search = re.search("\\$info=%s" % rom.cloneof, self.info)
|
|
if not search:
|
|
return None
|
|
|
|
start = search.start()
|
|
|
|
info = self.info[start:self.info.find('$end', start)].splitlines()
|
|
|
|
for i in range(len(info) - 1, -1, -1):
|
|
if info[i].startswith('$'):
|
|
del info[i]
|
|
|
|
while info[0].strip() == '':
|
|
del info[0]
|
|
|
|
while info[len(info) - 1].strip() == '':
|
|
del info[len(info) - 1]
|
|
|
|
return '\n'.join(info)
|
|
|
|
def get_history(self, rom):
|
|
print(rom.name)
|
|
if not self.history:
|
|
return
|
|
|
|
search = re.search("\\$info=%s" % rom.name, self.history)
|
|
|
|
if not search:
|
|
search = re.search("\\$info=%s" % rom.cloneof, self.history)
|
|
if not search:
|
|
return None
|
|
|
|
start = search.start()
|
|
|
|
info = self.history[start:self.history.find('$end',
|
|
start)].splitlines()
|
|
|
|
for i in range(len(info) - 1, -1, -1):
|
|
if info[i].startswith('$'):
|
|
del info[i]
|
|
|
|
while info[0].strip() == '':
|
|
del info[0]
|
|
|
|
while info[len(info) - 1].strip() == '':
|
|
del info[len(info) - 1]
|
|
|
|
return '\n'.join(info)
|