Skip to content

feat: add home manager module - #150

Open
frostplexx wants to merge 6 commits into
Inrixia:masterfrom
frostplexx:flake
Open

feat: add home manager module#150
frostplexx wants to merge 6 commits into
Inrixia:masterfrom
frostplexx:flake

Conversation

@frostplexx

Copy link
Copy Markdown
Contributor

This PR adds a nix home manager module that lets users manage install TidaLuna and manage the following things in home manager:

  • installed stores
  • installed plugins
  • plugin settings

Themes and feature flag are currently missing from the module.

This module works by creating a luna-settings.json file inside tidalunas app directory. On startup this json is then read and the configuration applied. Any plugins and stores not defined in the json file are removed and their settings are cleared, meaning that the luna-settings.json is the only source of truth.

The additions to the readme should explain how to use the home manager module and I'm specifically looking for someone to test this on Linux. For reference, my own working configuration is added in this description too.

Click to see config
  programs.tidaluna = {
    enable = true;
    stores = [
      "https://github.com/meowarex/TidalLuna-Plugins/releases/download/latest/store.json"
      "https://github.com/Inrixia/luna-plugins/releases/download/dev/store.json"
    ];

    #To list settingsNames and settings:  const idb = await luna.core.ReactiveStore.getStore("@luna/pluginStorage").dump(); console.log(JSON.stringify(idb, null, 2));
    plugins = [
      {
        shortURL = "@meowarex/radiant-lyrics";
        settingsName = "RadiantLyrics";
        settings = {
          "lyricsGlowEnabled" = false;
          "trackTitleGlow" = false;
          "hideUIEnabled" = false;
          "playerBarVisible" = false;
          "qualityProgressColor" = false;
          "floatingPlayerBar" = true;
          "playerBarTint" = 10;
          "playerBarTintColor" = "#000000";
          "playerBarTintCustomColors" = [];
          "playerBarRadius" = 8;
          "playerBarSpacing" = 10;
          "CoverEverywhere" = false;
          "performanceMode" = false;
          "spinningArt" = true;
          "textGlow" = 20;
          "backgroundScale" = 15;
          "backgroundRadius" = 25;
          "backgroundContrast" = 120;
          "backgroundBlur" = 80;
          "backgroundBrightness" = 40;
          "spinSpeed" = 45;
          "settingsAffectNowPlaying" = true;
          "stickyLyrics" = false;
          "stickyLyricsIcon" = "sparkle";
          "lyricsStyle" = 2;
          "syllableStyle" = 0;
          "contextAwareLyrics" = true;
          "blurInactive" = true;
          "bubbledLyrics" = true;
          "syllableLogging" = false;
          "lyricsFontSize" = 100;
          "romanizeLyrics" = false;
        };
      }
      {
        shortURL = "DiscordRPC";
        settingsName = "DiscordRPC";
        settings = {
          "displayOnPause" = false;
          "displayArtistIcon" = true;
          "displayPlaylistButton" = true;
          "customStatusText" = "{track} by {artist}";
        };
      }
      {
        shortURL = "DesktopConnect";
      }
      {
        shortURL = "NoBuffer";
      }
      {
        shortURL = "Themer";
        settingsName = "Themer";
        settings = {
          "css" = builtins.readFile (
            pkgs.fetchurl {
              url = "https://raw.githubusercontent.com/frostplexx/catppuccin-tidal/refs/heads/main/mocha.css";
              sha256 = "sha256-eN17wamb5sz3cY2ZfFwS2nYkYaUZTJV11chWhEKVrfU=";
            }
          );
        };
      }
    ];
  };

@xaiyadev

Copy link
Copy Markdown
Contributor

Wanted to this for a longer time but didnt get to deep into it because the Luna store was a bit funky.

This is actually pretty cool, if it works, gonna maybe try it out later !! Thank you <3

