Skip to content

Commit

Permalink
Feature: outputToken MinUI (#817)
Browse files Browse the repository at this point in the history
Co-authored-by: Julia Mono Brunenberg <[email protected]>
  • Loading branch information
juliadin and Julia Mono Brunenberg authored Nov 29, 2023
1 parent d107a0b commit 1f79a36
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/output/tokens.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
- `{minui}` the [MinUI](../usage/handheld/minui.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
Expand Down
73 changes: 73 additions & 0 deletions docs/usage/handheld/minui.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# MiyooCFW

[MinUI](https://github.com/shauninman/MinUI/) is a custom launcher supporting the Powkiddy RGB30, Trimui Smart (and Pro), Miyoo Mini (and Plus), as well as Anbernic RG35XX. It is focused on providing a minimalistic and easy to use frontend for the most important 8 and 16 bit consoles.

## BIOS Files

MinUI is strictly *bring your own BIOS*. You can find information on the required BIOS files [here](https://github.com/shauninman/MinUI/blob/main/skeleton/EXTRAS/README.txt)

!!! info

The following information is not guaranteed to be up to date and is based off the information from the link above at the time of writing as well as community contributions. Please reference the information provided by the developers of MinUI when running into troubles.

Place these files under `/Bios/<PAK-name>/<Filename>`:

| Console | PAK | File | MD5 |
|:--------|:---:|:-----|:---:|
| NEC TurboGrafx-16 | PCE | `syscard3.pce` | `38179df8f4ac870017db21ebcbf53114` |
| Nintendo GameBoy | GB | `gb_bios.bin` | `32fbbd84168d3482956eb3c5051637f5` |
| Nintendo GameBoy Color | GBC | `gbc_bios.bin` | `dbfce9db9deaa2567f6a84fde55f9680` |
| Nintendo GameBoy Advance | GBA | `gba_bios.bin` | `a860e8c0b6d573d191e4ec7db1b1e4f6` |
| Nintendo GameBoy Advance | MGBA | `gba_bios.bin` | `a860e8c0b6d573d191e4ec7db1b1e4f6` |
| Nintendo Pokemon Mini | PKM | `bios.min` | `1e4fb124a3a886865acb574f388c803d` |
| Nintendo Super GameBoy | SGB | `sgb.bios` | `d574d4f9c12f305074798f54c091a8b4` |
| Sony PlayStation | PS | `scph1001.bin` | `924e392ed05558ffdb115408c263dccf` |

## ROMs

MinUI supports many many systems and ROM formats. Check the folders [here (base)](https://github.com/shauninman/MinUI/tree/main/skeleton/BASE/Roms) and [here (extras)](https://github.com/shauninman/MinUI/tree/main/skeleton/EXTRAS/Roms) for a comprehensive list about the indivudual systems. Most supported systems and their ROMS can be automatically sorted by `igir` using the `{minui}` output token. See the [replaceable tokens page](../../output/tokens.md) for more information.

MinUI uses the names unter /Roms on the SD card in a more creative way than most other frontends. The folder names consist of a *UI name* and a *PAK name*. The *UI name* is used as the name shown in the User interface as a list item name, while the *PAK name* controls which software pack is used to open the files within. Files with the same *UI name* but different *PAK name* are listed in the same list in the UI but are opened with different PAKs. `igir` uses the vendor recommendations for the folder names with some exceptions.

MinUI requires multi-file releases to be grouped into subfolders (bin/cue releases of the PS1 for example). It is recommended to use `--dir-game-subdir=multiple` - which is the default at this time.

More details about these features can be found [here](https://github.com/shauninman/MinUI/tree/main/skeleton/BASE) under the sections `Roms` and `Disc-based games`.

=== ":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\{minui}" ^
--dir-letter ^
--no-bios
```

=== ":simple-apple: macOS"

Replace the `/Volumes/MinUI` drive name with whatever your SD card is named:

```shell
igir copy extract test clean \
--dat "No-Intro*.zip" \
--input ROMs/ \
--output "/Volumes/MinUI/roms/{minui}" \
--dir-letter \
--no-bios
```

=== ":simple-linux: Linux"

Replace the `/media/MinUI` path with wherever your SD card is mounted:

```shell
igir copy extract test clean \
--dat "No-Intro*.zip" \
--input ROMs/ \
--output "/media/MinUI/roms/{minui}" \
--dir-letter \
--no-bios
```
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ nav:
- usage/handheld/jelos.md
- usage/desktop/lakka.md
- usage/desktop/launchbox.md
- usage/handheld/minui.md
- usage/handheld/miyoocfw.md
- usage/handheld/onionos.md
- usage/desktop/openemu.md
Expand Down
1 change: 1 addition & 0 deletions src/modules/argumentsParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,7 @@ Advanced usage:
{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")
{minui} The ROM's emulator-specific /Roms/* directory for MinUI (e.g. "Game Boy (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")
Expand Down
30 changes: 30 additions & 0 deletions src/types/gameConsole.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ interface OutputTokens {
// @see https://github.com/FunKey-Project/FunKey-OS/tree/master/FunKey/board/funkey/rootfs-overlay/usr/games/collections
funkeyos?: string,

// MinUI roms go into the /Roms folder on the SD card
// @see https://github.com/shauninman/MinUI/tree/main/skeleton/BASE/Roms
// @see https://github.com/shauninman/MinUI/tree/main/skeleton/EXTRAS/Roms
// There are some special considerations about naming these folders
// to influence UI presentation
// @see https://github.com/shauninman/MinUI/blob/main/skeleton/BASE/README.txt
minui?: string,

// MiyooCFW Roms go into the /roms subfolder of the SD card
// @see https://github.com/TriForceX/MiyooCFW/wiki/Emulator-Info
miyoocfw?: string,
Expand Down Expand Up @@ -316,6 +324,7 @@ export default class GameConsole {
funkeyos: 'PCE-TurboGrafx',
miyoocfw: 'PCE',
twmenu: 'tg16',
minui: 'TurboGrafx-16 (PCE)',
}),
new GameConsole(/(PC Engine|TurboGrafx) CD/i, [/* '.bin', '.cue' */], {
pocket: 'pcecd',
Expand All @@ -324,6 +333,7 @@ export default class GameConsole {
batocera: 'pcenginecd',
jelos: 'tg16cd',
miyoocfw: 'PCE',
minui: 'TurboGrafx-16 CD (PCE)',
}),
new GameConsole(/SuperGrafx/i, ['.sgx'], {
pocket: 'pce',
Expand Down Expand Up @@ -352,6 +362,7 @@ export default class GameConsole {
jelos: 'fds',
funkeyos: 'NES',
miyoocfw: 'NES',
minui: 'Famicom Disk System (FC)',
}),
new GameConsole(/Game (and|&) Watch/i, ['.mgw'], {
mister: 'GameNWatch',
Expand All @@ -372,6 +383,7 @@ export default class GameConsole {
funkeyos: 'Game Boy',
miyoocfw: 'GB',
twmenu: 'gb',
minui: 'Game Boy (GB)',
}), // pocket:sgb for spiritualized1997
new GameConsole(/GBA|Game ?Boy Advance/i, ['.gba', '.srl'], {
pocket: 'gba',
Expand All @@ -382,6 +394,7 @@ export default class GameConsole {
funkeyos: 'Game Boy Advance',
miyoocfw: 'GBA',
twmenu: 'gba',
minui: 'Game Boy Advance (GBA)',
}),
new GameConsole(/GBC|Game ?Boy Color/i, ['.gbc'], {
pocket: 'gbc',
Expand All @@ -392,6 +405,7 @@ export default class GameConsole {
funkeyos: 'Game Boy Color',
miyoocfw: 'GB',
twmenu: 'gb',
minui: 'Game Boy Color (GBC)',
}),
new GameConsole(/Nintendo 64|N64/i, ['.n64', '.v64', '.z64'], {
mister: 'N64',
Expand Down Expand Up @@ -422,6 +436,7 @@ export default class GameConsole {
funkeyos: 'NES',
miyoocfw: 'NES',
twmenu: 'nes',
minui: 'Nintendo Entertainment System (FC)',
}),
new GameConsole(/Pokemon Mini/i, ['.min'], {
pocket: 'poke_mini',
Expand All @@ -431,6 +446,7 @@ export default class GameConsole {
jelos: 'pokemini',
funkeyos: 'Pokemini',
miyoocfw: 'POKEMINI',
minui: 'Pokemon mini (PKM)', // uses unrendedable unicode char in original install
}),
new GameConsole(/Satellaview/i, ['.bs'], {
pocket: 'snes',
Expand All @@ -453,12 +469,14 @@ export default class GameConsole {
funkeyos: 'SNES',
miyoocfw: 'SNES',
twmenu: 'snes',
minui: 'Super Nintendo Entertainment System (SFC)',
}),
new GameConsole(/Virtual Boy/i, ['.vb', '.vboy'], {
onion: 'VB',
batocera: 'virtualboy',
jelos: 'virtualboy',
funkeyos: 'Virtualboy',
minui: 'Virtual Boy (VB)',
}),
new GameConsole(/Wii/i, [/* '.iso' */], {
batocera: 'wii',
Expand Down Expand Up @@ -494,6 +512,7 @@ export default class GameConsole {
onion: 'THIRTYTWOX',
batocera: 'sega32x',
jelos: 'sega32x',
minui: 'Sega 32X (MD)', // added for sorting convenience
}),
new GameConsole(/Dreamcast/i, [/* '.bin', '.cue' */], {
batocera: 'dreamcast',
Expand All @@ -508,6 +527,7 @@ export default class GameConsole {
funkeyos: 'Game Gear',
miyoocfw: 'SMS',
twmenu: 'gg',
minui: 'Sega Game Gear (GG)',
}),
new GameConsole(/Master System/i, ['.sms'], {
pocket: 'sms',
Expand All @@ -518,13 +538,15 @@ export default class GameConsole {
funkeyos: 'Sega Master System',
miyoocfw: 'SMS',
twmenu: 'sms',
minui: 'Sega Master System (SMS)',
}),
new GameConsole(/(Mega|Sega) CD/i, [/* '.bin', '.cue' */], {
mister: 'MegaCD',
onion: 'SEGACD',
batocera: 'segacd',
jelos: 'segacd',
miyoocfw: 'SMD',
minui: 'Sega CD (MD)', // added for sorting convenience
}),
new GameConsole(/Mega Drive|Genesis/i, ['.gen', '.md', '.mdx', '.sgd', '.smd'], {
pocket: 'genesis',
Expand All @@ -535,6 +557,7 @@ export default class GameConsole {
funkeyos: 'Sega Genesis',
miyoocfw: 'SMD',
twmenu: 'gen',
minui: 'Sega Genesis (MD)',
}),
new GameConsole(/Saturn/i, [/* '.bin', '.cue' */], {
batocera: 'saturn',
Expand Down Expand Up @@ -598,13 +621,15 @@ export default class GameConsole {
jelos: 'ngp',
funkeyos: 'Neo Geo Pocket',
twmenu: 'ngp',
minui: 'Neo Geo Pocket (NGPC)', // added for sorting convenience
}),
new GameConsole(/Neo ?Geo Pocket Color/i, ['.ngc'], {
onion: 'NGP',
batocera: 'ngpc',
jelos: 'ngpc',
funkeyos: 'Neo Geo Pocket',
twmenu: 'ngp',
minui: 'Neo Geo Pocket Color (NGPC)', // added for sorting convenience
}),
// Sony
new GameConsole(/PlayStation|psx/i, [/* '.bin', '.cue' */], {
Expand All @@ -614,6 +639,7 @@ export default class GameConsole {
jelos: 'psx',
funkeyos: 'PS1',
miyoocfw: 'PS1',
minui: 'Sony PlayStation (PS)',
}),
new GameConsole(/PlayStation 2|ps2/i, [/* '.bin', '.cue' */], {
batocera: 'ps2',
Expand Down Expand Up @@ -725,4 +751,8 @@ export default class GameConsole {
getTWMenu(): string | undefined {
return this.outputTokens.twmenu;
}

getMinUI(): string | undefined {
return this.outputTokens.minui;
}
}
5 changes: 5 additions & 0 deletions src/types/outputFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,11 @@ export default class OutputFactory {
output = output.replace('{twmenu}', twmenu);
}

const minui = gameConsole.getMinUI();
if (minui) {
output = output.replace('{minui}', minui);
}

return output;
}

Expand Down
64 changes: 64 additions & 0 deletions test/outputFactory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,70 @@ describe('token replacement', () => {
)).rejects.toThrow(/failed to replace/);
},
);

test.each([
['game.pce', path.join('Roms', 'TurboGrafx-16 (PCE)', 'game.pce')],
['game.fds', path.join('Roms', 'Famicom Disk System (FC)', 'game.fds')],
['game.gb', path.join('Roms', 'Game Boy (GB)', 'game.gb')],
['game.sgb', path.join('Roms', 'Game Boy (GB)', 'game.sgb')],
['game.gba', path.join('Roms', 'Game Boy Advance (GBA)', 'game.gba')],
['game.srl', path.join('Roms', 'Game Boy Advance (GBA)', 'game.srl')],
['game.gbc', path.join('Roms', 'Game Boy Color (GBC)', 'game.gbc')],
['game.nes', path.join('Roms', 'Nintendo Entertainment System (FC)', 'game.nes')],
['game.nez', path.join('Roms', 'Nintendo Entertainment System (FC)', 'game.nez')],
['game.min', path.join('Roms', 'Pokemon mini (PKM)', 'game.min')],
['game.sfc', path.join('Roms', 'Super Nintendo Entertainment System (SFC)', 'game.sfc')],
['game.smc', path.join('Roms', 'Super Nintendo Entertainment System (SFC)', 'game.smc')],
['game.vb', path.join('Roms', 'Virtual Boy (VB)', 'game.vb')],
['game.vboy', path.join('Roms', 'Virtual Boy (VB)', 'game.vboy')],
['game.32x', path.join('Roms', 'Sega 32X (MD)', 'game.32x')],
['game.gg', path.join('Roms', 'Sega Game Gear (GG)', 'game.gg')],
['game.sms', path.join('Roms', 'Sega Master System (SMS)', 'game.sms')],
['game.gen', path.join('Roms', 'Sega Genesis (MD)', 'game.gen')],
['game.md', path.join('Roms', 'Sega Genesis (MD)', 'game.md')],
['game.mdx', path.join('Roms', 'Sega Genesis (MD)', 'game.mdx')],
['game.sgd', path.join('Roms', 'Sega Genesis (MD)', 'game.sgd')],
['game.smd', path.join('Roms', 'Sega Genesis (MD)', 'game.smd')],
['game.ngp', path.join('Roms', 'Neo Geo Pocket (NGPC)', 'game.ngp')],
['game.ngc', path.join('Roms', 'Neo Geo Pocket Color (NGPC)', 'game.ngc')],
])(
'should replace {minui} for known extension: %s',
async (outputRomFilename, expectedPath) => {
const options = new Options({ commands: ['copy'], output: 'Roms/{minui}' });
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',
'game.mgw',
])(
'should throw on {minui} for unknown extension: %s',
async (outputRomFilename) => {
const options = new Options({ commands: ['copy'], output: 'roms/{minui}' });
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/);
},
);
});

describe('should respect "--dir-mirror"', () => {
Expand Down

0 comments on commit 1f79a36

Please sign in to comment.