From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp12.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id UKlEJlI1p2N8fAEAbAwnHQ (envelope-from ) for ; Sat, 24 Dec 2022 18:22:26 +0100 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp12.migadu.com with LMTPS id kOpoJlI1p2N0uAAAauVa8A (envelope-from ) for ; Sat, 24 Dec 2022 18:22:26 +0100 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id D5F0D1E3A for ; Sat, 24 Dec 2022 18:22:25 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1p98Dk-0008CX-PS; Sat, 24 Dec 2022 12:22:04 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p98Dk-0008CL-0C for guix-patches@gnu.org; Sat, 24 Dec 2022 12:22:04 -0500 Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1p98Di-000072-Ij for guix-patches@gnu.org; Sat, 24 Dec 2022 12:22:02 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1p98Dh-0002BR-W0 for guix-patches@gnu.org; Sat, 24 Dec 2022 12:22:02 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#59866] [PATCH v5.1] services: mpd: Refactor MPD service. Resent-From: Liliana Marie Prikler Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sat, 24 Dec 2022 17:22:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 59866 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: mirai@makinata.eu, 59866@debbugs.gnu.org Received: via spool by 59866-submit@debbugs.gnu.org id=B59866.16719024688315 (code B ref 59866); Sat, 24 Dec 2022 17:22:01 +0000 Received: (at 59866) by debbugs.gnu.org; 24 Dec 2022 17:21:08 +0000 Received: from localhost ([127.0.0.1]:47060 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p98Co-0002A1-4Y for submit@debbugs.gnu.org; Sat, 24 Dec 2022 12:21:08 -0500 Received: from mail-wm1-f66.google.com ([209.85.128.66]:36855) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p98Cl-000293-1E for 59866@debbugs.gnu.org; Sat, 24 Dec 2022 12:21:05 -0500 Received: by mail-wm1-f66.google.com with SMTP id c65-20020a1c3544000000b003cfffd00fc0so8196499wma.1 for <59866@debbugs.gnu.org>; Sat, 24 Dec 2022 09:21:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:from:to:cc:subject:date :message-id:reply-to; bh=ciboyAGhoWIxNKcuoCKq/EpiuvbsahqbNAca0qttacI=; b=jm6axPxaDrG7hhrzcLIx2G5OsN5pLyV0RJVISaZ4H91nYU1DnaOlHHV7Q52HyGQQZu yCkWgflbmzs2JqwqPwVyJhF0A1Ahwn0zYtKTkQWH85es8REc0nG0TxPIQL5qvxlt6JgR BXs0hOhW6wg+RL6SPBoYdMEVXfFHwxSuQpeKmwuhyAiZ/+Wr8HwUZDz7RkYMNwc3NR50 RCSV4/bUZ1xzW9pVlklMGXToC6kMN4IAhnks+IUpkJR3zVEcYM/CaUnilaJyPaupWl7/ ui0nWu/IgJPE9sTMSEKvtEvvCdySmjxx9kLyKPKK0kasOrt3jF8Ou0GQBxwxmc34tNxN YdbQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=ciboyAGhoWIxNKcuoCKq/EpiuvbsahqbNAca0qttacI=; b=ns8+PRxAO7Dg4iB9UtdC9O+KbAw8T+784Ikt78Bgehj5Voykq2xJu0YUJeyd6nmbSL 1Qs13phigNXVbH5IFW5W94Ewiyxa78QeEzNvAJX3sMTq2Vn3ITGaX0lUq1oHFQfZLvEs 443iJ7+hfIWmZep5ZAhbzrGxeK47WcYYyvPVsvQ4qE8m9BPe096FJybsNQhF2P3Kgg7P 0SDtSK3cNS8FczRQfCdrJsMJOwTnTrfu6+rq+ZaKQAws4u+fm+HpCq6nxdKdQu6hL9ag rVJ5ehDBR4HHaMVsFJJFvuStDhmrfYSGkXah5uaMoRiGqJNA0WrNmuCb7OyVOY7RamIn xYFQ== X-Gm-Message-State: AFqh2krnzAeglcCw0ZEFSExZbGH30VjSCR6WVGFIkMPP3DavwMPH0tL9 qzAXfGiYEE0l/qaOlH2yqVQ= X-Google-Smtp-Source: AMrXdXt8/8GXl8d4to1GUILweXsVwfyM+P5ja6VY+Py8AhRn4lNwTrjfGa+v019T2qjMg2s4KijQmg== X-Received: by 2002:a05:600c:601e:b0:3c6:e61e:ae71 with SMTP id az30-20020a05600c601e00b003c6e61eae71mr11584043wmb.1.1671902456530; Sat, 24 Dec 2022 09:20:56 -0800 (PST) Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at. [85.127.52.93]) by smtp.gmail.com with ESMTPSA id i2-20020a05600c354200b003d35acb0fd7sm14347049wmq.34.2022.12.24.09.20.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 24 Dec 2022 09:20:56 -0800 (PST) Message-ID: <4a93981e06259ffac47ecc6f988c37d1910593ee.camel@gmail.com> From: Liliana Marie Prikler Date: Sat, 24 Dec 2022 18:20:54 +0100 In-Reply-To: <099d959851cb9ce9bf4afdedd01825b7ccf78a73.1671891059.git.mirai@makinata.eu> References: <099d959851cb9ce9bf4afdedd01825b7ccf78a73.1671891059.git.mirai@makinata.eu> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable User-Agent: Evolution 3.46.0 MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+larch=yhetil.org@gnu.org Sender: guix-patches-bounces+larch=yhetil.org@gnu.org X-Migadu-Country: US X-Migadu-Flow: FLOW_IN ARC-Seal: i=1; s=key1; d=yhetil.org; t=1671902546; a=rsa-sha256; cv=none; b=GJoCpbY3CqCyYdIUYyALh63A9JyyjRNWtaKhPXfmItkhnDgeKm3PefczHZfIUHDv3BWqcr zzJI1/gIuEqkZpTt2rKIp3qF/soU9OYR28ufRTdWGQHsZ5WeYOyvLjsylpWAUSach4c3kU dUVlaQ3kidbXBzlP8E5zdgBWaORF9h3+QO0WRjsei+swjDhjpPyWRId3Vmbu1cos1ohPFS LG4yDuApPNg5GaCWzLbiqQ0rfsaC49VPS7+pNs2DnRNo4K4+sz0I4sPkA+QGok3Iccle1V MrXIeak+L43KPWiEIHXRhZ9thba+HuFr/rbiBQR5GC13cBgrj/Y64iB66/Y67A== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=gmail.com header.s=20210112 header.b=jm6axPxa; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=fail reason="SPF not aligned (relaxed)" header.from=gmail.com (policy=none) ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1671902546; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding:resent-cc: resent-from:resent-sender:resent-message-id:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=ciboyAGhoWIxNKcuoCKq/EpiuvbsahqbNAca0qttacI=; b=MyoO+s0ZurXWhSmOA6hPeuP3FQr3Sd6FEolLap6xPIeH82txPYq7A+1qs0OC3cqUbeBSA7 VMT6Pu4Gt6oDrYL/42iaTrtAYN5lcCMkoG4bSuuWDe7uVIAs3Q7OYv/MbPQtl/HhhlyZXA XvoxZAZ/ae7ZGD8D5jhZkHbiDuIDssDD80uhzPizBTlvo/TUSK8C8KMqQUApesmZXJff/X 1fgqPlD3oNrUQy3l0gPNCre3onEGfcYQTA8TxwyfIVl0P3GEVDRY8rhP38kulzwpjLvm1w xx5H8cE3pcrQmGeE4G00T0AASIJigiZHvindcreNwFrtM1yy/sO/yIPUi4rgww== X-Spam-Score: -2.01 X-Migadu-Queue-Id: D5F0D1E3A Authentication-Results: aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=gmail.com header.s=20210112 header.b=jm6axPxa; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=fail reason="SPF not aligned (relaxed)" header.from=gmail.com (policy=none) X-Migadu-Scanner: scn0.migadu.com X-Migadu-Spam-Score: -2.01 X-TUID: 2dEG4UaNW7qr Am Samstag, dem 24.12.2022 um 14:11 +0000 schrieb mirai@makinata.eu: > From: Bruno Victal >=20 > Introduces 'mpd-plugin' and 'mpd-partition' records. > Expands 'mpd-output' and 'mpd-configuration' records. > Deprecates redundant abbreviated fields in 'mpd-configuration' and > avoids > serializing unused fields that may introduce undesired behavior. > Replace free-form-args serialization by making 'mpd-serialize-field' > handle > multiple types and using it with 'generic-serialize-alist'. > Reduce code weight by removing cosmetic indented serialization > procedures. > Offload logging from shepherd to MPD. > Implement log-rotation via rottlog. > Implement Shepherd actions: 'reopen' and 'configuration'. The things you wrote here read a like a less structured ChangeLog. The section between header and ChangeLog should instead be used to give some wider context if needed, imo. > * gnu/services/audio.scm > (mpd-plugin, mpd-partition): New record. >=20 > (mpd-plugin?, mpd-partition?, list-of-string?, list-of-symbol?) > (list-of-mpd-plugin?, list-of-mpd-partition?) > (list-of-mpd-plugin-or-output?, port?): New predicate. >=20 > (mpd-serialize-field): Handle multiple types. >=20 > (mpd-configuration) > [package, group, shepherd-requirement, log-file, log-level, music- > directory] > [playlist-directory, endpoints, database, partitions, neighbors, > inputs] > [archive-plugins, input-cache-size, decoders, resampler, filters] > [playlist-plugins, extra-options]: New field. > [music-dir, playlist-dir, address]: Deprecate shorthand field. > [db-file, state-file, sticker-file, port, outputs]: Change admissible > type. >=20 > (mpd-log-rotation): New procedure. >=20 > (mpd-shepherd-service) > [actions]: New shepherd actions: 'reopen' and 'configuration'. > [requirement]: Splice with 'shepherd-requirement' field. > [start]: Use 'package' field. Remove #:log-file parameter. >=20 > (mpd-service-activation): Create logging directory. Handle migration > from old-style configuration. >=20 > (mpd-accounts): Do not hardcode username, change primary group to > "nogroup". While I welcome the extensibility here, I think the default should still be mpd:mpd. I think you should make it so that you can pass a user-account and user-group to the mpd service so that they can be reused (with a sanitizer that creates a user/group from string). > (mpd-service-type): Extend rottlog-service-type for log-rotation. > Update activation-service-type extension to reflect mpd-accounts > procedure change. >=20 > * doc/guix.texi (Audio Services)[Music Player Daemon]: Update doc. > --- >=20 > =C2=A0Changes since v5: > =C2=A0* Serialize default_port field-name as "port". >=20 > =C2=A0doc/guix.texi=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= | 177 +++++++++++++--- > =C2=A0gnu/services/audio.scm | 463 +++++++++++++++++++++++++++++++-------= - > -- > =C2=A02 files changed, 506 insertions(+), 134 deletions(-) >=20 > diff --git a/doc/guix.texi b/doc/guix.texi > index e25692fd27..5663d1913a 100644 > --- a/doc/guix.texi > +++ b/doc/guix.texi > @@ -109,6 +109,7 @@ Copyright @copyright{} 2022 Reily Siegel@* > =C2=A0Copyright @copyright{} 2022 Simon Streit@* > =C2=A0Copyright @copyright{} 2022 (@* > =C2=A0Copyright @copyright{} 2022 John Kehayias@* > +Copyright @copyright{} 2022 Bruno Victal@* > =C2=A0 > =C2=A0Permission is granted to copy, distribute and/or modify this > document > =C2=A0under the terms of the GNU Free Documentation License, Version 1.3 > or > @@ -33014,79 +33015,187 @@ The service type for @command{mpd} > =C2=A0Data type representing the configuration of @command{mpd}. > =C2=A0 > =C2=A0@table @asis > -@item @code{user} (default: @code{"mpd"}) > +@item @code{package} (default: @code{mpd}) (type: file-like) > +The MPD package. > + > +@item @code{user} (default: @code{"mpd"}) (type: string) > =C2=A0The user to run mpd as. > =C2=A0 > -@item @code{music-dir} (default: @code{"~/Music"}) > +@item @code{group} (type: maybe-string) > +The group to run mpd as. > + > +@item @code{shepherd-requirement} (default: @code{()}) (type: list- > of-symbol) > +This is a list of symbols naming Shepherd services that this service > +will depend on. > + > +@item @code{log-file} (default: @code{"/var/log/mpd/log"}) (type: > maybe-string) > +The location of the log file.=C2=A0 Set to @code{syslog} to use the loca= l > +syslog daemon or @code{%unset-value} to omit this directive from the > +configuration file. > + > +@item @code{log-level} (type: maybe-string) > +Supress any messages below this threshold.=C2=A0 Available values: > +@code{notice}, @code{info}, @code{verbose}, @code{warning} and > +@code{error}. > + > +@item @code{music-directory} (type: maybe-string) > =C2=A0The directory to scan for music files. > =C2=A0 > -@item @code{playlist-dir} (default: @code{"~/.mpd/playlists"}) > +@item @code{playlist-directory} (type: maybe-string) > =C2=A0The directory to store playlists. > =C2=A0 > -@item @code{db-file} (default: @code{"~/.mpd/tag_cache"}) > +@item @code{db-file} (type: maybe-string) > =C2=A0The location of the music database. > =C2=A0 > -@item @code{state-file} (default: @code{"~/.mpd/state"}) > +@item @code{state-file} (type: maybe-string) > =C2=A0The location of the file that stores current MPD's state. > =C2=A0 > -@item @code{sticker-file} (default: @code{"~/.mpd/sticker.sql"}) > +@item @code{sticker-file} (type: maybe-string) > =C2=A0The location of the sticker database. > =C2=A0 > -@item @code{port} (default: @code{"6600"}) > -The port to run mpd on. > +@item @code{default-port} (default: @code{6600}) (type: maybe- > integer) > +The default port to run mpd on. > + > +@item @code{endpoints} (type: maybe-list-of-string) > +The addresses that mpd will bind to.=C2=A0 A different port may be > +specified, e.g. @code{localhost:6602}.=C2=A0 IPv6 addresses must be > +enclosed in square brackets if a different port is used. > +To use a Unix domain socket, an absolute path or a path starting > with @code{~} > +can be specified here. LGTM, but "A different port" should probably be "A port different from @var{default-port}. > +@item @code{database} (type: maybe-mpd-plugin) > +MPD database plugin configuration. > + > +@item @code{partitions} (default: @code{()}) (type: list-of-mpd- > partition) > +List of MPD "partitions". > =C2=A0 > -@item @code{address} (default: @code{"any"}) > -The address that mpd will bind to.=C2=A0 To use a Unix domain socket, > -an absolute path can be specified here. > +@item @code{neighbors} (default: @code{()}) (type: list-of-mpd- > plugin) > +List of MPD neighbor plugin configurations. > =C2=A0 > -@item @code{outputs} (default: @code{"(list (mpd-output))"}) > -The audio outputs that MPD can use.=C2=A0 By default this is a single > output using pulseaudio. > +@item @code{inputs} (default: @code{()}) (type: list-of-mpd-plugin) > +List of MPD input plugin configurations. > + > +@item @code{archive-plugins} (default: @code{()}) (type: list-of- > mpd-plugin) > +List of MPD archive plugin configurations. > + > +@item @code{input-cache-size} (type: maybe-string) > +MPD input cache size. > + > +@item @code{decoders} (default: @code{()}) (type: list-of-mpd- > plugin) > +List of MPD decoder plugin configurations. > + > +@item @code{resampler} (type: maybe-mpd-plugin) > +MPD resampler plugin configuration. > + > +@item @code{filters} (default: @code{()}) (type: list-of-mpd-plugin) > +List of MPD filter plugin configurations. > + > +@item @code{outputs} (type: list-of-mpd-plugin-or-output) > +The audio outputs that MPD can use.=C2=A0 By default this is a single > output > +using pulseaudio. > + > +@item @code{playlist-plugins} (default: @code{()}) (type: list-of- > mpd-plugin) > +List of MPD playlist plugin configurations. > + > +@item @code{extra-options} (default: @code{()}) (type: alist) > +An association list of option symbols/strings to string values to be > +appended to the configuration. > + > +@end table > +@end deftp > + > +@deftp {Data Type} mpd-plugin > +Data type representing a @command{mpd} plugin. > + > +@table @asis > +@item @code{plugin} (type: maybe-string) > +Plugin name. > + > +@item @code{name} (type: maybe-string) > +Name. > + > +@item @code{enabled?} (type: maybe-boolean) > +Whether the plugin is enabled/disabled. > + > +@item @code{extra-options} (default: @code{()}) (type: alist) > +An association list of option symbols/strings to string values to be > +appended to the plugin configuration.=C2=A0 See > +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD=C2=A0plugin > +reference} for available options. > + > +@end table > +@end deftp > + > +@deftp {Data Type} mpd-partition > +Data type representing a @command{mpd} partition. > + > +@table @asis > +@item @code{name} (type: string) > +Partition name. > + > +@item @code{extra-options} (default: @code{()}) (type: alist) > +An association list of option symbols/strings to string values to be > +appended to the partition configuration.=C2=A0 See > +@uref{ > https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions > ,Configuring > +Partitions} for available options. > =C2=A0 > =C2=A0@end table > =C2=A0@end deftp > =C2=A0 > =C2=A0@deftp {Data Type} mpd-output > -Data type representing an @command{mpd} audio output. > +Data type representing a @command{mpd} audio output. > =C2=A0 > =C2=A0@table @asis > -@item @code{name} (default: @code{"MPD"}) > +@item @code{name} (default: @code{"MPD"}) (type: string) > =C2=A0The name of the audio output. > =C2=A0 > -@item @code{type} (default: @code{"pulse"}) > +@item @code{type} (default: @code{"pulse"}) (type: string) > =C2=A0The type of audio output. > =C2=A0 > -@item @code{enabled?} (default: @code{#t}) > +@item @code{enabled?} (default: @code{#t}) (type: boolean) > =C2=A0Specifies whether this audio output is enabled when MPD is started.= =C2=A0 > By > =C2=A0default, all audio outputs are enabled.=C2=A0 This is just the defa= ult > =C2=A0setting when there is no state file; with a state file, the previou= s > =C2=A0state is restored. > =C2=A0 > -@item @code{tags?} (default: @code{#t}) > +@item @code{format} (type: maybe-string) > +Force a specific audio format on output.=C2=A0 See > +@uref{ > https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Gl > obal > +Audio Format} for a more detailed description. > + > +@item @code{tags?} (default: @code{#t}) (type: boolean) > =C2=A0If set to @code{#f}, then MPD will not send tags to this output.=C2= =A0 > This > =C2=A0is only useful for output plugins that can receive tags, for exampl= e > the > =C2=A0@code{httpd} output plugin. > =C2=A0 > -@item @code{always-on?} (default: @code{#f}) > +@item @code{always-on?} (default: @code{#f}) (type: boolean) > =C2=A0If set to @code{#t}, then MPD attempts to keep this audio output > always > -open.=C2=A0 This may be useful for streaming servers, when you don=E2=80= =99t want > to > +open.=C2=A0 This may be useful for streaming servers, when you don?t wan= t > to > =C2=A0disconnect all listeners even when playback is accidentally stopped= . > =C2=A0 > -@item @code{mixer-type} > -This field accepts a symbol that specifies which mixer should be > used > +@item @code{mixer-type} (default: @code{"none"}) (type: string) > +This field accepts a string that specifies which mixer should be > used > =C2=A0for this audio output: the @code{hardware} mixer, the > @code{software} > =C2=A0mixer, the @code{null} mixer (allows setting the volume, but with n= o > =C2=A0effect; this can be used as a trick to implement an external mixer > =C2=A0External Mixer) or no mixer (@code{none}). > =C2=A0 > -@item @code{extra-options} (default: @code{'()}) > -An association list of option symbols to string values to be > appended to > -the audio output configuration. > +@item @code{replay-gain-handler} (type: maybe-string) > +This field accepts a string that specifies how > +@uref{ > https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay > +Gain} is to be applied.=C2=A0 @code{software} uses an internal software > +volume control, @code{mixer} uses the configured (hardware) mixer > +control and @code{none} disables replay gain on this audio output. > + > +@item @code{extra-options} (default: @code{()}) (type: alist) > +An association list of option symbols/strings to string values to be > +appended to the audio output configuration. > =C2=A0 > =C2=A0@end table > =C2=A0@end deftp > =C2=A0 > -The following example shows a configuration of @code{mpd} that > provides > -an HTTP audio streaming output. > +The following example shows a configuration of @command{mpd} that > +configures some of its plugins and provides a HTTP audio streaming > output. > =C2=A0 > =C2=A0@lisp > =C2=A0(service mpd-service-type > @@ -33098,7 +33207,19 @@ an HTTP audio streaming output. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (mixer-type 'null) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (extra-options > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 `((encoder . "= vorbis") > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (port=C2= =A0=C2=A0=C2=A0 . "8080")))))))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (port=C2= =A0=C2=A0=C2=A0 . "8080")))))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (decoders > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (list (mpd-plugin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (plugin "mikmod") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (enabled? #f)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-plugin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (plugin "openmpt") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (enabled? #t) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (extra-options `((repeat-c= ount . -1) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (interpolation-filter . > 1)))))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (resampler = (mpd-plugin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (plugin = "libsamplerate") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (extra-o= ptions `((type . 0))))))) > =C2=A0@end lisp > =C2=A0 > =C2=A0 > diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm > index 1a1026f342..e456205e99 100644 > --- a/gnu/services/audio.scm > +++ b/gnu/services/audio.scm > @@ -21,19 +21,27 @@ > =C2=A0 > =C2=A0(define-module (gnu services audio) > =C2=A0=C2=A0 #:use-module (guix gexp) > +=C2=A0 #:use-module (guix deprecation) > +=C2=A0 #:use-module (guix diagnostics) > +=C2=A0 #:use-module (guix i18n) > =C2=A0=C2=A0 #:use-module (gnu services) > =C2=A0=C2=A0 #:use-module (gnu services configuration) > =C2=A0=C2=A0 #:use-module (gnu services shepherd) > +=C2=A0 #:use-module (gnu services admin) > =C2=A0=C2=A0 #:use-module (gnu system shadow) > =C2=A0=C2=A0 #:use-module (gnu packages admin) > =C2=A0=C2=A0 #:use-module (gnu packages mpd) > =C2=A0=C2=A0 #:use-module (guix records) > =C2=A0=C2=A0 #:use-module (ice-9 match) > -=C2=A0 #:use-module (ice-9 format) > =C2=A0=C2=A0 #:use-module (srfi srfi-1) > +=C2=A0 #:use-module (srfi srfi-8) > =C2=A0=C2=A0 #:use-module (srfi srfi-26) > =C2=A0=C2=A0 #:export (mpd-output > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = mpd-output? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-p= lugin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-p= lugin? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-p= artition > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-p= artition? > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = mpd-configuration > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = mpd-configuration? > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = mpd-service-type)) > @@ -52,180 +60,421 @@ (define (uglify-field-name field-name) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #\-) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "_"))) > =C2=A0 > -(define (free-form-args? val) > -=C2=A0 (match val > -=C2=A0=C2=A0=C2=A0 (() #t) > -=C2=A0=C2=A0=C2=A0 ((((? symbol?) . (? string?)) . val) (free-form-args?= val)) > -=C2=A0=C2=A0=C2=A0 (_ #f))) > +(define list-of-string? > +=C2=A0 (list-of string?)) > =C2=A0 > -(define* (mpd-serialize-field field-name value #:optional (indent- > level 0)) > -=C2=A0 #~(begin > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (use-modules ((ice-9 format))) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (format #f "~v/~a \"~a\"~%" #$indent-leve= l #$(if (string? > field-name) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 field-name > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 (uglify- > field-name field-name)) #$value))) > +(define list-of-symbol? > +=C2=A0 (list-of symbol?)) > =C2=A0 > -(define* (mpd-serialize-free-form-args field-name value #:optional > (indent-level 0)) > -=C2=A0 (generic-serialize-alist string-append (cut mpd-serialize-field <= > > <> indent-level) value)) > +(define (mpd-serialize-field field-name value) > +=C2=A0 (let ((field (if (string? field-name) field-name > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (uglify-field-name field-name))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (value (if (boolean? value) (= if value "yes" "no") value))) > +=C2=A0=C2=A0=C2=A0 #~(format #f "~a \"~a\"~%" #$field #$value))) > =C2=A0 > =C2=A0(define mpd-serialize-number mpd-serialize-field) > =C2=A0 > =C2=A0(define mpd-serialize-string mpd-serialize-field) > =C2=A0 > -(define* (mpd-serialize-boolean field-name value #:optional (indent- > level 0)) > -=C2=A0 (mpd-serialize-field field-name (if value "yes" "no") indent- > level)) > +(define mpd-serialize-boolean mpd-serialize-field) > =C2=A0 > -(define (mpd-serialize-list-of-mpd-output field-name value) > -=C2=A0 #~(string-append "\naudio_output {\n" > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$@(map (cut serialize-configuration <= > > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-output-fields) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 value) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "}\n")) > +(define (mpd-serialize-alist field-name value) > +=C2=A0 #~(string-append #$@(generic-serialize-alist list > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-serialize-field > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 value))) > =C2=A0 > -(define (mpd-serialize-configuration configuration) > -=C2=A0 (mixed-text-file > -=C2=A0=C2=A0 "mpd.conf" > -=C2=A0=C2=A0 (serialize-configuration configuration mpd-configuration- > fields))) > +(define-maybe string (prefix mpd-)) > +(define-maybe list-of-string (prefix mpd-)) > +(define-maybe boolean (prefix mpd-)) > + > +;;; TODO: Procedures for deprecated fields, to be removed. > + > +(define mpd-deprecated-fields '((music-dir . music-directory) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (playlist-dir . playlist-directory) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (address . endpoints))) > + > +(define (port? value) (or (string? value) (integer? value))) > + > +(define (mpd-serialize-deprecated-field field-name value) > +=C2=A0 (if (maybe-value-set? value) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (begin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (warn-about-deprecation > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 field-name #f > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #:replacement (assoc-re= f mpd-deprecated-fields field-name)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (match field-name > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ('playlist-dir (m= pd-serialize-string "playlist_directory" > value)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ('music-dir (mpd-= serialize-string "music_directory" > value)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ('address (mpd-se= rialize-string "bind_to_address" > value)))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "")) > + > +(define (mpd-serialize-port field-name value) > +=C2=A0 (when (string? value) > +=C2=A0=C2=A0=C2=A0 (warning > +=C2=A0=C2=A0=C2=A0=C2=A0 (G_ "string value for '~a' is deprecated, use i= nteger > instead~%") > +=C2=A0=C2=A0=C2=A0=C2=A0 field-name)) > +=C2=A0 (mpd-serialize-field "port" value)) > + > +(define-maybe port (prefix mpd-)) > + > +;;; > + > +;; Generic MPD plugin record, lists only the most prevalent fields. > +(define-configuration mpd-plugin > +=C2=A0 (plugin > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "Plugin name.") > + > +=C2=A0 (name > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "Name.") > + > +=C2=A0 (enabled? > +=C2=A0=C2=A0 maybe-boolean > +=C2=A0=C2=A0 "Whether the plugin is enabled/disabled.") > + > +=C2=A0 (extra-options > +=C2=A0=C2=A0 (alist '()) > +=C2=A0=C2=A0 "An association list of option symbols/strings to string va= lues > +to be appended to the plugin configuration. See > +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD=C2=A0plugin > reference} > +for available options.") > + > +=C2=A0 (prefix mpd-)) > + > +(define (mpd-serialize-mpd-plugin field-name value) > +=C2=A0 #~(format #f "~a {~%~a}~%" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 '#$fi= eld-name > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$(se= rialize-configuration value mpd-plugin-fields))) > + > +(define (mpd-serialize-list-of-mpd-plugin field-name value) > +=C2=A0 #~(string-append #$@(map (cut mpd-serialize-mpd-plugin field-name > <>) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 value))) > =C2=A0 > -(define mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> > 1)) > -(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> > <> 1)) > -(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> > <> 1)) > -(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean > <> <> 1)) > -(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize- > free-form-args <> <> 1)) > +(define list-of-mpd-plugin? (list-of mpd-plugin?)) > + > +(define-maybe mpd-plugin (prefix mpd-)) > + > +(define-configuration mpd-partition > +=C2=A0 (name > +=C2=A0=C2=A0 string > +=C2=A0=C2=A0 "Partition name.") > + > +=C2=A0 (extra-options > +=C2=A0=C2=A0 (alist '()) > +=C2=A0=C2=A0 "An association list of option symbols/strings to string va= lues > +to be appended to the partition configuration. See > +@uref{ > https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions > ,Configuring=C2=A0Partitions} > +for available options.") > + > +=C2=A0 (prefix mpd-)) > + > +(define (mpd-serialize-mpd-partition field-name value) > +=C2=A0 #~(format #f "partition {~%~a}~%" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$(se= rialize-configuration value mpd-partition-fields))) > + > +(define (mpd-serialize-list-of-mpd-partition field-name value) > +=C2=A0 #~(string-append #$@(map (cut mpd-serialize-mpd-partition #f <>) > value))) > + > +(define list-of-mpd-partition? > +=C2=A0 (list-of mpd-partition?)) > =C2=A0 > =C2=A0(define-configuration mpd-output > =C2=A0=C2=A0 (name > =C2=A0=C2=A0=C2=A0 (string "MPD") > =C2=A0=C2=A0=C2=A0 "The name of the audio output.") > + > =C2=A0=C2=A0 (type > =C2=A0=C2=A0=C2=A0 (string "pulse") > =C2=A0=C2=A0=C2=A0 "The type of audio output.") > + > =C2=A0=C2=A0 (enabled? > =C2=A0=C2=A0=C2=A0 (boolean #t) > =C2=A0=C2=A0=C2=A0 "Specifies whether this audio output is enabled when M= PD is > started. By > =C2=A0default, all audio outputs are enabled. This is just the default > =C2=A0setting when there is no state file; with a state file, the previou= s > =C2=A0state is restored.") > + > +=C2=A0 (format > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "Force a specific audio format on output. See > +@uref{ > https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Gl > obal=C2=A0Audio Format} > +for a more detailed description.") > +=C2=A0=C2=A0=20 > =C2=A0=C2=A0 (tags? > =C2=A0=C2=A0=C2=A0 (boolean #t) > =C2=A0=C2=A0=C2=A0 "If set to @code{#f}, then MPD will not send tags to t= his output. > This > =C2=A0is only useful for output plugins that can receive tags, for exampl= e > the > =C2=A0@code{httpd} output plugin.") > + > =C2=A0=C2=A0 (always-on? > =C2=A0=C2=A0=C2=A0 (boolean #f) > =C2=A0=C2=A0=C2=A0 "If set to @code{#t}, then MPD attempts to keep this a= udio output > always > =C2=A0open. This may be useful for streaming servers, when you don=E2=80= =99t want > to > =C2=A0disconnect all listeners even when playback is accidentally > stopped.") > + > =C2=A0=C2=A0 (mixer-type > =C2=A0=C2=A0=C2=A0 (string "none") > -=C2=A0=C2=A0 "This field accepts a symbol that specifies which mixer sho= uld be > used > +=C2=A0=C2=A0 "This field accepts a string that specifies which mixer sho= uld be > used > =C2=A0for this audio output: the @code{hardware} mixer, the > @code{software} > =C2=A0mixer, the @code{null} mixer (allows setting the volume, but with n= o > =C2=A0effect; this can be used as a trick to implement an external mixer > =C2=A0External Mixer) or no mixer (@code{none}).") > + > +=C2=A0 (replay-gain-handler > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "This field accepts a string that specifies how > +@uref{ > https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay=C2=A0Ga= i > n} > +is to be applied. @code{software} uses an internal software volume > control, > +@code{mixer} uses the configured (hardware) mixer control and > @code{none} > +disables replay gain on this audio output.") > + > =C2=A0=C2=A0 (extra-options > -=C2=A0=C2=A0 (free-form-args '()) > -=C2=A0=C2=A0 "An association list of option symbols to string values to = be > appended to > -the audio output configuration.") > -=C2=A0 (prefix mpd-subsystem-)) > +=C2=A0=C2=A0 (alist '()) > +=C2=A0=C2=A0 "An association list of option symbols/strings to string va= lues > +to be appended to the audio output configuration.") > =C2=A0 > -(define list-of-mpd-output? > -=C2=A0 (list-of mpd-output?)) > +=C2=A0 (prefix mpd-)) > + > +(define (mpd-serialize-mpd-output field-name value) > +=C2=A0 #~(format #f "audio_output {~%~a}~%" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$(se= rialize-configuration value mpd-output-fields))) > + > +(define (mpd-serialize-list-of-mpd-plugin-or-output field-name > value) > +=C2=A0 (receive (plugins outputs) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (partition mpd-plugin? value) > +=C2=A0=C2=A0=C2=A0 #~(string-append #$@(map (cut mpd-serialize-mpd-plugi= n > "audio_output" <>) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 plugins) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$@(map (cut mpd-serialize= -mpd-output #f <>) > outputs)))) > + > +(define list-of-mpd-plugin-or-output? > +=C2=A0 (list-of (lambda (x) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (or (mpd-output? x) (mpd-plugin? x))))) > =C2=A0 > =C2=A0(define-configuration mpd-configuration > +=C2=A0 (package > +=C2=A0=C2=A0 (file-like mpd) > +=C2=A0=C2=A0 "The MPD package." > +=C2=A0=C2=A0 empty-serializer) > + > =C2=A0=C2=A0 (user > =C2=A0=C2=A0=C2=A0 (string "mpd") > =C2=A0=C2=A0=C2=A0 "The user to run mpd as.") > -=C2=A0 (music-dir > -=C2=A0=C2=A0 (string "~/Music") > + > +=C2=A0 (group > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "The group to run mpd as.") > + > +=C2=A0 (shepherd-requirement > +=C2=A0=C2=A0 (list-of-symbol '()) > +=C2=A0=C2=A0 "This is a list of symbols naming Shepherd services that th= is > service > +will depend on." > +=C2=A0=C2=A0 empty-serializer) > + > +=C2=A0 (log-file > +=C2=A0=C2=A0 (maybe-string "/var/log/mpd/log") > +=C2=A0=C2=A0 "The location of the log file. Set to @code{syslog} to use = the > +local syslog daemon or @code{%unset-value} to omit this directive > +from the configuration file.") > + > +=C2=A0 (log-level > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "Supress any messages below this threshold. > +Available values: @code{notice}, @code{info}, @code{verbose}, > +@code{warning} and @code{error}.") > + > +=C2=A0 (music-directory > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "The directory to scan for music files.") > + > +=C2=A0 (music-dir ; TODO: deprecated, remove later > +=C2=A0=C2=A0 maybe-string > =C2=A0=C2=A0=C2=A0 "The directory to scan for music files." > -=C2=A0=C2=A0 (lambda (_ x) > -=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-field "music_directory" x))) > -=C2=A0 (playlist-dir > -=C2=A0=C2=A0 (string "~/.mpd/playlists") > +=C2=A0=C2=A0 mpd-serialize-deprecated-field) > + > +=C2=A0 (playlist-directory > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "The directory to store playlists.") > + > +=C2=A0 (playlist-dir ; TODO: deprecated, remove later > +=C2=A0=C2=A0 maybe-string > =C2=A0=C2=A0=C2=A0 "The directory to store playlists." > -=C2=A0=C2=A0 (lambda (_ x) > -=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-field "playlist_directory" x))) > +=C2=A0=C2=A0 mpd-serialize-deprecated-field) > + > =C2=A0=C2=A0 (db-file > -=C2=A0=C2=A0 (string "~/.mpd/tag_cache") > +=C2=A0=C2=A0 maybe-string > =C2=A0=C2=A0=C2=A0 "The location of the music database.") > + > =C2=A0=C2=A0 (state-file > -=C2=A0=C2=A0 (string "~/.mpd/state") > +=C2=A0=C2=A0 maybe-string > =C2=A0=C2=A0=C2=A0 "The location of the file that stores current MPD's st= ate.") > + > =C2=A0=C2=A0 (sticker-file > -=C2=A0=C2=A0 (string "~/.mpd/sticker.sql") > +=C2=A0=C2=A0 maybe-string > =C2=A0=C2=A0=C2=A0 "The location of the sticker database.") > -=C2=A0 (port > -=C2=A0=C2=A0 (string "6600") > -=C2=A0=C2=A0 "The port to run mpd on.") > -=C2=A0 (address > -=C2=A0=C2=A0 (string "any") > + > +=C2=A0 (default-port > +=C2=A0=C2=A0 (maybe-port 6600) ; TODO: switch to integer > +=C2=A0=C2=A0 "The default port to run mpd on.") > + > +=C2=A0 (endpoints > +=C2=A0=C2=A0 maybe-list-of-string > +=C2=A0=C2=A0 "The addresses that mpd will bind to. A different port may = be > +specified, e.g. @code{localhost:6602}. IPv6 addresses must be > +enclosed in square brackets if a different port is used. > +To use a Unix domain socket, an absolute path or a path starting > with @code{~} > +can be specified here." > +=C2=A0=C2=A0 (lambda (_ x) > +=C2=A0=C2=A0=C2=A0=C2=A0 (if (maybe-value-set? x) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #~(string-append #$@(ma= p > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 (cut mpd-serialize-field > "bind_to_address" <>) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 x)) ""))) > + > +=C2=A0 (address ; TODO: deprecated, remove later > +=C2=A0=C2=A0 maybe-string > =C2=A0=C2=A0=C2=A0 "The address that mpd will bind to. > =C2=A0To use a Unix domain socket, an absolute path can be specified > here." > +=C2=A0=C2=A0 mpd-serialize-deprecated-field) > + > +=C2=A0 (database > +=C2=A0=C2=A0 maybe-mpd-plugin > +=C2=A0=C2=A0 "MPD database plugin configuration.") > + > +=C2=A0 (partitions > +=C2=A0=C2=A0 (list-of-mpd-partition '()) > +=C2=A0=C2=A0 "List of MPD \"partitions\".") > +=C2=A0=20 > +=C2=A0 (neighbors > +=C2=A0=C2=A0 (list-of-mpd-plugin '()) > +=C2=A0=C2=A0 "List of MPD neighbor plugin configurations.") > + > +=C2=A0 (inputs > +=C2=A0=C2=A0 (list-of-mpd-plugin '()) > +=C2=A0=C2=A0 "List of MPD input plugin configurations." > +=C2=A0=C2=A0 (lambda (_ x) > +=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-list-of-mpd-plugin "input" x))) > + > +=C2=A0 (archive-plugins > +=C2=A0=C2=A0 (list-of-mpd-plugin '()) > +=C2=A0=C2=A0 "List of MPD archive plugin configurations." > =C2=A0=C2=A0=C2=A0 (lambda (_ x) > -=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-field "bind_to_address" x))) > +=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-list-of-mpd-plugin "archive_plug= in" x))) > + > +=C2=A0 (input-cache-size > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "MPD input cache size." > +=C2=A0=C2=A0 (lambda (_ x) > +=C2=A0=C2=A0=C2=A0=C2=A0 (if (maybe-value-set? x) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #~(string-append "\ninp= ut_cache {\n" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 #$(mpd-serialize-string "size" x) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 "}\n") ""))) > + > +=C2=A0 (decoders > +=C2=A0=C2=A0 (list-of-mpd-plugin '()) > +=C2=A0=C2=A0 "List of MPD decoder plugin configurations." > +=C2=A0=C2=A0 (lambda (_ x) > +=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-list-of-mpd-plugin "decoder" x))= ) > + > +=C2=A0 (resampler > +=C2=A0=C2=A0 maybe-mpd-plugin > +=C2=A0=C2=A0 "MPD resampler plugin configuration.") > + > +=C2=A0 (filters > +=C2=A0=C2=A0 (list-of-mpd-plugin '()) > +=C2=A0=C2=A0 "List of MPD filter plugin configurations." > +=C2=A0=C2=A0 (lambda (_ x) > +=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-list-of-mpd-plugin "filter" x))) > + > =C2=A0=C2=A0 (outputs > -=C2=A0=C2=A0 (list-of-mpd-output (list (mpd-output))) > +=C2=A0=C2=A0 (list-of-mpd-plugin-or-output (list (mpd-output))) > =C2=A0=C2=A0=C2=A0 "The audio outputs that MPD can use. > =C2=A0By default this is a single output using pulseaudio.") > + > +=C2=A0 (playlist-plugins > +=C2=A0=C2=A0 (list-of-mpd-plugin '()) > +=C2=A0=C2=A0 "List of MPD playlist plugin configurations." > +=C2=A0=C2=A0 (lambda (_ x) > +=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-list-of-mpd-plugin "playlist_plu= gin" x))) > + > +=C2=A0 (extra-options > +=C2=A0=C2=A0 (alist '()) > +=C2=A0=C2=A0 "An association list of option symbols/strings to string va= lues > to be > +appended to the configuration.") > + > =C2=A0=C2=A0 (prefix mpd-)) > =C2=A0 > -(define (mpd-file-name config file) > -=C2=A0 "Return a path in /var/run/mpd/ that is writable > -=C2=A0=C2=A0 by @code{user} from @code{config}." > -=C2=A0 (string-append "/var/run/mpd/" > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 (mpd-configuration-user config) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 "/" file)) > +(define (mpd-serialize-configuration configuration) > +=C2=A0 (mixed-text-file > +=C2=A0=C2=A0 "mpd.conf" > +=C2=A0=C2=A0 (serialize-configuration configuration mpd-configuration- > fields))) > + > +(define (mpd-log-rotation config) > +=C2=A0 (match-record config (log-file) > +=C2=A0=C2=A0=C2=A0 (log-rotation > +=C2=A0=C2=A0=C2=A0=C2=A0 (files (list log-file)) > +=C2=A0=C2=A0=C2=A0=C2=A0 (post-rotate #~(begin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (use-modules (gnu se= rvices herd)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (with-shepherd-actio= n 'mpd ('reopen) #f)))))) > =C2=A0 > =C2=A0(define (mpd-shepherd-service config) > -=C2=A0 (shepherd-service > -=C2=A0=C2=A0 (documentation "Run the MPD (Music Player Daemon)") > -=C2=A0=C2=A0 (requirement '(user-processes)) > -=C2=A0=C2=A0 (provision '(mpd)) > -=C2=A0=C2=A0 (start #~(make-forkexec-constructor > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (list #$(file-append mpd "/bin/mpd") > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "--no-daemon" > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$(mpd-serialize-configuration config)= ) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= #:environment-variables > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= ;; Required to detect PulseAudio when run under a user > account. > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (list (string-append > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "XDG_RUNTIME_DIR=3D/run/user/" > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (number->string > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (passwd:uid > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (getpwnam #$(mpd-con= figuration-user > config)))))) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= #:log-file #$(mpd-file-name config "log"))) > -=C2=A0=C2=A0 (stop=C2=A0 #~(make-kill-destructor)))) > +=C2=A0 (match-record config (user package shepherd- > requirement) > +=C2=A0=C2=A0=C2=A0 (let* ((config-file (mpd-serialize-configuration conf= ig))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (shepherd-service > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (documentation "Run the MPD (Music = Player Daemon)") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (requirement `(user-processes loopb= ack ,@shepherd- > requirement)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (provision '(mpd)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (start #~(make-forkexec-constructor > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 (list #$(file-append package "/bin/mpd") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "--no-daemon" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$config-file) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 #:environment-variables > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 ;; Required to detect PulseAudio when run under a > user account. > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 (list (string-append > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "XDG_RUN= TIME_DIR=3D/run/user/" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (number-= >string (passwd:uid (getpwnam > #$user))))))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (stop=C2=A0 #~(make-kill-destructor= )) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (actions > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (list (shepherd-configuration= -action config-file) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 (shepherd-action > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 (name 'reopen) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 (documentation "Re-open log files and flush caches.") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 (procedure > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 #~(lambda (pid) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (if pid > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (begin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 (kill pid SIGHUP) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 (format #t > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "Issued SIGHUP to Servi= ce MPD (PID > ~a)." > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 pid)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (format = #t "Service MPD is not > running."))))))))))) > =C2=A0 > =C2=A0(define (mpd-service-activation config) > -=C2=A0 (with-imported-modules '((guix build utils)) > +=C2=A0 (match-record config (user log-file) > =C2=A0=C2=A0=C2=A0=C2=A0 #~(begin > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (use-modules (guix build= utils)) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (define %user > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (getpw #$(mpd-con= figuration-user config))) > - > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (let ((directory #$(mpd-file-= name config ".mpd"))) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (mkdir-p director= y) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (chown directory = (passwd:uid %user) (passwd:gid %user)) > - > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; Make /var/run/= mpd/USER user-owned as well. > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (chown (dirname d= irectory) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 (passwd:uid %user) (passwd:gid %user)))))) > - > - > -(define %mpd-accounts > -=C2=A0 ;; Default account and group for MPD. > -=C2=A0 (list (user-group (name "mpd") (system? #t)) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (user-account > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (name "mpd") > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (group "mpd") > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (system? #t) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (comment "Music Player = Daemon (MPD) user") > =C2=A0 > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; Note: /var/run/mpd h= osts one sub-directory per user, of > which > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; /var/run/mpd/mpd cor= responds to the "mpd" user. > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (home-directory "/var/r= un/mpd/mpd") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; TODO: remove me, migrates = from the old location at > /var/run/mpd > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;;=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 to the new one at /var/lib/mpd. > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (let* ((user (getpw #$user)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 (deprecated-directory (string-append "/var/run/mpd/" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 #$user "/.mpd")) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 (new-directory (string-append (passwd:dir user) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "/.config/mpd"))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (when (and (file-= exists? deprecated-directory) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (not (file-exists? new-dir= ectory))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (rena= me-file deprecated-directory new-directory) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (chow= n new-directory (passwd:uid user) (passwd:gid > user)))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (mkdir-p (dirname #$log-file)= )))) I'm not sure whether we should migrate the logs here. I do think the logs should be stored in /var/log rather than /var/run, but other than that I'm not even sure there's much value in changing the /var/run/mpd structure. What's your use case for doing so? Cheers