Two SQLite databases live at <storage>/.replay-control/:

  • metadata.db – rebuildable cache (game library, external metadata, thumbnail index)
  • user_data.db – persistent user customizations (never auto-deleted)

Schema defined in replay-control-core-server/src/metadata/metadata_db/mod.rs and user_data_db.rs.

metadata.db

game_library

Primary game catalog. One row per ROM file. Populated by the scan pipeline, enriched by the enrichment pipeline.

ColumnTypePurpose
systemTEXTSystem folder name (PK part 1)
rom_filenameTEXTROM filename (PK part 2)
rom_pathTEXTFull path to ROM file
display_nameTEXTHuman-readable name (nullable)
base_titleTEXTTags stripped, used for grouping variants
series_keyTEXTAlgorithmic franchise key (base_title minus trailing numbers/roman numerals)
regionTEXTDetected region string
developerTEXTFrom arcade_db at scan time or LaunchBox via enrichment
search_textTEXTPre-computed search string
genreTEXTDetail genre (e.g., “Maze / Shooter”)
genre_groupTEXTNormalized genre for filtering (e.g., “Shooter”)
ratingREALLaunchBox community rating
rating_countINTEGERNumber of ratings
playersINTEGERMax player count
is_cloneINTEGERWhether this is a variant of another ROM
is_m3uINTEGERWhether this is an M3U playlist entry
is_translationINTEGERTranslation patch detected
is_hackINTEGERROM hack detected
is_specialINTEGERExcluded from recommendations (FastROM, 60Hz, unlicensed, etc.)
box_art_urlTEXTResolved box art URL (e.g., /media/snes/boxart/Name.png)
driver_statusTEXTArcade driver status (good/imperfect/preliminary)
size_bytesINTEGERROM file size
crc32INTEGERCRC32 hash (NULL for CD/computer/arcade)
hash_mtimeINTEGERFile mtime when CRC32 was computed (cache key)
hash_matched_nameTEXTNo-Intro canonical name if CRC32 matched
release_yearINTEGERFrom TOSEC tags or LaunchBox enrichment

PRIMARY KEY: (system, rom_filename)

game_library_meta

Per-system scan metadata. Used by the startup pipeline for mtime-based cache verification.

ColumnTypePurpose
systemTEXTSystem folder name (PK)
dir_mtime_secsINTEGERDirectory mtime at last scan
scanned_atINTEGERUnix timestamp of last scan
rom_countINTEGERNumber of ROMs found
total_size_bytesINTEGERTotal size of all ROMs

game_metadata

External metadata from LaunchBox import. One row per ROM that has been matched.

ColumnTypePurpose
systemTEXTSystem folder name (PK part 1)
rom_filenameTEXTROM filename (PK part 2)
descriptionTEXTGame description
genreTEXTGenre string
developerTEXTDeveloper name
publisherTEXTPublisher name
release_yearINTEGERRelease year
ratingREALCommunity rating
rating_countINTEGERNumber of ratings
cooperativeINTEGERSupports co-op (boolean)
playersINTEGERMax players
box_art_pathTEXTImage path from import
screenshot_pathTEXTScreenshot path
title_pathTEXTTitle screen path
sourceTEXTData source identifier
fetched_atINTEGERUnix timestamp of import

game_alias

Alternative names for games (from Wikidata or other sources). Used for search and variant resolution.

ColumnTypePurpose
systemTEXTPK part 1
base_titleTEXTPK part 2
alias_nameTEXTAlternative name (PK part 3)
alias_regionTEXTRegion for this alias
sourceTEXTData source

game_series

Franchise/series relationships (from Wikidata). Links games that belong to the same series.

ColumnTypePurpose
systemTEXTPK part 1
base_titleTEXTPK part 2
series_nameTEXTSeries identifier (PK part 3)
series_orderINTEGERPosition in series (nullable)
sourceTEXTData source
follows_base_titleTEXTPrevious game in chain
followed_by_base_titleTEXTNext game in chain

thumbnail_index

Index of available thumbnails from libretro-thumbnails repos. Populated by the thumbnail update pipeline (GitHub API) or rebuilt from disk.

ColumnTypePurpose
repo_nameTEXTSource repo identifier (PK part 1)
kindTEXTImage kind: “Named_Boxarts”, “Named_Snaps”, etc. (PK part 2)
filenameTEXTImage filename (PK part 3)
symlink_targetTEXTTarget if symlinked in the repo

FK: repo_name references data_sources(source_name)

data_sources

Tracks imported data sources and their versions.

ColumnTypePurpose
source_nameTEXTUnique identifier (PK)
source_typeTEXTCategory (e.g., “libretro-thumbnails”)
version_hashTEXTContent hash for change detection
imported_atINTEGERUnix timestamp
entry_countINTEGERNumber of entries imported
branchTEXTGit branch name

Indexes

Each index is designed for specific query patterns (comments from the source):

IndexColumnsCovers
idx_game_library_genre(system, genre) WHERE genre IS NOT NULL AND genre != ''similar_by_genre, system_genre_groups
idx_game_library_genre_group(system, genre_group) WHERE genre_group != ''Genre group filtering
idx_game_library_series_key(series_key) WHERE series_key != ''series_siblings
idx_game_library_developer_title(developer, base_title) WHERE developer != ''find_developer_matches, games_by_developer, top_developers
idx_game_library_base_title(system, base_title) WHERE base_title != ''regional_variants, translations, hacks, specials, find_best_rom
idx_data_sources_type(source_type)get_data_source_stats, clear_thumbnail_index
idx_game_alias_name(alias_name COLLATE NOCASE)search_aliases (LIKE queries)
idx_game_alias_system_alias(system, alias_name)alias_variants, alias_base_titles
idx_game_series_name(series_name COLLATE NOCASE)Series name lookups
idx_game_series_system(system, series_name)System-scoped series queries
idx_game_series_order(series_name, series_order) WHERE series_order IS NOT NULLNeighbor lookups, max order queries

The thumbnail_index PK (repo_name, kind, filename) covers repo_name-only prefix lookups, so no separate index is needed.

user_data.db

Defined in replay-control-core-server/src/metadata/user_data_db.rs. Separate from metadata.db so user choices survive metadata clears and rebuilds.

box_art_overrides

User-selected box art for specific ROMs.

ColumnTypePurpose
systemTEXTPK part 1
rom_filenameTEXTPK part 2
override_pathTEXTPath to selected image
set_atINTEGERUnix timestamp

game_videos

User-saved video links for games.

ColumnTypePurpose
systemTEXTPK part 1
base_titleTEXTFor cross-ROM video sharing
rom_filenameTEXTPK part 2
video_idTEXTUnique video identifier (PK part 3)
urlTEXTCanonical video URL
platformTEXTe.g., “youtube”
platform_video_idTEXTPlatform-specific ID
titleTEXTHuman-readable title
added_atINTEGERUnix timestamp
from_recommendationINTEGERWhether pinned from search
tagTEXTCategory: “trailer”, “gameplay”, “1cc”, or NULL

Index: idx_game_videos_base_title ON (system, base_title) – enables sharing videos across ROMs of the same game.

Schema Migrations

Handled inline in init_tables() with idempotent ALTER TABLE ... ADD COLUMN statements (errors silently ignored if column already exists). Example: release_year column added to game_library for TOSEC tag parsing.

Corruption Handling

Both databases probe all tables at open time via probe_tables(). For metadata.db, corruption triggers automatic delete-and-recreate (it’s a rebuildable cache). For user_data.db, corruption is flagged but the DB is not destroyed – the caller decides (user data is irreplaceable).