Just wanted to mention that themes in general dont work just yet, iirc
And feature flags are a funky thing of tidal themselfes,, enabling them also kinda disables them and yadayadayada

@frostplexx

Copy link
Copy Markdown
Contributor Author

My current approach also isn't super clean, especially the weird division between settingsName and shortURL so I'm definitely open for discussion regarding that! I haven't looked into how feature flags work at all but I imagined something like:

featureFlags = {
	Ai_chatbox = true;
	Compact_player = true;
	...
}

Which will tell TidaLuna to try and activate those flags and if anything is not working it will just silently fail.

@Inrixia

Inrixia commented Mar 25, 2026

Copy link
Copy Markdown
Owner

So sorry I never commented. I reviewed this and it looks ok.

But I'm planning to change how some settings are being handled and would like to hold off merging until that's done. 💜

@frostplexx
frostplexx force-pushed the flake branch 2 times, most recently from 7ddf7ce to d178330 Compare April 9, 2026 09:12
@meowarex

meowarex commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

This is amazing!!! I can't wait for this to merge 💖

Copilot AI lite review requested due to automatic review settings July 16, 2026 06:56

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a declarative “seed settings” mechanism (intended for Nix Home Manager) that writes a luna-settings.json into the app bundle and applies it on startup to reconcile plugin stores, installed plugins, and plugin settings.

Changes:

  • Add renderer-side startup logic to read and apply seed settings via IPC before loading stored user plugins.
  • Add a Home Manager module that patches the packaged app to include luna-settings.json derived from Nix configuration.
  • Document Home Manager usage in the README and expose the module from flake.nix.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
render/src/index.ts Calls seed-settings application during startup before loading stored plugins.
render/src/helpers/applySeedSettingsJSOn.ts Implements seed settings application + plugin reconciliation based on store manifests.
native/injector.ts Adds IPC handler to load and return luna-settings.json from the bundle directory.
nix/home-manager.nix Adds a Home Manager module to generate and bundle luna-settings.json and expose options.
flake.nix Exposes the Home Manager module via homeManagerModules.default.
README.md Adds Home Manager documentation and updates section headings.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +13 to +17
// Full replace of store URLs
if (Array.isArray(seed.stores)) {
const pluginStores = ReactiveStore.getStore("@luna/pluginStores");
await pluginStores.set("storeUrls", seed.stores);
}
Comment on lines +44 to +45
const declaredNames = new Set<string>(pluginNames.filter((n): n is string => typeof n === "string"));

