-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmodule.nix
214 lines (189 loc) · 7.23 KB
/
module.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
self:
{ lib
, pkgs
, config
, ...
}:
with lib;
let
lure = self.packages.${pkgs.system}.default;
cfg = config.services.lure;
escapePercentLiteral = str: replaceStrings [ "%" ] [ "%%" ] str;
supportedServices = [ "lastfm" "listenbrainz" ];
commonServiceOptions = service: {
username = mkOption {
type = types.str;
description = "${if service == "lastfm" then "Last.fm" else "ListenBrainz"} username to check for listening activity.";
};
check_interval = mkOption {
type = types.int;
description = "Interval in seconds to check for listening activity.";
default = 16;
};
};
in
{
options.services.lure = {
enable = mkEnableOption "Enable lure service.";
package = mkOption {
type = types.package;
description = "The lure package to use.";
default = lure;
};
environment = mkOption {
type = types.attrsOf types.str;
description = "Environment variables to set for the service.";
example = { "LURE_LOG" = "trace"; };
default = { };
};
useService = mkOption {
type = types.nullOr (types.enum supportedServices);
description = "Which service to enable for checking your listening status.";
default = null;
};
services = {
lastfm = mkOption {
type = types.nullOr (types.submodule {
options = commonServiceOptions "lastfm" // {
api_key = mkOption {
type = with types; either str path;
description = ''
The API key to use for the Last.fm API.
WARNING: Since this key basically gives full access to the API
over YOUR account, it is recommended to use a path to a file that
contains the key, instead of entering the key as a string, so it's
stored securely.
'';
};
};
});
default = null;
description = "Options for the Last.fm service.";
};
listenbrainz = mkOption {
type = types.nullOr (types.submodule {
options = commonServiceOptions "listenbrainz" // {
api_url = mkOption {
type = types.str;
description = "The API URL of the ListenBrainz instance.";
default = "https://api.listenbrainz.org";
};
};
});
default = null;
description = "Options for the ListenBrainz service.";
};
};
revolt = {
status = {
template = mkOption {
type = types.str;
description = ''
The status template that will be used.
The following placeholders can be used:
- %NAME%: The name of the song.
- %ARTIST%: The artist of the song.
'';
default = "🎵 Listening to %NAME% by %ARTIST%";
};
idle = mkOption {
type = types.nullOr types.str;
description = ''
The idle status.
If this option is not set, the status will be returned to
the previous status when not listening to anything.
'';
default = null;
};
};
api_url = mkOption {
type = types.str;
description = "The API URL of the instance.";
default = "https://api.revolt.chat";
};
session_token = mkOption {
type = with types; either str path;
description = ''
The `X-Session-Token` to use for the API.
WARNING: Since this token basically gives full access to your account,
it is recommended to use a path to a file that contains the token,
instead of entering the token as a string, so it's stored securely.
'';
};
};
};
config =
let
lastfmServiceEnabled = cfg.useService == "lastfm" && cfg.services.lastfm != null;
listenbrainzServiceEnabled = cfg.useService == "listenbrainz" && cfg.services.listenbrainz != null;
in
mkIf (cfg.enable && cfg.useService != null) {
assertions = [
{
assertion = cfg.useService == "lastfm" -> cfg.services.lastfm != null;
message = "'services.lastfm' options must be provided when using LastFM service.";
}
{
assertion = cfg.useService == "listenbrainz" -> cfg.services.listenbrainz != null;
message = "'services.listenbrainz' options must be provided when using ListenBrainz service.";
}
];
warnings = [ ]
++ optional (isString cfg.revolt.session_token) "'revolt.session_token' is specified as a string, PLEASE consider using a path to a file instead for the sake of security."
++ optional (lastfmServiceEnabled && isString cfg.services.lastfm.api_key) "'services.lastfm.api_key' is specified as a string, PLEASE consider using a path to a file instead for the sake of security.";
systemd.services.lure = {
description = "Lure service";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
startLimitIntervalSec = 60;
startLimitBurst = 3;
serviceConfig = {
ExecStart = "${cfg.package}/bin/lure start";
Restart = "on-failure";
RestartSec = "15s";
LoadCredential =
let
credentials = [ ]
++ optional (lastfmServiceEnabled && isPath cfg.services.lastfm.api_key) "lastfm-api-key:${cfg.services.lastfm.api_key}"
++ optional (isPath cfg.revolt.session_token) "revolt-session-token:${cfg.revolt.session_token}";
in
credentials;
};
environment = mkMerge [
(cfg.environment)
{
LURE_ENABLE = cfg.useService;
LURE_REVOLT__STATUS__TEMPLATE = escapePercentLiteral cfg.revolt.status.template;
LURE_REVOLT__API_URL = cfg.revolt.api_url;
}
(optionalAttrs lastfmServiceEnabled (mkMerge [
{
LURE_SERVICES__LASTFM__USERNAME = cfg.services.lastfm.username;
LURE_SERVICES__LASTFM__CHECK_INTERVAL = toString cfg.services.lastfm.check_interval;
}
(optionalAttrs (isString cfg.services.lastfm.api_key) {
LURE_SERVICES__LASTFM__API_KEY = cfg.services.lastfm.api_key;
})
(optionalAttrs (isPath cfg.services.lastfm.api_key) {
LURE_SERVICES__LASTFM__API_KEY_FILE = "%d/lastfm-api-key";
})
]))
(optionalAttrs listenbrainzServiceEnabled {
LURE_SERVICES__LISTENBRAINZ__USERNAME = cfg.services.listenbrainz.username;
LURE_SERVICES__LISTENBRAINZ__API_URL = cfg.services.listenbrainz.api_url;
LURE_SERVICES__LISTENBRAINZ__CHECK_INTERVAL = toString cfg.services.listenbrainz.check_interval;
})
(optionalAttrs (cfg.revolt.status.idle != null) {
LURE_REVOLT__STATUS__IDLE = escapePercentLiteral cfg.revolt.status.idle;
})
(optionalAttrs (isString cfg.revolt.session_token) {
LURE_REVOLT__SESSION_TOKEN = cfg.revolt.session_token;
})
(optionalAttrs (isPath cfg.revolt.session_token) {
LURE_REVOLT__SESSION_TOKEN_FILE = "%d/revolt-session-token";
})
];
};
};
}