{
  callPackage,
  lib,
  ...
}: let
  spicePkgs = callPackage ../pkgs {};
in {
  types = callPackage ./types.nix {};

  createXpuiINI = lib.generators.toINI {
    # specifies how to format a key/value pair
    mkKeyValue =
      lib.generators.mkKeyValueDefault
      {
        # specifies the generated string for a subset of nix values
        mkValueString = v:
          if v == true
          then "1"
          else if v == false
          then "0"
          # else if isString v then ''"${v}"''
          # and delegates all other values to the default generator
          else lib.generators.mkValueStringDefault {} v;
      } "=";
  };

  spicetifyBuilder = callPackage ./spicetify-builder.nix {};

  xpuiBuilder = callPackage ./xpui-builder.nix {};

  getThemePath = theme:
    if (builtins.hasAttr "appendName" theme)
    then
      (
        if theme.appendName
        then "${theme.src}/${theme.name}"
        else theme.src
      )
    else theme.src;

  # same thing but if its a string it looks it up in the default pkgs
  getTheme = theme: let
    themeType = builtins.typeOf theme;
  in (
    if builtins.typeOf theme == "string"
    then
      (
        if builtins.hasAttr theme spicePkgs.themes
        then
          (
            lib.trivial.warn
            ''
              Using a string like so:
              programs.spicetify.theme = "${theme}";
              is deprecated. Please use the following format:
              programs.spicetify.theme = let
                spicePkgs = spicetify-nix.packages.${"$\{pkgs.system}"}.default;
              in
                spicePkgs.themes.${theme};
            ''
            spicePkgs.themes.${theme}
          )
        else throw "Unknown theme ${theme}. Try using the lib.theme type instead of a string."
      )
    else if theme == null
    then
      lib.trivial.warn
      "spicetify: null theme passed to getTheme, assuming official.Default"
      spicePkgs.themes.official.Default
    else theme
  );

  getExtension = ext:
    if builtins.typeOf ext == "string"
    then
      (
        if builtins.hasAttr ext spicePkgs.extensions
        then
          (lib.trivial.warn
            ''
              Using a string like so:
              programs.spicetify.enabledExtensions = [ "${ext}" ];
              is deprecated. Please use the following format:
              programs.spicetify.enabledExtensions = let
                spicePkgs = spicetify-nix.packages.${"$\{pkgs.system}"}.default;
              in
                with spicePkgs.extensions [ ${spicePkgs.extensions._lib.sanitizeName ext} ];
            ''
            spicePkgs.extensions.${ext})
        else throw "Unknown extension ${ext}. Try using the lib.extension type instead of a string."
      )
    else ext;

  getApp = app:
    if builtins.typeOf app == "string"
    then
      (
        if builtins.hasAttr app spicePkgs.apps
        then
          (
            lib.trivial.warn
            ''
              Using a string like so:
              programs.spicetify.enabledCustomApps = [ "${app}" ];
              is deprecated. Please use the following format:
              programs.spicetify.enabledCustomApps = let
                spicePkgs = spicetify-nix.packages.${"$\{pkgs.system}"}.default;
              in
                with spicePkgs.apps [ ${app} ];
            ''
            spicePkgs.apps.${app}
          )
        else throw "Unknown CustomApp ${app}. Try using the lib.app type instead of a string."
      )
    else app;
}
