diff --git a/README.md b/README.md index c9404a478..40c189098 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ $ igir --help | $$ | $$| \ | $$ | $$ $$ ROM collection manager | $$ | $$| \ | $$ | $$ $$ https://igir.io/ | $$ | $$ \$$$$ | $$ | $$$$$$$\ - _| $$_ | $$__| $$ _| $$_ | $$ | $$ v2.1.0 + _| $$_ | $$__| $$ _| $$_ | $$ | $$ v2.1.1 | $$ \ \$$ $$| $$ \| $$ | $$ \$$$$$$ \$$$$$$ \$$$$$$ \$$ \$$ @@ -204,12 +204,15 @@ Advanced usage: {outputName} The output file's filename without extension {outputExt} The output file's extension - {pocket} The ROM's core-specific /Assets/* directory for the Analogue Pocket (e.g. "gb") - {mister} The ROM's core-specific /games/* directory for the MiSTer FPGA (e.g. "Gameboy") - {onion} The ROM's emulator-specific /Roms/* directory for OnionOS/GarlicOS (e.g. "GB") {batocera} The ROM's emulator-specific /roms/* directory for Batocera (e.g. "gb") + {funkeyos} The ROM's emulator-specific /* directory for FunKey OS (e.g. "Game Boy") {jelos} The ROM's emulator-specific /roms/* directory for JELOS (e.g. "gb") - {funkeyos} The ROM's emulator-specific /Roms* directory for FunKey OS (e.g. "Game Boy") + {mister} The ROM's core-specific /games/* directory for the MiSTer FPGA (e.g. "Gameboy") + {miyoocfw} The ROM's emulator-specific /roms/* directory for MiyooCFW (e.g. "GB") + {onion} The ROM's emulator-specific /Roms/* directory for OnionOS/GarlicOS (e.g. "GB") + {pocket} The ROM's core-specific /Assets/* directory for the Analogue Pocket (e.g. "gb") + {twmenu} The ROM's emulator-specific /roms/* directory for TWiLightMenu++ on the DSi/3DS ( + e.g. "gb") Example use cases: diff --git a/docs/output/tokens.md b/docs/output/tokens.md index 955e9a73a..2554a5519 100644 --- a/docs/output/tokens.md +++ b/docs/output/tokens.md @@ -73,6 +73,7 @@ To help sort ROMs into unique file structures for popular frontends & hardware, - `{batocera}` the [Batocera](../usage/desktop/batocera.md) emulator's directory for the ROM - `{funkeyos}` the [FunKey OS](../usage/handheld/funkeyos.md) emulator's directory for the ROM +- `{miyoocfw}` the [MiyooCFW](../usage/handheld/miyoocfw.md) emulator's directory for the ROM - `{jelos}` the [JELOS](../usage/handheld/jelos.md) emulator's directory for the ROM - `{mister}` the [MiSTer FPGA](../usage/hardware/mister.md) core's directory for the ROM - `{onion}` the [OnionOS / GarlicOS](../usage/handheld/onionos.md) emulator's directory for the ROM diff --git a/docs/usage/handheld/miyoocfw.md b/docs/usage/handheld/miyoocfw.md new file mode 100644 index 000000000..4749c36bf --- /dev/null +++ b/docs/usage/handheld/miyoocfw.md @@ -0,0 +1,67 @@ +# MiyooCFW + +[MiyooCFW](https://github.com/TriForceX/MiyooCFW/wiki) ([Code](https://github.com/TriForceX/MiyooCFW)) is a custom firmware for BittBoy, PocketGo, PowKiddy V90-Q90-Q20 and third party handheld consoles. It is based on the buildroot build environment and loosely based on OpenDingux. While it is intended for the named less powerful handhelds, it packs a good and wide selection of emulators. Some tinkering with the BIOS files is required though, but no worries, most of that is covered below or in their [Wiki](https://github.com/TriForceX/MiyooCFW/wiki/Emulator-Info) + +## BIOS Files + +MiyooCFW doesn't seem to have a centralized folder for putting BIOS files so it's a chore to prepare the card for running the provided emulators. Here's a try to help with finding the right ones and putting them in the right place. + +!!! info + + Please keep in mind that this information is based on the table in the official [MiyooCFW Emulator Info](https://github.com/TriForceX/MiyooCFW/wiki/Emulator-Info) and might be out of date. Please refer to the official list for reference. + +| System | Emulator | Folder | Filenames | MD5SUMs | Comments | +|----------|----------|--------|-----------|---------|----------| +| GB/GBC | Gambatte | /.gambatte/bios/BIOS | `gb_bios.bin` `gbc_bios.bin` | `32fbbd84168d3482956eb3c5051637f5` `dbfce9db9deaa2567f6a84fde55f9680` | Only required for authentic boot screen | +| GBA | GPSP | /emus/gpsp_gameblabla/ | `gba_bios.bin` | `a860e8c0b6d573d191e4ec7db1b1e4f6` | | +| GBA | GPSP Rumble | /emus/gpsp/ | `gba_bios.bin` | `a860e8c0b6d573d191e4ec7db1b1e4f6` | | +| NES | FCEUX | /.fceux/ | `disksys.rom` | `ca30b50f880eb660a320674ed365ef7a` | For Famicom Disk System | +| Sega Master System / Game Gear | SMS Plus GX | /emus/smsplusgx/bios/ | `BIOS.col` | `840481177270d5642a14ca71ee72844c` | System.dat calls this `bios.sms` | +| Sega Megadrive / Genesis | Picodrive | /.picodrive/ | `bios_cd_e.bin` `bios_cd_j.bin` `bios_cd_u.bin` | `e66fa1dc5820d254611fdcdba0662372` `278a9397d192149e84e820ac621a8edd` `2efd74e3232ff260e371b99f84024f7f` | for Mega-CD only. System.dat uses different casing. | +| PC Engine / Turbogfx-16 | Temper | /.temper/syscards/ | `syscard3.pce` | `38179df8f4ac870017db21ebcbf53114` | for CD based games | +| SNK NeoGeo | GNGeo | /roms/NEOGEO/ | `NEOGEO.zip` | unknown | version from FBA 0.2.97.39 works | +| Sony PlayStation 1 | PCSX ReARMed | /emus/pcsx_rearmed/bios/ | `SCPH1001.BIN` | `924e392ed05558ffdb115408c263dccf` | Optional but required for LLE, activate in options | +| GCE Vectrex | Vecxemu | /.vecxemu/ | `rom.dat` | `ab082fa8c8e632dd68589a8c7741388f` | not part of 'System.dat', available as part of vecxemu [here](https://github.com/gameblabla/vecxemu/raw/master/rom.dat) | + +## ROMs + +MiyooCFW supports many many systems and ROM formats. Check the table on the [MiyooCFW Wiki](https://github.com/TriForceX/MiyooCFW/wiki/Emulator-Info) for more precise instructions about the indivudual systems. Most supported systems and their ROMS can be automatically sorted by `igir` using the `{miyoocfw}` output token. See the [replaceable tokens page](../../output/tokens.md) for more information. + +=== ":simple-windowsxp: Windows" + + Replace the `E:\` drive letter with wherever your SD card is: + + ```batch + igir copy extract test clean ^ + --dat "No-Intro*.zip" ^ + --input ROMs\ ^ + --output "E:\roms\{miyoocfw}" ^ + --dir-letter ^ + --no-bios + ``` + +=== ":simple-apple: macOS" + + Replace the `/Volumes/MiyooCFW` drive name with whatever your SD card is named: + + ```shell + igir copy extract test clean \ + --dat "No-Intro*.zip" \ + --input ROMs/ \ + --output "/Volumes/MiyooCFW/roms/{miyoocfw}" \ + --dir-letter \ + --no-bios + ``` + +=== ":simple-linux: Linux" + + Replace the `/media/MiyooCFW` path with wherever your SD card is mounted: + + ```shell + igir copy extract test clean \ + --dat "No-Intro*.zip" \ + --input ROMs/ \ + --output "/media/MiyooCFW/roms/{miyoocfw}" \ + --dir-letter \ + --no-bios + ``` diff --git a/mkdocs.yml b/mkdocs.yml index daa096f02..326ce80e6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -57,6 +57,7 @@ nav: - usage/handheld/jelos.md - usage/desktop/lakka.md - usage/desktop/launchbox.md + - usage/handheld/miyoocfw.md - usage/handheld/onionos.md - usage/desktop/openemu.md - usage/desktop/recalbox.md diff --git a/package-lock.json b/package-lock.json index 89ecf037b..c98a934f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "igir", - "version": "2.1.0", + "version": "2.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "igir", - "version": "2.1.0", + "version": "2.1.1", "hasInstallScript": true, "license": "GPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 106d6c631..4640d2d2e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "igir", - "version": "2.1.0", + "version": "2.1.1", "description": "🕹 A video game ROM collection manager to help filter, sort, patch, archive, and report on collections on any OS.", "keywords": [ "1g1r", diff --git a/src/modules/argumentsParser.ts b/src/modules/argumentsParser.ts index 9efd310ea..b61741e78 100644 --- a/src/modules/argumentsParser.ts +++ b/src/modules/argumentsParser.ts @@ -678,9 +678,10 @@ Advanced usage: {outputExt} The output file's extension {batocera} The ROM's emulator-specific /roms/* directory for Batocera (e.g. "gb") - {funkeyos} The ROM's emulator-specific /Roms* directory for FunKey OS (e.g. "Game Boy") + {funkeyos} The ROM's emulator-specific /* directory for FunKey OS (e.g. "Game Boy") {jelos} The ROM's emulator-specific /roms/* directory for JELOS (e.g. "gb") {mister} The ROM's core-specific /games/* directory for the MiSTer FPGA (e.g. "Gameboy") + {miyoocfw} The ROM's emulator-specific /roms/* directory for MiyooCFW (e.g. "GB") {onion} The ROM's emulator-specific /Roms/* directory for OnionOS/GarlicOS (e.g. "GB") {pocket} The ROM's core-specific /Assets/* directory for the Analogue Pocket (e.g. "gb") {twmenu} The ROM's emulator-specific /roms/* directory for TWiLightMenu++ on the DSi/3DS (e.g. "gb") diff --git a/src/types/gameConsole.ts b/src/types/gameConsole.ts index 18c6818e4..95208a2a1 100644 --- a/src/types/gameConsole.ts +++ b/src/types/gameConsole.ts @@ -26,6 +26,10 @@ interface OutputTokens { // @see https://github.com/FunKey-Project/FunKey-OS/tree/master/FunKey/board/funkey/rootfs-overlay/usr/games/collections funkeyos?: string, + // MiyooCFW Roms go into the /roms subfolder of the SD card + // @see https://github.com/TriForceX/MiyooCFW/wiki/Emulator-Info + miyoocfw?: string, + // TWiLightMenu++ Roms go into the /roms subfolder on the 3DS/DSi SD card // @see https://github.com/DS-Homebrew/TWiLightMenu/tree/master/7zfile/roms twmenu?: string, @@ -87,6 +91,7 @@ export default class GameConsole { onion: 'ATARI', batocera: 'atari2600', jelos: 'atari2600', + miyoocfw: '2600', twmenu: 'a26', }), new GameConsole(/5200/, ['.a52'], { @@ -115,6 +120,7 @@ export default class GameConsole { batocera: 'lynx', jelos: 'atarilynx', funkeyos: 'Atari lynx', + miyoocfw: 'LYNX', }), new GameConsole(/Atari.*ST/i, ['.msa', '.st', '.stx'], { mister: 'AtariST', @@ -141,6 +147,7 @@ export default class GameConsole { batocera: 'wswan', jelos: 'wonderswan', funkeyos: 'WonderSwan', + miyoocfw: 'WSWAN', twmenu: 'ws', }), new GameConsole(/WonderSwan Color/i, ['.wsc'], { @@ -150,6 +157,7 @@ export default class GameConsole { batocera: 'wswanc', jelos: 'wonderswancolor', funkeyos: 'WonderSwan', + miyoocfw: 'WSWAN', // TODO: check if this works twmenu: 'ws', }), // Bit Corporation @@ -241,6 +249,7 @@ export default class GameConsole { onion: 'VECTREX', batocera: 'vectrex', jelos: 'vectrex', + miyoocfw: 'VECTREX', }), // Interton new GameConsole(/VC ?4000/i, [/* '.bin' */], { @@ -305,6 +314,7 @@ export default class GameConsole { batocera: 'pcengine', jelos: 'tg16', funkeyos: 'PCE-TurboGrafx', + miyoocfw: 'PCE', twmenu: 'tg16', }), new GameConsole(/(PC Engine|TurboGrafx) CD/i, [/* '.bin', '.cue' */], { @@ -313,6 +323,7 @@ export default class GameConsole { onion: 'PCECD', batocera: 'pcenginecd', jelos: 'tg16cd', + miyoocfw: 'PCE', }), new GameConsole(/SuperGrafx/i, ['.sgx'], { pocket: 'pce', @@ -340,6 +351,7 @@ export default class GameConsole { batocera: 'fds', jelos: 'fds', funkeyos: 'NES', + miyoocfw: 'NES', }), new GameConsole(/Game (and|&) Watch/i, ['.mgw'], { mister: 'GameNWatch', @@ -358,6 +370,7 @@ export default class GameConsole { batocera: 'gb', jelos: 'gb', funkeyos: 'Game Boy', + miyoocfw: 'GB', twmenu: 'gb', }), // pocket:sgb for spiritualized1997 new GameConsole(/GBA|Game ?Boy Advance/i, ['.gba', '.srl'], { @@ -367,6 +380,7 @@ export default class GameConsole { batocera: 'gba', jelos: 'gba', funkeyos: 'Game Boy Advance', + miyoocfw: 'GBA', twmenu: 'gba', }), new GameConsole(/GBC|Game ?Boy Color/i, ['.gbc'], { @@ -376,6 +390,7 @@ export default class GameConsole { batocera: 'gbc', jelos: 'gbc', funkeyos: 'Game Boy Color', + miyoocfw: 'GB', twmenu: 'gb', }), new GameConsole(/Nintendo 64|N64/i, ['.n64', '.v64', '.z64'], { @@ -405,6 +420,7 @@ export default class GameConsole { batocera: 'nes', jelos: 'nes', funkeyos: 'NES', + miyoocfw: 'NES', twmenu: 'nes', }), new GameConsole(/Pokemon Mini/i, ['.min'], { @@ -414,6 +430,7 @@ export default class GameConsole { batocera: 'pokemini', jelos: 'pokemini', funkeyos: 'Pokemini', + miyoocfw: 'POKEMINI', }), new GameConsole(/Satellaview/i, ['.bs'], { pocket: 'snes', @@ -434,6 +451,7 @@ export default class GameConsole { batocera: 'snes', jelos: 'snes', funkeyos: 'SNES', + miyoocfw: 'SNES', twmenu: 'snes', }), new GameConsole(/Virtual Boy/i, ['.vb', '.vboy'], { @@ -488,6 +506,7 @@ export default class GameConsole { batocera: 'gamegear', jelos: 'gamegear', funkeyos: 'Game Gear', + miyoocfw: 'SMS', twmenu: 'gg', }), new GameConsole(/Master System/i, ['.sms'], { @@ -497,6 +516,7 @@ export default class GameConsole { batocera: 'mastersystem', jelos: 'mastersystem', funkeyos: 'Sega Master System', + miyoocfw: 'SMS', twmenu: 'sms', }), new GameConsole(/(Mega|Sega) CD/i, [/* '.bin', '.cue' */], { @@ -504,6 +524,7 @@ export default class GameConsole { onion: 'SEGACD', batocera: 'segacd', jelos: 'segacd', + miyoocfw: 'SMD', }), new GameConsole(/Mega Drive|Genesis/i, ['.gen', '.md', '.mdx', '.sgd', '.smd'], { pocket: 'genesis', @@ -512,6 +533,7 @@ export default class GameConsole { batocera: 'megadrive', jelos: 'genesis', funkeyos: 'Sega Genesis', + miyoocfw: 'SMD', twmenu: 'gen', }), new GameConsole(/Saturn/i, [/* '.bin', '.cue' */], { @@ -563,6 +585,7 @@ export default class GameConsole { onion: 'NEOGEO', batocera: 'neogeo', jelos: 'neogeo', + miyoocfw: 'NEOGEO', }), new GameConsole(/Neo ?Geo CD/i, [/* '.bin', '.cue' */], { onion: 'NEOCD', @@ -590,6 +613,7 @@ export default class GameConsole { batocera: 'psx', jelos: 'psx', funkeyos: 'PS1', + miyoocfw: 'PS1', }), new GameConsole(/PlayStation 2|ps2/i, [/* '.bin', '.cue' */], { batocera: 'ps2', @@ -694,6 +718,10 @@ export default class GameConsole { return this.outputTokens.funkeyos; } + getMiyooCFW(): string | undefined { + return this.outputTokens.miyoocfw; + } + getTWMenu(): string | undefined { return this.outputTokens.twmenu; } diff --git a/src/types/outputFactory.ts b/src/types/outputFactory.ts index 3e11b212b..2f38a62d7 100644 --- a/src/types/outputFactory.ts +++ b/src/types/outputFactory.ts @@ -294,10 +294,16 @@ export default class OutputFactory { output = output.replace('{funkeyos}', funkeyos); } + const miyoocfw = gameConsole.getMiyooCFW(); + if (miyoocfw) { + output = output.replace('{miyoocfw}', miyoocfw); + } + const twmenu = gameConsole.getTWMenu(); if (twmenu) { output = output.replace('{twmenu}', twmenu); } + return output; } diff --git a/test/outputFactory.test.ts b/test/outputFactory.test.ts index 8dd555534..7fc36ca18 100644 --- a/test/outputFactory.test.ts +++ b/test/outputFactory.test.ts @@ -592,7 +592,68 @@ describe('token replacement', () => { 'should throw on {twmenu} for unknown extension: %s', async (outputRomFilename) => { const options = new Options({ commands: ['copy'], output: 'roms/{twmenu}' }); + const rom = new ROM({ name: outputRomFilename, size: 0, crc: '' }); + + await expect(async () => OutputFactory.getPath( + options, + dummyDat, + dummyGame, + dummyRelease, + rom, + await rom.toFile(), + )).rejects.toThrow(/failed to replace/); + }, + ); + test.each([ + ['game.a26', path.join('roms', '2600', 'game.a26')], + ['game.lnx', path.join('roms', 'LYNX', 'game.lnx')], + ['game.ws', path.join('roms', 'WSWAN', 'game.ws')], + ['game.wsc', path.join('roms', 'WSWAN', 'game.wsc')], // TODO: check if this works + ['game.vec', path.join('roms', 'VECTREX', 'game.vec')], + ['game.pce', path.join('roms', 'PCE', 'game.pce')], + ['game.gb', path.join('roms', 'GB', 'game.gb')], + ['game.sgb', path.join('roms', 'GB', 'game.sgb')], + ['game.gbc', path.join('roms', 'GB', 'game.gbc')], + ['game.gba', path.join('roms', 'GBA', 'game.gba')], + ['game.srl', path.join('roms', 'GBA', 'game.srl')], + ['game.nes', path.join('roms', 'NES', 'game.nes')], + ['game.fds', path.join('roms', 'NES', 'game.fds')], + ['game.sfc', path.join('roms', 'SNES', 'game.sfc')], + ['game.smc', path.join('roms', 'SNES', 'game.smc')], + ['game.min', path.join('roms', 'POKEMINI', 'game.min')], + ['game.gg', path.join('roms', 'SMS', 'game.gg')], + ['game.sms', path.join('roms', 'SMS', 'game.sms')], + ['game.gen', path.join('roms', 'SMD', 'game.gen')], + ['game.md', path.join('roms', 'SMD', 'game.md')], + ['game.smd', path.join('roms', 'SMD', 'game.smd')], + ])( + 'should replace {miyoocfw} for known extension: %s', + async (outputRomFilename, expectedPath) => { + const options = new Options({ commands: ['copy'], output: 'roms/{miyoocfw}' }); + const rom = new ROM({ name: outputRomFilename, size: 0, crc: '' }); + + const outputPath = OutputFactory.getPath( + options, + dummyDat, + dummyGame, + dummyRelease, + rom, + await rom.toFile(), + ); + expect(outputPath.format()).toEqual(expectedPath); + }, + ); + + test.each([ + 'game.bin', + 'game.rom', + // satellaview is not supported by https://github.com/TriForceX/MiyooCFW/wiki/Emulator-Info + 'game.bs', + ])( + 'should throw on {miyoocfw} for unknown extension: %s', + async (outputRomFilename) => { + const options = new Options({ commands: ['copy'], output: 'roms/{miyoocfw}' }); const rom = new ROM({ name: outputRomFilename, size: 0, crc: '' }); await expect(async () => OutputFactory.getPath(