mirror of
https://github.com/ksherlock/ample.git
synced 2026-04-06 10:19:51 +00:00
* Initialize and finalize AmpleWin: Full-featured Windows Port with Adaptive UI, optimized engine, and internationalized documentation * Update media args * AmpleWin: Finalized Windows Port with Adaptive UI, Optimized Engine, VGM Recording, and Shared Directory Support * Fix NameError: subprocess not defined in main.py * UI: Remove redundant MAME path label from Paths tab * UI: Implement smart slot validation for disabled options and click-to-browse Shared Directory * feat(win): editable console, launch logic fixes & doc updates * Fix path quoting issues, add file selectors for A/V, and normalize shared dir path * feat: sync with Ample v0.285 resources, update to MAME 0.285, and add ROM search filter * v0.285: Expand ROM library, implement download failover, and advanced SCSI sub-slot emulation * Adjust ROM download priority: prefer callapple.org for stability, mdk.cab as fallback * Sync roms.plist with upstream/master * docs(agent): record upstream synchronization session * refactor: rename mame_bin to mame directory * chore: update .gitignore for mame directory rename * fix(main): update download and detection paths to 'mame' * fix(main): robust path resolution for pyinstaller builds * docs(readme): add build_exe.bat to project structure * fix(build): remove creation of empty mame directory to avoid confusion * feat(build): auto-generate application icon from Assets.xcassets * Add AmpleLinux - Linux Port of Ample (Apple II/Mac emulator frontend) - Ported from AmpleWin with ~20 Linux-specific adaptations - Replaced winreg with gsettings/KDE dark mode detection - Replaced os.startfile with xdg-open - Removed MAME auto-download (users install via package manager) - Added system-wide MAME detection (PATH, /usr/bin, /usr/games) - Removed all .exe suffixes from binary references - Created AmpleLinux.sh launcher script - Dual-language READMEs (English + Traditional Chinese) * Fix: use python3 -m pip instead of pip3/pip for modern Linux compatibility * feat(linux): Finalize AmpleLinux port documentation and build scripts * Fix formatting for Windows and Linux user notes Updated user guidance for Windows and Linux users. * feat(linux): interactive .desktop install, runtime icon loading, updated docs * docs(linux): clarify mame_downloader.py usage status * docs: add PR draft template * fix(linux): add binutils dependency check for pyinstaller * Update: mame 0.286 --------- Co-authored-by: User <user@example.com>
142 lines
5.1 KiB
Python
142 lines
5.1 KiB
Python
import xml.etree.ElementTree as ET
|
|
import os
|
|
import plistlib
|
|
|
|
class DataManager:
|
|
def __init__(self, resources_path, hash_path=None):
|
|
self.resources_path = resources_path
|
|
self.hash_path = hash_path
|
|
self.models = self.load_plist('models.plist')
|
|
self.roms = self.load_plist('roms.plist')
|
|
self.machine_cache = {}
|
|
self.software_cache = {}
|
|
|
|
def load_plist(self, filename):
|
|
path = os.path.join(self.resources_path, filename)
|
|
if not os.path.exists(path):
|
|
print(f"DEBUG: DataManager failed to find: {path}")
|
|
return None
|
|
with open(path, 'rb') as f:
|
|
return plistlib.load(f)
|
|
|
|
def get_machine_description(self, machine_name):
|
|
if machine_name in self.machine_cache:
|
|
return self.machine_cache[machine_name]
|
|
|
|
desc = self.load_plist(f'{machine_name}.plist')
|
|
if desc:
|
|
self.machine_cache[machine_name] = desc
|
|
return desc
|
|
|
|
def get_software_lists(self, machine_name):
|
|
desc = self.get_machine_description(machine_name)
|
|
if not desc or 'software' not in desc:
|
|
return []
|
|
|
|
results = []
|
|
for item in desc['software']:
|
|
xml_file = None
|
|
filter_val = None
|
|
if isinstance(item, str):
|
|
xml_file = item
|
|
elif isinstance(item, dict):
|
|
xml_file = item.get('name')
|
|
filter_val = item.get('filter')
|
|
elif isinstance(item, list) and len(item) >= 1:
|
|
xml_file = item[0]
|
|
if len(item) >= 2:
|
|
filter_val = item[1]
|
|
|
|
if xml_file:
|
|
# Ensure .xml extension
|
|
if not xml_file.endswith(".xml"):
|
|
xml_file += ".xml"
|
|
|
|
list_name = xml_file.replace(".xml", "")
|
|
software_items = self.load_software_xml(xml_file)
|
|
|
|
# We always append to results if the XML exists,
|
|
# even if items are empty (to show the header at least)
|
|
if xml_file in self.software_cache:
|
|
filtered_items = software_items
|
|
if filter_val:
|
|
# Improved comma-aware filtering
|
|
filtered_items = []
|
|
for s in software_items:
|
|
comp = s.get('compatibility')
|
|
if not comp:
|
|
filtered_items.append(s)
|
|
else:
|
|
if filter_val in comp.split(','):
|
|
filtered_items.append(s)
|
|
|
|
results.append({
|
|
'name': list_name,
|
|
'description': self.software_cache[xml_file]['description'],
|
|
'items': filtered_items
|
|
})
|
|
return results
|
|
|
|
def load_software_xml(self, xml_file):
|
|
if xml_file in self.software_cache:
|
|
return self.software_cache[xml_file]['items']
|
|
|
|
if not self.hash_path:
|
|
return []
|
|
|
|
path = os.path.join(self.hash_path, xml_file)
|
|
if not os.path.exists(path):
|
|
return []
|
|
|
|
try:
|
|
tree = ET.parse(path)
|
|
root = tree.getroot()
|
|
|
|
list_desc = root.attrib.get('description', xml_file.replace(".xml", ""))
|
|
items = []
|
|
|
|
for sw in root.findall('software'):
|
|
sw_name = sw.attrib.get('name')
|
|
sw_desc = sw.find('description')
|
|
sw_desc_text = sw_desc.text if sw_desc is not None else sw_name
|
|
|
|
# Check for compatibility
|
|
compatibility = None
|
|
for sharedfeat in sw.findall('sharedfeat'):
|
|
if sharedfeat.attrib.get('name') == 'compatibility':
|
|
compatibility = sharedfeat.attrib.get('value')
|
|
break
|
|
|
|
items.append({
|
|
'name': sw_name,
|
|
'description': sw_desc_text,
|
|
'compatibility': compatibility
|
|
})
|
|
|
|
# Sort items by description
|
|
items.sort(key=lambda x: x['description'].lower())
|
|
|
|
self.software_cache[xml_file] = {
|
|
'description': list_desc,
|
|
'items': items
|
|
}
|
|
return items
|
|
except Exception as e:
|
|
print(f"Error parsing software XML {xml_file}: {e}")
|
|
return []
|
|
|
|
def get_flat_machines(self, models=None):
|
|
if models is None:
|
|
models = self.models
|
|
|
|
machines = []
|
|
for model in models:
|
|
if 'value' in model and model['value']:
|
|
machines.append({
|
|
'name': model['value'],
|
|
'description': model.get('description', model['value'])
|
|
})
|
|
if 'children' in model:
|
|
machines.extend(self.get_flat_machines(model['children']))
|
|
return machines
|