Files
homelabstack/scripts/igir-strip-snes-headers.sh
T
ginnoir 57aba346f9 feat(roms): add igir report + SNES header-strip ops scripts
igir-report.ps1: read-only igir report over the EmuDeck tree on valhalla,
matching ROMs by checksum against libretro's No-Intro + Redump DAT sets
(sparse-cloned + cached). Scoped (-Platforms) or whole-library (-All);
CSV per run under /storage1/igir/reports. Uses node:lts (alpine breaks
igir on musl) and metadat/no-intro (not the curated dat/ folder).

igir-strip-snes-headers.sh: reversible backup-then-strip of 512-byte SNES
copier headers (size%1024==512) that igir can't auto-detect, renaming to
.sfc so headered ROMs match headerless No-Intro.
2026-06-05 20:54:17 -05:00

80 lines
2.9 KiB
Bash

#!/usr/bin/env bash
# scripts/igir-strip-snes-headers.sh (runs ON valhalla)
#
# SNES copier ROMs carry a 512-byte header (file size % 1024 == 512). igir
# detects SNES headers by content *signature*, which these copier headers lack,
# so it can't strip them and they never match headerless No-Intro DATs — even
# though their headerless checksum IS in No-Intro. This script blind-strips that
# 512-byte header (the universally-correct fix for SNES) and renames to .sfc.
#
# It is a MUTATION of the live EmuDeck tree (RomM + EmuDeck read it). Every
# touched file is tar'd to a backup first, so the change is fully reversible.
#
# Usage (default folder = snes):
# ssh ginnoir@valhalla 'bash -s' < scripts/igir-strip-snes-headers.sh
# ssh ginnoir@valhalla 'bash -s -- sfc' < scripts/igir-strip-snes-headers.sh
# ssh ginnoir@valhalla 'bash -s -- snes 1' < scripts/igir-strip-snes-headers.sh # 2nd arg=1 => dry run
#
# Restore from a backup:
# tar xzf /storage1/igir/backup/<folder>-headered-<stamp>.tar.gz \
# -C /storage1/Emulation/roms/<folder>
set -uo pipefail
FOLDER="${1:-snes}"
DRYRUN="${2:-0}"
ROOT="/storage1/Emulation/roms/$FOLDER"
BK="/storage1/igir/backup"
STAMP="$(date +%Y-%m-%d)"
[ -d "$ROOT" ] || { echo "No such folder: $ROOT"; exit 1; }
mkdir -p "$BK"
cd "$ROOT" || exit 1
shopt -s nullglob nocaseglob
# Collect headered SNES ROMs (size % 1024 == 512).
list="$(mktemp)"; : > "$list"
for f in *.smc *.sfc *.fig *.swc; do
[ -f "$f" ] || continue
s=$(stat -c %s "$f")
[ $((s % 1024)) -eq 512 ] && printf '%s\0' "$f" >> "$list"
done
n=$(grep -zc . "$list" || true)
echo "Headered files in '$FOLDER': $n"
if [ "$n" -eq 0 ]; then echo "Nothing to strip."; rm -f "$list"; exit 0; fi
if [ "$DRYRUN" = "1" ]; then
echo "(dry run) would back up to $BK/$FOLDER-headered-$STAMP.tar.gz and strip $n files."
rm -f "$list"; exit 0
fi
# Back up originals before mutating.
bkfile="$BK/$FOLDER-headered-$STAMP.tar.gz"
tar --null -czf "$bkfile" -T "$list"
echo "Backup: $bkfile ($(stat -c %s "$bkfile") bytes, $(tar tzf "$bkfile" | wc -l) files)"
# Strip: drop first 512 bytes, verify new size, write as .sfc, remove old.
stripped=0; errors=0
while IFS= read -r -d '' f; do
s=$(stat -c %s "$f")
base="${f%.*}"; target="$base.sfc"; tmp="$f.hl.tmp"
tail -c +513 "$f" > "$tmp"
ns=$(stat -c %s "$tmp")
if [ "$ns" -ne $((s - 512)) ]; then
echo "SIZE MISMATCH, skipped: $f ($s -> $ns)"; rm -f "$tmp"; errors=$((errors+1)); continue
fi
if [ "$target" != "$f" ] && [ -e "$target" ]; then target="$base (headerless).sfc"; fi
mv -f "$tmp" "$target"
[ "$target" != "$f" ] && rm -f "$f"
stripped=$((stripped+1))
done < "$list"
rm -f "$list"
# Verify none remain.
left=0
for f in *.smc *.sfc *.fig *.swc; do
[ -f "$f" ] || continue
s=$(stat -c %s "$f")
[ $((s % 1024)) -eq 512 ] && left=$((left+1))
done
echo "RESULT stripped=$stripped errors=$errors remaining_headered=$left"