upd
This commit is contained in:
55
flake.nix
55
flake.nix
@@ -3,19 +3,66 @@
|
|||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
# home-manager is declared so consumers can do
|
||||||
|
# inputs.home-manager.follows = "steam-rom-manager/home-manager"
|
||||||
|
# and so nix flake check can instantiate the module correctly.
|
||||||
home-manager = {
|
home-manager = {
|
||||||
url = "github:nix-community/home-manager";
|
url = "github:nix-community/home-manager";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, home-manager, ... }:
|
outputs =
|
||||||
|
{
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
home-manager,
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
supportedSystems = [ "x86_64-linux" "aarch64-linux" ];
|
# Linux systems where Steam (and AppImages) are supported.
|
||||||
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
|
# Darwin is intentionally excluded: the SRM AppImage is Linux-only.
|
||||||
|
linuxSystems = [
|
||||||
|
"x86_64-linux"
|
||||||
|
"aarch64-linux"
|
||||||
|
];
|
||||||
|
forLinux = nixpkgs.lib.genAttrs linuxSystems;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
# Home Manager module — available under both the conventional .default
|
||||||
|
# key and an explicit name for clarity in consumer flakes.
|
||||||
homeManagerModules.default = import ./modules/steam-rom-manager;
|
homeManagerModules.default = import ./modules/steam-rom-manager;
|
||||||
homeManagerModules.steam-rom-manager = import ./modules/steam-rom-manager;
|
homeManagerModules.steam-rom-manager = import ./modules/steam-rom-manager;
|
||||||
|
|
||||||
|
# `nix flake check` target: instantiate the module with a minimal config
|
||||||
|
# to catch evaluation errors before they reach users.
|
||||||
|
checks = forLinux (
|
||||||
|
system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
hmLib = home-manager.lib;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
module-eval =
|
||||||
|
(hmLib.homeManagerConfiguration {
|
||||||
|
inherit pkgs;
|
||||||
|
modules = [
|
||||||
|
self.homeManagerModules.default
|
||||||
|
{
|
||||||
|
home = {
|
||||||
|
username = "test";
|
||||||
|
homeDirectory = "/home/test";
|
||||||
|
stateVersion = "24.11";
|
||||||
|
};
|
||||||
|
programs.steam-rom-manager = {
|
||||||
|
enable = true;
|
||||||
|
steamUsername = "testuser";
|
||||||
|
# retroarch is cross-platform; use it as the check target
|
||||||
|
emulators.retroarch.enable = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}).activationPackage;
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,276 +1,266 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
with lib;
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
|
version = "2.5.34";
|
||||||
|
|
||||||
cfg = config.programs.steam-rom-manager;
|
cfg = config.programs.steam-rom-manager;
|
||||||
|
|
||||||
# Function to find the main binary in a package
|
# Single source of truth for built-in emulator metadata (package, romFolder,
|
||||||
findMainBinary = pkg:
|
# fileTypes). options.nix imports the same file so both files stay in sync.
|
||||||
|
knownEmulators = import ./emulators.nix pkgs;
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Build an ordered JSON object for one parser entry.
|
||||||
|
# SRM requires keys in a specific order; builtins.toJSON does not guarantee
|
||||||
|
# order, so we construct the JSON string manually from an ordered list.
|
||||||
|
#
|
||||||
|
# Schema version 25 corresponds to SRM ≥ 2.5.x. If you upgrade SRM and the
|
||||||
|
# config format changes, bump `version` here and audit the field list.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
mkParserConfig =
|
||||||
|
name: emu:
|
||||||
let
|
let
|
||||||
pkgName = pkg.pname or (builtins.parseDrvName pkg.name).name;
|
known = knownEmulators.${name} or null;
|
||||||
|
romFolder =
|
||||||
commonVariants = [
|
if emu.romFolder != "" then
|
||||||
pkgName
|
emu.romFolder
|
||||||
"${pkgName}-qt"
|
else if known != null then
|
||||||
"${pkgName}-gtk"
|
known.romFolder
|
||||||
"${pkgName}-emu"
|
else
|
||||||
"Ryujinx"
|
lib.warn "steam-rom-manager: unknown emulator '${name}', romFolder not set" "";
|
||||||
|
fileTypes =
|
||||||
|
if emu.fileTypes != [ ] then
|
||||||
|
emu.fileTypes
|
||||||
|
else if known != null then
|
||||||
|
known.fileTypes
|
||||||
|
else
|
||||||
|
lib.warn "steam-rom-manager: unknown emulator '${name}', fileTypes not set" [ ];
|
||||||
|
parserType = emu.parserType;
|
||||||
|
|
||||||
|
# lib.getExe resolves the primary binary without IFD path probing.
|
||||||
|
exePath = lib.getExe emu.package;
|
||||||
|
|
||||||
|
orderedConfig = [
|
||||||
|
{
|
||||||
|
name = "parserType";
|
||||||
|
value = parserType;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "configTitle";
|
||||||
|
value = emu.configTitle;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "steamDirectory";
|
||||||
|
value = "\${steamdirglobal}";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "romDirectory";
|
||||||
|
value = "${cfg.environmentVariables.romsDirectory}/${romFolder}";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "steamCategories";
|
||||||
|
value = emu.steamCategories;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "executableArgs";
|
||||||
|
value = emu.extraArgs;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "executableModifier";
|
||||||
|
value = emu.executableModifier;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "startInDirectory";
|
||||||
|
value = "${cfg.environmentVariables.romsDirectory}/${romFolder}";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "titleModifier";
|
||||||
|
value = emu.titleModifier;
|
||||||
|
}
|
||||||
|
# fetchControllerTemplatesButton / removeControllersButton are UI-only
|
||||||
|
# action triggers in SRM; they have no meaningful config value and must
|
||||||
|
# be present as null for schema compatibility.
|
||||||
|
{
|
||||||
|
name = "fetchControllerTemplatesButton";
|
||||||
|
value = null;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "removeControllersButton";
|
||||||
|
value = null;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "steamInputEnabled";
|
||||||
|
value = if emu.steamInputEnabled then "1" else "0";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "imageProviders";
|
||||||
|
value = cfg.enabledProviders;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "onlineImageQueries";
|
||||||
|
value = emu.onlineImageQueries;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "imagePool";
|
||||||
|
value = emu.imagePool;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "drmProtect";
|
||||||
|
value = emu.drmProtected;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "userAccounts";
|
||||||
|
value = {
|
||||||
|
specifiedAccounts = emu.userAccounts;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "parserInputs";
|
||||||
|
value = {
|
||||||
|
glob = "\${title}@(${lib.concatStringsSep "|" fileTypes})";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "executable";
|
||||||
|
value = {
|
||||||
|
path = exePath;
|
||||||
|
shortcutPassthrough = emu.shortcutPassthrough;
|
||||||
|
appendArgsToExecutable = emu.appendArgsToExecutable;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "titleFromVariable";
|
||||||
|
value = {
|
||||||
|
limitToGroups = [ ];
|
||||||
|
caseInsensitiveVariables = false;
|
||||||
|
skipFileIfVariableWasNotFound = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "fuzzyMatch";
|
||||||
|
value = {
|
||||||
|
replaceDiacritics = true;
|
||||||
|
removeCharacters = true;
|
||||||
|
removeBrackets = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "controllers";
|
||||||
|
value = {
|
||||||
|
ps4 = null;
|
||||||
|
ps5 = null;
|
||||||
|
ps5_edge = null;
|
||||||
|
xbox360 = null;
|
||||||
|
xboxone = null;
|
||||||
|
xboxelite = null;
|
||||||
|
switch_joycon_left = null;
|
||||||
|
switch_joycon_right = null;
|
||||||
|
switch_pro = null;
|
||||||
|
neptune = null;
|
||||||
|
steamcontroller_gordon = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "imageProviderAPIs";
|
||||||
|
value = {
|
||||||
|
sgdb = cfg.imageProviderSettings.sgdb;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "defaultImage";
|
||||||
|
value = {
|
||||||
|
tall = "";
|
||||||
|
long = "";
|
||||||
|
hero = "";
|
||||||
|
logo = "";
|
||||||
|
icon = "";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "localImages";
|
||||||
|
value = {
|
||||||
|
tall = "";
|
||||||
|
long = "";
|
||||||
|
hero = "";
|
||||||
|
logo = "";
|
||||||
|
icon = "";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "parserId";
|
||||||
|
value = name;
|
||||||
|
}
|
||||||
|
# SRM userConfigurations schema version — bump when upgrading past a
|
||||||
|
# breaking config format change in SRM itself.
|
||||||
|
{
|
||||||
|
name = "version";
|
||||||
|
value = 25;
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
existingVariant = findFirst
|
makeOrderedJSON =
|
||||||
(variant: builtins.pathExists "${pkg}/bin/${variant}")
|
pairs:
|
||||||
null
|
let
|
||||||
commonVariants;
|
joined = builtins.concatStringsSep "," (
|
||||||
|
map (pair: "\"${pair.name}\":${builtins.toJSON pair.value}") pairs
|
||||||
|
);
|
||||||
|
in
|
||||||
|
"{${joined}}";
|
||||||
in
|
in
|
||||||
if existingVariant != null
|
|
||||||
then existingVariant
|
|
||||||
else pkgName;
|
|
||||||
|
|
||||||
# Common emulator configurations with default packages
|
|
||||||
commonEmulatorConfigs = {
|
|
||||||
ryujinx = {
|
|
||||||
romFolder = "switch";
|
|
||||||
fileTypes = [ ".nca" ".NCA" ".nro" ".NRO" ".nso" ".NSO" ".nsp" ".NSP" ".xci" ".XCI" ];
|
|
||||||
package = pkgs.ryujinx;
|
|
||||||
};
|
|
||||||
yuzu = {
|
|
||||||
romFolder = "switch";
|
|
||||||
fileTypes = [ ".nsp" ".NSP" ".xci" ".XCI" ];
|
|
||||||
package = pkgs.yuzu;
|
|
||||||
};
|
|
||||||
pcsx2 = {
|
|
||||||
romFolder = "ps2";
|
|
||||||
fileTypes = [ ".iso" ".ISO" ".bin" ".BIN" ".chd" ".CHD" ];
|
|
||||||
package = pkgs.pcsx2;
|
|
||||||
};
|
|
||||||
rpcs3 = {
|
|
||||||
romFolder = "ps3";
|
|
||||||
fileTypes = [ ".iso" ".ISO" ".bin" ".BIN" ".pkg" ".PKG" ];
|
|
||||||
package = pkgs.rpcs3;
|
|
||||||
};
|
|
||||||
dolphin-emu = {
|
|
||||||
romFolder = "gc";
|
|
||||||
fileTypes = [ ".iso" ".ISO" ".gcm" ".GCM" ".ciso" ".CISO" ];
|
|
||||||
package = pkgs.dolphin-emu;
|
|
||||||
};
|
|
||||||
duckstation = {
|
|
||||||
romFolder = "psx";
|
|
||||||
fileTypes = [ ".iso" ".ISO" ".bin" ".BIN" ".chd" ".CHD" ".pbp" ".PBP" ];
|
|
||||||
package = pkgs.duckstation;
|
|
||||||
};
|
|
||||||
melonDS = {
|
|
||||||
romFolder = "nds";
|
|
||||||
fileTypes = [ ".nds" ".NDS" ];
|
|
||||||
package = pkgs.melonDS;
|
|
||||||
};
|
|
||||||
cemu = {
|
|
||||||
romFolder = "wiiu";
|
|
||||||
fileTypes = [ ".wud" ".WUD" ".wux" ".WUX" ".rpx" ".RPX" ];
|
|
||||||
package = pkgs.cemu;
|
|
||||||
};
|
|
||||||
ppsspp = {
|
|
||||||
romFolder = "psp";
|
|
||||||
fileTypes = [ ".iso" ".ISO" ".cso" ".CSO" ".pbp" ".PBP" ];
|
|
||||||
package = pkgs.ppsspp;
|
|
||||||
};
|
|
||||||
mame = {
|
|
||||||
romFolder = "arcade";
|
|
||||||
fileTypes = [ ".zip" ".ZIP" ".7z" ".7Z" ];
|
|
||||||
package = pkgs.mame;
|
|
||||||
};
|
|
||||||
dosbox = {
|
|
||||||
romFolder = "dos";
|
|
||||||
fileTypes = [ ".exe" ".EXE" ".bat" ".BAT" ".com" ".COM" ];
|
|
||||||
package = pkgs.dosbox;
|
|
||||||
};
|
|
||||||
snes9x = {
|
|
||||||
romFolder = "snes";
|
|
||||||
fileTypes = [ ".smc" ".SMC" ".sfc" ".SFC" ".fig" ".FIG" ];
|
|
||||||
package = pkgs.snes9x-gtk;
|
|
||||||
};
|
|
||||||
mgba = {
|
|
||||||
romFolder = "gba";
|
|
||||||
fileTypes = [ ".gba" ".GBA" ];
|
|
||||||
package = pkgs.mgba;
|
|
||||||
};
|
|
||||||
mupen64plus = {
|
|
||||||
romFolder = "n64";
|
|
||||||
fileTypes = [ ".n64" ".N64" ".v64" ".V64" ".z64" ".Z64" ];
|
|
||||||
package = pkgs.mupen64plus;
|
|
||||||
};
|
|
||||||
retroarch = {
|
|
||||||
romFolder = "retroarch";
|
|
||||||
fileTypes = [ ".zip" ".ZIP" ".7z" ".7Z" ".iso" ".ISO" ".bin" ".BIN" ".chd" ".CHD" ];
|
|
||||||
package = pkgs.retroarch;
|
|
||||||
};
|
|
||||||
flycast = {
|
|
||||||
romFolder = "dreamcast";
|
|
||||||
fileTypes = [ ".gdi" ".GDI" ".cdi" ".CDI" ".chd" ".CHD" ];
|
|
||||||
package = pkgs.flycast;
|
|
||||||
};
|
|
||||||
citra = {
|
|
||||||
romFolder = "3ds";
|
|
||||||
fileTypes = [ ".3ds" ".3DS" ".cia" ".CIA" ".cxi" ".CXI" ];
|
|
||||||
package = pkgs.citra-nightly;
|
|
||||||
};
|
|
||||||
"Non-SRM Shortcuts" = {
|
|
||||||
parserType = "Non-SRM Shortcuts";
|
|
||||||
romFolder = "";
|
|
||||||
fileTypes = [ ];
|
|
||||||
package = pkgs.steam;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Create parser configuration
|
|
||||||
mkParserConfig = name: emu:
|
|
||||||
let
|
|
||||||
# Use the provided package or fall back to the default if available
|
|
||||||
package = emu.package;
|
|
||||||
# Get the binary name dynamically
|
|
||||||
binaryName = findMainBinary package;
|
|
||||||
|
|
||||||
orderedConfig = [
|
|
||||||
# Basic parser configuration
|
|
||||||
{ name = "parserType"; value = emu.parserType; }
|
|
||||||
{ name = "configTitle"; value = emu.configTitle; }
|
|
||||||
{ name = "steamDirectory"; value = "\${steamdirglobal}"; }
|
|
||||||
{ name = "romDirectory"; value = "${cfg.environmentVariables.romsDirectory}/${if emu.romFolder != "" then emu.romFolder else commonEmulatorConfigs.${name}.romFolder}"; }
|
|
||||||
{ name = "steamCategories"; value = emu.steamCategories; }
|
|
||||||
|
|
||||||
# Executable configuration
|
|
||||||
{ name = "executableArgs"; value = emu.extraArgs; }
|
|
||||||
{ name = "executableModifier"; value = emu.executableModifier; }
|
|
||||||
{ name = "startInDirectory"; value = "${cfg.environmentVariables.romsDirectory}/${if emu.romFolder != "" then emu.romFolder else commonEmulatorConfigs.${name}.romFolder}"; }
|
|
||||||
{ name = "titleModifier"; value = emu.titleModifier; }
|
|
||||||
|
|
||||||
# Controller settings
|
|
||||||
{ name = "fetchControllerTemplatesButton"; value = null; }
|
|
||||||
{ name = "removeControllersButton"; value = null; }
|
|
||||||
{ name = "steamInputEnabled"; value = if emu.steamInputEnabled then "1" else "0"; }
|
|
||||||
|
|
||||||
# Image provider configuration
|
|
||||||
{ name = "imageProviders"; value = cfg.enabledProviders; }
|
|
||||||
{ name = "onlineImageQueries"; value = emu.onlineImageQueries; }
|
|
||||||
{ name = "imagePool"; value = emu.imagePool; }
|
|
||||||
|
|
||||||
# DRM and user account settings
|
|
||||||
{ name = "drmProtect"; value = emu.drmProtected; }
|
|
||||||
{ name = "userAccounts"; value = {
|
|
||||||
specifiedAccounts = emu.userAccounts;
|
|
||||||
}; }
|
|
||||||
|
|
||||||
# Parser-specific settings
|
|
||||||
{ name = "parserInputs"; value = {
|
|
||||||
glob = "\${title}@(${concatStringsSep "|" (if emu.fileTypes != [] then emu.fileTypes else commonEmulatorConfigs.${name}.fileTypes)})";
|
|
||||||
}; }
|
|
||||||
|
|
||||||
# Executable details
|
|
||||||
{ name = "executable"; value = {
|
|
||||||
path = "${package}/bin/${binaryName}";
|
|
||||||
shortcutPassthrough = emu.shortcutPassthrough;
|
|
||||||
appendArgsToExecutable = emu.appendArgsToExecutable;
|
|
||||||
}; }
|
|
||||||
|
|
||||||
# Title and fuzzy matching configuration
|
|
||||||
{ name = "titleFromVariable"; value = {
|
|
||||||
limitToGroups = [];
|
|
||||||
caseInsensitiveVariables = false;
|
|
||||||
skipFileIfVariableWasNotFound = false;
|
|
||||||
}; }
|
|
||||||
|
|
||||||
{ name = "fuzzyMatch"; value = {
|
|
||||||
replaceDiacritics = true;
|
|
||||||
removeCharacters = true;
|
|
||||||
removeBrackets = true;
|
|
||||||
}; }
|
|
||||||
|
|
||||||
# Controller configuration
|
|
||||||
{ name = "controllers"; value = {
|
|
||||||
ps4 = null;
|
|
||||||
ps5 = null;
|
|
||||||
ps5_edge = null;
|
|
||||||
xbox360 = null;
|
|
||||||
xboxone = null;
|
|
||||||
xboxelite = null;
|
|
||||||
switch_joycon_left = null;
|
|
||||||
switch_joycon_right = null;
|
|
||||||
switch_pro = null;
|
|
||||||
neptune = null;
|
|
||||||
steamcontroller_gordon = null;
|
|
||||||
}; }
|
|
||||||
|
|
||||||
# Image provider API configuration
|
|
||||||
{ name = "imageProviderAPIs"; value = {
|
|
||||||
sgdb = cfg.imageProviderSettings.sgdb;
|
|
||||||
}; }
|
|
||||||
|
|
||||||
# Default and local image settings
|
|
||||||
{ name = "defaultImage"; value = {
|
|
||||||
tall = "";
|
|
||||||
long = "";
|
|
||||||
hero = "";
|
|
||||||
logo = "";
|
|
||||||
icon = "";
|
|
||||||
}; }
|
|
||||||
|
|
||||||
{ name = "localImages"; value = {
|
|
||||||
tall = "";
|
|
||||||
long = "";
|
|
||||||
hero = "";
|
|
||||||
logo = "";
|
|
||||||
icon = "";
|
|
||||||
}; }
|
|
||||||
|
|
||||||
# Parser identification
|
|
||||||
{ name = "parserId"; value = name; }
|
|
||||||
{ name = "version"; value = 25; }
|
|
||||||
];
|
|
||||||
|
|
||||||
# Function to convert our ordered list into properly formatted JSON
|
|
||||||
makeOrderedJSON = pairs:
|
|
||||||
let
|
|
||||||
joined = builtins.concatStringsSep ","
|
|
||||||
(map (pair: "\"${pair.name}\":${builtins.toJSON pair.value}") pairs);
|
|
||||||
in
|
|
||||||
"{${joined}}";
|
|
||||||
in
|
|
||||||
makeOrderedJSON orderedConfig;
|
makeOrderedJSON orderedConfig;
|
||||||
|
|
||||||
# Fetch the SVG icon file
|
# ---------------------------------------------------------------------------
|
||||||
|
# Icon — pinned to the commit that introduced the current SVG so the hash
|
||||||
|
# does not break when unrelated files change on master.
|
||||||
|
# Commit: 1670cbe8871a632708e0440ccef52c5c5c403ddc (2024-01-12)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
steam-rom-manager-icon = pkgs.fetchurl {
|
steam-rom-manager-icon = pkgs.fetchurl {
|
||||||
name = "steam-rom-manager.svg";
|
name = "steam-rom-manager.svg";
|
||||||
url = "https://raw.githubusercontent.com/SteamGridDB/steam-rom-manager/master/src/assets/icons/steam-rom-manager.svg";
|
url = "https://raw.githubusercontent.com/SteamGridDB/steam-rom-manager/1670cbe8871a632708e0440ccef52c5c5c403ddc/src/assets/icons/steam-rom-manager.svg";
|
||||||
hash = "sha256-DKzNIs5UhIWAVRTfinvCb8WqeDniPWw9Z08/p/Zpa9E=";
|
hash = "sha256-DKzNIs5UhIWAVRTfinvCb8WqeDniPWw9Z08/p/Zpa9E=";
|
||||||
};
|
};
|
||||||
|
|
||||||
# # Create Steam ROM Manager package
|
# ---------------------------------------------------------------------------
|
||||||
|
# Wrap the upstream AppImage with appimage-run.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
steam-rom-manager-appimage = pkgs.writeShellScriptBin "steam-rom-manager" ''
|
steam-rom-manager-appimage = pkgs.writeShellScriptBin "steam-rom-manager" ''
|
||||||
exec ${pkgs.appimage-run}/bin/appimage-run ${pkgs.fetchurl {
|
exec ${pkgs.appimage-run}/bin/appimage-run ${
|
||||||
name = "steam-rom-manager-2.5.30.AppImage";
|
pkgs.fetchurl {
|
||||||
url = "https://github.com/SteamGridDB/steam-rom-manager/releases/download/v2.5.30/Steam-ROM-Manager-2.5.30.AppImage";
|
name = "steam-rom-manager-${version}.AppImage";
|
||||||
hash = "sha256-2prpPNgB8EYrswYc98RRrQtHc/s9asbtACRCDyyGQqg=";
|
url = "https://github.com/SteamGridDB/steam-rom-manager/releases/download/v${version}/Steam-ROM-Manager-${version}.AppImage";
|
||||||
}} "$@"
|
hash = "sha256-QbXwfT91BQ15/DL3IYC3qZcahlsQvkUKTwMUUpZY+U8=";
|
||||||
'';
|
}
|
||||||
|
} "$@"
|
||||||
|
'';
|
||||||
|
|
||||||
in {
|
in
|
||||||
imports = [
|
{
|
||||||
./options.nix
|
imports = [ ./options.nix ];
|
||||||
];
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
home.packages = [ pkgs.appimage-run steam-rom-manager-appimage ]
|
|
||||||
++ mapAttrsToList (_: v: v.package) (filterAttrs (_: v: v.enable) cfg.emulators);
|
|
||||||
|
|
||||||
xdg.dataFile = {
|
home.packages = [
|
||||||
"icons/hicolor/scalable/apps/steam-rom-manager.svg".source = steam-rom-manager-icon;
|
pkgs.appimage-run
|
||||||
};
|
steam-rom-manager-appimage
|
||||||
|
]
|
||||||
|
++ lib.mapAttrsToList (_: v: v.package) (lib.filterAttrs (_: v: v.enable) cfg.emulators);
|
||||||
|
|
||||||
|
xdg.dataFile."icons/hicolor/scalable/apps/steam-rom-manager.svg".source = steam-rom-manager-icon;
|
||||||
|
|
||||||
xdg.desktopEntries.steam-rom-manager = {
|
xdg.desktopEntries.steam-rom-manager = {
|
||||||
name = "Steam ROM Manager";
|
name = "Steam ROM Manager";
|
||||||
exec = "${steam-rom-manager-appimage}/bin/steam-rom-manager";
|
exec = "${steam-rom-manager-appimage}/bin/steam-rom-manager";
|
||||||
icon = "steam-rom-manager";
|
icon = "steam-rom-manager";
|
||||||
categories = [ "Game" "Utility" ];
|
categories = [
|
||||||
|
"Game"
|
||||||
|
"Utility"
|
||||||
|
];
|
||||||
type = "Application";
|
type = "Application";
|
||||||
terminal = false;
|
terminal = false;
|
||||||
comment = "Add ROMs to Steam with artwork";
|
comment = "Add ROMs to Steam with artwork";
|
||||||
@@ -282,12 +272,10 @@ in {
|
|||||||
};
|
};
|
||||||
|
|
||||||
xdg.configFile = {
|
xdg.configFile = {
|
||||||
|
# userSettings schema version 8 corresponds to SRM ≥ 2.4.x.
|
||||||
"steam-rom-manager/userData/userSettings.json".text = builtins.toJSON {
|
"steam-rom-manager/userData/userSettings.json".text = builtins.toJSON {
|
||||||
fuzzyMatcher = {
|
fuzzyMatcher = {
|
||||||
timestamps = {
|
timestamps = { inherit (cfg.fuzzyMatcher.timestamps) check download; };
|
||||||
check = cfg.fuzzyMatcher.timestamps.check;
|
|
||||||
download = cfg.fuzzyMatcher.timestamps.download;
|
|
||||||
};
|
|
||||||
verbose = cfg.fuzzyMatcher.verbose;
|
verbose = cfg.fuzzyMatcher.verbose;
|
||||||
filterProviders = cfg.fuzzyMatcher.filterProviders;
|
filterProviders = cfg.fuzzyMatcher.filterProviders;
|
||||||
};
|
};
|
||||||
@@ -316,18 +304,13 @@ in {
|
|||||||
version = 8;
|
version = 8;
|
||||||
};
|
};
|
||||||
|
|
||||||
"steam-rom-manager/userData/userConfigurations.json".text =
|
"steam-rom-manager/userData/userConfigurations.json".text =
|
||||||
let
|
let
|
||||||
configs = mapAttrsToList (name: emu:
|
configs = lib.mapAttrsToList (name: emu: mkParserConfig name emu) (
|
||||||
mkParserConfig name (emu // {
|
lib.filterAttrs (_: v: v.enable) cfg.emulators
|
||||||
romFolder = if emu.romFolder != "" then emu.romFolder else commonEmulatorConfigs.${name}.romFolder;
|
);
|
||||||
# binaryName = if emu.binaryName != "" then emu.binaryName else commonEmulatorConfigs.${name}.binaryName;
|
in
|
||||||
})
|
"[${lib.concatStringsSep "," configs}]";
|
||||||
) (filterAttrs (_: v: v.enable) cfg.emulators);
|
|
||||||
|
|
||||||
configsJson = "[${concatStringsSep "," configs}]";
|
|
||||||
in
|
|
||||||
configsJson;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
249
modules/steam-rom-manager/emulators.nix
Normal file
249
modules/steam-rom-manager/emulators.nix
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
# emulators.nix — single source of truth for built-in emulator metadata.
|
||||||
|
#
|
||||||
|
# Both default.nix (for romFolder/fileTypes fallbacks) and options.nix (for
|
||||||
|
# package defaults) import this file directly, preventing the two files from
|
||||||
|
# drifting out of sync.
|
||||||
|
#
|
||||||
|
# Each entry may contain:
|
||||||
|
# package — nixpkgs derivation (required)
|
||||||
|
# romFolder — sub-directory name under romsDirectory (required)
|
||||||
|
# fileTypes — list of file extensions matched by the glob parser (required)
|
||||||
|
# parserType — SRM parser type string; omit to use the default "Glob"
|
||||||
|
|
||||||
|
pkgs: {
|
||||||
|
|
||||||
|
ryujinx = {
|
||||||
|
# ryujinx was removed from nixpkgs; ryubing is the maintained community fork
|
||||||
|
package = pkgs.ryubing;
|
||||||
|
romFolder = "switch";
|
||||||
|
fileTypes = [
|
||||||
|
".nca"
|
||||||
|
".NCA"
|
||||||
|
".nro"
|
||||||
|
".NRO"
|
||||||
|
".nso"
|
||||||
|
".NSO"
|
||||||
|
".nsp"
|
||||||
|
".NSP"
|
||||||
|
".xci"
|
||||||
|
".XCI"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# yuzu was removed from nixpkgs after the Nintendo lawsuit; eden is the successor
|
||||||
|
yuzu = {
|
||||||
|
package = pkgs.eden;
|
||||||
|
romFolder = "switch";
|
||||||
|
fileTypes = [
|
||||||
|
".nsp"
|
||||||
|
".NSP"
|
||||||
|
".xci"
|
||||||
|
".XCI"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
pcsx2 = {
|
||||||
|
package = pkgs.pcsx2;
|
||||||
|
romFolder = "ps2";
|
||||||
|
fileTypes = [
|
||||||
|
".iso"
|
||||||
|
".ISO"
|
||||||
|
".bin"
|
||||||
|
".BIN"
|
||||||
|
".chd"
|
||||||
|
".CHD"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
rpcs3 = {
|
||||||
|
package = pkgs.rpcs3;
|
||||||
|
romFolder = "ps3";
|
||||||
|
fileTypes = [
|
||||||
|
".iso"
|
||||||
|
".ISO"
|
||||||
|
".bin"
|
||||||
|
".BIN"
|
||||||
|
".pkg"
|
||||||
|
".PKG"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
dolphin-emu = {
|
||||||
|
# Use pkgs.dolphin-emu (the user-facing wrapper), not pkgs.dolphinEmu
|
||||||
|
package = pkgs.dolphin-emu;
|
||||||
|
romFolder = "gc";
|
||||||
|
fileTypes = [
|
||||||
|
".iso"
|
||||||
|
".ISO"
|
||||||
|
".gcm"
|
||||||
|
".GCM"
|
||||||
|
".ciso"
|
||||||
|
".CISO"
|
||||||
|
".rvz"
|
||||||
|
".RVZ"
|
||||||
|
".wbfs"
|
||||||
|
".WBFS"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
duckstation = {
|
||||||
|
package = pkgs.duckstation;
|
||||||
|
romFolder = "psx";
|
||||||
|
fileTypes = [
|
||||||
|
".iso"
|
||||||
|
".ISO"
|
||||||
|
".bin"
|
||||||
|
".BIN"
|
||||||
|
".chd"
|
||||||
|
".CHD"
|
||||||
|
".pbp"
|
||||||
|
".PBP"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
melonDS = {
|
||||||
|
package = pkgs.melonDS;
|
||||||
|
romFolder = "nds";
|
||||||
|
fileTypes = [
|
||||||
|
".nds"
|
||||||
|
".NDS"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
cemu = {
|
||||||
|
package = pkgs.cemu;
|
||||||
|
romFolder = "wiiu";
|
||||||
|
fileTypes = [
|
||||||
|
".wud"
|
||||||
|
".WUD"
|
||||||
|
".wux"
|
||||||
|
".WUX"
|
||||||
|
".rpx"
|
||||||
|
".RPX"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
ppsspp = {
|
||||||
|
package = pkgs.ppsspp;
|
||||||
|
romFolder = "psp";
|
||||||
|
fileTypes = [
|
||||||
|
".iso"
|
||||||
|
".ISO"
|
||||||
|
".cso"
|
||||||
|
".CSO"
|
||||||
|
".pbp"
|
||||||
|
".PBP"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
mame = {
|
||||||
|
package = pkgs.mame;
|
||||||
|
romFolder = "arcade";
|
||||||
|
fileTypes = [
|
||||||
|
".zip"
|
||||||
|
".ZIP"
|
||||||
|
".7z"
|
||||||
|
".7Z"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
dosbox = {
|
||||||
|
package = pkgs.dosbox;
|
||||||
|
romFolder = "dos";
|
||||||
|
fileTypes = [
|
||||||
|
".exe"
|
||||||
|
".EXE"
|
||||||
|
".bat"
|
||||||
|
".BAT"
|
||||||
|
".com"
|
||||||
|
".COM"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
snes9x = {
|
||||||
|
package = pkgs.snes9x-gtk;
|
||||||
|
romFolder = "snes";
|
||||||
|
fileTypes = [
|
||||||
|
".smc"
|
||||||
|
".SMC"
|
||||||
|
".sfc"
|
||||||
|
".SFC"
|
||||||
|
".fig"
|
||||||
|
".FIG"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
mgba = {
|
||||||
|
package = pkgs.mgba;
|
||||||
|
romFolder = "gba";
|
||||||
|
fileTypes = [
|
||||||
|
".gba"
|
||||||
|
".GBA"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
mupen64plus = {
|
||||||
|
package = pkgs.mupen64plus;
|
||||||
|
romFolder = "n64";
|
||||||
|
fileTypes = [
|
||||||
|
".n64"
|
||||||
|
".N64"
|
||||||
|
".v64"
|
||||||
|
".V64"
|
||||||
|
".z64"
|
||||||
|
".Z64"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
retroarch = {
|
||||||
|
package = pkgs.retroarch;
|
||||||
|
romFolder = "retroarch";
|
||||||
|
fileTypes = [
|
||||||
|
".zip"
|
||||||
|
".ZIP"
|
||||||
|
".7z"
|
||||||
|
".7Z"
|
||||||
|
".iso"
|
||||||
|
".ISO"
|
||||||
|
".bin"
|
||||||
|
".BIN"
|
||||||
|
".chd"
|
||||||
|
".CHD"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
flycast = {
|
||||||
|
package = pkgs.flycast;
|
||||||
|
romFolder = "dreamcast";
|
||||||
|
fileTypes = [
|
||||||
|
".gdi"
|
||||||
|
".GDI"
|
||||||
|
".cdi"
|
||||||
|
".CDI"
|
||||||
|
".chd"
|
||||||
|
".CHD"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# citra-nightly was removed from nixpkgs; azahar is the maintained successor
|
||||||
|
citra = {
|
||||||
|
package = pkgs.azahar;
|
||||||
|
romFolder = "3ds";
|
||||||
|
fileTypes = [
|
||||||
|
".3ds"
|
||||||
|
".3DS"
|
||||||
|
".cia"
|
||||||
|
".CIA"
|
||||||
|
".cxi"
|
||||||
|
".CXI"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
"Non-SRM Shortcuts" = {
|
||||||
|
package = pkgs.steam;
|
||||||
|
parserType = "Non-SRM Shortcuts";
|
||||||
|
romFolder = "";
|
||||||
|
fileTypes = [ ];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,360 +1,387 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
with lib;
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.programs.steam-rom-manager;
|
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 = {
|
fuzzyMatcher = {
|
||||||
timestamps = {
|
timestamps = {
|
||||||
check = mkOption {
|
check = lib.mkOption {
|
||||||
type = types.int;
|
type = lib.types.int;
|
||||||
default = 0;
|
default = 0;
|
||||||
description = "Timestamp for fuzzy matcher check";
|
description = "Epoch timestamp of the last fuzzy-matcher data check.";
|
||||||
};
|
};
|
||||||
download = mkOption {
|
download = lib.mkOption {
|
||||||
type = types.int;
|
type = lib.types.int;
|
||||||
default = 0;
|
default = 0;
|
||||||
description = "Timestamp for fuzzy matcher download";
|
description = "Epoch timestamp of the last fuzzy-matcher data download.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
verbose = mkOption {
|
verbose = lib.mkOption {
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = "Enable verbose logging for fuzzy matcher";
|
description = "Enable verbose logging for the fuzzy matcher.";
|
||||||
};
|
};
|
||||||
filterProviders = mkOption {
|
filterProviders = lib.mkOption {
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
description = "Filter image providers";
|
description = "Restrict image lookups to the configured providers.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Environment variables written into userSettings.json
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
environmentVariables = {
|
environmentVariables = {
|
||||||
steamDirectory = mkOption {
|
steamDirectory = lib.mkOption {
|
||||||
type = types.str;
|
type = lib.types.str;
|
||||||
default = "${config.home.homeDirectory}/.local/share/Steam";
|
default = "${config.home.homeDirectory}/.local/share/Steam";
|
||||||
description = "Steam installation directory";
|
description = "Path to the Steam data directory.";
|
||||||
};
|
};
|
||||||
|
romsDirectory = lib.mkOption {
|
||||||
romsDirectory = mkOption {
|
type = lib.types.str;
|
||||||
type = types.str;
|
|
||||||
default = "${config.home.homeDirectory}/Emulation/roms";
|
default = "${config.home.homeDirectory}/Emulation/roms";
|
||||||
description = "Base directory for ROM files";
|
description = "Root directory that contains per-system ROM sub-folders.";
|
||||||
};
|
};
|
||||||
|
retroarchPath = lib.mkOption {
|
||||||
retroarchPath = mkOption {
|
type = lib.types.str;
|
||||||
type = types.str;
|
|
||||||
default = "";
|
default = "";
|
||||||
description = "Path to RetroArch executable";
|
description = "Path to the RetroArch executable (leave empty if not using RetroArch).";
|
||||||
};
|
};
|
||||||
|
raCoresDirectory = lib.mkOption {
|
||||||
raCoresDirectory = mkOption {
|
type = lib.types.str;
|
||||||
type = types.str;
|
|
||||||
default = "";
|
default = "";
|
||||||
description = "RetroArch cores directory";
|
description = "Directory containing RetroArch cores.";
|
||||||
};
|
};
|
||||||
|
localImagesDirectory = lib.mkOption {
|
||||||
localImagesDirectory = mkOption {
|
type = lib.types.str;
|
||||||
type = types.str;
|
|
||||||
default = "";
|
default = "";
|
||||||
description = "Directory for local images";
|
description = "Directory for locally stored artwork.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Preview settings
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
previewSettings = {
|
previewSettings = {
|
||||||
retrieveCurrentSteamImages = mkOption {
|
retrieveCurrentSteamImages = lib.mkOption {
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
description = "Retrieve current Steam images";
|
description = "Download existing Steam artwork when previewing.";
|
||||||
};
|
};
|
||||||
|
disableCategories = lib.mkOption {
|
||||||
disableCategories = mkOption {
|
type = lib.types.bool;
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
default = false;
|
||||||
description = "Disable Steam categories";
|
description = "Do not apply Steam category tags to shortcuts.";
|
||||||
};
|
};
|
||||||
|
deleteDisabledShortcuts = lib.mkOption {
|
||||||
deleteDisabledShortcuts = mkOption {
|
type = lib.types.bool;
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
default = false;
|
||||||
description = "Delete disabled shortcuts";
|
description = "Remove shortcuts for parsers that are disabled.";
|
||||||
};
|
};
|
||||||
|
imageZoomPercentage = lib.mkOption {
|
||||||
imageZoomPercentage = mkOption {
|
type = lib.types.int;
|
||||||
type = types.int;
|
|
||||||
default = 30;
|
default = 30;
|
||||||
description = "Image zoom percentage in preview";
|
description = "Zoom level (%) used when displaying artwork in the preview pane.";
|
||||||
};
|
};
|
||||||
|
preload = lib.mkOption {
|
||||||
preload = mkOption {
|
type = lib.types.bool;
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
default = false;
|
||||||
description = "Preload images";
|
description = "Pre-fetch artwork while the preview loads.";
|
||||||
};
|
};
|
||||||
|
hideUserAccount = lib.mkOption {
|
||||||
hideUserAccount = mkOption {
|
type = lib.types.bool;
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
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;
|
# Image providers
|
||||||
default = [ "sgdb" "steamCDN" ];
|
# -------------------------------------------------------------------------
|
||||||
description = "Enabled 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 = {
|
imageProviderSettings = {
|
||||||
sgdb = {
|
sgdb = {
|
||||||
nsfw = mkOption {
|
nsfw = lib.mkOption {
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = "Allow NSFW content from SteamGridDB";
|
description = "Include NSFW artwork from SteamGridDB.";
|
||||||
};
|
};
|
||||||
|
humor = lib.mkOption {
|
||||||
humor = mkOption {
|
type = lib.types.bool;
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
default = false;
|
||||||
description = "Allow humor content from SteamGridDB";
|
description = "Include humour-tagged artwork from SteamGridDB.";
|
||||||
};
|
};
|
||||||
|
styles = lib.mkOption {
|
||||||
styles = mkOption {
|
type = lib.types.listOf lib.types.str;
|
||||||
type = types.listOf types.str;
|
default = [ ];
|
||||||
default = [];
|
description = "Preferred grid artwork styles (e.g. \"alternate\", \"blurred\").";
|
||||||
description = "Preferred art styles for SteamGridDB";
|
|
||||||
};
|
};
|
||||||
|
stylesHero = lib.mkOption {
|
||||||
stylesHero = mkOption {
|
type = lib.types.listOf lib.types.str;
|
||||||
type = types.listOf types.str;
|
default = [ ];
|
||||||
default = [];
|
description = "Preferred hero artwork styles.";
|
||||||
description = "Preferred hero art styles for SteamGridDB";
|
|
||||||
};
|
};
|
||||||
|
stylesLogo = lib.mkOption {
|
||||||
stylesLogo = mkOption {
|
type = lib.types.listOf lib.types.str;
|
||||||
type = types.listOf types.str;
|
default = [ ];
|
||||||
default = [];
|
description = "Preferred logo styles.";
|
||||||
description = "Preferred logo styles for SteamGridDB";
|
|
||||||
};
|
};
|
||||||
|
stylesIcon = lib.mkOption {
|
||||||
stylesIcon = mkOption {
|
type = lib.types.listOf lib.types.str;
|
||||||
type = types.listOf types.str;
|
default = [ ];
|
||||||
default = [];
|
description = "Preferred icon styles.";
|
||||||
description = "Preferred icon styles for SteamGridDB";
|
|
||||||
};
|
};
|
||||||
|
imageMotionTypes = lib.mkOption {
|
||||||
imageMotionTypes = mkOption {
|
type = lib.types.listOf lib.types.str;
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [ "static" ];
|
default = [ "static" ];
|
||||||
description = "Allowed image motion types";
|
description = "Allowed motion types (\"static\", \"animated\").";
|
||||||
};
|
};
|
||||||
|
sizes = lib.mkOption {
|
||||||
sizes = mkOption {
|
type = lib.types.listOf lib.types.str;
|
||||||
type = types.listOf types.str;
|
default = [ ];
|
||||||
default = [];
|
description = "Preferred grid image sizes.";
|
||||||
description = "Preferred image sizes";
|
|
||||||
};
|
};
|
||||||
|
sizesHero = lib.mkOption {
|
||||||
sizesHero = mkOption {
|
type = lib.types.listOf lib.types.str;
|
||||||
type = types.listOf types.str;
|
default = [ ];
|
||||||
default = [];
|
description = "Preferred hero image sizes.";
|
||||||
description = "Preferred hero image sizes";
|
|
||||||
};
|
};
|
||||||
|
sizesIcon = lib.mkOption {
|
||||||
sizesIcon = mkOption {
|
type = lib.types.listOf lib.types.str;
|
||||||
type = types.listOf types.str;
|
default = [ ];
|
||||||
default = [];
|
description = "Preferred icon sizes.";
|
||||||
description = "Preferred icon sizes";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
batchDownloadSize = mkOption {
|
# -------------------------------------------------------------------------
|
||||||
type = types.int;
|
# Miscellaneous top-level settings
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
batchDownloadSize = lib.mkOption {
|
||||||
|
type = lib.types.int;
|
||||||
default = 50;
|
default = 50;
|
||||||
description = "Number of images to download in a batch";
|
description = "Number of images to download per batch.";
|
||||||
};
|
};
|
||||||
|
|
||||||
dnsServers = mkOption {
|
dnsServers = lib.mkOption {
|
||||||
type = types.listOf types.str;
|
type = lib.types.listOf lib.types.str;
|
||||||
default = [];
|
default = [ ];
|
||||||
description = "Custom DNS servers for image downloads";
|
description = "Custom DNS servers used for artwork downloads (leave empty for system DNS).";
|
||||||
};
|
};
|
||||||
|
|
||||||
language = mkOption {
|
language = lib.mkOption {
|
||||||
type = types.str;
|
type = lib.types.str;
|
||||||
default = "en-US";
|
default = "en-US";
|
||||||
description = "Application language";
|
example = "de-DE";
|
||||||
|
description = "BCP-47 language tag for the SRM UI.";
|
||||||
};
|
};
|
||||||
|
|
||||||
theme = mkOption {
|
theme = lib.mkOption {
|
||||||
type = types.str;
|
type = lib.types.str;
|
||||||
default = "Deck";
|
default = "Deck";
|
||||||
description = "Application theme";
|
example = "Default";
|
||||||
|
description = "SRM UI theme name.";
|
||||||
};
|
};
|
||||||
|
|
||||||
emudeckInstall = mkOption {
|
emudeckInstall = lib.mkOption {
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = "Is this an EmuDeck installation";
|
description = "Set to true when SRM is managed alongside EmuDeck.";
|
||||||
};
|
};
|
||||||
|
|
||||||
autoUpdate = mkOption {
|
autoUpdate = lib.mkOption {
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = "Enable automatic updates";
|
description = "Allow SRM to update itself automatically (not recommended in a Nix-managed setup).";
|
||||||
};
|
};
|
||||||
|
|
||||||
offlineMode = mkOption {
|
offlineMode = lib.mkOption {
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = "Run in offline mode";
|
description = "Run SRM without fetching remote artwork.";
|
||||||
};
|
};
|
||||||
|
|
||||||
navigationWidth = mkOption {
|
navigationWidth = lib.mkOption {
|
||||||
type = types.int;
|
type = lib.types.int;
|
||||||
default = 0;
|
default = 0;
|
||||||
description = "Navigation panel width";
|
description = "Width in pixels of the navigation sidebar (0 = default).";
|
||||||
};
|
};
|
||||||
|
|
||||||
clearLogOnTest = mkOption {
|
clearLogOnTest = lib.mkOption {
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
description = "Clear log when testing configuration";
|
description = "Clear the log panel each time a parser test is run.";
|
||||||
};
|
};
|
||||||
|
|
||||||
steamUsername = mkOption {
|
steamUsername = lib.mkOption {
|
||||||
type = types.str;
|
type = lib.types.str;
|
||||||
description = "Steam username for configuration";
|
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, ... }: {
|
# Emulator parser configurations
|
||||||
options = {
|
# -------------------------------------------------------------------------
|
||||||
enable = mkEnableOption "emulator configuration";
|
emulators = lib.mkOption {
|
||||||
package = mkOption {
|
type = lib.types.attrsOf (
|
||||||
type = types.package;
|
lib.types.submodule (
|
||||||
default =
|
{ name, ... }:
|
||||||
if name == "pcsx2" then pkgs.pcsx2
|
{
|
||||||
else if name == "citra" then pkgs.citra-nightly
|
options = {
|
||||||
else if name == "yuzu" then pkgs.yuzu
|
|
||||||
else if name == "ryujinx" then pkgs.ryubing
|
enable = lib.mkEnableOption "emulator parser for ${name}";
|
||||||
else if name == "rpcs3" then pkgs.rpcs3
|
|
||||||
else if name == "dolphin-emu" then pkgs.dolphinEmu
|
package = lib.mkOption {
|
||||||
else if name == "duckstation" then pkgs.duckstation
|
type = lib.types.package;
|
||||||
else if name == "melonDS" then pkgs.melonDS
|
# Resolve against knownEmulators first; fall back to pkgs.<name> so
|
||||||
else if name == "cemu" then pkgs.cemu
|
# users can supply any arbitrary emulator key without a code change.
|
||||||
else if name == "ppsspp" then pkgs.ppsspp
|
default = if knownEmulators ? ${name} then knownEmulators.${name}.package else pkgs.${name};
|
||||||
else if name == "mame" then pkgs.mame
|
description = "Package providing the emulator binary.";
|
||||||
else if name == "dosbox" then pkgs.dosbox
|
};
|
||||||
else if name == "snes9x" then pkgs.snes9x-gtk
|
|
||||||
else if name == "mgba" then pkgs.mgba
|
parserType = lib.mkOption {
|
||||||
else if name == "mupen64plus" then pkgs.mupen64plus
|
type = lib.types.str;
|
||||||
else if name == "retroarch" then pkgs.retroarch
|
default =
|
||||||
else if name == "flycast" then pkgs.flycast
|
if knownEmulators ? ${name} && knownEmulators.${name} ? parserType then
|
||||||
else if name == "Non-SRM Shortcuts" then pkgs.steam
|
knownEmulators.${name}.parserType
|
||||||
else pkgs.${name};
|
else
|
||||||
description = "Emulator package";
|
"Glob";
|
||||||
};
|
description = "SRM parser type (usually \"Glob\" for file-based ROMs).";
|
||||||
parserType = mkOption {
|
};
|
||||||
type = types.str;
|
|
||||||
default = "Glob";
|
configTitle = lib.mkOption {
|
||||||
description = "Parser type";
|
type = lib.types.str;
|
||||||
};
|
default = name;
|
||||||
configTitle = mkOption {
|
description = "Human-readable label shown inside SRM for this parser.";
|
||||||
type = types.str;
|
};
|
||||||
default = name;
|
|
||||||
description = "Configuration title";
|
romFolder = lib.mkOption {
|
||||||
};
|
type = lib.types.str;
|
||||||
romFolder = mkOption {
|
default = "";
|
||||||
type = types.str;
|
description = ''
|
||||||
default = "";
|
Sub-folder under <option>environmentVariables.romsDirectory</option>
|
||||||
description = "Name of the ROM folder (defaults to common configuration)";
|
that contains ROMs for this emulator. Defaults to the built-in
|
||||||
};
|
value for known emulators; must be set explicitly for custom ones.
|
||||||
steamCategories = mkOption {
|
'';
|
||||||
type = types.listOf types.str;
|
};
|
||||||
default = [""];
|
|
||||||
description = "List of Steam categories";
|
steamCategories = lib.mkOption {
|
||||||
};
|
type = lib.types.listOf lib.types.str;
|
||||||
extraArgs = mkOption {
|
default = [ "" ];
|
||||||
type = types.str;
|
description = "Steam categories / collection tags to apply to shortcuts.";
|
||||||
default = "--fullscreen \"\${filePath}\"";
|
};
|
||||||
description = "Additional emulator arguments";
|
|
||||||
};
|
extraArgs = lib.mkOption {
|
||||||
executableModifier = mkOption {
|
type = lib.types.str;
|
||||||
type = types.str;
|
default = "--fullscreen \"\${filePath}\"";
|
||||||
default = "\"\${exePath}\"";
|
description = "Command-line arguments passed to the emulator.";
|
||||||
description = "Executable modifier";
|
};
|
||||||
};
|
|
||||||
titleModifier = mkOption {
|
executableModifier = lib.mkOption {
|
||||||
type = types.str;
|
type = lib.types.str;
|
||||||
default = "\${fuzzyTitle}";
|
default = "\"\${exePath}\"";
|
||||||
description = "Title modifier";
|
description = "SRM executable modifier expression.";
|
||||||
};
|
};
|
||||||
# fetchControllerTemplatesButton = mkOption {
|
|
||||||
# type = types.str;
|
titleModifier = lib.mkOption {
|
||||||
# default = null;
|
type = lib.types.str;
|
||||||
# description = "Fetch controller templates button";
|
default = "\${fuzzyTitle}";
|
||||||
# };
|
description = "SRM title modifier expression.";
|
||||||
# removeControllersButton = mkOption {
|
};
|
||||||
# type = types.str;
|
|
||||||
# default = null;
|
steamInputEnabled = lib.mkOption {
|
||||||
# description = "Remove controller templates button";
|
type = lib.types.bool;
|
||||||
# };
|
default = false;
|
||||||
steamInputEnabled = mkOption {
|
description = "Enable Steam Input controller remapping for shortcuts.";
|
||||||
type = types.bool;
|
};
|
||||||
default = false;
|
|
||||||
description = "Enable Steam input";
|
onlineImageQueries = lib.mkOption {
|
||||||
};
|
type = lib.types.listOf lib.types.str;
|
||||||
onlineImageQueries = mkOption {
|
default = [ "\${fuzzyTitle}" ];
|
||||||
type = types.listOf types.str;
|
description = "Query strings used to search for artwork online.";
|
||||||
default = [ "\${fuzzyTitle}" ];
|
};
|
||||||
description = "List of online image queries";
|
|
||||||
};
|
imagePool = lib.mkOption {
|
||||||
imagePool = mkOption {
|
type = lib.types.str;
|
||||||
type = types.str;
|
default = "\${fuzzyTitle}";
|
||||||
default = "\${fuzzyTitle}";
|
description = "SRM image pool identifier for artwork caching.";
|
||||||
description = "image pool";
|
};
|
||||||
};
|
|
||||||
drmProtected = mkOption {
|
drmProtected = lib.mkOption {
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = "DRM protected";
|
description = "Mark shortcuts as DRM-protected.";
|
||||||
};
|
};
|
||||||
userAccounts = mkOption {
|
|
||||||
type = types.listOf types.str;
|
userAccounts = lib.mkOption {
|
||||||
default = [ "Global" ];
|
type = lib.types.listOf lib.types.str;
|
||||||
description = "List of user accounts";
|
default = [ "Global" ];
|
||||||
};
|
description = "Steam accounts to apply this parser to (\"Global\" applies to all).";
|
||||||
fileTypes = mkOption {
|
};
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [];
|
fileTypes = lib.mkOption {
|
||||||
description = "List of ROM file types (defaults to common configuration)";
|
type = lib.types.listOf lib.types.str;
|
||||||
};
|
default = [ ];
|
||||||
shortcutPassthrough = mkOption {
|
description = ''
|
||||||
type = types.bool;
|
File extensions matched by the glob parser (e.g. <literal>".iso"</literal>).
|
||||||
default = false;
|
Defaults to the built-in list for known emulators; must be set for custom ones.
|
||||||
description = "Enable shortcut passthrough";
|
'';
|
||||||
};
|
};
|
||||||
appendArgsToExecutable = mkOption {
|
|
||||||
type = types.bool;
|
shortcutPassthrough = lib.mkOption {
|
||||||
default = true;
|
type = lib.types.bool;
|
||||||
description = "Append arguments to executable";
|
default = false;
|
||||||
};
|
description = "Pass through existing Steam shortcuts rather than replacing them.";
|
||||||
};
|
};
|
||||||
}));
|
|
||||||
default = {};
|
appendArgsToExecutable = lib.mkOption {
|
||||||
description = "Emulator configurations";
|
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