upd
This commit is contained in:
@@ -1,360 +1,387 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.programs.steam-rom-manager;
|
||||
in {
|
||||
options.programs.steam-rom-manager = {
|
||||
enable = mkEnableOption "Steam ROM Manager";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = steam-rom-manager;
|
||||
description = "Steam ROM Manager package";
|
||||
};
|
||||
|
||||
# Single source of truth for built-in emulator metadata.
|
||||
knownEmulators = import ./emulators.nix pkgs;
|
||||
|
||||
# Valid image provider identifiers accepted by SRM.
|
||||
validProviders = [
|
||||
"sgdb"
|
||||
"steamCDN"
|
||||
];
|
||||
in
|
||||
{
|
||||
options.programs.steam-rom-manager = {
|
||||
|
||||
enable = lib.mkEnableOption "Steam ROM Manager";
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Fuzzy matcher
|
||||
# -------------------------------------------------------------------------
|
||||
fuzzyMatcher = {
|
||||
timestamps = {
|
||||
check = mkOption {
|
||||
type = types.int;
|
||||
check = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 0;
|
||||
description = "Timestamp for fuzzy matcher check";
|
||||
description = "Epoch timestamp of the last fuzzy-matcher data check.";
|
||||
};
|
||||
download = mkOption {
|
||||
type = types.int;
|
||||
download = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 0;
|
||||
description = "Timestamp for fuzzy matcher download";
|
||||
description = "Epoch timestamp of the last fuzzy-matcher data download.";
|
||||
};
|
||||
};
|
||||
verbose = mkOption {
|
||||
type = types.bool;
|
||||
verbose = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Enable verbose logging for fuzzy matcher";
|
||||
description = "Enable verbose logging for the fuzzy matcher.";
|
||||
};
|
||||
filterProviders = mkOption {
|
||||
type = types.bool;
|
||||
filterProviders = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Filter image providers";
|
||||
description = "Restrict image lookups to the configured providers.";
|
||||
};
|
||||
};
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Environment variables written into userSettings.json
|
||||
# -------------------------------------------------------------------------
|
||||
environmentVariables = {
|
||||
steamDirectory = mkOption {
|
||||
type = types.str;
|
||||
steamDirectory = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "${config.home.homeDirectory}/.local/share/Steam";
|
||||
description = "Steam installation directory";
|
||||
description = "Path to the Steam data directory.";
|
||||
};
|
||||
|
||||
romsDirectory = mkOption {
|
||||
type = types.str;
|
||||
romsDirectory = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "${config.home.homeDirectory}/Emulation/roms";
|
||||
description = "Base directory for ROM files";
|
||||
description = "Root directory that contains per-system ROM sub-folders.";
|
||||
};
|
||||
|
||||
retroarchPath = mkOption {
|
||||
type = types.str;
|
||||
retroarchPath = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
description = "Path to RetroArch executable";
|
||||
description = "Path to the RetroArch executable (leave empty if not using RetroArch).";
|
||||
};
|
||||
|
||||
raCoresDirectory = mkOption {
|
||||
type = types.str;
|
||||
raCoresDirectory = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
description = "RetroArch cores directory";
|
||||
description = "Directory containing RetroArch cores.";
|
||||
};
|
||||
|
||||
localImagesDirectory = mkOption {
|
||||
type = types.str;
|
||||
localImagesDirectory = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
description = "Directory for local images";
|
||||
description = "Directory for locally stored artwork.";
|
||||
};
|
||||
};
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Preview settings
|
||||
# -------------------------------------------------------------------------
|
||||
previewSettings = {
|
||||
retrieveCurrentSteamImages = mkOption {
|
||||
type = types.bool;
|
||||
retrieveCurrentSteamImages = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Retrieve current Steam images";
|
||||
description = "Download existing Steam artwork when previewing.";
|
||||
};
|
||||
|
||||
disableCategories = mkOption {
|
||||
type = types.bool;
|
||||
disableCategories = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Disable Steam categories";
|
||||
description = "Do not apply Steam category tags to shortcuts.";
|
||||
};
|
||||
|
||||
deleteDisabledShortcuts = mkOption {
|
||||
type = types.bool;
|
||||
deleteDisabledShortcuts = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Delete disabled shortcuts";
|
||||
description = "Remove shortcuts for parsers that are disabled.";
|
||||
};
|
||||
|
||||
imageZoomPercentage = mkOption {
|
||||
type = types.int;
|
||||
imageZoomPercentage = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 30;
|
||||
description = "Image zoom percentage in preview";
|
||||
description = "Zoom level (%) used when displaying artwork in the preview pane.";
|
||||
};
|
||||
|
||||
preload = mkOption {
|
||||
type = types.bool;
|
||||
preload = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Preload images";
|
||||
description = "Pre-fetch artwork while the preview loads.";
|
||||
};
|
||||
|
||||
hideUserAccount = mkOption {
|
||||
type = types.bool;
|
||||
hideUserAccount = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Hide user account in preview";
|
||||
description = "Hide the Steam account name in the preview pane.";
|
||||
};
|
||||
};
|
||||
|
||||
enabledProviders = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ "sgdb" "steamCDN" ];
|
||||
description = "Enabled image providers";
|
||||
# -------------------------------------------------------------------------
|
||||
# Image providers
|
||||
# -------------------------------------------------------------------------
|
||||
enabledProviders = lib.mkOption {
|
||||
type = lib.types.listOf (lib.types.enum validProviders);
|
||||
default = [
|
||||
"sgdb"
|
||||
"steamCDN"
|
||||
];
|
||||
description = ''
|
||||
Ordered list of image providers SRM should query.
|
||||
Valid values: ${lib.concatStringsSep ", " (map (p: ''"${p}"'') validProviders)}.
|
||||
'';
|
||||
};
|
||||
|
||||
imageProviderSettings = {
|
||||
sgdb = {
|
||||
nsfw = mkOption {
|
||||
type = types.bool;
|
||||
nsfw = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Allow NSFW content from SteamGridDB";
|
||||
description = "Include NSFW artwork from SteamGridDB.";
|
||||
};
|
||||
|
||||
humor = mkOption {
|
||||
type = types.bool;
|
||||
humor = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Allow humor content from SteamGridDB";
|
||||
description = "Include humour-tagged artwork from SteamGridDB.";
|
||||
};
|
||||
|
||||
styles = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "Preferred art styles for SteamGridDB";
|
||||
styles = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Preferred grid artwork styles (e.g. \"alternate\", \"blurred\").";
|
||||
};
|
||||
|
||||
stylesHero = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "Preferred hero art styles for SteamGridDB";
|
||||
stylesHero = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Preferred hero artwork styles.";
|
||||
};
|
||||
|
||||
stylesLogo = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "Preferred logo styles for SteamGridDB";
|
||||
stylesLogo = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Preferred logo styles.";
|
||||
};
|
||||
|
||||
stylesIcon = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "Preferred icon styles for SteamGridDB";
|
||||
stylesIcon = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Preferred icon styles.";
|
||||
};
|
||||
|
||||
imageMotionTypes = mkOption {
|
||||
type = types.listOf types.str;
|
||||
imageMotionTypes = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "static" ];
|
||||
description = "Allowed image motion types";
|
||||
description = "Allowed motion types (\"static\", \"animated\").";
|
||||
};
|
||||
|
||||
sizes = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "Preferred image sizes";
|
||||
sizes = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Preferred grid image sizes.";
|
||||
};
|
||||
|
||||
sizesHero = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "Preferred hero image sizes";
|
||||
sizesHero = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Preferred hero image sizes.";
|
||||
};
|
||||
|
||||
sizesIcon = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "Preferred icon sizes";
|
||||
sizesIcon = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Preferred icon sizes.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
batchDownloadSize = mkOption {
|
||||
type = types.int;
|
||||
# -------------------------------------------------------------------------
|
||||
# Miscellaneous top-level settings
|
||||
# -------------------------------------------------------------------------
|
||||
batchDownloadSize = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 50;
|
||||
description = "Number of images to download in a batch";
|
||||
description = "Number of images to download per batch.";
|
||||
};
|
||||
|
||||
dnsServers = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "Custom DNS servers for image downloads";
|
||||
dnsServers = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Custom DNS servers used for artwork downloads (leave empty for system DNS).";
|
||||
};
|
||||
|
||||
language = mkOption {
|
||||
type = types.str;
|
||||
language = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "en-US";
|
||||
description = "Application language";
|
||||
example = "de-DE";
|
||||
description = "BCP-47 language tag for the SRM UI.";
|
||||
};
|
||||
|
||||
theme = mkOption {
|
||||
type = types.str;
|
||||
theme = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "Deck";
|
||||
description = "Application theme";
|
||||
example = "Default";
|
||||
description = "SRM UI theme name.";
|
||||
};
|
||||
|
||||
emudeckInstall = mkOption {
|
||||
type = types.bool;
|
||||
emudeckInstall = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Is this an EmuDeck installation";
|
||||
description = "Set to true when SRM is managed alongside EmuDeck.";
|
||||
};
|
||||
|
||||
autoUpdate = mkOption {
|
||||
type = types.bool;
|
||||
autoUpdate = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Enable automatic updates";
|
||||
description = "Allow SRM to update itself automatically (not recommended in a Nix-managed setup).";
|
||||
};
|
||||
|
||||
offlineMode = mkOption {
|
||||
type = types.bool;
|
||||
offlineMode = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Run in offline mode";
|
||||
description = "Run SRM without fetching remote artwork.";
|
||||
};
|
||||
|
||||
navigationWidth = mkOption {
|
||||
type = types.int;
|
||||
navigationWidth = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 0;
|
||||
description = "Navigation panel width";
|
||||
description = "Width in pixels of the navigation sidebar (0 = default).";
|
||||
};
|
||||
|
||||
clearLogOnTest = mkOption {
|
||||
type = types.bool;
|
||||
clearLogOnTest = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Clear log when testing configuration";
|
||||
description = "Clear the log panel each time a parser test is run.";
|
||||
};
|
||||
|
||||
steamUsername = mkOption {
|
||||
type = types.str;
|
||||
description = "Steam username for configuration";
|
||||
steamUsername = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
example = "john";
|
||||
description = ''
|
||||
Steam account username used to build the SRM environment-variable
|
||||
reference <literal>''${<username>}</literal> in userSettings.json.
|
||||
This must match the account name shown in Steam (not the display name).
|
||||
'';
|
||||
};
|
||||
|
||||
emulators = mkOption {
|
||||
type = types.attrsOf (types.submodule ({ name, ... }: {
|
||||
options = {
|
||||
enable = mkEnableOption "emulator configuration";
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default =
|
||||
if name == "pcsx2" then pkgs.pcsx2
|
||||
else if name == "citra" then pkgs.citra-nightly
|
||||
else if name == "yuzu" then pkgs.yuzu
|
||||
else if name == "ryujinx" then pkgs.ryubing
|
||||
else if name == "rpcs3" then pkgs.rpcs3
|
||||
else if name == "dolphin-emu" then pkgs.dolphinEmu
|
||||
else if name == "duckstation" then pkgs.duckstation
|
||||
else if name == "melonDS" then pkgs.melonDS
|
||||
else if name == "cemu" then pkgs.cemu
|
||||
else if name == "ppsspp" then pkgs.ppsspp
|
||||
else if name == "mame" then pkgs.mame
|
||||
else if name == "dosbox" then pkgs.dosbox
|
||||
else if name == "snes9x" then pkgs.snes9x-gtk
|
||||
else if name == "mgba" then pkgs.mgba
|
||||
else if name == "mupen64plus" then pkgs.mupen64plus
|
||||
else if name == "retroarch" then pkgs.retroarch
|
||||
else if name == "flycast" then pkgs.flycast
|
||||
else if name == "Non-SRM Shortcuts" then pkgs.steam
|
||||
else pkgs.${name};
|
||||
description = "Emulator package";
|
||||
};
|
||||
parserType = mkOption {
|
||||
type = types.str;
|
||||
default = "Glob";
|
||||
description = "Parser type";
|
||||
};
|
||||
configTitle = mkOption {
|
||||
type = types.str;
|
||||
default = name;
|
||||
description = "Configuration title";
|
||||
};
|
||||
romFolder = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Name of the ROM folder (defaults to common configuration)";
|
||||
};
|
||||
steamCategories = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [""];
|
||||
description = "List of Steam categories";
|
||||
};
|
||||
extraArgs = mkOption {
|
||||
type = types.str;
|
||||
default = "--fullscreen \"\${filePath}\"";
|
||||
description = "Additional emulator arguments";
|
||||
};
|
||||
executableModifier = mkOption {
|
||||
type = types.str;
|
||||
default = "\"\${exePath}\"";
|
||||
description = "Executable modifier";
|
||||
};
|
||||
titleModifier = mkOption {
|
||||
type = types.str;
|
||||
default = "\${fuzzyTitle}";
|
||||
description = "Title modifier";
|
||||
};
|
||||
# fetchControllerTemplatesButton = mkOption {
|
||||
# type = types.str;
|
||||
# default = null;
|
||||
# description = "Fetch controller templates button";
|
||||
# };
|
||||
# removeControllersButton = mkOption {
|
||||
# type = types.str;
|
||||
# default = null;
|
||||
# description = "Remove controller templates button";
|
||||
# };
|
||||
steamInputEnabled = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Enable Steam input";
|
||||
};
|
||||
onlineImageQueries = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ "\${fuzzyTitle}" ];
|
||||
description = "List of online image queries";
|
||||
};
|
||||
imagePool = mkOption {
|
||||
type = types.str;
|
||||
default = "\${fuzzyTitle}";
|
||||
description = "image pool";
|
||||
};
|
||||
drmProtected = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "DRM protected";
|
||||
};
|
||||
userAccounts = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ "Global" ];
|
||||
description = "List of user accounts";
|
||||
};
|
||||
fileTypes = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "List of ROM file types (defaults to common configuration)";
|
||||
};
|
||||
shortcutPassthrough = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Enable shortcut passthrough";
|
||||
};
|
||||
appendArgsToExecutable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Append arguments to executable";
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = {};
|
||||
description = "Emulator configurations";
|
||||
# -------------------------------------------------------------------------
|
||||
# Emulator parser configurations
|
||||
# -------------------------------------------------------------------------
|
||||
emulators = lib.mkOption {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule (
|
||||
{ name, ... }:
|
||||
{
|
||||
options = {
|
||||
|
||||
enable = lib.mkEnableOption "emulator parser for ${name}";
|
||||
|
||||
package = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
# Resolve against knownEmulators first; fall back to pkgs.<name> so
|
||||
# users can supply any arbitrary emulator key without a code change.
|
||||
default = if knownEmulators ? ${name} then knownEmulators.${name}.package else pkgs.${name};
|
||||
description = "Package providing the emulator binary.";
|
||||
};
|
||||
|
||||
parserType = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default =
|
||||
if knownEmulators ? ${name} && knownEmulators.${name} ? parserType then
|
||||
knownEmulators.${name}.parserType
|
||||
else
|
||||
"Glob";
|
||||
description = "SRM parser type (usually \"Glob\" for file-based ROMs).";
|
||||
};
|
||||
|
||||
configTitle = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = name;
|
||||
description = "Human-readable label shown inside SRM for this parser.";
|
||||
};
|
||||
|
||||
romFolder = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
description = ''
|
||||
Sub-folder under <option>environmentVariables.romsDirectory</option>
|
||||
that contains ROMs for this emulator. Defaults to the built-in
|
||||
value for known emulators; must be set explicitly for custom ones.
|
||||
'';
|
||||
};
|
||||
|
||||
steamCategories = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "" ];
|
||||
description = "Steam categories / collection tags to apply to shortcuts.";
|
||||
};
|
||||
|
||||
extraArgs = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "--fullscreen \"\${filePath}\"";
|
||||
description = "Command-line arguments passed to the emulator.";
|
||||
};
|
||||
|
||||
executableModifier = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "\"\${exePath}\"";
|
||||
description = "SRM executable modifier expression.";
|
||||
};
|
||||
|
||||
titleModifier = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "\${fuzzyTitle}";
|
||||
description = "SRM title modifier expression.";
|
||||
};
|
||||
|
||||
steamInputEnabled = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Enable Steam Input controller remapping for shortcuts.";
|
||||
};
|
||||
|
||||
onlineImageQueries = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "\${fuzzyTitle}" ];
|
||||
description = "Query strings used to search for artwork online.";
|
||||
};
|
||||
|
||||
imagePool = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "\${fuzzyTitle}";
|
||||
description = "SRM image pool identifier for artwork caching.";
|
||||
};
|
||||
|
||||
drmProtected = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Mark shortcuts as DRM-protected.";
|
||||
};
|
||||
|
||||
userAccounts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "Global" ];
|
||||
description = "Steam accounts to apply this parser to (\"Global\" applies to all).";
|
||||
};
|
||||
|
||||
fileTypes = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = ''
|
||||
File extensions matched by the glob parser (e.g. <literal>".iso"</literal>).
|
||||
Defaults to the built-in list for known emulators; must be set for custom ones.
|
||||
'';
|
||||
};
|
||||
|
||||
shortcutPassthrough = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Pass through existing Steam shortcuts rather than replacing them.";
|
||||
};
|
||||
|
||||
appendArgsToExecutable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Append <option>extraArgs</option> to the executable path in the shortcut.";
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
default = { };
|
||||
description = "Attribute set of emulator parser configurations keyed by emulator name.";
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user