Comment on lines +61 to +63
const baseName = pluginFile.replace(/\.mjs$/, "");
const pluginUrl = `${storeUrl}/${baseName}`;
try {
Comment thread render/src/index.ts
Comment on lines 20 to 22
import { LunaPlugin } from "./LunaPlugin";
import { applySeedSettings } from "./helpers/applySeedSettingsJSOn";

Comment thread README.md
Comment on lines +87 to +88
Then Enable TidaLuna using

Comment thread nix/home-manager.nix
Comment on lines +105 to +109
settingsName = lib.mkOption {
type = lib.types.str;
description = "Key used for plugin settings storage.";
example = "RadiantLyrics";
};
Comment thread nix/home-manager.nix
Comment on lines +33 to +38
builtins.listToAttrs (
map (p: {
name = p.settingsName;
value = p.settings;
}) (lib.filter (p: p.settings != { }) cfg.plugins)
);
Comment thread native/injector.ts
Comment on lines +417 to +421
try {
return JSON.parse(await readFile(seedPath, "utf8"));
} catch {
return null;
}
Comment thread README.md
Comment on lines +82 to +84
home-manager.sharedModules = [
inputs.tidaluna.homeManagerModules.default
]
@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown

Flake Review Results for #150

Available systems: aarch64-darwin, aarch64-linux, armv6l-linux, armv7l-linux, i686-linux, powerpc64le-linux, riscv64-linux, x86_64-darwin, x86_64-freebsd, x86_64-linux
Requested systems: aarch64-darwin, x86_64-linux

🔄 Modified (2)

  • packages.aarch64-darwin.default

    • Output: /nix/store/2f9fg80by3rhj5ha8xk4n49nzvclv52c-tidal-2.41.3
    Derivation diff
    - /nix/store/18lk7s01rpzjzqv811widpsjhfihxqhw-tidal-2.41.3.drv:{out}
    + /nix/store/cqck0xspwb9pk88kaiqm3gridj3kmi8p-tidal-2.41.3.drv:{out}
    • The input derivation named `TidaLuna-1.16.5-beta` differs
      - /nix/store/mq7qr34i62xn55yv0460kv289vmh9fdi-TidaLuna-1.16.5-beta.drv:{out}
      + /nix/store/hqawkfl570w4vrx65nizglc13hfpqcr6-TidaLuna-1.16.5-beta.drv:{out}
      • The set of input source names do not match:
          - f24rfmk1h0ljr139mkx7rn1rdka4rkj1-source
          + f40wh60lf5pi6zc791gn7ipqr86sxh5q-source
      • The input derivation named `TidaLuna-pnpm-deps` differs
        - /nix/store/700zb2nqagpqb0wb36rb67wqyghqq00v-TidaLuna-pnpm-deps.drv:{out}
        + /nix/store/bc1q5fd7cnpgsd2xapp6r6cyxl9b0qhy-TidaLuna-pnpm-deps.drv:{out}
        • The set of input source names do not match:
            - f24rfmk1h0ljr139mkx7rn1rdka4rkj1-source
            + f40wh60lf5pi6zc791gn7ipqr86sxh5q-source
        • The environments do not match:
            src=''
            /nix/store/3xmch65rcfbxfhrx8c18qgsq0qa4qszn-f24rfmk1h0ljr139mkx7rn1rdka4rkj1-source/nix/store/lds7wpn5bqlq3yn4myw1lf9iqf14vnl6-f40wh60lf5pi6zc791gn7ipqr86sxh5q-source
        ''
      • Skipping environment comparison
    • Skipping environment comparison
  • packages.x86_64-linux.default

    • Output: /nix/store/ybhnfg0mjs38iy7ppavx5km6vq1jjwfc-tidal-hifi-6.3.1-Mavy
    Derivation diff
    - /nix/store/kavqpgbcmlmrbrbykikffh08qg8ihcp9-tidal-hifi-6.3.1-Mavy.drv:{out}
    + /nix/store/10llakdjr4rd0vs366id0mi4bg008kkb-tidal-hifi-6.3.1-Mavy.drv:{out}
    • The input derivation named `TidaLuna-1.16.5-beta` differs
      - /nix/store/5r4y5pnkcwbjrcmlx3fk53dbj6z7lz16-TidaLuna-1.16.5-beta.drv:{out}
      + /nix/store/9nprvn4lpgq6zlmfz072x5k15jvg4laj-TidaLuna-1.16.5-beta.drv:{out}
      • The set of input source names do not match:
          - f24rfmk1h0ljr139mkx7rn1rdka4rkj1-source
          + f40wh60lf5pi6zc791gn7ipqr86sxh5q-source
      • The input derivation named `TidaLuna-pnpm-deps` differs
        - /nix/store/ag9kdx5nxa5x40y06cisqxkr6i9p1v8m-TidaLuna-pnpm-deps.drv:{out}
        + /nix/store/avl3p5887x8zsdgi2qc805c0xwf1yjf5-TidaLuna-pnpm-deps.drv:{out}
        • The set of input source names do not match:
            - f24rfmk1h0ljr139mkx7rn1rdka4rkj1-source
            + f40wh60lf5pi6zc791gn7ipqr86sxh5q-source
        • The environments do not match:
            src=''
            /nix/store/3xmch65rcfbxfhrx8c18qgsq0qa4qszn-f24rfmk1h0ljr139mkx7rn1rdka4rkj1-source/nix/store/lds7wpn5bqlq3yn4myw1lf9iqf14vnl6-f40wh60lf5pi6zc791gn7ipqr86sxh5q-source
        ''
      • Skipping environment comparison
    • Skipping environment comparison

Generated by flake-review

Copilot AI review requested due to automatic review settings August 26, 2026 06:32

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

There are correctness issues in plugin reconciliation timing (can load undeclared plugins before removal) and mismatches between the documented example config and the Home Manager module’s required fields.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (4)

render/src/index.ts:21

  • The helper filename/import applySeedSettingsJSOn looks like a typo ("JSOn"), which makes it easy to mis-type and can cause awkward rename/casing issues on different filesystems; consider renaming the file to applySeedSettingsJSON.ts (or similar) and updating this import to match.
import { applySeedSettings } from "./helpers/applySeedSettingsJSOn";

nix/home-manager.nix:109

  • The PR description’s sample config includes plugin entries that only specify shortURL (no settings), but this module currently requires settingsName for every plugin. Making settingsName optional (only needed when settings is non-empty) would match the documented usage and avoid forcing dummy values.
              settingsName = lib.mkOption {
                type = lib.types.str;
                description = "Key used for plugin settings storage.";
                example = "RadiantLyrics";
              };

nix/home-manager.nix:38

  • If settingsName becomes optional, the pluginSettings attrset construction must avoid using a null attribute name (which will make evaluation fail). Filter out entries without settingsName (and ideally assert when settings is non-empty but settingsName is missing).
      builtins.listToAttrs (
        map (p: {
          name = p.settingsName;
          value = p.settings;
        }) (lib.filter (p: p.settings != { }) cfg.plugins)
      );

README.md:85

  • The Home Manager snippet has two issues: it uses inputs.tidaluna... but earlier in the README the input is named inputs.tidaLuna, and the sharedModules assignment is missing a trailing ;. As written, the example won’t evaluate as valid Nix.
home-manager.sharedModules = [
    inputs.tidaluna.homeManagerModules.default
]

- **Files reviewed:** 6/6 changed files
- **Comments generated:** 1
- **Review effort level:** Lite
</details>

Comment thread render/src/helpers/applySeedSettingsJSOn.ts Outdated
@meowarex

Copy link
Copy Markdown
Contributor

FINALLLYYYY <3

@Inrixia

Inrixia commented Aug 26, 2026

Copy link
Copy Markdown
Owner

Sorry, I'm the reason this got delayed merging.

Its unlikely I'll have the changes I'd planned done soon so please let me know if it's ready to merge again.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 26, 2026 07:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

There’s a confirmed mismatch in plugin URL construction that can prevent resolving/installing plugins from stores, and the README’s Home Manager snippet is currently invalid/inconsistent.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (3)

Previously missed (2) — in code that hasn't changed since the last review.

render/src/helpers/applySeedSettingsJSOn.ts:70

  • The plugin URL derivation doesn’t match the existing Plugin Store UI logic (plugins/ui/src/SettingsPage/PluginStoreTab/LunaStore.tsx builds URLs with plugin.replace(" ", ".")). If a store’s plugins entries contain spaces or otherwise require normalization, pluginUrl will be wrong and LunaPlugin.fetchPackage()/installs will fail.
                    manifest.plugins.map(async (pluginFile: string) => {
                        if (typeof pluginFile !== "string") return;
                        const baseName = pluginFile.replace(/\.mjs$/, "");
                        const pluginUrl = `${storeUrl}/${baseName}`;
                        try {

README.md:84

  • The Home Manager snippet has an inconsistent flake input name (inputs.tidaluna vs earlier inputs.tidaLuna) and is missing the closing ];, which makes it invalid Nix as written.
home-manager.sharedModules = [
    inputs.tidaluna.homeManagerModules.default
]

render/src/index.ts:21

  • The helper filename/import path uses applySeedSettingsJSOn (mixed casing) which looks like a typo for JSON and makes the module harder to discover/search for. Consider renaming to applySeedSettingsJSON.ts (and updating the import) for clarity.
import { applySeedSettings } from "./helpers/applySeedSettingsJSOn";
  • Files reviewed: 6/6 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread README.md Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 26, 2026 07:29

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

There are confirmed correctness/usability issues in the plugin resolver and Home Manager module/docs that can break installs or make the documented configs fail to evaluate.

Review details

Suppressed comments (8)

Previously missed (4) — in code that hasn't changed since the last review.

render/src/helpers/applySeedSettingsJSOn.ts:77

  • Store manifests can contain plugin entries with spaces; the UI converts spaces to dots when constructing plugin URLs (see plugins/ui/src/SettingsPage/PluginStoreTab/LunaStore.tsx:90), but this resolver uses the raw string. This can generate invalid URLs and fail to install declared plugins; it also fetches every plugin's package.json which is unnecessary for mapping store entries to URLs.
                    manifest.plugins.map(async (pluginFile: string) => {
                        if (typeof pluginFile !== "string") return;
                        const baseName = pluginFile.replace(/\.mjs$/, "");
                        const pluginUrl = `${storeUrl}/${baseName}`;
                        try {

nix/home-manager.nix:120

  • plugins defaults to an empty list, which means enabling the module without explicitly setting programs.tidaluna.plugins will produce a seed config that removes all non-core plugins on next startup. Defaulting this option to null makes plugin management opt-in (users can still explicitly set plugins = []; if they want none).
      default = [ ];
    };

README.md:109

  • This file path reference appears incorrect: the default store list is in plugins/ui/src/SettingsPage/Storage.tsx (see the addToStores(...) calls), not plugins/ui/src/SettingsPage/PluginStoreTab/index.tsx.
The list of stores which come default with TidaLuna can be found in `plugins/ui/src/SettingsPage/PluginStoreTab/index.tsx`.

nix/home-manager.nix:11

  • Using config._module.args.pkgs relies on internal Home Manager implementation details; the module can receive pkgs directly as an argument, which is the standard pattern and avoids breakage across HM versions.
  pkgs = config._module.args.pkgs;

render/src/index.ts:21

  • The helper filename/import path applySeedSettingsJSOn looks like a typo (mixed-case "JSOn") and is easy to misread/grep; consider renaming the helper to applySeedSettingsJSON.ts (or similar) and updating the import accordingly.
import { applySeedSettings } from "./helpers/applySeedSettingsJSOn";

nix/home-manager.nix:109

  • settingsName is required for every plugin entry, but the PR description example includes plugin entries with only shortURL (no settings). Making settingsName optional improves usability and matches the described configuration shape (it’s only needed when settings is non-empty).
              settingsName = lib.mkOption {
                type = lib.types.str;
                description = "Key used for plugin settings storage.";
                example = "RadiantLyrics";
              };

nix/home-manager.nix:38

  • pluginSettings always uses p.settingsName as the attribute name; if settingsName is omitted (as allowed by the README/PR description examples), this will fail at eval time. Filter out entries without settingsName when constructing pluginSettings.
      builtins.listToAttrs (
        map (p: {
          name = p.settingsName;
          value = p.settings;
        }) (lib.filter (p: p.settings != { }) cfg.plugins)
      );

README.md:85

  • The Home Manager snippet is not valid Nix as written: it’s missing the terminating ];, and it uses inputs.tidaluna while the earlier input example defines inputs.tidaLuna. As-is, users will get a parse/attribute error when copying this.
home-manager.sharedModules = [
    inputs.tidaluna.homeManagerModules.default
]

- **Files reviewed:** 6/6 changed files
- **Comments generated:** 0 new
- **Review effort level:** Lite
</details>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants