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:
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