exl100

Émulateur Exelvision EXL 100 (1984) dans le navigateur : dsp-cpp en WebAssembly, cartouches et cassettes BASIC
git clone https://git.schurger.org/exl100.git
Log | Files | Refs | README

commit 3d2d82a0d2217761372fcbbe78f64e4c8f7dac8f
parent dc75262734fe3bd87e4f285475ccd10f6dfb5a3c
Author: Jean Schurger <jean@schurger.org>
Date:   Wed,  4 Nov 2026 17:30:16 -0500

Couverture webmo.fr : +3 cartouches (Pindo, Edigraf, Exelvox) et +démos

Vérification de la couverture du site de préservation webmo.fr (ti99/exelvision) : il
manquait 3 cartouches absentes du pack TOSEC (PINDO = hash MAME 16K ; EDIGRAF et EXELVOX
= dumps 32768 qui se chargent quand même), téléchargées de webmo.fr par get_cartridges.py.
Cassettes élargies à la catégorie Démos (dont « Faites parler votre EXL100 »), cap 160 :
18 cartouches + 108 cassettes. Puce de filtre « Démos » ajoutée. Restent hors couverture
les cassettes webmo exclusives en .wav uniquement et celles à 64 Ko (extension mémoire).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QyJB9yqUAYm3wRQi4uytj9

Diffstat:
Mtools/get_cartridges.py | 29+++++++++++++++++++++++++----
Mweb/shell.html.in | 1+
2 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/tools/get_cartridges.py b/tools/get_cartridges.py @@ -50,7 +50,7 @@ def slug_of(title): s = re.sub(r"[^a-z0-9]+", "-", s).strip("-") return s or "cart" -# Catégorie depuis le dossier TOSEC (Games / Applications / Educational). +# Catégorie depuis le dossier TOSEC (Games / Applications / Educational / Demos). def cat_of(root): if "Games" in root: return "jeu" @@ -58,8 +58,28 @@ def cat_of(root): return "educatif" if "Applications" in root: return "application" + if "Demos" in root: + return "demo" return "" +# Cartouches présentes sur webmo.fr mais absentes du pack TOSEC (dumps bourrés à 32768, qui se +# chargent quand même). PINDO correspond au hash MAME. +WEBMO = "https://p7398.webmo.fr/httpdocs/exelvision/website/telechargement" +WEBMO_CARTS = { + "pindo.bin": ("PINDO.ROM", {"t": "Pindo", "by": "Minipuce", "y": "1986", "cat": "jeu"}), + "edigraf.bin": ("EDIGRAF.ROM", {"t": "Edigraf", "by": "P. Glajean", "y": "1987", "cat": "application"}), + "exelvox.bin": ("EXELVOX.ROM", {"t": "Exelvox", "by": "Exelvision", "y": "198x", "cat": "application"}), +} +def webmo_cartridges(titles): + for out, (fn, meta) in WEBMO_CARTS.items(): + req = urllib.request.Request(f"{WEBMO}/{fn}", headers={"User-Agent": "Mozilla/5.0"}) + with urllib.request.urlopen(req, timeout=60) as r: + data = r.read() + with open(os.path.join(OUT, out), "wb") as f: + f.write(data) + titles[out] = meta + print(f" {out:22s} {len(data):6d} o (webmo.fr) {meta['t']}", file=sys.stderr) + def main(): rar = os.path.join(tempfile.gettempdir(), "exl100-tosec.rar") if not os.path.exists(rar) or os.path.getsize(rar) < 1_000_000: @@ -91,6 +111,7 @@ def main(): titles[out] = {"t": title, "by": by, "y": year, "cat": cat_of(root)} print(f" {out:22s} {len(data):6d} o crc={zlib.crc32(data) & 0xffffffff:08x} {title} — {by} {year}", file=sys.stderr) + webmo_cartridges(titles) # PINDO, EDIGRAF, EXELVOX (absents de TOSEC) with open(os.path.join(OUT, "titles.json"), "w", encoding="utf-8") as f: json.dump(dict(sorted(titles.items(), key=lambda kv: kv[1]["t"].lower())), f, ensure_ascii=False, indent=1) @@ -100,14 +121,14 @@ def main(): # Cassettes [K7] (programmes BASIC) : jeux et applications, versions de base seulement. TAPES_OUT = os.path.join(HERE, "roms", "tapes") TAPE_SKIP = ("[h ", "[a]", "[b", "[req 64kb]", "side b", "(beta)", "[unreleased]", "(side a)") -def extract_tapes(tmp, limit=120): +def extract_tapes(tmp, limit=160): os.makedirs(TAPES_OUT, exist_ok=True) titles = {} for root, _, files in os.walk(tmp): if "- [K7] " not in root: continue - # On garde les jeux et applications, pas les démos ni compilations. - if ("Games" not in root and "Educational" not in root and "Applications" not in root): + # Jeux, applications, éducatif ET démos (dont « Faites parler votre EXL100 »). + if not any(c in root for c in ("Games", "Educational", "Applications", "Demos")): continue for fn in sorted(files): if not fn.lower().endswith(".zip"): diff --git a/web/shell.html.in b/web/shell.html.in @@ -155,6 +155,7 @@ <button class="chip" type="button" data-f="jeu">Jeux</button> <button class="chip" type="button" data-f="application">Applications</button> <button class="chip" type="button" data-f="educatif">Éducatif</button> + <button class="chip" type="button" data-f="demo">Démos</button> </div> <div id="programs" class="programs" role="listbox" aria-label="Programmes"></div> <p class="modal-src">Contenu préservé par le pack <b>TOSEC</b> sur