LibraryService class handles game discovery, cataloging, and management. It scans ROM directories, computes file hashes for reliable identification, and maintains a persistent library with support for zip archives.
Constructor
Configuration
getConfig()
Get the current library configuration.LibraryConfig
setRomsBasePath()
Set the base directory for ROM files. Each system gets a subdirectory under this path.Absolute path to the ROMs base directory
Promise<void>
System management
getSystems()
Get all configured game systems.GameSystem[]
Unique system identifier (e.g.,
'nes', 'snes')Display name (e.g.,
'Nintendo Entertainment System')Short name for folders (e.g.,
'NES')Console manufacturer
Console generation number
Release year
Supported file extensions (e.g.,
['.nes', '.unf'])Directory path where ROMs for this system are stored
addSystem()
Add a new game system to the configuration.System configuration object
Promise<void>
removeSystem()
Remove a system and all its games from the library.System identifier
Promise<void>
updateSystemPath()
Update the ROM directory path for a system.System identifier
New directory path
Promise<void>
Game management
getGames()
Get all games, optionally filtered by system.Optional system filter
Game[]
Unique game ID (SHA-256 hash of ROM content)
Game title
System display name
System identifier
Path to the ROM file
File modification timestamp (for cache invalidation)
ROM hashes (CRC32, SHA-1, MD5) used for matching against databases
Original zip file path (if extracted from zip)
Cover art URL (e.g.,
artwork://abc123.png)Aspect ratio for dynamic card sizing (0.4-1.8)
Game metadata (developer, publisher, genre, description, etc.)
getGame()
Get a single game by ID.Game ID (SHA-256 hash)
Game | undefined
addGame()
Manually add a single game to the library.Full path to the ROM file
System identifier
Promise<Game | null> - Returns null if the file is not a valid ROM for the system
For zip files on non-arcade systems, this automatically extracts the first matching ROM and caches it.
removeGame()
Remove a game from the library.Game ID
Promise<void>
If the game was extracted from a zip archive, the cached ROM file is automatically deleted.
updateGame()
Update game metadata.Game ID
Fields to update
Promise<void>
Scanning
scanDirectory()
Scan a directory for ROM files and add them to the library. This is the core scanning method that powers all other scan operations.Directory to scan
Optional system filter. If omitted, auto-detects system from folder names.
Promise<Game[]> - Array of discovered games
Emits: scanProgress event for each game processed
Progress event emitted during scanning
The game that was just discovered or re-verified
Whether this game is newly added (true) or already existed (false)
Number of files processed so far
Total number of ROM files found
Number of files skipped via mtime cache (no re-hash needed)
scanSystemFolders()
Scan all configured system ROM directories.Promise<Game[]> - Array of all discovered games across all systems
Emits: scanProgress event for each game processed
ROM hashing
computeRomHashes()
Compute CRC32, SHA-1, and MD5 hashes for a ROM file in a single pass. Also returns the SHA-256 game ID.Path to the ROM file
Promise<{ gameId: string; hashes: RomHashes }>
This method streams the file and computes all hashes in parallel, making it efficient for large ROM files.
Events
LibraryService extends EventEmitter and emits the following events:Emitted for each game discovered during a scan. This allows the UI to show real-time progress and display games as they’re found.
Performance optimizations
LibraryService implements several optimizations for fast scanning:mtime cache
Files are only re-hashed if their modification time has changed. Scanning unchanged directories is near-instant.Reverse indexes
O(1) lookups by ROM path and archive path using internal maps:Prioritized processing
New (unknown) files are processed first so they appear in the UI immediately. Known files are verified in the background.Bounded concurrency
Hashes 4 files in parallel to maximize throughput without overwhelming the disk I/O:Zip extraction caching
Extracted ROMs from zip archives are cached with hash-prefixed filenames to avoid re-extraction on subsequent scans.Usage example
Error handling
Scanning continues even if individual files fail:Source reference
- Implementation:
apps/desktop/src/main/services/LibraryService.ts:53 - Usage example:
apps/desktop/src/main/ipc/handlers.ts:22