mirror of
https://git.in.rschanz.org/ryan77627/guix.git
synced 2025-01-11 21:59:08 -05:00
services: mpd: Refactor MPD service.
Refactor mpd-service-type to support additional mpd.conf directives and move activation-service-extension into service constructor. * gnu/services/audio.scm (mpd-plugin, mpd-partition): New records. (mpd-serialize-boolean): Alias to and integrate logic into... (mpd-serialize-field): ... this. (mpd-serialize-list-of-string): New variable. (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 variables. (mpd-file-name, mpd-service-activation): Remove variables. (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 fields. [music-dir, playlist-dir, address]: Deprecate shorthand fields. [db-file, state-file, sticker-file, port, outputs]: Change admissible type. (mpd-shepherd-service) [actions]: New shepherd actions: 'reopen' and 'configuration'. [requirement]: Splice with 'shepherd-requirement' field. [start]: Use 'package' field. Remove #:log-file parameter. Move activation-service extension into constructor. (mpd-accounts): Honor user and group names from configuration. (mpd-log-rotation): New procedure. (mpd-service-type)[extensions]: Add rottlog-service-type extension. Remove activation-service-type extension. (mpd-output-name, mpd-output-type, mpd-output-enabled?, mpd-output-format) (mpd-output-tags?, mpd-output-always-on?, mpd-output-mixer-type) (mpd-output-replay-gain-handler, mpd-output-extra-options) (mpd-plugin-plugin, mpd-plugin-name, mpd-plugin-enabled?) (mpd-plugin-extra-options) (mpd-partition-name, mpd-partition-extra-options) (mpd-configuration-package, mpd-configuration-user) (mpd-configuration-group, mpd-configuration-shepherd-requirement) (mpd-configuration-log-file, mpd-configuration-log-level) (mpd-configuration-music-directory, mpd-configuration-music-dir) (mpd-configuration-playlist-directory, mpd-configuration-playlist-dir) (mpd-configuration-db-file, mpd-configuration-state-file) (mpd-configuration-sticker-file, mpd-configuration-default-port) (mpd-configuration-endpoints, mpd-configuration-address) (mpd-configuration-database, mpd-configuration-partitions) (mpd-configuration-neighbors, mpd-configuration-inputs) (mpd-configuration-archive-plugins, mpd-configuration-input-cache-size) (mpd-configuration-decoders, mpd-configuration-resampler) (mpd-configuration-filters, mpd-configuration-outputs) (mpd-configuration-playlist-plugins, mpd-configuration-extra-options): Export accessors. * doc/guix.texi (Audio Services)[Music Player Daemon]: Update documentation. Signed-off-by: Liliana Marie Prikler <liliana.prikler@gmail.com>
This commit is contained in:
parent
d7fd9ec209
commit
5c5f0fc113
2 changed files with 540 additions and 124 deletions
177
doc/guix.texi
177
doc/guix.texi
|
@ -109,6 +109,7 @@ Copyright @copyright{} 2022 Reily Siegel@*
|
|||
Copyright @copyright{} 2022 Simon Streit@*
|
||||
Copyright @copyright{} 2022 (@*
|
||||
Copyright @copyright{} 2022 John Kehayias@*
|
||||
Copyright @copyright{} 2022 Bruno Victal@*
|
||||
Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@*
|
||||
Copyright @copyright{} 2023 Giacomo Leidi@*
|
||||
Copyright @copyright{} 2022 Antero Mejr@*
|
||||
|
@ -33185,79 +33186,187 @@ The service type for @command{mpd}
|
|||
Data type representing the configuration of @command{mpd}.
|
||||
|
||||
@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)
|
||||
The user to run mpd as.
|
||||
|
||||
@item @code{music-dir} (default: @code{"~/Music"})
|
||||
@item @code{group} (default: @code{"mpd"}) (type: 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. Set to @code{syslog} to use the local
|
||||
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. Available values:
|
||||
@code{notice}, @code{info}, @code{verbose}, @code{warning} and
|
||||
@code{error}.
|
||||
|
||||
@item @code{music-directory} (type: maybe-string)
|
||||
The directory to scan for music files.
|
||||
|
||||
@item @code{playlist-dir} (default: @code{"~/.mpd/playlists"})
|
||||
@item @code{playlist-directory} (type: maybe-string)
|
||||
The directory to store playlists.
|
||||
|
||||
@item @code{db-file} (default: @code{"~/.mpd/tag_cache"})
|
||||
@item @code{db-file} (type: maybe-string)
|
||||
The location of the music database.
|
||||
|
||||
@item @code{state-file} (default: @code{"~/.mpd/state"})
|
||||
@item @code{state-file} (type: maybe-string)
|
||||
The location of the file that stores current MPD's state.
|
||||
|
||||
@item @code{sticker-file} (default: @code{"~/.mpd/sticker.sql"})
|
||||
@item @code{sticker-file} (type: maybe-string)
|
||||
The location of the sticker database.
|
||||
|
||||
@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{address} (default: @code{"any"})
|
||||
The address that mpd will bind to. To use a Unix domain socket,
|
||||
an absolute path can be specified here.
|
||||
@item @code{endpoints} (type: maybe-list-of-string)
|
||||
The addresses that mpd will bind to. A port different from @var{default-port}
|
||||
may be specified, e.g. @code{localhost:6602} and IPv6 addresses must be
|
||||
enclosed in square brackets when a different port is used.
|
||||
To use a Unix domain socket, an absolute path or a path starting with @code{~}
|
||||
can be specified here.
|
||||
|
||||
@item @code{outputs} (default: @code{"(list (mpd-output))"})
|
||||
The audio outputs that MPD can use. By default this is a single output using pulseaudio.
|
||||
@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".
|
||||
|
||||
@item @code{neighbors} (default: @code{()}) (type: list-of-mpd-plugin)
|
||||
List of MPD neighbor plugin configurations.
|
||||
|
||||
@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. 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. See
|
||||
@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin
|
||||
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. See
|
||||
@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring
|
||||
Partitions} for available options.
|
||||
|
||||
@end table
|
||||
@end deftp
|
||||
|
||||
@deftp {Data Type} mpd-output
|
||||
Data type representing an @command{mpd} audio output.
|
||||
Data type representing a @command{mpd} audio output.
|
||||
|
||||
@table @asis
|
||||
@item @code{name} (default: @code{"MPD"})
|
||||
@item @code{name} (default: @code{"MPD"}) (type: string)
|
||||
The name of the audio output.
|
||||
|
||||
@item @code{type} (default: @code{"pulse"})
|
||||
@item @code{type} (default: @code{"pulse"}) (type: string)
|
||||
The type of audio output.
|
||||
|
||||
@item @code{enabled?} (default: @code{#t})
|
||||
@item @code{enabled?} (default: @code{#t}) (type: boolean)
|
||||
Specifies whether this audio output is enabled when MPD is started. By
|
||||
default, all audio outputs are enabled. This is just the default
|
||||
setting when there is no state file; with a state file, the previous
|
||||
state is restored.
|
||||
|
||||
@item @code{tags?} (default: @code{#t})
|
||||
@item @code{format} (type: maybe-string)
|
||||
Force a specific audio format on output. See
|
||||
@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global
|
||||
Audio Format} for a more detailed description.
|
||||
|
||||
@item @code{tags?} (default: @code{#t}) (type: boolean)
|
||||
If set to @code{#f}, then MPD will not send tags to this output. This
|
||||
is only useful for output plugins that can receive tags, for example the
|
||||
@code{httpd} output plugin.
|
||||
|
||||
@item @code{always-on?} (default: @code{#f})
|
||||
@item @code{always-on?} (default: @code{#f}) (type: boolean)
|
||||
If set to @code{#t}, then MPD attempts to keep this audio output always
|
||||
open. This may be useful for streaming servers, when you don’t want to
|
||||
open. This may be useful for streaming servers, when you don?t want to
|
||||
disconnect all listeners even when playback is accidentally stopped.
|
||||
|
||||
@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
|
||||
for this audio output: the @code{hardware} mixer, the @code{software}
|
||||
mixer, the @code{null} mixer (allows setting the volume, but with no
|
||||
effect; this can be used as a trick to implement an external mixer
|
||||
External Mixer) or no mixer (@code{none}).
|
||||
|
||||
@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. @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.
|
||||
|
||||
@end table
|
||||
@end deftp
|
||||
|
||||
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.
|
||||
|
||||
@lisp
|
||||
(service mpd-service-type
|
||||
|
@ -33269,7 +33378,19 @@ an HTTP audio streaming output.
|
|||
(mixer-type 'null)
|
||||
(extra-options
|
||||
`((encoder . "vorbis")
|
||||
(port . "8080"))))))))
|
||||
(port . "8080"))))))
|
||||
(decoders
|
||||
(list (mpd-plugin
|
||||
(plugin "mikmod")
|
||||
(enabled? #f))
|
||||
(mpd-plugin
|
||||
(plugin "openmpt")
|
||||
(enabled? #t)
|
||||
(extra-options `((repeat-count . -1)
|
||||
(interpolation-filter . 1))))))
|
||||
(resampler (mpd-plugin
|
||||
(plugin "libsamplerate")
|
||||
(extra-options `((type . 0)))))))
|
||||
@end lisp
|
||||
|
||||
|
||||
|
|
|
@ -21,9 +21,13 @@
|
|||
|
||||
(define-module (gnu services audio)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix deprecation)
|
||||
#:use-module (guix diagnostics)
|
||||
#:use-module (guix i18n)
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu services configuration)
|
||||
#:use-module (gnu services shepherd)
|
||||
#:use-module (gnu services admin)
|
||||
#:use-module (gnu system shadow)
|
||||
#:use-module (gnu packages admin)
|
||||
#:use-module (gnu packages mpd)
|
||||
|
@ -31,10 +35,61 @@ (define-module (gnu services audio)
|
|||
#:use-module (ice-9 match)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-26)
|
||||
#:use-module (srfi srfi-71)
|
||||
#:export (mpd-output
|
||||
mpd-output?
|
||||
mpd-output-name
|
||||
mpd-output-type
|
||||
mpd-output-enabled?
|
||||
mpd-output-format
|
||||
mpd-output-tags?
|
||||
mpd-output-always-on?
|
||||
mpd-output-mixer-type
|
||||
mpd-output-replay-gain-handler
|
||||
mpd-output-extra-options
|
||||
|
||||
mpd-plugin
|
||||
mpd-plugin?
|
||||
mpd-plugin-plugin
|
||||
mpd-plugin-name
|
||||
mpd-plugin-enabled?
|
||||
mpd-plugin-extra-options
|
||||
|
||||
mpd-partition
|
||||
mpd-partition?
|
||||
mpd-partition-name
|
||||
mpd-partition-extra-options
|
||||
|
||||
mpd-configuration
|
||||
mpd-configuration?
|
||||
mpd-configuration-package
|
||||
mpd-configuration-user
|
||||
mpd-configuration-group
|
||||
mpd-configuration-shepherd-requirement
|
||||
mpd-configuration-log-file
|
||||
mpd-configuration-log-level
|
||||
mpd-configuration-music-directory
|
||||
mpd-configuration-music-dir
|
||||
mpd-configuration-playlist-directory
|
||||
mpd-configuration-playlist-dir
|
||||
mpd-configuration-db-file
|
||||
mpd-configuration-state-file
|
||||
mpd-configuration-sticker-file
|
||||
mpd-configuration-default-port
|
||||
mpd-configuration-endpoints
|
||||
mpd-configuration-address
|
||||
mpd-configuration-database
|
||||
mpd-configuration-partitions
|
||||
mpd-configuration-neighbors
|
||||
mpd-configuration-inputs
|
||||
mpd-configuration-archive-plugins
|
||||
mpd-configuration-input-cache-size
|
||||
mpd-configuration-decoders
|
||||
mpd-configuration-resampler
|
||||
mpd-configuration-filters
|
||||
mpd-configuration-outputs
|
||||
mpd-configuration-playlist-plugins
|
||||
mpd-configuration-extra-options
|
||||
mpd-service-type))
|
||||
|
||||
;;; Commentary:
|
||||
|
@ -50,34 +105,125 @@ (define (uglify-field-name field-name)
|
|||
str)
|
||||
#\-) "_")))
|
||||
|
||||
(define list-of-string?
|
||||
(list-of string?))
|
||||
|
||||
(define list-of-symbol?
|
||||
(list-of symbol?))
|
||||
|
||||
(define (mpd-serialize-field field-name value)
|
||||
#~(format #f "~a ~s~%" #$(if (string? field-name)
|
||||
field-name
|
||||
(uglify-field-name field-name))
|
||||
#$(if (string? value)
|
||||
value
|
||||
(object->string value))))
|
||||
(let ((field (if (string? field-name) field-name
|
||||
(uglify-field-name field-name)))
|
||||
(value (cond
|
||||
((boolean? value) (if value "yes" "no"))
|
||||
((string? value) value)
|
||||
(else (object->string value)))))
|
||||
#~(format #f "~a ~s~%" #$field #$value)))
|
||||
|
||||
(define (mpd-serialize-alist field-name value)
|
||||
#~(string-append #$@(generic-serialize-alist list mpd-serialize-field
|
||||
value)))
|
||||
|
||||
(define mpd-serialize-string mpd-serialize-field)
|
||||
(define mpd-serialize-boolean mpd-serialize-field)
|
||||
|
||||
(define (mpd-serialize-boolean field-name value)
|
||||
(mpd-serialize-field field-name (if value "yes" "no")))
|
||||
(define (mpd-serialize-list-of-string field-name value)
|
||||
#~(string-concatenate #$(map (cut mpd-serialize-string field-name <>) value)))
|
||||
|
||||
(define (mpd-serialize-list-of-mpd-output field-name value)
|
||||
#~(string-append "\naudio_output {\n"
|
||||
#$@(map (cut serialize-configuration <>
|
||||
mpd-output-fields)
|
||||
value)
|
||||
"}\n"))
|
||||
(define-maybe string (prefix mpd-))
|
||||
(define-maybe list-of-string (prefix mpd-))
|
||||
(define-maybe boolean (prefix mpd-))
|
||||
|
||||
(define (mpd-serialize-configuration configuration)
|
||||
(mixed-text-file
|
||||
"mpd.conf"
|
||||
(serialize-configuration configuration mpd-configuration-fields)))
|
||||
;;; TODO: Procedures for deprecated fields, to be removed.
|
||||
|
||||
(define mpd-deprecated-fields '((music-dir . music-directory)
|
||||
(playlist-dir . playlist-directory)
|
||||
(address . endpoints)))
|
||||
|
||||
(define (port? value) (or (string? value) (integer? value)))
|
||||
|
||||
(define (mpd-serialize-deprecated-field field-name value)
|
||||
(if (maybe-value-set? value)
|
||||
(begin
|
||||
(warn-about-deprecation
|
||||
field-name #f
|
||||
#:replacement (assoc-ref mpd-deprecated-fields field-name))
|
||||
(match field-name
|
||||
('playlist-dir (mpd-serialize-string "playlist_directory" value))
|
||||
('music-dir (mpd-serialize-string "music_directory" value))
|
||||
('address (mpd-serialize-string "bind_to_address" value))))
|
||||
""))
|
||||
|
||||
(define (mpd-serialize-port field-name value)
|
||||
(when (string? value)
|
||||
(warning
|
||||
(G_ "string value for '~a' is deprecated, use integer instead~%")
|
||||
field-name))
|
||||
(mpd-serialize-field "port" value))
|
||||
|
||||
(define-maybe port (prefix mpd-))
|
||||
|
||||
;;;
|
||||
|
||||
;; Generic MPD plugin record, lists only the most prevalent fields.
|
||||
(define-configuration mpd-plugin
|
||||
(plugin
|
||||
maybe-string
|
||||
"Plugin name.")
|
||||
|
||||
(name
|
||||
maybe-string
|
||||
"Name.")
|
||||
|
||||
(enabled?
|
||||
maybe-boolean
|
||||
"Whether the plugin is enabled/disabled.")
|
||||
|
||||
(extra-options
|
||||
(alist '())
|
||||
"An association list of option symbols/strings to string values
|
||||
to be appended to the plugin configuration. See
|
||||
@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin reference}
|
||||
for available options.")
|
||||
|
||||
(prefix mpd-))
|
||||
|
||||
(define (mpd-serialize-mpd-plugin field-name value)
|
||||
#~(format #f "~a {~%~a}~%"
|
||||
'#$field-name
|
||||
#$(serialize-configuration value mpd-plugin-fields)))
|
||||
|
||||
(define (mpd-serialize-list-of-mpd-plugin field-name value)
|
||||
#~(string-append #$@(map (cut mpd-serialize-mpd-plugin field-name <>)
|
||||
value)))
|
||||
|
||||
(define list-of-mpd-plugin? (list-of mpd-plugin?))
|
||||
|
||||
(define-maybe mpd-plugin (prefix mpd-))
|
||||
|
||||
(define-configuration mpd-partition
|
||||
(name
|
||||
string
|
||||
"Partition name.")
|
||||
|
||||
(extra-options
|
||||
(alist '())
|
||||
"An association list of option symbols/strings to string values
|
||||
to be appended to the partition configuration. See
|
||||
@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring Partitions}
|
||||
for available options.")
|
||||
|
||||
(prefix mpd-))
|
||||
|
||||
(define (mpd-serialize-mpd-partition field-name value)
|
||||
#~(format #f "partition {~%~a}~%"
|
||||
#$(serialize-configuration value mpd-partition-fields)))
|
||||
|
||||
(define (mpd-serialize-list-of-mpd-partition field-name value)
|
||||
#~(string-append #$@(map (cut mpd-serialize-mpd-partition #f <>) value)))
|
||||
|
||||
(define list-of-mpd-partition?
|
||||
(list-of mpd-partition?))
|
||||
|
||||
(define-configuration mpd-output
|
||||
(name
|
||||
|
@ -95,6 +241,12 @@ (define-configuration mpd-output
|
|||
setting when there is no state file; with a state file, the previous
|
||||
state is restored.")
|
||||
|
||||
(format
|
||||
maybe-string
|
||||
"Force a specific audio format on output. See
|
||||
@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global Audio Format}
|
||||
for a more detailed description.")
|
||||
|
||||
(tags?
|
||||
(boolean #t)
|
||||
"If set to @code{#f}, then MPD will not send tags to this output. This
|
||||
|
@ -109,125 +261,268 @@ (define-configuration mpd-output
|
|||
|
||||
(mixer-type
|
||||
(string "none")
|
||||
"This field accepts a symbol that specifies which mixer should be used
|
||||
"This field accepts a string that specifies which mixer should be used
|
||||
for this audio output: the @code{hardware} mixer, the @code{software}
|
||||
mixer, the @code{null} mixer (allows setting the volume, but with no
|
||||
effect; this can be used as a trick to implement an external mixer
|
||||
External Mixer) or no mixer (@code{none}).")
|
||||
|
||||
(replay-gain-handler
|
||||
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. @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.")
|
||||
|
||||
(extra-options
|
||||
(alist '())
|
||||
"An association list of option symbols to string values to be appended to
|
||||
the audio output configuration.")
|
||||
"An association list of option symbols/strings to string values
|
||||
to be appended to the audio output configuration.")
|
||||
|
||||
(prefix mpd-))
|
||||
|
||||
(define list-of-mpd-output?
|
||||
(list-of mpd-output?))
|
||||
(define (mpd-serialize-mpd-output field-name value)
|
||||
#~(format #f "audio_output {~%~a}~%"
|
||||
#$(serialize-configuration value mpd-output-fields)))
|
||||
|
||||
(define (mpd-serialize-list-of-mpd-plugin-or-output field-name value)
|
||||
(let ((plugins outputs (partition mpd-plugin? value)))
|
||||
#~(string-append #$@(map (cut mpd-serialize-mpd-plugin "audio_output" <>)
|
||||
plugins)
|
||||
#$@(map (cut mpd-serialize-mpd-output #f <>) outputs))))
|
||||
|
||||
(define list-of-mpd-plugin-or-output?
|
||||
(list-of (lambda (x)
|
||||
(or (mpd-output? x) (mpd-plugin? x)))))
|
||||
|
||||
(define-configuration mpd-configuration
|
||||
(package
|
||||
(file-like mpd)
|
||||
"The MPD package."
|
||||
empty-serializer)
|
||||
|
||||
(user
|
||||
(string "mpd")
|
||||
"The user to run mpd as.")
|
||||
|
||||
(music-dir
|
||||
(string "~/Music")
|
||||
"The directory to scan for music files."
|
||||
(lambda (_ x)
|
||||
(mpd-serialize-field "music_directory" x)))
|
||||
(group
|
||||
(string "mpd")
|
||||
"The group to run mpd as.")
|
||||
|
||||
(playlist-dir
|
||||
(string "~/.mpd/playlists")
|
||||
(shepherd-requirement
|
||||
(list-of-symbol '())
|
||||
"This is a list of symbols naming Shepherd services that this service
|
||||
will depend on."
|
||||
empty-serializer)
|
||||
|
||||
(log-file
|
||||
(maybe-string "/var/log/mpd/log")
|
||||
"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.")
|
||||
|
||||
(log-level
|
||||
maybe-string
|
||||
"Supress any messages below this threshold.
|
||||
Available values: @code{notice}, @code{info}, @code{verbose},
|
||||
@code{warning} and @code{error}.")
|
||||
|
||||
(music-directory
|
||||
maybe-string
|
||||
"The directory to scan for music files.")
|
||||
|
||||
(music-dir ; TODO: deprecated, remove later
|
||||
maybe-string
|
||||
"The directory to scan for music files."
|
||||
mpd-serialize-deprecated-field)
|
||||
|
||||
(playlist-directory
|
||||
maybe-string
|
||||
"The directory to store playlists.")
|
||||
|
||||
(playlist-dir ; TODO: deprecated, remove later
|
||||
maybe-string
|
||||
"The directory to store playlists."
|
||||
(lambda (_ x)
|
||||
(mpd-serialize-field "playlist_directory" x)))
|
||||
mpd-serialize-deprecated-field)
|
||||
|
||||
(db-file
|
||||
(string "~/.mpd/tag_cache")
|
||||
maybe-string
|
||||
"The location of the music database.")
|
||||
|
||||
(state-file
|
||||
(string "~/.mpd/state")
|
||||
maybe-string
|
||||
"The location of the file that stores current MPD's state.")
|
||||
|
||||
(sticker-file
|
||||
(string "~/.mpd/sticker.sql")
|
||||
maybe-string
|
||||
"The location of the sticker database.")
|
||||
|
||||
(port
|
||||
(string "6600")
|
||||
"The port to run mpd on.")
|
||||
(default-port
|
||||
(maybe-port 6600)
|
||||
"The default port to run mpd on.")
|
||||
|
||||
(address
|
||||
(string "any")
|
||||
(endpoints
|
||||
maybe-list-of-string
|
||||
"The addresses that mpd will bind to. A port different from
|
||||
@var{default-port} may be specified, e.g. @code{localhost:6602} and
|
||||
IPv6 addresses must be enclosed in square brackets when a different
|
||||
port is used.
|
||||
To use a Unix domain socket, an absolute path or a path starting with @code{~}
|
||||
can be specified here."
|
||||
(lambda (_ endpoints)
|
||||
(if (maybe-value-set? endpoints)
|
||||
(mpd-serialize-list-of-string "bind_to_address" endpoints)
|
||||
"")))
|
||||
|
||||
(address ; TODO: deprecated, remove later
|
||||
maybe-string
|
||||
"The address that mpd will bind to.
|
||||
To use a Unix domain socket, an absolute path can be specified here."
|
||||
mpd-serialize-deprecated-field)
|
||||
|
||||
(database
|
||||
maybe-mpd-plugin
|
||||
"MPD database plugin configuration.")
|
||||
|
||||
(partitions
|
||||
(list-of-mpd-partition '())
|
||||
"List of MPD \"partitions\".")
|
||||
|
||||
(neighbors
|
||||
(list-of-mpd-plugin '())
|
||||
"List of MPD neighbor plugin configurations.")
|
||||
|
||||
(inputs
|
||||
(list-of-mpd-plugin '())
|
||||
"List of MPD input plugin configurations."
|
||||
(lambda (_ x)
|
||||
(mpd-serialize-field "bind_to_address" x)))
|
||||
(mpd-serialize-list-of-mpd-plugin "input" x)))
|
||||
|
||||
(archive-plugins
|
||||
(list-of-mpd-plugin '())
|
||||
"List of MPD archive plugin configurations."
|
||||
(lambda (_ x)
|
||||
(mpd-serialize-list-of-mpd-plugin "archive_plugin" x)))
|
||||
|
||||
(input-cache-size
|
||||
maybe-string
|
||||
"MPD input cache size."
|
||||
(lambda (_ x)
|
||||
(if (maybe-value-set? x)
|
||||
#~(string-append "\ninput_cache {\n"
|
||||
#$(mpd-serialize-string "size" x)
|
||||
"}\n") "")))
|
||||
|
||||
(decoders
|
||||
(list-of-mpd-plugin '())
|
||||
"List of MPD decoder plugin configurations."
|
||||
(lambda (_ x)
|
||||
(mpd-serialize-list-of-mpd-plugin "decoder" x)))
|
||||
|
||||
(resampler
|
||||
maybe-mpd-plugin
|
||||
"MPD resampler plugin configuration.")
|
||||
|
||||
(filters
|
||||
(list-of-mpd-plugin '())
|
||||
"List of MPD filter plugin configurations."
|
||||
(lambda (_ x)
|
||||
(mpd-serialize-list-of-mpd-plugin "filter" x)))
|
||||
|
||||
(outputs
|
||||
(list-of-mpd-output (list (mpd-output)))
|
||||
(list-of-mpd-plugin-or-output (list (mpd-output)))
|
||||
"The audio outputs that MPD can use.
|
||||
By default this is a single output using pulseaudio.")
|
||||
|
||||
(playlist-plugins
|
||||
(list-of-mpd-plugin '())
|
||||
"List of MPD playlist plugin configurations."
|
||||
(lambda (_ x)
|
||||
(mpd-serialize-list-of-mpd-plugin "playlist_plugin" x)))
|
||||
|
||||
(extra-options
|
||||
(alist '())
|
||||
"An association list of option symbols/strings to string values to be
|
||||
appended to the configuration.")
|
||||
|
||||
(prefix mpd-))
|
||||
|
||||
(define (mpd-file-name config file)
|
||||
"Return a path in /var/run/mpd/ that is writable
|
||||
by @code{user} from @code{config}."
|
||||
(string-append "/var/run/mpd/"
|
||||
(mpd-configuration-user config)
|
||||
"/" file))
|
||||
(define (mpd-serialize-configuration configuration)
|
||||
(mixed-text-file
|
||||
"mpd.conf"
|
||||
(serialize-configuration configuration mpd-configuration-fields)))
|
||||
|
||||
(define (mpd-log-rotation config)
|
||||
(match-record config <mpd-configuration> (log-file)
|
||||
(log-rotation
|
||||
(files (list log-file))
|
||||
(post-rotate #~(begin
|
||||
(use-modules (gnu services herd))
|
||||
(with-shepherd-action 'mpd ('reopen) #f))))))
|
||||
|
||||
(define (mpd-shepherd-service config)
|
||||
(shepherd-service
|
||||
(documentation "Run the MPD (Music Player Daemon)")
|
||||
(requirement '(user-processes))
|
||||
(provision '(mpd))
|
||||
(start #~(make-forkexec-constructor
|
||||
(list #$(file-append mpd "/bin/mpd")
|
||||
"--no-daemon"
|
||||
#$(mpd-serialize-configuration config))
|
||||
#:environment-variables
|
||||
;; Required to detect PulseAudio when run under a user account.
|
||||
(list (string-append
|
||||
"XDG_RUNTIME_DIR=/run/user/"
|
||||
(number->string
|
||||
(passwd:uid
|
||||
(getpwnam #$(mpd-configuration-user config))))))
|
||||
#:log-file #$(mpd-file-name config "log")))
|
||||
(stop #~(make-kill-destructor))))
|
||||
(match-record config <mpd-configuration> (user package shepherd-requirement
|
||||
log-file playlist-directory
|
||||
db-file state-file sticker-file)
|
||||
(let* ((config-file (mpd-serialize-configuration config)))
|
||||
(shepherd-service
|
||||
(documentation "Run the MPD (Music Player Daemon)")
|
||||
(requirement `(user-processes loopback ,@shepherd-requirement))
|
||||
(provision '(mpd))
|
||||
(start #~(begin
|
||||
(and=> #$(maybe-value log-file)
|
||||
(compose mkdir-p dirname))
|
||||
|
||||
(define (mpd-service-activation config)
|
||||
(with-imported-modules '((guix build utils))
|
||||
#~(begin
|
||||
(use-modules (guix build utils))
|
||||
(define %user
|
||||
(getpw #$(mpd-configuration-user config)))
|
||||
(let ((user (getpw #$user)))
|
||||
(for-each
|
||||
(lambda (x)
|
||||
(when (and x (not (file-exists? x)))
|
||||
(mkdir-p x)
|
||||
(chown x (passwd:uid user) (passwd:gid user))))
|
||||
(list #$(maybe-value playlist-directory)
|
||||
(and=> #$(maybe-value db-file) dirname)
|
||||
(and=> #$(maybe-value state-file) dirname)
|
||||
(and=> #$(maybe-value sticker-file) dirname))))
|
||||
|
||||
(let ((directory #$(mpd-file-name config ".mpd")))
|
||||
(mkdir-p directory)
|
||||
(chown directory (passwd:uid %user) (passwd:gid %user))
|
||||
(make-forkexec-constructor
|
||||
(list #$(file-append package "/bin/mpd")
|
||||
"--no-daemon"
|
||||
#$config-file)
|
||||
#:environment-variables
|
||||
;; Required to detect PulseAudio when run under a user account.
|
||||
(list (string-append
|
||||
"XDG_RUNTIME_DIR=/run/user/"
|
||||
(number->string (passwd:uid (getpwnam #$user))))))))
|
||||
(stop #~(make-kill-destructor))
|
||||
(actions
|
||||
(list (shepherd-configuration-action config-file)
|
||||
(shepherd-action
|
||||
(name 'reopen)
|
||||
(documentation "Re-open log files and flush caches.")
|
||||
(procedure
|
||||
#~(lambda (pid)
|
||||
(if pid
|
||||
(begin
|
||||
(kill pid SIGHUP)
|
||||
(format #t
|
||||
"Issued SIGHUP to Service MPD (PID ~a)."
|
||||
pid))
|
||||
(format #t "Service MPD is not running.")))))))))))
|
||||
|
||||
;; Make /var/run/mpd/USER user-owned as well.
|
||||
(chown (dirname directory)
|
||||
(passwd:uid %user) (passwd:gid %user))))))
|
||||
|
||||
|
||||
(define %mpd-accounts
|
||||
;; Default account and group for MPD.
|
||||
(list (user-group (name "mpd") (system? #t))
|
||||
(user-account
|
||||
(name "mpd")
|
||||
(group "mpd")
|
||||
(system? #t)
|
||||
(comment "Music Player Daemon (MPD) user")
|
||||
|
||||
;; Note: /var/run/mpd hosts one sub-directory per user, of which
|
||||
;; /var/run/mpd/mpd corresponds to the "mpd" user.
|
||||
(home-directory "/var/run/mpd/mpd")
|
||||
|
||||
(shell (file-append shadow "/sbin/nologin")))))
|
||||
(define (mpd-accounts config)
|
||||
(match-record config <mpd-configuration> (user group)
|
||||
(list (user-group
|
||||
(name group)
|
||||
(system? #t))
|
||||
(user-account
|
||||
(name user)
|
||||
(group group)
|
||||
(system? #t)
|
||||
(comment "Music Player Daemon (MPD) user")
|
||||
;; MPD can use $HOME (or $XDG_CONFIG_HOME) to place its data
|
||||
(home-directory "/var/lib/mpd")
|
||||
(shell (file-append shadow "/sbin/nologin"))))))
|
||||
|
||||
(define mpd-service-type
|
||||
(service-type
|
||||
|
@ -237,7 +532,7 @@ (define mpd-service-type
|
|||
(list (service-extension shepherd-root-service-type
|
||||
(compose list mpd-shepherd-service))
|
||||
(service-extension account-service-type
|
||||
(const %mpd-accounts))
|
||||
(service-extension activation-service-type
|
||||
mpd-service-activation)))
|
||||
mpd-accounts)
|
||||
(service-extension rottlog-service-type
|
||||
(compose list mpd-log-rotation))))
|
||||
(default-value (mpd-configuration))))
|
||||
|
|
Loading…
Reference in a new issue