Skip to content

Commit fb8cc8c

Browse files
lavalink: init at 4.0.8; nixos/lavalink: init (#344687)
2 parents 8b59e90 + b10f83f commit fb8cc8c

File tree

7 files changed

+441
-0
lines changed

7 files changed

+441
-0
lines changed

maintainers/maintainer-list.nix

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16679,6 +16679,13 @@
1667916679
githubId = 17240342;
1668016680
name = "Nano Twerpus";
1668116681
};
16682+
nanoyaki = {
16683+
name = "Hana Kretzer";
16684+
email = "[email protected]";
16685+
github = "nanoyaki";
16686+
githubId = 144328493;
16687+
keys = [ { fingerprint = "D89F 440C 6CD7 4753 090F EC7A 4682 C5CB 4D9D EA3C"; } ];
16688+
};
1668216689
naphta = {
1668316690
github = "naphta";
1668416691
githubId = 6709831;

nixos/doc/manual/release-notes/rl-2505.section.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@
173173

174174
- [nvidia-gpu](https://github.com/utkuozdemir/nvidia_gpu_exporter), a Prometheus exporter that scrapes `nvidia-smi` for GPU metrics. Available as [services.prometheus.exporters.nvidia-gpu](#opt-services.prometheus.exporters.nvidia-gpu.enable).
175175

176+
- [Lavalink](https://github.com/lavalink-devs/Lavalink), a standalone audio sending node based on Lavaplayer and Koe. Availble as [services.lavalink](#opt-services.lavalink.enable).
177+
176178
- [OpenGamepadUI](https://github.com/ShadowBlip/OpenGamepadUI/), an open source gamepad-native game launcher and overlay for Linux. Available as [programs.opengamepadui](#opt-programs.opengamepadui.enable).
177179

178180
- [InputPlumber](https://github.com/ShadowBlip/InputPlumber/), an open source input router and remapper daemon for Linux. Available as [services.inputplumber](#opt-services.inputplumber.enable).

nixos/modules/module-list.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@
408408
./services/audio/icecast.nix
409409
./services/audio/jack.nix
410410
./services/audio/jmusicbot.nix
411+
./services/audio/lavalink.nix
411412
./services/audio/liquidsoap.nix
412413
./services/audio/marytts.nix
413414
./services/audio/mopidy.nix
Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
{
2+
config,
3+
pkgs,
4+
lib,
5+
...
6+
}:
7+
8+
let
9+
inherit (lib)
10+
mkOption
11+
mkEnableOption
12+
mkIf
13+
types
14+
;
15+
16+
cfg = config.services.lavalink;
17+
18+
format = pkgs.formats.yaml { };
19+
in
20+
21+
{
22+
options.services.lavalink = {
23+
enable = mkEnableOption "Lavalink";
24+
25+
package = lib.mkPackageOption pkgs "lavalink" { };
26+
27+
password = mkOption {
28+
type = types.nullOr types.str;
29+
default = null;
30+
example = "s3cRe!p4SsW0rD";
31+
description = ''
32+
The password for Lavalink's authentication in plain text.
33+
'';
34+
};
35+
36+
port = mkOption {
37+
type = types.port;
38+
default = 2333;
39+
example = 4567;
40+
description = ''
41+
The port that Lavalink will use.
42+
'';
43+
};
44+
45+
address = mkOption {
46+
type = types.str;
47+
default = "0.0.0.0";
48+
example = "127.0.0.1";
49+
description = ''
50+
The network address to bind to.
51+
'';
52+
};
53+
54+
openFirewall = mkOption {
55+
type = types.bool;
56+
default = false;
57+
example = true;
58+
description = ''
59+
Whether to expose the port to the network.
60+
'';
61+
};
62+
63+
user = mkOption {
64+
type = types.str;
65+
default = "lavalink";
66+
example = "root";
67+
description = ''
68+
The user of the service.
69+
'';
70+
};
71+
72+
group = mkOption {
73+
type = types.str;
74+
default = "lavalink";
75+
example = "medias";
76+
description = ''
77+
The group of the service.
78+
'';
79+
};
80+
81+
home = mkOption {
82+
type = types.str;
83+
default = "/var/lib/lavalink";
84+
example = "/home/lavalink";
85+
description = ''
86+
The home directory for lavalink.
87+
'';
88+
};
89+
90+
enableHttp2 = mkEnableOption "HTTP/2 support";
91+
92+
jvmArgs = mkOption {
93+
type = types.str;
94+
default = "-Xmx4G";
95+
example = "-Djava.io.tmpdir=/var/lib/lavalink/tmp -Xmx6G";
96+
description = ''
97+
Set custom JVM arguments.
98+
'';
99+
};
100+
101+
environmentFile = mkOption {
102+
type = types.nullOr types.str;
103+
default = null;
104+
example = "/run/secrets/lavalink/passwordEnvFile";
105+
description = ''
106+
Add custom environment variables from a file.
107+
See <https://lavalink.dev/configuration/index.html#example-environment-variables> for the full documentation.
108+
'';
109+
};
110+
111+
plugins = mkOption {
112+
type = types.listOf (
113+
types.submodule {
114+
options = {
115+
dependency = mkOption {
116+
type = types.str;
117+
example = "dev.lavalink.youtube:youtube-plugin:1.8.0";
118+
description = ''
119+
The coordinates of the plugin.
120+
'';
121+
};
122+
123+
repository = mkOption {
124+
type = types.str;
125+
example = "https://maven.example.com/releases";
126+
default = "https://maven.lavalink.dev/releases";
127+
description = ''
128+
The plugin repository. Defaults to the lavalink releases repository.
129+
130+
To use the snapshots repository, use <https://maven.lavalink.dev/snapshots> instead
131+
'';
132+
};
133+
134+
hash = mkOption {
135+
type = types.str;
136+
example = lib.fakeHash;
137+
description = ''
138+
The hash of the plugin.
139+
'';
140+
};
141+
142+
configName = mkOption {
143+
type = types.nullOr types.str;
144+
example = "youtube";
145+
default = null;
146+
description = ''
147+
The name of the plugin to use as the key for the plugin configuration.
148+
'';
149+
};
150+
151+
extraConfig = mkOption {
152+
type = types.submodule { freeformType = format.type; };
153+
default = { };
154+
description = ''
155+
The configuration for the plugin.
156+
157+
The {option}`services.lavalink.plugins.*.configName` option must be set.
158+
'';
159+
};
160+
};
161+
}
162+
);
163+
default = [ ];
164+
165+
example = lib.literalExpression ''
166+
[
167+
{
168+
dependency = "dev.lavalink.youtube:youtube-plugin:1.8.0";
169+
repository = "https://maven.lavalink.dev/snapshots";
170+
hash = lib.fakeHash;
171+
configName = "youtube";
172+
extraConfig = {
173+
enabled = true;
174+
allowSearch = true;
175+
allowDirectVideoIds = true;
176+
allowDirectPlaylistIds = true;
177+
};
178+
}
179+
]
180+
'';
181+
182+
description = ''
183+
A list of plugins for lavalink.
184+
'';
185+
};
186+
187+
extraConfig = mkOption {
188+
type = types.submodule { freeformType = format.type; };
189+
190+
description = ''
191+
Configuration to write to {file}`application.yml`.
192+
See <https://lavalink.dev/configuration/#example-applicationyml> for the full documentation.
193+
194+
Individual configuration parameters can be overwritten using environment variables.
195+
See <https://lavalink.dev/configuration/#example-environment-variables> for more information.
196+
'';
197+
198+
default = { };
199+
200+
example = lib.literalExpression ''
201+
{
202+
lavalink.server = {
203+
sources.twitch = true;
204+
205+
filters.volume = true;
206+
};
207+
208+
logging.file.path = "./logs/";
209+
}
210+
'';
211+
};
212+
};
213+
214+
config =
215+
let
216+
pluginSymlinks = lib.concatStringsSep "\n" (
217+
map (
218+
pluginCfg:
219+
let
220+
pluginParts = lib.match ''^(.*?:(.*?):)([0-9]+\.[0-9]+\.[0-9]+)$'' pluginCfg.dependency;
221+
222+
pluginWebPath = lib.replaceStrings [ "." ":" ] [ "/" "/" ] (lib.elemAt pluginParts 0);
223+
224+
pluginFileName = lib.elemAt pluginParts 1;
225+
pluginVersion = lib.elemAt pluginParts 2;
226+
227+
pluginFile = "${pluginFileName}-${pluginVersion}.jar";
228+
pluginUrl = "${pluginCfg.repository}/${pluginWebPath}${pluginVersion}/${pluginFile}";
229+
230+
plugin = pkgs.fetchurl {
231+
url = pluginUrl;
232+
inherit (pluginCfg) hash;
233+
};
234+
in
235+
"ln -sf ${plugin} ${cfg.home}/plugins/${pluginFile}"
236+
) cfg.plugins
237+
);
238+
239+
pluginExtraConfigs = builtins.listToAttrs (
240+
builtins.map (
241+
pluginConfig: lib.attrsets.nameValuePair pluginConfig.configName pluginConfig.extraConfig
242+
) (lib.lists.filter (pluginCfg: pluginCfg.configName != null) cfg.plugins)
243+
);
244+
245+
config = lib.attrsets.recursiveUpdate cfg.extraConfig {
246+
server = {
247+
inherit (cfg) port address;
248+
http2.enabled = cfg.enableHttp2;
249+
};
250+
251+
plugins = pluginExtraConfigs;
252+
lavalink.plugins = (
253+
builtins.map (
254+
pluginConfig:
255+
builtins.removeAttrs pluginConfig [
256+
"name"
257+
"extraConfig"
258+
"hash"
259+
]
260+
) cfg.plugins
261+
);
262+
};
263+
264+
configWithPassword = lib.attrsets.recursiveUpdate config (
265+
lib.attrsets.optionalAttrs (cfg.password != null) { lavalink.server.password = cfg.password; }
266+
);
267+
268+
configFile = format.generate "application.yml" configWithPassword;
269+
in
270+
mkIf cfg.enable {
271+
assertions = [
272+
{
273+
assertion =
274+
!(lib.lists.any (
275+
pluginCfg: pluginCfg.extraConfig != { } && pluginCfg.configName == null
276+
) cfg.plugins);
277+
message = "Plugins with extra configuration need to have the `configName` attribute defined";
278+
}
279+
];
280+
281+
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
282+
283+
users.groups = mkIf (cfg.group == "lavalink") { lavalink = { }; };
284+
users.users = mkIf (cfg.user == "lavalink") {
285+
lavalink = {
286+
inherit (cfg) home;
287+
group = "lavalink";
288+
description = "The user for the Lavalink server";
289+
isSystemUser = true;
290+
};
291+
};
292+
293+
systemd.tmpfiles.settings."10-lavalink" =
294+
let
295+
dirConfig = {
296+
inherit (cfg) user group;
297+
mode = "0700";
298+
};
299+
in
300+
{
301+
"${cfg.home}/plugins".d = mkIf (cfg.plugins != [ ]) dirConfig;
302+
${cfg.home}.d = dirConfig;
303+
};
304+
305+
systemd.services.lavalink = {
306+
description = "Lavalink Service";
307+
308+
wantedBy = [ "multi-user.target" ];
309+
after = [
310+
"syslog.target"
311+
"network.target"
312+
];
313+
314+
script = ''
315+
${pluginSymlinks}
316+
317+
ln -sf ${configFile} ${cfg.home}/application.yml
318+
export _JAVA_OPTIONS="${cfg.jvmArgs}"
319+
320+
${lib.getExe cfg.package}
321+
'';
322+
323+
serviceConfig = {
324+
User = cfg.user;
325+
Group = cfg.group;
326+
327+
Type = "simple";
328+
Restart = "on-failure";
329+
330+
EnvironmentFile = cfg.environmentFile;
331+
WorkingDirectory = cfg.home;
332+
};
333+
};
334+
};
335+
}

nixos/tests/all-tests.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,7 @@ in
713713
languagetool = handleTest ./languagetool.nix { };
714714
lanraragi = handleTest ./lanraragi.nix { };
715715
latestKernel.login = handleTest ./login.nix { latestKernel = true; };
716+
lavalink = runTest ./lavalink.nix;
716717
leaps = handleTest ./leaps.nix { };
717718
lemmy = handleTest ./lemmy.nix { };
718719
libinput = handleTest ./libinput.nix { };

0 commit comments

Comments
 (0)