Subject: [bug#74801] [PATCH v2] gnu: home: services: Add home-mpv-service-type.

From: Tomas Volf <[email-masked]>
Date: Wed, 2 Apr 2025 16:05:33 +0200

This commit adds a new service type to generate configuration file for the mpv
media player.

Originally I attempted to use Guix Records (via define-configuration) for
this, but ran into the bug #74748, so I had to switch to procedures instead.
The usage is (hopefully) sufficiently described in the documentation.  When
the bug is resolved, I will update it to use define-configuration instead.

The full list of supported options is documented, however I decided to *not*
document types and purpose for each individual fields.  While I had mostly
working prototype to extract the documentation from mpv, once I realized it
would be few 10k of lines added, I decided it is not worth it.  It would bloat
the .texi file (by more than 50%), be hard to maintain and, in my opinion,
would not provide enough value to justify that.  The current version seems
like sane middle ground.

Option to configure inputs (for mpv) will come later in a separate patch.

* gnu/home/services/mpv.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES): Register it.
* doc/guix.texi (mpv Media Player): Document it.

Change-Id: I2deb44799a28047cb5d67da97dc6007a9df873af
---
Update for 0.39.0.

 doc/guix.texi             |  428 ++++++
 gnu/home/services/mpv.scm | 2732 +++++++++++++++++++++++++++++++++++++
 gnu/local.mk              |    1 +
 3 files changed, 3161 insertions(+)
 create mode 100644 gnu/home/services/mpv.scm

diff --git a/doc/guix.texi b/doc/guix.texi
index 3d91dfd7b1..4019346588 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -49846,6 +49846,434 @@ Media Home Services
 @end table
 @end deftp

+@c This is ugly, but upstream does *not* capitalize the ``m'' even when
+@c at the beginning of a sentence.  So let us follow the branding.
+@node mpv Media Player
+@subsection mpv Media Player
+
+@cindex mpv, Home Service
+@cindex mpv, configuration
+Configuring the @uref{https://mpv.io/, mpv media player} can be somewhat
+daunting task, due to the sheer amount of options available, especially
+if one wants to be able to inherit the configuration in their code.  The
+@code{home-mpv-service-type} is provided to help with that problem.
+When the service is added to your home environment, file based on the
+passed configuration is generated and placed into the correct location.
+
+Due to the bug #74748, it does not use Guix Records to represent the
+configuration, but uses keyword arguments to achieve similar result.
+Example follows:
+
+@lisp
+(service home-mpv-service-type
+         (make-home-mpv-configuration
+          #:global (make-mpv-profile-configuration
+                    #:fullscreen #t
+                    #:alang '("jpn" "eng"))))
+@end lisp
+
+@defvar home-mpv-service-type
+This is the type of the mpv home service, whose value is a
+@code{home-mpv-configuration} object.
+@end defvar
+
+@deffn {Procedure} make-home-mpv-configuration
+Return a new instance of @code{home-mpv-configuration}.  Available
+keyword arguments are:
+
+@table @asis
+@item @code{inherit} (default: @code{#t})
+Inherit fields from an another instance.
+
+@item @code{global} (default: @code{(make-mpv-profile-configuration)})
+The global configuration preceding all profiles.
+
+@item @code{profiles} (default: @code{()})
+An alist containing configuration for any additional profiles to include
+in the configuration file.
+
+@lisp
+(make-home-mpv-configuration
+ #:profiles `((fullscreen . ,(make-mpv-profile-configuration
+                              #:fullscreen #t))))
+@end lisp
+
+@item @code{extra-config} (default: @code{#f})
+Additional content to include in the configuration file.  It is placed
+at the end of the file.
+
+@end table
+@end deffn
+
+@deffn {Procedure} make-mpv-profile-configuration
+Return a new instance of @code{mpv-profile-configuration}.  As above, it
+also supports the @code{#:inherit} argument.  Additionally it supports
+keyword arguments named after the options of @command{mpv}.  Hence
+@option{--fullscreen} (or @code{fullscreen} in the configuration file)
+becomes @code{#:fullscreen}.
+
+Few options are using their aliases instead.  @option{audio} instead of
+@option{aid}, @option{video} instead of @option{vid}, @option{sub}
+instead of @option{sid}, @option{screenshot-directory} instead of
+@option{screenshot-dir} and @option{watch-later-directory} instead of
+@option{watch-later-dir}.
+
+Valid values for the fields depend on their type.
+
+@table @asis
+@item Flags
+The value is evaluated for truthfulness.  Typically you would use
+@code{#f} or @code{#t}.
+
+@item Numerical fields
+Integer and integer64 fields are validated by @code{integer?}, float and
+double fields by @code{real?}.  Ranges are checked when applicable.
+
+@item Aspect
+Same as integer.
+
+@item ByteSize
+Same as integer64.
+
+@item Choice
+The value should be a symbol representing member of the enumeration.  If
+the choice has @samp{or ...} part, it can also be value of that
+alternative type.
+
+@item @var{type} list
+The value should be a list of the @var{type}.
+
+@end table
+
+Other types accept strings, with validation of the values where possible
+(e.g. type @samp{Color} is validated, but type @samp{Audio channels or
+channel map} is not).
+
+The full list of currently supported keyword arguments is below.  For
+the types, allowed values and full description please refer to the
+@command{mpv --list-options} and
+@uref{https://mpv.io/manual/stable/#options, mpv manual}.
+
+Only set fields are outputted to the configuration file.  Accessors are
+provided for every field, returning either their value or a sentinel
+object @code{%unset}.
+
+@code{ab-loop-a}, @code{ab-loop-b}, @code{ab-loop-count},
+@code{access-references}, @code{ad}, @code{ad-lavc-ac3drc},
+@code{ad-lavc-downmix}, @code{ad-lavc-o}, @code{ad-lavc-threads},
+@code{ad-queue-enable}, @code{ad-queue-max-bytes},
+@code{ad-queue-max-samples}, @code{ad-queue-max-secs}, @code{af},
+@code{audio}, @code{alang}, @code{allow-delayed-peak-detect},
+@code{alsa-buffer-time}, @code{alsa-ignore-chmap},
+@code{alsa-mixer-device}, @code{alsa-mixer-index},
+@code{alsa-mixer-name}, @code{alsa-non-interleaved},
+@code{alsa-periods}, @code{alsa-resample}, @code{ao},
+@code{ao-null-broken-delay}, @code{ao-null-broken-eof},
+@code{ao-null-buffer}, @code{ao-null-channel-layouts},
+@code{ao-null-format}, @code{ao-null-latency}, @code{ao-null-outburst},
+@code{ao-null-speed}, @code{ao-null-untimed}, @code{ao-pcm-append},
+@code{ao-pcm-file}, @code{ao-pcm-waveheader},
+@code{audio-backward-batch}, @code{audio-backward-overlap},
+@code{audio-buffer}, @code{audio-channels}, @code{audio-client-name},
+@code{audio-delay}, @code{audio-demuxer}, @code{audio-device},
+@code{audio-display}, @code{audio-exclusive}, @code{audio-exts},
+@code{audio-fallback-to-null}, @code{audio-file-auto},
+@code{audio-file-paths}, @code{audio-files}, @code{audio-format},
+@code{audio-normalize-downmix}, @code{audio-pitch-correction},
+@code{audio-resample-cutoff}, @code{audio-resample-filter-size},
+@code{audio-resample-linear}, @code{audio-resample-max-output-size},
+@code{audio-resample-phase-shift}, @code{audio-reversal-buffer},
+@code{audio-samplerate}, @code{audio-spdif},
+@code{audio-stream-silence}, @code{audio-swresample-o},
+@code{audio-wait-open}, @code{auto-window-resize},
+@code{autocreate-playlist}, @code{autofit}, @code{autofit-larger},
+@code{autofit-smaller}, @code{autoload-files}, @code{autosync},
+@code{background}, @code{background-color}, @code{blend-subtitles},
+@code{bluray-device}, @code{border}, @code{border-background},
+@code{brightness}, @code{cache}, @code{cache-on-disk},
+@code{cache-pause}, @code{cache-pause-initial}, @code{cache-pause-wait},
+@code{cache-secs}, @code{cdda-cdtext}, @code{cdda-device},
+@code{cdda-overlap}, @code{cdda-paranoia}, @code{cdda-sector-size},
+@code{cdda-skip}, @code{cdda-span-a}, @code{cdda-span-b},
+@code{cdda-speed}, @code{cdda-toc-offset},
+@code{chapter-merge-threshold}, @code{chapter-seek-threshold},
+@code{chapters-file}, @code{config}, @code{container-fps-override},
+@code{contrast}, @code{cookies}, @code{cookies-file},
+@code{corner-rounding}, @code{correct-downscaling}, @code{correct-pts},
+@code{cover-art-auto}, @code{cover-art-files},
+@code{cover-art-whitelist}, @code{cscale}, @code{cscale-antiring},
+@code{cscale-blur}, @code{cscale-clamp}, @code{cscale-param1},
+@code{cscale-param2}, @code{cscale-radius}, @code{cscale-taper},
+@code{cscale-window}, @code{cscale-wparam}, @code{cscale-wtaper},
+@code{cursor-autohide}, @code{cursor-autohide-fs-only}, @code{deband},
+@code{deband-grain}, @code{deband-iterations}, @code{deband-range},
+@code{deband-threshold}, @code{deinterlace},
+@code{deinterlace-field-parity}, @code{demuxer},
+@code{demuxer-backward-playback-step}, @code{demuxer-cache-dir},
+@code{demuxer-cache-unlink-files}, @code{demuxer-cache-wait},
+@code{demuxer-donate-buffer}, @code{demuxer-hysteresis-secs},
+@code{demuxer-lavf-allow-mimetype}, @code{demuxer-lavf-analyzeduration},
+@code{demuxer-lavf-buffersize}, @code{demuxer-lavf-format},
+@code{demuxer-lavf-hacks}, @code{demuxer-lavf-linearize-timestamps},
+@code{demuxer-lavf-o}, @code{demuxer-lavf-probe-info},
+@code{demuxer-lavf-probescore}, @code{demuxer-lavf-probesize},
+@code{demuxer-lavf-propagate-opts}, @code{demuxer-max-back-bytes},
+@code{demuxer-max-bytes}, @code{demuxer-mkv-probe-start-time},
+@code{demuxer-mkv-probe-video-duration},
+@code{demuxer-mkv-subtitle-preroll},
+@code{demuxer-mkv-subtitle-preroll-secs},
+@code{demuxer-mkv-subtitle-preroll-secs-index},
+@code{demuxer-rawaudio-channels}, @code{demuxer-rawaudio-format},
+@code{demuxer-rawaudio-rate}, @code{demuxer-rawvideo-codec},
+@code{demuxer-rawvideo-format}, @code{demuxer-rawvideo-fps},
+@code{demuxer-rawvideo-h}, @code{demuxer-rawvideo-mp-format},
+@code{demuxer-rawvideo-size}, @code{demuxer-rawvideo-w},
+@code{demuxer-readahead-secs}, @code{demuxer-seekable-cache},
+@code{demuxer-termination-timeout}, @code{demuxer-thread},
+@code{directory-filter-types}, @code{directory-mode},
+@code{display-fps-override}, @code{display-tags}, @code{dither},
+@code{dither-depth}, @code{dither-size-fruit}, @code{drag-and-drop},
+@code{drm-connector}, @code{drm-device}, @code{drm-draw-plane},
+@code{drm-draw-surface-size}, @code{drm-drmprime-video-plane},
+@code{drm-format}, @code{drm-mode}, @code{drm-vrr-enabled},
+@code{dscale}, @code{dscale-antiring}, @code{dscale-blur},
+@code{dscale-clamp}, @code{dscale-param1}, @code{dscale-param2},
+@code{dscale-radius}, @code{dscale-taper}, @code{dscale-window},
+@code{dscale-wparam}, @code{dscale-wtaper}, @code{dump-stats},
+@code{dvbin-card}, @code{dvbin-channel-switch-offset},
+@code{dvbin-file}, @code{dvbin-full-transponder}, @code{dvbin-prog},
+@code{dvbin-timeout}, @code{dvd-angle}, @code{dvd-device},
+@code{dvd-speed}, @code{edition}, @code{egl-config-id},
+@code{egl-output-format}, @code{embeddedfonts}, @code{end},
+@code{error-diffusion}, @code{external-files}, @code{fbo-format},
+@code{focus-on}, @code{force-media-title}, @code{force-render},
+@code{force-rgba-osd-rendering}, @code{force-seekable},
+@code{force-window}, @code{force-window-position}, @code{framedrop},
+@code{frames}, @code{fs-screen}, @code{fs-screen-name},
+@code{fullscreen}, @code{gamma}, @code{gamma-auto}, @code{gamma-factor},
+@code{gamut-mapping-mode}, @code{gapless-audio}, @code{geometry},
+@code{glsl-shader-opts}, @code{glsl-shaders}, @code{gpu-api},
+@code{gpu-context}, @code{gpu-debug}, @code{gpu-dumb-mode},
+@code{gpu-hwdec-interop}, @code{gpu-shader-cache},
+@code{gpu-shader-cache-dir}, @code{gpu-sw}, @code{gpu-tex-pad-x},
+@code{gpu-tex-pad-y}, @code{hdr-compute-peak},
+@code{hdr-contrast-recovery}, @code{hdr-contrast-smoothness},
+@code{hdr-peak-decay-rate}, @code{hdr-peak-percentile},
+@code{hdr-scene-threshold-high}, @code{hdr-scene-threshold-low},
+@code{hidpi-window-scale}, @code{hls-bitrate}, @code{hr-seek},
+@code{hr-seek-demuxer-offset}, @code{hr-seek-framedrop},
+@code{http-header-fields}, @code{http-proxy}, @code{hue}, @code{hwdec},
+@code{hwdec-codecs}, @code{hwdec-extra-frames},
+@code{hwdec-image-format}, @code{icc-3dlut-size}, @code{icc-cache},
+@code{icc-cache-dir}, @code{icc-force-contrast}, @code{icc-intent},
+@code{icc-profile}, @code{icc-profile-auto}, @code{icc-use-luma},
+@code{idle}, @code{ignore-path-in-watch-later-config},
+@code{image-display-duration}, @code{image-exts}, @code{image-lut},
+@code{image-lut-type}, @code{image-subs-video-resolution},
+@code{include}, @code{index}, @code{initial-audio-sync},
+@code{input-ar-delay}, @code{input-ar-rate},
+@code{input-builtin-bindings}, @code{input-builtin-dragging},
+@code{input-commands}, @code{input-conf}, @code{input-cursor},
+@code{input-cursor-passthrough}, @code{input-default-bindings},
+@code{input-doubleclick-time}, @code{input-dragging-deadzone},
+@code{input-ipc-client}, @code{input-ipc-server},
+@code{input-key-fifo-size}, @code{input-media-keys},
+@code{input-preprocess-wheel}, @code{input-right-alt-gr},
+@code{input-terminal}, @code{input-test},
+@code{input-touch-emulate-mouse}, @code{input-vo-keyboard},
+@code{interpolation}, @code{interpolation-preserve},
+@code{interpolation-threshold}, @code{inverse-tone-mapping},
+@code{jack-autostart}, @code{jack-connect}, @code{jack-name},
+@code{jack-port}, @code{jack-std-channel-layout}, @code{keep-open},
+@code{keep-open-pause}, @code{keepaspect}, @code{keepaspect-window},
+@code{lavfi-complex}, @code{length}, @code{libplacebo-opts},
+@code{linear-downscaling}, @code{linear-upscaling},
+@code{load-auto-profiles}, @code{load-osd-console}, @code{load-scripts},
+@code{load-select}, @code{load-stats-overlay},
+@code{load-unsafe-playlists}, @code{log-file}, @code{loop-file},
+@code{loop-playlist}, @code{lut}, @code{lut-type}, @code{mc},
+@code{media-controls}, @code{merge-files}, @code{metadata-codepage},
+@code{mf-fps}, @code{mf-type}, @code{monitoraspect},
+@code{monitorpixelaspect}, @code{msg-color}, @code{msg-level},
+@code{msg-module}, @code{msg-time}, @code{mute}, @code{native-fs},
+@code{native-keyrepeat}, @code{native-touch}, @code{network-timeout},
+@code{oac}, @code{oacopts}, @code{ocopy-metadata}, @code{of},
+@code{ofopts}, @code{on-all-workspaces}, @code{ontop},
+@code{ontop-level}, @code{opengl-check-pattern-a},
+@code{opengl-check-pattern-b}, @code{opengl-early-flush},
+@code{opengl-es}, @code{opengl-glfinish}, @code{opengl-pbo},
+@code{opengl-rectangle-textures}, @code{opengl-swapinterval},
+@code{opengl-waitvsync}, @code{orawts}, @code{ordered-chapters},
+@code{ordered-chapters-files}, @code{oremove-metadata}, @code{osc},
+@code{osd-align-x}, @code{osd-align-y}, @code{osd-back-color},
+@code{osd-bar}, @code{osd-bar-align-x}, @code{osd-bar-align-y},
+@code{osd-bar-h}, @code{osd-bar-outline-size}, @code{osd-bar-w},
+@code{osd-blur}, @code{osd-bold}, @code{osd-border-style},
+@code{osd-color}, @code{osd-duration}, @code{osd-font},
+@code{osd-font-provider}, @code{osd-font-size}, @code{osd-fonts-dir},
+@code{osd-fractions}, @code{osd-italic}, @code{osd-justify},
+@code{osd-level}, @code{osd-margin-x}, @code{osd-margin-y},
+@code{osd-msg1}, @code{osd-msg2}, @code{osd-msg3}, @code{osd-on-seek},
+@code{osd-outline-color}, @code{osd-outline-size},
+@code{osd-playing-msg}, @code{osd-playing-msg-duration},
+@code{osd-playlist-entry}, @code{osd-scale}, @code{osd-scale-by-window},
+@code{osd-shadow-offset}, @code{osd-spacing}, @code{osd-status-msg},
+@code{oset-metadata}, @code{ovc}, @code{ovcopts}, @code{panscan},
+@code{pause}, @code{pipewire-buffer}, @code{pipewire-remote},
+@code{pipewire-volume-mode}, @code{pitch}, @code{play-direction},
+@code{player-operation-mode}, @code{playlist-start},
+@code{prefetch-playlist}, @code{profile}, @code{pulse-allow-suspended},
+@code{pulse-buffer}, @code{pulse-host}, @code{pulse-latency-hacks},
+@code{quiet}, @code{really-quiet}, @code{rebase-start-time},
+@code{referrer}, @code{replaygain}, @code{replaygain-clip},
+@code{replaygain-fallback}, @code{replaygain-preamp},
+@code{reset-on-next-file}, @code{resume-playback},
+@code{resume-playback-check-mtime}, @code{rtsp-transport},
+@code{saturation}, @code{save-position-on-quit}, @code{scale},
+@code{scale-antiring}, @code{scale-blur}, @code{scale-clamp},
+@code{scale-param1}, @code{scale-param2}, @code{scale-radius},
+@code{scale-taper}, @code{scale-window}, @code{scale-wparam},
+@code{scale-wtaper}, @code{scaler-resizes-only}, @code{screen},
+@code{screen-name}, @code{screenshot-avif-encoder},
+@code{screenshot-avif-opts}, @code{screenshot-avif-pixfmt},
+@code{screenshot-directory}, @code{screenshot-format},
+@code{screenshot-high-bit-depth}, @code{screenshot-jpeg-quality},
+@code{screenshot-jpeg-source-chroma}, @code{screenshot-jxl-distance},
+@code{screenshot-jxl-effort}, @code{screenshot-png-compression},
+@code{screenshot-png-filter}, @code{screenshot-sw},
+@code{screenshot-tag-colorspace}, @code{screenshot-template},
+@code{screenshot-webp-compression}, @code{screenshot-webp-lossless},
+@code{screenshot-webp-quality}, @code{script-opts}, @code{scripts},
+@code{secondary-sid}, @code{secondary-sub-ass-override},
+@code{secondary-sub-delay}, @code{secondary-sub-pos},
+@code{secondary-sub-visibility}, @code{sharpen}, @code{show-in-taskbar},
+@code{shuffle}, @code{sub}, @code{sigmoid-center}, @code{sigmoid-slope},
+@code{sigmoid-upscaling}, @code{slang}, @code{snap-window},
+@code{speed}, @code{spirv-compiler}, @code{sstep}, @code{start},
+@code{stop-playback-on-init-failure}, @code{stop-screensaver},
+@code{stream-buffer-size}, @code{stream-dump}, @code{stream-lavf-o},
+@code{stream-record}, @code{stretch-dvd-subs},
+@code{stretch-image-subs-to-screen}, @code{sub-align-x},
+@code{sub-align-y}, @code{sub-ass}, @code{sub-ass-force-margins},
+@code{sub-ass-hinting}, @code{sub-ass-justify},
+@code{sub-ass-line-spacing}, @code{sub-ass-override},
+@code{sub-ass-scale-with-window}, @code{sub-ass-shaper},
+@code{sub-ass-style-overrides}, @code{sub-ass-styles},
+@code{sub-ass-use-video-data}, @code{sub-ass-video-aspect-override},
+@code{sub-ass-vsfilter-color-compat}, @code{sub-auto},
+@code{sub-auto-exts}, @code{sub-back-color}, @code{sub-blur},
+@code{sub-bold}, @code{sub-border-style}, @code{sub-clear-on-seek},
+@code{sub-codepage}, @code{sub-color}, @code{sub-create-cc-track},
+@code{sub-delay}, @code{sub-demuxer}, @code{sub-file-paths},
+@code{sub-files}, @code{sub-filter-jsre}, @code{sub-filter-regex},
+@code{sub-filter-regex-enable}, @code{sub-filter-regex-plain},
+@code{sub-filter-regex-warn}, @code{sub-filter-sdh},
+@code{sub-filter-sdh-enclosures}, @code{sub-filter-sdh-harder},
+@code{sub-fix-timing}, @code{sub-font}, @code{sub-font-provider},
+@code{sub-font-size}, @code{sub-fonts-dir},
+@code{sub-forced-events-only}, @code{sub-fps}, @code{sub-gauss},
+@code{sub-gray}, @code{sub-italic}, @code{sub-justify},
+@code{sub-lavc-o}, @code{sub-margin-x}, @code{sub-margin-y},
+@code{sub-outline-color}, @code{sub-outline-size},
+@code{sub-past-video-end}, @code{sub-pos}, @code{sub-scale},
+@code{sub-scale-by-window}, @code{sub-scale-with-window},
+@code{sub-shadow-offset}, @code{sub-spacing}, @code{sub-speed},
+@code{sub-stretch-durations}, @code{sub-use-margins},
+@code{sub-visibility}, @code{sub-vsfilter-bidi-compat},
+@code{subs-fallback}, @code{subs-fallback-forced},
+@code{subs-match-os-language}, @code{subs-with-matching-audio},
+@code{swapchain-depth}, @code{sws-allow-zimg}, @code{sws-bitexact},
+@code{sws-cgb}, @code{sws-chs}, @code{sws-cs}, @code{sws-cvs},
+@code{sws-fast}, @code{sws-lgb}, @code{sws-ls}, @code{sws-scaler},
+@code{target-colorspace-hint}, @code{target-contrast},
+@code{target-gamut}, @code{target-lut}, @code{target-peak},
+@code{target-prim}, @code{target-trc}, @code{taskbar-progress},
+@code{teletext-page}, @code{temporal-dither},
+@code{temporal-dither-period}, @code{term-osd}, @code{term-osd-bar},
+@code{term-osd-bar-chars}, @code{term-playing-msg},
+@code{term-status-msg}, @code{term-title}, @code{terminal},
+@code{title}, @code{title-bar}, @code{tls-ca-file},
+@code{tls-cert-file}, @code{tls-key-file}, @code{tls-verify},
+@code{tone-mapping}, @code{tone-mapping-max-boost},
+@code{tone-mapping-param}, @code{tone-mapping-visualize},
+@code{track-auto-selection}, @code{tscale}, @code{tscale-antiring},
+@code{tscale-blur}, @code{tscale-clamp}, @code{tscale-param1},
+@code{tscale-param2}, @code{tscale-radius}, @code{tscale-taper},
+@code{tscale-window}, @code{tscale-wparam}, @code{tscale-wtaper},
+@code{untimed}, @code{use-embedded-icc-profile},
+@code{use-filedir-conf}, @code{user-agent}, @code{vaapi-device},
+@code{vd}, @code{vd-apply-cropping}, @code{vd-lavc-assume-old-x264},
+@code{vd-lavc-bitexact}, @code{vd-lavc-check-hw-profile},
+@code{vd-lavc-dr}, @code{vd-lavc-fast}, @code{vd-lavc-film-grain},
+@code{vd-lavc-framedrop}, @code{vd-lavc-o}, @code{vd-lavc-show-all},
+@code{vd-lavc-skipframe}, @code{vd-lavc-skipidct},
+@code{vd-lavc-skiploopfilter}, @code{vd-lavc-software-fallback},
+@code{vd-lavc-threads}, @code{vd-queue-enable},
+@code{vd-queue-max-bytes}, @code{vd-queue-max-samples},
+@code{vd-queue-max-secs}, @code{vf}, @code{video}, @code{video-align-x},
+@code{video-align-y}, @code{video-aspect-method},
+@code{video-aspect-override}, @code{video-backward-batch},
+@code{video-backward-overlap}, @code{video-crop}, @code{video-exts},
+@code{video-latency-hacks}, @code{video-margin-ratio-bottom},
+@code{video-margin-ratio-left}, @code{video-margin-ratio-right},
+@code{video-margin-ratio-top}, @code{video-osd},
+@code{video-output-levels}, @code{video-pan-x}, @code{video-pan-y},
+@code{video-reversal-buffer}, @code{video-rotate}, @code{video-scale-x},
+@code{video-scale-y}, @code{video-sync},
+@code{video-sync-max-audio-change}, @code{video-sync-max-factor},
+@code{video-sync-max-video-change}, @code{video-timing-offset},
+@code{video-unscaled}, @code{video-zoom}, @code{vlang}, @code{vo},
+@code{vo-image-avif-encoder}, @code{vo-image-avif-opts},
+@code{vo-image-avif-pixfmt}, @code{vo-image-format},
+@code{vo-image-high-bit-depth}, @code{vo-image-jpeg-quality},
+@code{vo-image-jpeg-source-chroma}, @code{vo-image-jxl-distance},
+@code{vo-image-jxl-effort}, @code{vo-image-outdir},
+@code{vo-image-png-compression}, @code{vo-image-png-filter},
+@code{vo-image-tag-colorspace}, @code{vo-image-webp-compression},
+@code{vo-image-webp-lossless}, @code{vo-image-webp-quality},
+@code{vo-kitty-alt-screen}, @code{vo-kitty-cols},
+@code{vo-kitty-config-clear}, @code{vo-kitty-height},
+@code{vo-kitty-left}, @code{vo-kitty-rows}, @code{vo-kitty-top},
+@code{vo-kitty-use-shm}, @code{vo-kitty-width}, @code{vo-null-fps},
+@code{vo-sixel-alt-screen}, @code{vo-sixel-buffered},
+@code{vo-sixel-cols}, @code{vo-sixel-config-clear},
+@code{vo-sixel-dither}, @code{vo-sixel-fixedpalette},
+@code{vo-sixel-height}, @code{vo-sixel-left}, @code{vo-sixel-pad-x},
+@code{vo-sixel-pad-y}, @code{vo-sixel-reqcolors}, @code{vo-sixel-rows},
+@code{vo-sixel-threshold}, @code{vo-sixel-top}, @code{vo-sixel-width},
+@code{vo-tct-256}, @code{vo-tct-algo}, @code{vo-tct-buffering},
+@code{vo-tct-height}, @code{vo-tct-width}, @code{vo-vaapi-scaled-osd},
+@code{vo-vaapi-scaling}, @code{vo-vdpau-chroma-deint},
+@code{vo-vdpau-colorkey}, @code{vo-vdpau-composite-detect},
+@code{vo-vdpau-denoise}, @code{vo-vdpau-force-yuv}, @code{vo-vdpau-fps},
+@code{vo-vdpau-hqscaling}, @code{vo-vdpau-output-surfaces},
+@code{vo-vdpau-pullup}, @code{vo-vdpau-queuetime-fs},
+@code{vo-vdpau-queuetime-windowed}, @code{vo-vdpau-sharpen},
+@code{volume}, @code{volume-gain}, @code{volume-gain-max},
+@code{volume-gain-min}, @code{volume-max}, @code{vulkan-async-compute},
+@code{vulkan-async-transfer}, @code{vulkan-device},
+@code{vulkan-display-display}, @code{vulkan-display-mode},
+@code{vulkan-display-plane}, @code{vulkan-queue-count},
+@code{vulkan-swap-mode}, @code{watch-later-directory},
+@code{watch-later-options}, @code{wayland-app-id},
+@code{wayland-configure-bounds}, @code{wayland-content-type},
+@code{wayland-disable-vsync}, @code{wayland-edge-pixels-pointer},
+@code{wayland-edge-pixels-touch}, @code{wayland-present}, @code{wid},
+@code{window-dragging}, @code{window-maximized},
+@code{window-minimized}, @code{window-scale},
+@code{write-filename-in-watch-later-config},
+@code{x11-bypass-compositor}, @code{x11-name}, @code{x11-netwm},
+@code{x11-present}, @code{x11-wid-title}, @code{xv-adaptor},
+@code{xv-buffers}, @code{xv-ck}, @code{xv-ck-method},
+@code{xv-colorkey}, @code{xv-port}, @code{ytdl}, @code{ytdl-format},
+@code{ytdl-raw-options}, @code{zimg-dither}, @code{zimg-fast},
+@code{zimg-scaler}, @code{zimg-scaler-chroma},
+@code{zimg-scaler-chroma-param-a}, @code{zimg-scaler-chroma-param-b},
+@code{zimg-scaler-param-a}, @code{zimg-scaler-param-b}, and
+@code{zimg-threads}.
+
+@end deffn
+
 @node Sway window manager
 @subsection Sway window manager

diff --git a/gnu/home/services/mpv.scm b/gnu/home/services/mpv.scm
new file mode 100644
index 0000000000..e2fa44162a
--- /dev/null
+++ b/gnu/home/services/mpv.scm
@@ -0,0 +1,2732 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2024 Tomas Volf <[email-masked]>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu home services mpv)
+  #:use-module (gnu home services)
+  #:use-module (guix gexp)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 regex)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-2)
+  #:use-module (srfi srfi-9)
+  #:use-module (srfi srfi-26)
+  #:use-module (srfi srfi-71)
+  #:export (make-home-mpv-configuration
+            home-mpv-configuration?
+            home-mpv-configuration-global
+            home-mpv-configuration-profiles
+            home-mpv-configuration-extra-config
+            home-mpv-configuration-source-location
+
+            serialize-home-mpv-configuration
+
+            %unset
+
+            make-mpv-profile-configuration
+            mpv-profile-configuration?
+            ;; Field accessor procedures are exported by a syntax form when
+            ;; they are defined, so they are not listed here.
+
+            home-mpv-service-type))
+
+(define %unset '(*unset*))
+
+
+;;;
+;;; Basic types.
+;;;
+(define (serialize-type/boolean field-name value)
+  #~(string-append #$(symbol->string field-name)
+                   "="
+                   #$(if value "yes" "no")
+                   "\n"))
+(define type/boolean?
+  (const #t))
+
+(define (serialize-type/integer field-name value)
+  #~(string-append #$(symbol->string field-name)
+                   "="
+                   #$(number->string value)
+                   "\n"))
+(define (type/integer? n)
+  ;; We assume integer is a signed 32bit number.
+  (and-let* (((integer? n))
+             ((>= n -2147483648))
+             ((<= n  2147483647)))))
+
+(define (serialize-type/integer64 field-name value)
+  #~(string-append #$(symbol->string field-name)
+                   "="
+                   #$(number->string value)
+                   "\n"))
+(define (type/integer64? n)
+  ;; We assume integer is a signed 64bit number.
+  (and-let* (((integer? n))
+             ((>= n -9223372036854775808))
+             ((<= n  9223372036854775807)))))
+
+(define (serialize-type/string field-name value)
+  #~(string-append #$(symbol->string field-name)
+                   "="
+                   #$value
+                   "\n"))
+(define type/string?
+  string?)
+
+(define (serialize-type/float field-name value)
+  #~(string-append #$(symbol->string field-name)
+                   "="
+                   #$(number->string (exact->inexact value))
+                   "\n"))
+(define type/float?
+  ;; I am not sure how to validate floats.
+  real?)
+
+(define (serialize-type/double field-name value)
+  #~(string-append #$(symbol->string field-name)
+                   "="
+                   #$(number->string (exact->inexact value))
+                   "\n"))
+(define (type/double? value)
+  ;; I am not sure how to validate doubles.
+  real?)
+
+
+
+
+;;;
+;;; Additional types (possible based on the basic ones).
+;;;
+
+;;; Aspect seems to be treated as an integer, so define it in terms of it.
+(define serialize-type/aspect serialize-type/integer)
+(define type/aspect? type/integer?)
+
+;;; `Audio channels or channel map' seems to be basically a free form string
+;;; with no way to validate.
+(define serialize-type/audio-channels-or-channel-map serialize-type/string)
+(define type/audio-channels-or-channel-map? type/string?)
+
+;;; Does not seem possible to validate.
+(define serialize-type/audio-format serialize-type/string)
+(define type/audio-format? type/string?)
+
+;;; While most options list 4.6116860184274e+18 as a maximum value, we will
+;;; use integer64 here.  That should be enough for everyone for few more
+;;; years.
+(define serialize-type/byte-size serialize-type/integer64)
+(define type/byte-size? type/integer64?)
+
+(define (serialize-type/color field-name value)
+  #~(string-append #$(symbol->string field-name)
+                   "="
+                   #$(if (list? value)
+                         (string-join (map number->string value) "/")
+                         value)
+                   "\n"))
+(define (type/color? value)
+  (define (ok-num? n)
+    (and (number? n)
+         (>= n 0)
+         (<= n 1)))
+  (if (list? value)
+      ;; Either a list of 3(4) numbers encoding RGB(A) on range from 0 to 1...
+      (match value
+        (((? ok-num? r) (? ok-num? g) (? ok-num? b))
+         #t)
+        (((? ok-num? r) (? ok-num? g) (? ok-num? b) (? ok-num? alpha))
+         #t)
+        (_
+         #f))
+      ;; ... or RGB(A) hex encoding.
+      (string-match "^#([A-Fa-f0-9]{2})?[A-Fa-f0-9]{6}$" value)))
+
+;;; I do not see value mirroring fourcc.org's database here.  It is further
+;;; complicated by arbitrary hex being accepted as well.  So string it is.
+(define serialize-type/fourcc serialize-type/string)
+(define type/fourcc? type/string?)
+
+;;; No way to validate.
+(define serialize-type/image-format serialize-type/string)
+(define type/image-format? type/string?)
+
+;;; Looking at the documentation for --start, there is no way to make this
+;;; bullet-proof, especially since even chapter numbers are accepted.
+(define serialize-type/relative-time-or-percent-position serialize-type/string)
+(define type/relative-time-or-percent-position? type/string?)
+
+(define serialize-type/time serialize-type/string)
+(define type/time? type/string?)
+
+(define serialize-type/video-rectangle serialize-type/string)
+(define (type/video-rectangle? value)
+  (or (string-match "-?[0-9]+%?:-?[0-9]+%?" value)
+      (string-match
+       "^(-?[0-9]+%?(x-?[0-9]+%?)?)?([+-]-?[0-9]+%?[+-]-?[0-9]+%?)?$"
+       value)))
+
+(define serialize-type/window-geometry serialize-type/string)
+(define (type/window-geometry? value)
+  (or (string-match "-?[0-9]+%?:-?[0-9]+%?" value)
+      (string-match
+       "^(-?[0-9]+%?(x-?[0-9]+%?)?)?([+-]-?[0-9]+%?[+-]-?[0-9]+%?)?(/[0-9]+)?$"
+       value)))
+
+(define serialize-type/window-size serialize-type/string)
+(define (type/window-size? value)
+  (string-match "^([0-9]+%?(x[0-9]+%?)?)?$" value))
+
+(define (serialize-type/enumeration field-name value)
+  #~(string-append #$(symbol->string field-name)
+                   "="
+                   ;; This could be either symbol or (in case of enumerations
+                   ;; with alternate type) anything.  So just use `format'.
+                   #$(format #f "~s" value)
+                   "\n"))
+(define (type/enumeration? value)
+  ;; There is no general way to check enumerations.  The field always has to
+  ;; define custom sanitizer.
+  #t)
+
+
+
+
+;;;
+;;; List types.
+;;;
+(define (serialize-type/list-of-string field-name lst)
+  #~(string-append #$(symbol->string field-name)
+                   "="
+                   #$(string-join lst ",")
+                   "\n"))
+(define (type/list-of-string? lst)
+  (every type/string? lst))
+
+(define (serialize-type/list-of-key-value field-name lst)
+  #~(string-append #$(symbol->string field-name)
+                   "="
+                   #$(string-join (map (match-lambda
+                                         ((k . v) (format #f "~a=~a" k v)))
+                                       lst)
+                                  ",")
+                   "\n"))
+(define (type/list-of-key-value? lst)
+  (every (match-lambda
+           (((? string?) . (? string?)) #t)
+           (_ #f))
+         lst))
+
+(define serialize-type/list-of-object-setting serialize-type/list-of-string)
+(define type/list-of-object-setting? type/list-of-string?)
+
+(define serialize-type/list-of-output-verbosity serialize-type/list-of-key-value)
+(define type/list-of-output-verbosity? type/list-of-key-value?)
+
+
+
+
+;;;
+;;; Actual configuration record.  Contains a lot of generated code.
+;;;
+
+(define-record-type <profile-option>
+  (make-profile-option name type-check serializer)
+  profile-option?
+  (name       profile-option-name)
+  (type-check profile-option-type-check)
+  (serializer profile-option-serializer))
+
+(define %opts (make-hash-table))
+
+(define-syntax define-opt
+  (lambda (x)
+    (syntax-case x ()
+      ((_ name type extra-checks ...)
+       (let* ((d/n (syntax->datum #'name))
+              (d/t (syntax->datum #'type))
+              (d/accessor (string->symbol
+                           (format #f "mpv-profile-configuration-~a" d/n)))
+              (d/type-check (string->symbol
+                             (format #f "type/~a?" d/t)))
+              (d/serializer (string->symbol
+                             (format #f "serialize-type/~a" d/t))))
+         (with-syntax
+             ((kw (datum->syntax x (symbol->keyword d/n)))
+              (accessor (datum->syntax x d/accessor))
+              (type-check (datum->syntax x d/type-check))
+              (serializer (datum->syntax x d/serializer))
+              (val (datum->syntax x 'val)))
+           #'(begin
+               (hashq-set! %opts 'name
+                           (make-profile-option (symbol->string 'name)
+                                                (lambda (val)
+                                                  (and (type-check val)
+                                                       extra-checks ...))
+                                                serializer))
+               (define-public (accessor cfg)
+                 (let ((x (hashq-ref (%mpv-profile-configuration-data cfg)
+                                     'name
+                                     %unset)))
+                   (if (eq? x %unset)
+                       %unset
+                       (car x)))))))))))
+
+;;; Generated code - START.
+(define-opt ab-loop-a time)
+(define-opt ab-loop-b time)
+(define-opt
+  ab-loop-count
+  enumeration
+  (or (memq val '(inf))
+      (and (integer? val)
+           (>= val 0)
+           (<= val 2147483647))))
+(define-opt access-references boolean)
+(define-opt ad string)
+(define-opt
+  ad-lavc-ac3drc
+  float
+  (>= val 0)
+  (<= val 6))
+(define-opt ad-lavc-downmix boolean)
+(define-opt ad-lavc-o list-of-key-value)
+(define-opt
+  ad-lavc-threads
+  integer
+  (>= val 0)
+  (<= val 16))
+(define-opt ad-queue-enable boolean)
+(define-opt
+  ad-queue-max-bytes
+  byte-size
+  (>= val 0)
+  (<= val 4.6116860184274e18))
+(define-opt
+  ad-queue-max-samples
+  integer64
+  (>= val 0))
+(define-opt ad-queue-max-secs double (>= val 0))
+(define-opt af list-of-object-setting)
+(define-opt
+  audio
+  enumeration
+  (or (memq val '(no auto))
+      (and (integer? val) (>= val 0) (<= val 8190))))
+(define-opt alang list-of-string)
+(define-opt allow-delayed-peak-detect boolean)
+(define-opt
+  alsa-buffer-time
+  integer
+  (>= val 0)
+  (<= val 2147483647))
+(define-opt alsa-ignore-chmap boolean)
+(define-opt alsa-mixer-device string)
+(define-opt
+  alsa-mixer-index
+  integer
+  (>= val 0)
+  (<= val 99))
+(define-opt alsa-mixer-name string)
+(define-opt alsa-non-interleaved boolean)
+(define-opt
+  alsa-periods
+  integer
+  (>= val 0)
+  (<= val 2147483647))
+(define-opt alsa-resample boolean)
+(define-opt ao list-of-object-setting)
+(define-opt ao-null-broken-delay boolean)
+(define-opt ao-null-broken-eof boolean)
+(define-opt
+  ao-null-buffer
+  float
+  (>= val 0)
+  (<= val 100))
+(define-opt
+  ao-null-channel-layouts
+  audio-channels-or-channel-map)
+(define-opt ao-null-format audio-format)
+(define-opt
+  ao-null-latency
+  float
+  (>= val 0)
+  (<= val 100))
+(define-opt
+  ao-null-outburst
+  integer
+  (>= val 1)
+  (<= val 100000))
+(define-opt
+  ao-null-speed
+  float
+  (>= val 0)
+  (<= val 10000))
+(define-opt ao-null-untimed boolean)
+(define-opt ao-pcm-append boolean)
+(define-opt ao-pcm-file string)
+(define-opt ao-pcm-waveheader boolean)
+(define-opt
+  audio-backward-batch
+  integer
+  (>= val 0)
+  (<= val 1024))
+(define-opt
+  audio-backward-overlap
+  enumeration
+  (or (memq val '(auto))
+      (and (integer? val) (>= val 0) (<= val 1024))))
+(define-opt
+  audio-buffer
+  double
+  (>= val 0)
+  (<= val 10))
+(define-opt
+  audio-channels
+  audio-channels-or-channel-map)
+(define-opt audio-client-name string)
+(define-opt audio-delay float)
+(define-opt audio-demuxer string)
+(define-opt audio-device string)
+(define-opt
+  audio-display
+  enumeration
+  (memq val '(no embedded-first external-first)))
+(define-opt audio-exclusive boolean)
+(define-opt audio-exts list-of-string)
+(define-opt audio-fallback-to-null boolean)
+(define-opt
+  audio-file-auto
+  enumeration
+  (memq val '(no exact fuzzy all)))
+(define-opt audio-file-paths list-of-string)
+(define-opt audio-files list-of-string)
+(define-opt audio-format audio-format)
+(define-opt audio-normalize-downmix boolean)
+(define-opt audio-pitch-correction boolean)
+(define-opt
+  audio-resample-cutoff
+  double
+  (>= val 0)
+  (<= val 1))
+(define-opt
+  audio-resample-filter-size
+  integer
+  (>= val 0)
+  (<= val 32))
+(define-opt audio-resample-linear boolean)
+(define-opt
+  audio-resample-max-output-size
+  double)
+(define-opt
+  audio-resample-phase-shift
+  integer
+  (>= val 0)
+  (<= val 30))
+(define-opt
+  audio-reversal-buffer
+  byte-size
+  (>= val 0)
+  (<= val 4.6116860184274e18))
+(define-opt
+  audio-samplerate
+  integer
+  (>= val 0)
+  (<= val 768000))
+(define-opt audio-spdif string)
+(define-opt audio-stream-silence boolean)
+(define-opt audio-swresample-o list-of-key-value)
+(define-opt
+  audio-wait-open
+  float
+  (>= val 0)
+  (<= val 60))
+(define-opt auto-window-resize boolean)
+(define-opt
+  autocreate-playlist
+  enumeration
+  (memq val '(no filter same)))
+(define-opt autofit window-size)
+(define-opt autofit-larger window-size)
+(define-opt autofit-smaller window-size)
+(define-opt autoload-files boolean)
+(define-opt
+  autosync
+  enumeration
+  (or (memq val '(no))
+      (and (integer? val) (>= val 0) (<= val 10000))))
+(define-opt
+  background
+  enumeration
+  (memq val '(none color tiles)))
+(define-opt background-color color)
+(define-opt
+  blend-subtitles
+  enumeration
+  (memq val '(no yes video)))
+(define-opt bluray-device string)
+(define-opt border boolean)
+(define-opt
+  border-background
+  enumeration
+  (memq val '(none color tiles)))
+(define-opt
+  brightness
+  float
+  (>= val -100)
+  (<= val 100))
+(define-opt
+  cache
+  enumeration
+  (memq val '(no auto yes)))
+(define-opt cache-on-disk boolean)
+(define-opt cache-pause boolean)
+(define-opt cache-pause-initial boolean)
+(define-opt cache-pause-wait float (>= val 0))
+(define-opt cache-secs double (>= val 0))
+(define-opt cdda-cdtext boolean)
+(define-opt cdda-device string)
+(define-opt
+  cdda-overlap
+  integer
+  (>= val 0)
+  (<= val 75))
+(define-opt
+  cdda-paranoia
+  integer
+  (>= val 0)
+  (<= val 2))
+(define-opt
+  cdda-sector-size
+  integer
+  (>= val 1)
+  (<= val 100))
+(define-opt cdda-skip boolean)
+(define-opt cdda-span-a integer)
+(define-opt cdda-span-b integer)
+(define-opt
+  cdda-speed
+  integer
+  (>= val 1)
+  (<= val 100))
+(define-opt cdda-toc-offset integer)
+(define-opt
+  chapter-merge-threshold
+  integer
+  (>= val 0)
+  (<= val 10000))
+(define-opt chapter-seek-threshold double)
+(define-opt chapters-file string)
+(define-opt config boolean)
+(define-opt
+  container-fps-override
+  double
+  (>= val 0))
+(define-opt
+  contrast
+  float
+  (>= val -100)
+  (<= val 100))
+(define-opt cookies boolean)
+(define-opt cookies-file string)
+(define-opt
+  corner-rounding
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt correct-downscaling boolean)
+(define-opt correct-pts boolean)
+(define-opt
+  cover-art-auto
+  enumeration
+  (memq val '(no exact fuzzy all)))
+(define-opt cover-art-files list-of-string)
+(define-opt cover-art-whitelist list-of-string)
+(define-opt
+  cscale
+  enumeration
+  (memq val
+        '(bilinear
+          bicubic_fast
+          oversample
+          spline16
+          spline36
+          spline64
+          sinc
+          lanczos
+          ginseng
+          bicubic
+          hermite
+          catmull_rom
+          mitchell
+          robidoux
+          robidouxsharp
+          box
+          nearest
+          triangle
+          gaussian
+          jinc
+          ewa_lanczos
+          ewa_hanning
+          ewa_ginseng
+          ewa_lanczossharp
+          ewa_lanczos4sharpest
+          ewa_lanczossoft
+          haasnsoft
+          ewa_robidoux
+          ewa_robidouxsharp
+          bartlett
+          cosine
+          hanning
+          tukey
+          hamming
+          quadric
+          welch
+          kaiser
+          blackman
+          sphinx)))
+(define-opt
+  cscale-antiring
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt cscale-blur float)
+(define-opt
+  cscale-clamp
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt cscale-param1 float)
+(define-opt cscale-param2 float)
+(define-opt
+  cscale-radius
+  float
+  (>= val 0.5)
+  (<= val 16))
+(define-opt
+  cscale-taper
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt
+  cscale-window
+  enumeration
+  (memq val
+        '(bartlett
+          cosine
+          hanning
+          tukey
+          hamming
+          quadric
+          welch
+          kaiser
+          blackman
+          sphinx
+          jinc)))
+(define-opt cscale-wparam float)
+(define-opt
+  cscale-wtaper
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt
+  cursor-autohide
+  enumeration
+  (or (memq val '(no always))
+      (and (integer? val) (>= val 0) (<= val 30000))))
+(define-opt cursor-autohide-fs-only boolean)
+(define-opt deband boolean)
+(define-opt
+  deband-grain
+  float
+  (>= val 0)
+  (<= val 4096))
+(define-opt
+  deband-iterations
+  integer
+  (>= val 0)
+  (<= val 16))
+(define-opt
+  deband-range
+  float
+  (>= val 1)
+  (<= val 64))
+(define-opt
+  deband-threshold
+  float
+  (>= val 0)
+  (<= val 4096))
+(define-opt
+  deinterlace
+  enumeration
+  (memq val '(no yes auto)))
+(define-opt
+  deinterlace-field-parity
+  enumeration
+  (memq val '(tff bff auto)))
+(define-opt demuxer string)
+(define-opt
+  demuxer-backward-playback-step
+  double
+  (>= val 0))
+(define-opt demuxer-cache-dir string)
+(define-opt
+  demuxer-cache-unlink-files
+  enumeration
+  (memq val '(immediate whendone no)))
+(define-opt demuxer-cache-wait boolean)
+(define-opt demuxer-donate-buffer boolean)
+(define-opt
+  demuxer-hysteresis-secs
+  double
+  (>= val 0))
+(define-opt demuxer-lavf-allow-mimetype boolean)
+(define-opt
+  demuxer-lavf-analyzeduration
+  float
+  (>= val 0)
+  (<= val 3600))
+(define-opt
+  demuxer-lavf-buffersize
+  integer
+  (>= val 1)
+  (<= val 10485760))
+(define-opt demuxer-lavf-format string)
+(define-opt demuxer-lavf-hacks boolean)
+(define-opt
+  demuxer-lavf-linearize-timestamps
+  enumeration
+  (memq val '(no auto yes)))
+(define-opt demuxer-lavf-o list-of-key-value)
+(define-opt
+  demuxer-lavf-probe-info
+  enumeration
+  (memq val '(no yes auto nostreams)))
+(define-opt
+  demuxer-lavf-probescore
+  integer
+  (>= val 1)
+  (<= val 100))
+(define-opt
+  demuxer-lavf-probesize
+  integer
+  (>= val 32)
+  (<= val 2147483647))
+(define-opt demuxer-lavf-propagate-opts boolean)
+(define-opt
+  demuxer-max-back-bytes
+  byte-size
+  (>= val 0)
+  (<= val 4.6116860184274e18))
+(define-opt
+  demuxer-max-bytes
+  byte-size
+  (>= val 0)
+  (<= val 4.6116860184274e18))
+(define-opt demuxer-mkv-probe-start-time boolean)
+(define-opt
+  demuxer-mkv-probe-video-duration
+  enumeration
+  (memq val '(no yes full)))
+(define-opt
+  demuxer-mkv-subtitle-preroll
+  enumeration
+  (memq val '(no yes index)))
+(define-opt
+  demuxer-mkv-subtitle-preroll-secs
+  double
+  (>= val 0))
+(define-opt
+  demuxer-mkv-subtitle-preroll-secs-index
+  double
+  (>= val 0))
+(define-opt
+  demuxer-rawaudio-channels
+  audio-channels-or-channel-map)
+(define-opt
+  demuxer-rawaudio-format
+  enumeration
+  (memq val
+        '(u8 s8
+             u16le
+             u16be
+             s16le
+             s16be
+             u24le
+             u24be
+             s24le
+             s24be
+             u32le
+             u32be
+             s32le
+             s32be
+             floatle
+             floatbe
+             doublele
+             doublebe
+             u16
+             s16
+             u24
+             s24
+             u32
+             s32
+             float
+             double)))
+(define-opt
+  demuxer-rawaudio-rate
+  integer
+  (>= val 1000)
+  (<= val 384000))
+(define-opt demuxer-rawvideo-codec string)
+(define-opt demuxer-rawvideo-format fourcc)
+(define-opt
+  demuxer-rawvideo-fps
+  float
+  (>= val 0.001)
+  (<= val 1000))
+(define-opt
+  demuxer-rawvideo-h
+  integer
+  (>= val 1)
+  (<= val 8192))
+(define-opt
+  demuxer-rawvideo-mp-format
+  image-format)
+(define-opt
+  demuxer-rawvideo-size
+  integer
+  (>= val 1)
+  (<= val 268435456))
+(define-opt
+  demuxer-rawvideo-w
+  integer
+  (>= val 1)
+  (<= val 8192))
+(define-opt
+  demuxer-readahead-secs
+  double
+  (>= val 0))
+(define-opt
+  demuxer-seekable-cache
+  enumeration
+  (memq val '(auto no yes)))
+(define-opt demuxer-termination-timeout double)
+(define-opt demuxer-thread boolean)
+(define-opt
+  directory-filter-types
+  list-of-string)
+(define-opt
+  directory-mode
+  enumeration
+  (memq val '(auto lazy recursive ignore)))
+(define-opt
+  display-fps-override
+  double
+  (>= val 0))
+(define-opt display-tags list-of-string)
+(define-opt
+  dither
+  enumeration
+  (memq val '(fruit ordered error-diffusion no)))
+(define-opt
+  dither-depth
+  enumeration
+  (or (memq val '(no auto))
+      (and (integer? val) (>= val -1) (<= val 16))))
+(define-opt
+  dither-size-fruit
+  integer
+  (>= val 2)
+  (<= val 8))
+(define-opt
+  drag-and-drop
+  enumeration
+  (memq val '(no auto replace append insert-next)))
+(define-opt drm-connector string)
+(define-opt drm-device string)
+(define-opt
+  drm-draw-plane
+  enumeration
+  (or (memq val '(primary overlay))
+      (and (integer? val)
+           (>= val 0)
+           (<= val 2147483647))))
+(define-opt drm-draw-surface-size window-size)
+(define-opt
+  drm-drmprime-video-plane
+  enumeration
+  (or (memq val '(primary overlay))
+      (and (integer? val)
+           (>= val 0)
+           (<= val 2147483647))))
+(define-opt
+  drm-format
+  enumeration
+  (memq val
+        '(xrgb8888 xrgb2101010 xbgr8888 xbgr2101010 yuyv)))
+(define-opt drm-mode string)
+(define-opt
+  drm-vrr-enabled
+  enumeration
+  (memq val '(no yes auto)))
+(define-opt
+  dscale
+  enumeration
+  (memq val
+        '(bilinear
+          bicubic_fast
+          oversample
+          spline16
+          spline36
+          spline64
+          sinc
+          lanczos
+          ginseng
+          bicubic
+          hermite
+          catmull_rom
+          mitchell
+          robidoux
+          robidouxsharp
+          box
+          nearest
+          triangle
+          gaussian
+          jinc
+          ewa_lanczos
+          ewa_hanning
+          ewa_ginseng
+          ewa_lanczossharp
+          ewa_lanczos4sharpest
+          ewa_lanczossoft
+          haasnsoft
+          ewa_robidoux
+          ewa_robidouxsharp
+          bartlett
+          cosine
+          hanning
+          tukey
+          hamming
+          quadric
+          welch
+          kaiser
+          blackman
+          sphinx)))
+(define-opt
+  dscale-antiring
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt dscale-blur float)
+(define-opt
+  dscale-clamp
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt dscale-param1 float)
+(define-opt dscale-param2 float)
+(define-opt
+  dscale-radius
+  float
+  (>= val 0.5)
+  (<= val 16))
+(define-opt
+  dscale-taper
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt
+  dscale-window
+  enumeration
+  (memq val
+        '(bartlett
+          cosine
+          hanning
+          tukey
+          hamming
+          quadric
+          welch
+          kaiser
+          blackman
+          sphinx
+          jinc)))
+(define-opt dscale-wparam float)
+(define-opt
+  dscale-wtaper
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt dump-stats string)
+(define-opt
+  dvbin-card
+  integer
+  (>= val 0)
+  (<= val 15))
+(define-opt dvbin-channel-switch-offset integer)
+(define-opt dvbin-file string)
+(define-opt dvbin-full-transponder boolean)
+(define-opt dvbin-prog string)
+(define-opt
+  dvbin-timeout
+  integer
+  (>= val 1)
+  (<= val 30))
+(define-opt
+  dvd-angle
+  integer
+  (>= val 1)
+  (<= val 99))
+(define-opt dvd-device string)
+(define-opt dvd-speed integer)
+(define-opt
+  edition
+  enumeration
+  (or (memq val '(auto))
+      (and (integer? val) (>= val 0) (<= val 8190))))
+(define-opt egl-config-id integer)
+(define-opt
+  egl-output-format
+  enumeration
+  (memq val
+        '(auto rgb8
+               rgba8
+               rgb10
+               rgb10_a2
+               rgb16
+               rgba16
+               rgb16f
+               rgba16f
+               rgb32f
+               rgba32f)))
+(define-opt embeddedfonts boolean)
+(define-opt
+  end
+  relative-time-or-percent-position)
+(define-opt error-diffusion string)
+(define-opt external-files list-of-string)
+(define-opt fbo-format string)
+(define-opt
+  focus-on
+  enumeration
+  (memq val '(never open all)))
+(define-opt force-media-title string)
+(define-opt force-render boolean)
+(define-opt force-rgba-osd-rendering boolean)
+(define-opt force-seekable boolean)
+(define-opt
+  force-window
+  enumeration
+  (memq val '(no yes immediate)))
+(define-opt force-window-position boolean)
+(define-opt
+  framedrop
+  enumeration
+  (memq val '(no vo decoder decoder+vo)))
+(define-opt
+  frames
+  enumeration
+  (or (memq val '(all))
+      (and (integer? val)
+           (>= val 0)
+           (<= val 2147483647))))
+(define-opt
+  fs-screen
+  enumeration
+  (or (memq val '(all current))
+      (and (integer? val) (>= val 0) (<= val 32))))
+(define-opt fs-screen-name string)
+(define-opt fullscreen boolean)
+(define-opt
+  gamma
+  float
+  (>= val -100)
+  (<= val 100))
+(define-opt gamma-auto boolean)
+(define-opt
+  gamma-factor
+  float
+  (>= val 0.1)
+  (<= val 2))
+(define-opt
+  gamut-mapping-mode
+  enumeration
+  (memq val
+        '(auto clip
+               perceptual
+               relative
+               saturation
+               absolute
+               desaturate
+               darken
+               warn
+               linear)))
+(define-opt
+  gapless-audio
+  enumeration
+  (memq val '(no yes weak)))
+(define-opt geometry window-geometry)
+(define-opt glsl-shader-opts list-of-key-value)
+(define-opt glsl-shaders list-of-string)
+(define-opt gpu-api list-of-object-setting)
+(define-opt gpu-context list-of-object-setting)
+(define-opt gpu-debug boolean)
+(define-opt
+  gpu-dumb-mode
+  enumeration
+  (memq val '(auto yes no)))
+(define-opt gpu-hwdec-interop string)
+(define-opt gpu-shader-cache boolean)
+(define-opt gpu-shader-cache-dir string)
+(define-opt gpu-sw boolean)
+(define-opt
+  gpu-tex-pad-x
+  integer
+  (>= val 0)
+  (<= val 4096))
+(define-opt
+  gpu-tex-pad-y
+  integer
+  (>= val 0)
+  (<= val 4096))
+(define-opt
+  hdr-compute-peak
+  enumeration
+  (memq val '(auto yes no)))
+(define-opt
+  hdr-contrast-recovery
+  float
+  (>= val 0)
+  (<= val 2))
+(define-opt
+  hdr-contrast-smoothness
+  float
+  (>= val 1)
+  (<= val 100))
+(define-opt
+  hdr-peak-decay-rate
+  float
+  (>= val 0)
+  (<= val 1000))
+(define-opt
+  hdr-peak-percentile
+  float
+  (>= val 0)
+  (<= val 100))
+(define-opt
+  hdr-scene-threshold-high
+  float
+  (>= val 0)
+  (<= val 20))
+(define-opt
+  hdr-scene-threshold-low
+  float
+  (>= val 0)
+  (<= val 20))
+(define-opt hidpi-window-scale boolean)
+(define-opt
+  hls-bitrate
+  enumeration
+  (or (memq val '(no min max))
+      (and (integer? val)
+           (>= val 0)
+           (<= val 2147483647))))
+(define-opt
+  hr-seek
+  enumeration
+  (memq val '(no absolute yes always default)))
+(define-opt hr-seek-demuxer-offset float)
+(define-opt hr-seek-framedrop boolean)
+(define-opt http-header-fields list-of-string)
+(define-opt http-proxy string)
+(define-opt hue float (>= val -100) (<= val 100))
+(define-opt hwdec list-of-string)
+(define-opt hwdec-codecs string)
+(define-opt
+  hwdec-extra-frames
+  integer
+  (>= val 0)
+  (<= val 256))
+(define-opt hwdec-image-format image-format)
+(define-opt icc-3dlut-size string)
+(define-opt icc-cache boolean)
+(define-opt icc-cache-dir string)
+(define-opt
+  icc-force-contrast
+  enumeration
+  (or (memq val '(no inf))
+      (and (integer? val) (>= val 0) (<= val 1000000))))
+(define-opt icc-intent integer)
+(define-opt icc-profile string)
+(define-opt icc-profile-auto boolean)
+(define-opt icc-use-luma boolean)
+(define-opt
+  idle
+  enumeration
+  (memq val '(no once yes)))
+(define-opt
+  ignore-path-in-watch-later-config
+  boolean)
+(define-opt
+  image-display-duration
+  double
+  (>= val 0))
+(define-opt image-exts list-of-string)
+(define-opt image-lut string)
+(define-opt
+  image-lut-type
+  enumeration
+  (memq val '(auto native normalized conversion)))
+(define-opt image-subs-video-resolution boolean)
+(define-opt include string)
+(define-opt
+  index
+  enumeration
+  (memq val '(default recreate)))
+(define-opt initial-audio-sync boolean)
+(define-opt input-ar-delay integer)
+(define-opt input-ar-rate integer)
+(define-opt input-builtin-bindings boolean)
+(define-opt input-builtin-dragging boolean)
+(define-opt input-commands list-of-string)
+(define-opt input-conf string)
+(define-opt input-cursor boolean)
+(define-opt input-cursor-passthrough boolean)
+(define-opt input-default-bindings boolean)
+(define-opt
+  input-doubleclick-time
+  integer
+  (>= val 0)
+  (<= val 1000))
+(define-opt input-dragging-deadzone integer)
+(define-opt input-ipc-client string)
+(define-opt input-ipc-server string)
+(define-opt
+  input-key-fifo-size
+  integer
+  (>= val 2)
+  (<= val 65000))
+(define-opt input-media-keys boolean)
+(define-opt input-preprocess-wheel boolean)
+(define-opt input-right-alt-gr boolean)
+(define-opt input-terminal boolean)
+(define-opt input-test boolean)
+(define-opt input-touch-emulate-mouse boolean)
+(define-opt input-vo-keyboard boolean)
+(define-opt interpolation boolean)
+(define-opt interpolation-preserve boolean)
+(define-opt interpolation-threshold float)
+(define-opt inverse-tone-mapping boolean)
+(define-opt jack-autostart boolean)
+(define-opt jack-connect boolean)
+(define-opt jack-name string)
+(define-opt jack-port string)
+(define-opt
+  jack-std-channel-layout
+  enumeration
+  (memq val '(waveext any)))
+(define-opt
+  keep-open
+  enumeration
+  (memq val '(no yes always)))
+(define-opt keep-open-pause boolean)
+(define-opt keepaspect boolean)
+(define-opt keepaspect-window boolean)
+(define-opt lavfi-complex string)
+(define-opt
+  length
+  relative-time-or-percent-position)
+(define-opt libplacebo-opts list-of-key-value)
+(define-opt linear-downscaling boolean)
+(define-opt linear-upscaling boolean)
+(define-opt
+  load-auto-profiles
+  enumeration
+  (memq val '(no yes auto)))
+(define-opt load-osd-console boolean)
+(define-opt load-scripts boolean)
+(define-opt load-select boolean)
+(define-opt load-stats-overlay boolean)
+(define-opt load-unsafe-playlists boolean)
+(define-opt log-file string)
+(define-opt
+  loop-file
+  enumeration
+  (or (memq val '(no inf yes))
+      (and (integer? val) (>= val 0) (<= val 10000))))
+(define-opt
+  loop-playlist
+  enumeration
+  (or (memq val '(no inf yes force))
+      (and (integer? val) (>= val 1) (<= val 10000))))
+(define-opt lut string)
+(define-opt
+  lut-type
+  enumeration
+  (memq val '(auto native normalized conversion)))
+(define-opt mc float (>= val 0) (<= val 100))
+(define-opt
+  media-controls
+  enumeration
+  (memq val '(no player yes)))
+(define-opt merge-files boolean)
+(define-opt metadata-codepage string)
+(define-opt mf-fps double)
+(define-opt mf-type string)
+(define-opt
+  monitoraspect
+  float
+  (>= val 0)
+  (<= val 9))
+(define-opt
+  monitorpixelaspect
+  float
+  (>= val 0.03125)
+  (<= val 32))
+(define-opt msg-color boolean)
+(define-opt msg-level list-of-output-verbosity)
+(define-opt msg-module boolean)
+(define-opt msg-time boolean)
+(define-opt mute boolean)
+(define-opt native-fs boolean)
+(define-opt native-keyrepeat boolean)
+(define-opt native-touch boolean)
+(define-opt network-timeout double (>= val 0))
+(define-opt oac string)
+(define-opt oacopts list-of-key-value)
+(define-opt ocopy-metadata boolean)
+(define-opt of string)
+(define-opt ofopts list-of-key-value)
+(define-opt on-all-workspaces boolean)
+(define-opt ontop boolean)
+(define-opt
+  ontop-level
+  enumeration
+  (or (memq val '(window system desktop))
+      (and (integer? val)
+           (>= val 0)
+           (<= val 2147483647))))
+(define-opt opengl-check-pattern-a integer)
+(define-opt opengl-check-pattern-b integer)
+(define-opt
+  opengl-early-flush
+  enumeration
+  (memq val '(no yes auto)))
+(define-opt
+  opengl-es
+  enumeration
+  (memq val '(auto yes no)))
+(define-opt opengl-glfinish boolean)
+(define-opt opengl-pbo boolean)
+(define-opt opengl-rectangle-textures boolean)
+(define-opt opengl-swapinterval integer)
+(define-opt opengl-waitvsync boolean)
+(define-opt orawts boolean)
+(define-opt ordered-chapters boolean)
+(define-opt ordered-chapters-files string)
+(define-opt oremove-metadata list-of-string)
+(define-opt osc boolean)
+(define-opt
+  osd-align-x
+  enumeration
+  (memq val '(left center right)))
+(define-opt
+  osd-align-y
+  enumeration
+  (memq val '(top center bottom)))
+(define-opt osd-back-color color)
+(define-opt osd-bar boolean)
+(define-opt
+  osd-bar-align-x
+  float
+  (>= val -1)
+  (<= val 1))
+(define-opt
+  osd-bar-align-y
+  float
+  (>= val -1)
+  (<= val 1))
+(define-opt
+  osd-bar-h
+  float
+  (>= val 0.1)
+  (<= val 50))
+(define-opt
+  osd-bar-outline-size
+  float
+  (>= val 0)
+  (<= val 1000))
+(define-opt
+  osd-bar-w
+  float
+  (>= val 1)
+  (<= val 100))
+(define-opt
+  osd-blur
+  float
+  (>= val 0)
+  (<= val 20))
+(define-opt osd-bold boolean)
+(define-opt
+  osd-border-style
+  enumeration
+  (memq val
+        '(outline-and-shadow opaque-box background-box)))
+(define-opt osd-color color)
+(define-opt
+  osd-duration
+  integer
+  (>= val 0)
+  (<= val 3600000))
+(define-opt osd-font string)
+(define-opt
+  osd-font-provider
+  enumeration
+  (memq val '(auto none fontconfig)))
+(define-opt
+  osd-font-size
+  float
+  (>= val 1)
+  (<= val 9000))
+(define-opt osd-fonts-dir string)
+(define-opt osd-fractions boolean)
+(define-opt osd-italic boolean)
+(define-opt
+  osd-justify
+  enumeration
+  (memq val '(auto left center right)))
+(define-opt
+  osd-level
+  enumeration
+  (memq val '(#{0}# #{1}# #{2}# #{3}#)))
+(define-opt
+  osd-margin-x
+  integer
+  (>= val 0)
+  (<= val 300))
+(define-opt
+  osd-margin-y
+  integer
+  (>= val 0)
+  (<= val 600))
+(define-opt osd-msg1 string)
+(define-opt osd-msg2 string)
+(define-opt osd-msg3 string)
+(define-opt
+  osd-on-seek
+  enumeration
+  (memq val '(no bar msg msg-bar)))
+(define-opt osd-outline-color color)
+(define-opt osd-outline-size float)
+(define-opt osd-playing-msg string)
+(define-opt
+  osd-playing-msg-duration
+  integer
+  (>= val 0)
+  (<= val 3600000))
+(define-opt
+  osd-playlist-entry
+  enumeration
+  (memq val '(title filename both)))
+(define-opt
+  osd-scale
+  float
+  (>= val 0)
+  (<= val 100))
+(define-opt osd-scale-by-window boolean)
+(define-opt osd-shadow-offset float)
+(define-opt
+  osd-spacing
+  float
+  (>= val -10)
+  (<= val 10))
+(define-opt osd-status-msg string)
+(define-opt oset-metadata list-of-key-value)
+(define-opt ovc string)
+(define-opt ovcopts list-of-key-value)
+(define-opt panscan float (>= val 0) (<= val 1))
+(define-opt pause boolean)
+(define-opt
+  pipewire-buffer
+  enumeration
+  (or (memq val '(native))
+      (and (integer? val) (>= val 1) (<= val 2000))))
+(define-opt pipewire-remote string)
+(define-opt
+  pipewire-volume-mode
+  enumeration
+  (memq val '(channel global)))
+(define-opt
+  pitch
+  double
+  (>= val 0.01)
+  (<= val 100))
+(define-opt
+  play-direction
+  enumeration
+  (memq val '(forward + backward -)))
+(define-opt
+  player-operation-mode
+  enumeration
+  (memq val '(cplayer pseudo-gui)))
+(define-opt
+  playlist-start
+  enumeration
+  (or (memq val '(auto no))
+      (and (integer? val)
+           (>= val 0)
+           (<= val 2147483647))))
+(define-opt prefetch-playlist boolean)
+(define-opt profile list-of-string)
+(define-opt pulse-allow-suspended boolean)
+(define-opt
+  pulse-buffer
+  enumeration
+  (or (memq val '(native))
+      (and (integer? val) (>= val 1) (<= val 2000))))
+(define-opt pulse-host string)
+(define-opt pulse-latency-hacks boolean)
+(define-opt quiet boolean)
+(define-opt really-quiet boolean)
+(define-opt rebase-start-time boolean)
+(define-opt referrer string)
+(define-opt
+  replaygain
+  enumeration
+  (memq val '(no track album)))
+(define-opt replaygain-clip boolean)
+(define-opt
+  replaygain-fallback
+  float
+  (>= val -200)
+  (<= val 60))
+(define-opt
+  replaygain-preamp
+  float
+  (>= val -150)
+  (<= val 150))
+(define-opt reset-on-next-file list-of-string)
+(define-opt resume-playback boolean)
+(define-opt resume-playback-check-mtime boolean)
+(define-opt
+  rtsp-transport
+  enumeration
+  (memq val '(lavf udp tcp http udp_multicast)))
+(define-opt
+  saturation
+  float
+  (>= val -100)
+  (<= val 100))
+(define-opt save-position-on-quit boolean)
+(define-opt
+  scale
+  enumeration
+  (memq val
+        '(bilinear
+          bicubic_fast
+          oversample
+          spline16
+          spline36
+          spline64
+          sinc
+          lanczos
+          ginseng
+          bicubic
+          hermite
+          catmull_rom
+          mitchell
+          robidoux
+          robidouxsharp
+          box
+          nearest
+          triangle
+          gaussian
+          jinc
+          ewa_lanczos
+          ewa_hanning
+          ewa_ginseng
+          ewa_lanczossharp
+          ewa_lanczos4sharpest
+          ewa_lanczossoft
+          haasnsoft
+          ewa_robidoux
+          ewa_robidouxsharp
+          bartlett
+          cosine
+          hanning
+          tukey
+          hamming
+          quadric
+          welch
+          kaiser
+          blackman
+          sphinx)))
+(define-opt
+  scale-antiring
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt scale-blur float)
+(define-opt
+  scale-clamp
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt scale-param1 float)
+(define-opt scale-param2 float)
+(define-opt
+  scale-radius
+  float
+  (>= val 0.5)
+  (<= val 16))
+(define-opt
+  scale-taper
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt
+  scale-window
+  enumeration
+  (memq val
+        '(bartlett
+          cosine
+          hanning
+          tukey
+          hamming
+          quadric
+          welch
+          kaiser
+          blackman
+          sphinx
+          jinc)))
+(define-opt scale-wparam float)
+(define-opt
+  scale-wtaper
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt scaler-resizes-only boolean)
+(define-opt
+  screen
+  enumeration
+  (or (memq val '(default))
+      (and (integer? val) (>= val 0) (<= val 32))))
+(define-opt screen-name string)
+(define-opt screenshot-avif-encoder string)
+(define-opt
+  screenshot-avif-opts
+  list-of-key-value)
+(define-opt screenshot-avif-pixfmt string)
+(define-opt screenshot-directory string)
+(define-opt
+  screenshot-format
+  enumeration
+  (memq val '(jpg jpeg png webp jxl avif)))
+(define-opt screenshot-high-bit-depth boolean)
+(define-opt
+  screenshot-jpeg-quality
+  integer
+  (>= val 0)
+  (<= val 100))
+(define-opt
+  screenshot-jpeg-source-chroma
+  boolean)
+(define-opt
+  screenshot-jxl-distance
+  double
+  (>= val 0)
+  (<= val 15))
+(define-opt
+  screenshot-jxl-effort
+  integer
+  (>= val 1)
+  (<= val 9))
+(define-opt
+  screenshot-png-compression
+  integer
+  (>= val 0)
+  (<= val 9))
+(define-opt
+  screenshot-png-filter
+  integer
+  (>= val 0)
+  (<= val 5))
+(define-opt screenshot-sw boolean)
+(define-opt screenshot-tag-colorspace boolean)
+(define-opt screenshot-template string)
+(define-opt
+  screenshot-webp-compression
+  integer
+  (>= val 0)
+  (<= val 6))
+(define-opt screenshot-webp-lossless boolean)
+(define-opt
+  screenshot-webp-quality
+  integer
+  (>= val 0)
+  (<= val 100))
+(define-opt script-opts list-of-key-value)
+(define-opt scripts list-of-string)
+(define-opt
+  secondary-sid
+  enumeration
+  (or (memq val '(no auto))
+      (and (integer? val) (>= val 0) (<= val 8190))))
+(define-opt
+  secondary-sub-ass-override
+  enumeration
+  (memq val '(no yes scale force strip)))
+(define-opt secondary-sub-delay float)
+(define-opt
+  secondary-sub-pos
+  float
+  (>= val 0)
+  (<= val 150))
+(define-opt secondary-sub-visibility boolean)
+(define-opt sharpen float)
+(define-opt show-in-taskbar boolean)
+(define-opt shuffle boolean)
+(define-opt
+  sub
+  enumeration
+  (or (memq val '(no auto))
+      (and (integer? val) (>= val 0) (<= val 8190))))
+(define-opt
+  sigmoid-center
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt
+  sigmoid-slope
+  float
+  (>= val 1)
+  (<= val 20))
+(define-opt sigmoid-upscaling boolean)
+(define-opt slang list-of-string)
+(define-opt snap-window boolean)
+(define-opt
+  speed
+  double
+  (>= val 0.01)
+  (<= val 100))
+(define-opt
+  spirv-compiler
+  enumeration
+  (memq val '(auto)))
+(define-opt sstep double (>= val 0))
+(define-opt
+  start
+  relative-time-or-percent-position)
+(define-opt
+  stop-playback-on-init-failure
+  boolean)
+(define-opt
+  stop-screensaver
+  enumeration
+  (memq val '(no yes always)))
+(define-opt
+  stream-buffer-size
+  byte-size
+  (>= val 4096)
+  (<= val 536870912))
+(define-opt stream-dump string)
+(define-opt stream-lavf-o list-of-key-value)
+(define-opt stream-record string)
+(define-opt stretch-dvd-subs boolean)
+(define-opt stretch-image-subs-to-screen boolean)
+(define-opt
+  sub-align-x
+  enumeration
+  (memq val '(left center right)))
+(define-opt
+  sub-align-y
+  enumeration
+  (memq val '(top center bottom)))
+(define-opt sub-ass boolean)
+(define-opt sub-ass-force-margins boolean)
+(define-opt
+  sub-ass-hinting
+  enumeration
+  (memq val '(none light normal native)))
+(define-opt sub-ass-justify boolean)
+(define-opt
+  sub-ass-line-spacing
+  float
+  (>= val -1000)
+  (<= val 1000))
+(define-opt
+  sub-ass-override
+  enumeration
+  (memq val '(no yes scale force strip)))
+(define-opt sub-ass-scale-with-window boolean)
+(define-opt
+  sub-ass-shaper
+  enumeration
+  (memq val '(simple complex)))
+(define-opt
+  sub-ass-style-overrides
+  list-of-string)
+(define-opt sub-ass-styles string)
+(define-opt
+  sub-ass-use-video-data
+  enumeration
+  (memq val '(none aspect-ratio all)))
+(define-opt
+  sub-ass-video-aspect-override
+  aspect
+  (>= val 0)
+  (<= val 10))
+(define-opt
+  sub-ass-vsfilter-color-compat
+  enumeration
+  (memq val '(no basic full force-601)))
+(define-opt
+  sub-auto
+  enumeration
+  (memq val '(no exact fuzzy all)))
+(define-opt sub-auto-exts list-of-string)
+(define-opt sub-back-color color)
+(define-opt
+  sub-blur
+  float
+  (>= val 0)
+  (<= val 20))
+(define-opt sub-bold boolean)
+(define-opt
+  sub-border-style
+  enumeration
+  (memq val
+        '(outline-and-shadow opaque-box background-box)))
+(define-opt sub-clear-on-seek boolean)
+(define-opt sub-codepage string)
+(define-opt sub-color color)
+(define-opt sub-create-cc-track boolean)
+(define-opt sub-delay float)
+(define-opt sub-demuxer string)
+(define-opt sub-file-paths list-of-string)
+(define-opt sub-files list-of-string)
+(define-opt sub-filter-jsre list-of-string)
+(define-opt sub-filter-regex list-of-string)
+(define-opt sub-filter-regex-enable boolean)
+(define-opt sub-filter-regex-plain boolean)
+(define-opt sub-filter-regex-warn boolean)
+(define-opt sub-filter-sdh boolean)
+(define-opt sub-filter-sdh-enclosures string)
+(define-opt sub-filter-sdh-harder boolean)
+(define-opt sub-fix-timing boolean)
+(define-opt sub-font string)
+(define-opt
+  sub-font-provider
+  enumeration
+  (memq val '(auto none fontconfig)))
+(define-opt
+  sub-font-size
+  float
+  (>= val 1)
+  (<= val 9000))
+(define-opt sub-fonts-dir string)
+(define-opt sub-forced-events-only boolean)
+(define-opt sub-fps float)
+(define-opt
+  sub-gauss
+  float
+  (>= val 0)
+  (<= val 3))
+(define-opt sub-gray boolean)
+(define-opt sub-italic boolean)
+(define-opt
+  sub-justify
+  enumeration
+  (memq val '(auto left center right)))
+(define-opt sub-lavc-o list-of-key-value)
+(define-opt
+  sub-margin-x
+  integer
+  (>= val 0)
+  (<= val 300))
+(define-opt
+  sub-margin-y
+  integer
+  (>= val 0)
+  (<= val 600))
+(define-opt sub-outline-color color)
+(define-opt sub-outline-size float)
+(define-opt sub-past-video-end boolean)
+(define-opt
+  sub-pos
+  float
+  (>= val 0)
+  (<= val 150))
+(define-opt
+  sub-scale
+  float
+  (>= val 0)
+  (<= val 100))
+(define-opt sub-scale-by-window boolean)
+(define-opt sub-scale-with-window boolean)
+(define-opt sub-shadow-offset float)
+(define-opt
+  sub-spacing
+  float
+  (>= val -10)
+  (<= val 10))
+(define-opt sub-speed float)
+(define-opt sub-stretch-durations boolean)
+(define-opt sub-use-margins boolean)
+(define-opt sub-visibility boolean)
+(define-opt sub-vsfilter-bidi-compat boolean)
+(define-opt
+  subs-fallback
+  enumeration
+  (memq val '(no default yes)))
+(define-opt
+  subs-fallback-forced
+  enumeration
+  (memq val '(no yes always)))
+(define-opt subs-match-os-language boolean)
+(define-opt
+  subs-with-matching-audio
+  enumeration
+  (memq val '(no forced yes)))
+(define-opt
+  swapchain-depth
+  integer
+  (>= val 1)
+  (<= val 8))
+(define-opt sws-allow-zimg boolean)
+(define-opt sws-bitexact boolean)
+(define-opt
+  sws-cgb
+  float
+  (>= val 0)
+  (<= val 100))
+(define-opt sws-chs integer)
+(define-opt
+  sws-cs
+  float
+  (>= val -100)
+  (<= val 100))
+(define-opt sws-cvs integer)
+(define-opt sws-fast boolean)
+(define-opt
+  sws-lgb
+  float
+  (>= val 0)
+  (<= val 100))
+(define-opt
+  sws-ls
+  float
+  (>= val -100)
+  (<= val 100))
+(define-opt
+  sws-scaler
+  enumeration
+  (memq val
+        '(fast-bilinear
+          bilinear
+          bicubic
+          x
+          point
+          area
+          bicublin
+          gauss
+          sinc
+          lanczos
+          spline)))
+(define-opt target-colorspace-hint boolean)
+(define-opt
+  target-contrast
+  enumeration
+  (or (memq val '(auto inf))
+      (and (integer? val) (>= val 10) (<= val 1000000))))
+(define-opt
+  target-gamut
+  enumeration
+  (memq val
+        '(auto bt.601-525
+               bt.601-625
+               bt.709
+               bt.2020
+               bt.470m
+               apple
+               adobe
+               prophoto
+               cie1931
+               dci-p3
+               display-p3
+               v-gamut
+               s-gamut
+               ebu3213
+               film-c
+               aces-ap0
+               aces-ap1)))
+(define-opt target-lut string)
+(define-opt
+  target-peak
+  enumeration
+  (or (memq val '(auto))
+      (and (integer? val) (>= val 10) (<= val 10000))))
+(define-opt
+  target-prim
+  enumeration
+  (memq val
+        '(auto bt.601-525
+               bt.601-625
+               bt.709
+               bt.2020
+               bt.470m
+               apple
+               adobe
+               prophoto
+               cie1931
+               dci-p3
+               display-p3
+               v-gamut
+               s-gamut
+               ebu3213
+               film-c
+               aces-ap0
+               aces-ap1)))
+(define-opt
+  target-trc
+  enumeration
+  (memq val
+        '(auto bt.1886
+               srgb
+               linear
+               gamma1.8
+               gamma2.0
+               gamma2.2
+               gamma2.4
+               gamma2.6
+               gamma2.8
+               prophoto
+               pq
+               hlg
+               v-log
+               s-log1
+               s-log2
+               st428)))
+(define-opt taskbar-progress boolean)
+(define-opt
+  teletext-page
+  integer
+  (>= val -1)
+  (<= val 999))
+(define-opt temporal-dither boolean)
+(define-opt
+  temporal-dither-period
+  integer
+  (>= val 1)
+  (<= val 128))
+(define-opt
+  term-osd
+  enumeration
+  (memq val '(force auto no)))
+(define-opt term-osd-bar boolean)
+(define-opt term-osd-bar-chars string)
+(define-opt term-playing-msg string)
+(define-opt term-status-msg string)
+(define-opt term-title string)
+(define-opt terminal boolean)
+(define-opt title string)
+(define-opt title-bar boolean)
+(define-opt tls-ca-file string)
+(define-opt tls-cert-file string)
+(define-opt tls-key-file string)
+(define-opt tls-verify boolean)
+(define-opt
+  tone-mapping
+  enumeration
+  (memq val
+        '(auto clip
+               mobius
+               reinhard
+               hable
+               gamma
+               linear
+               spline
+               bt.2390
+               bt.2446a
+               st2094-40
+               st2094-10)))
+(define-opt
+  tone-mapping-max-boost
+  float
+  (>= val 1)
+  (<= val 10))
+(define-opt tone-mapping-param float)
+(define-opt tone-mapping-visualize boolean)
+(define-opt track-auto-selection boolean)
+(define-opt
+  tscale
+  enumeration
+  (memq val
+        '(oversample
+          linear
+          spline16
+          spline36
+          spline64
+          sinc
+          lanczos
+          ginseng
+          bicubic
+          hermite
+          catmull_rom
+          mitchell
+          robidoux
+          robidouxsharp
+          box
+          nearest
+          triangle
+          gaussian
+          bartlett
+          cosine
+          hanning
+          tukey
+          hamming
+          quadric
+          welch
+          kaiser
+          blackman
+          sphinx
+          jinc)))
+(define-opt
+  tscale-antiring
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt tscale-blur float)
+(define-opt
+  tscale-clamp
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt tscale-param1 float)
+(define-opt tscale-param2 float)
+(define-opt
+  tscale-radius
+  float
+  (>= val 0.5)
+  (<= val 16))
+(define-opt
+  tscale-taper
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt
+  tscale-window
+  enumeration
+  (memq val
+        '(bartlett
+          cosine
+          hanning
+          tukey
+          hamming
+          quadric
+          welch
+          kaiser
+          blackman
+          sphinx
+          jinc)))
+(define-opt tscale-wparam float)
+(define-opt
+  tscale-wtaper
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt untimed boolean)
+(define-opt use-embedded-icc-profile boolean)
+(define-opt use-filedir-conf boolean)
+(define-opt user-agent string)
+(define-opt vaapi-device string)
+(define-opt vd string)
+(define-opt vd-apply-cropping boolean)
+(define-opt vd-lavc-assume-old-x264 boolean)
+(define-opt vd-lavc-bitexact boolean)
+(define-opt vd-lavc-check-hw-profile boolean)
+(define-opt
+  vd-lavc-dr
+  enumeration
+  (memq val '(auto no yes)))
+(define-opt vd-lavc-fast boolean)
+(define-opt
+  vd-lavc-film-grain
+  enumeration
+  (memq val '(auto cpu gpu)))
+(define-opt
+  vd-lavc-framedrop
+  enumeration
+  (memq val
+        '(none default nonref bidir nonkey all)))
+(define-opt vd-lavc-o list-of-key-value)
+(define-opt vd-lavc-show-all boolean)
+(define-opt
+  vd-lavc-skipframe
+  enumeration
+  (memq val
+        '(none default nonref bidir nonkey all)))
+(define-opt
+  vd-lavc-skipidct
+  enumeration
+  (memq val
+        '(none default nonref bidir nonkey all)))
+(define-opt
+  vd-lavc-skiploopfilter
+  enumeration
+  (memq val
+        '(none default nonref bidir nonkey all)))
+(define-opt
+  vd-lavc-software-fallback
+  enumeration
+  (or (memq val '(no yes))
+      (and (integer? val)
+           (>= val 1)
+           (<= val 2147483647))))
+(define-opt vd-lavc-threads integer (>= val 0))
+(define-opt vd-queue-enable boolean)
+(define-opt
+  vd-queue-max-bytes
+  byte-size
+  (>= val 0)
+  (<= val 4.6116860184274e18))
+(define-opt
+  vd-queue-max-samples
+  integer64
+  (>= val 0))
+(define-opt vd-queue-max-secs double (>= val 0))
+(define-opt vf list-of-object-setting)
+(define-opt
+  video
+  enumeration
+  (or (memq val '(no auto))
+      (and (integer? val) (>= val 0) (<= val 8190))))
+(define-opt
+  video-align-x
+  float
+  (>= val -1)
+  (<= val 1))
+(define-opt
+  video-align-y
+  float
+  (>= val -1)
+  (<= val 1))
+(define-opt
+  video-aspect-method
+  enumeration
+  (memq val '(bitstream container)))
+(define-opt
+  video-aspect-override
+  aspect
+  (>= val -1)
+  (<= val 10))
+(define-opt
+  video-backward-batch
+  integer
+  (>= val 0)
+  (<= val 1024))
+(define-opt
+  video-backward-overlap
+  enumeration
+  (or (memq val '(auto))
+      (and (integer? val) (>= val 0) (<= val 1024))))
+(define-opt video-crop video-rectangle)
+(define-opt video-exts list-of-string)
+(define-opt video-latency-hacks boolean)
+(define-opt
+  video-margin-ratio-bottom
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt
+  video-margin-ratio-left
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt
+  video-margin-ratio-right
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt
+  video-margin-ratio-top
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt video-osd boolean)
+(define-opt
+  video-output-levels
+  enumeration
+  (memq val '(auto limited full)))
+(define-opt video-pan-x float)
+(define-opt video-pan-y float)
+(define-opt
+  video-reversal-buffer
+  byte-size
+  (>= val 0)
+  (<= val 4.6116860184274e18))
+(define-opt
+  video-rotate
+  enumeration
+  (or (memq val '(no))
+      (and (integer? val) (>= val 0) (<= val 359))))
+(define-opt
+  video-scale-x
+  float
+  (>= val 0)
+  (<= val 10000))
+(define-opt
+  video-scale-y
+  float
+  (>= val 0)
+  (<= val 10000))
+(define-opt
+  video-sync
+  enumeration
+  (memq val
+        '(audio display-resample
+                display-resample-vdrop
+                display-resample-desync
+                display-tempo
+                display-adrop
+                display-vdrop
+                display-desync
+                desync)))
+(define-opt
+  video-sync-max-audio-change
+  double
+  (>= val 0)
+  (<= val 1))
+(define-opt
+  video-sync-max-factor
+  integer
+  (>= val 1)
+  (<= val 10))
+(define-opt
+  video-sync-max-video-change
+  double
+  (>= val 0))
+(define-opt
+  video-timing-offset
+  double
+  (>= val 0)
+  (<= val 1))
+(define-opt
+  video-unscaled
+  enumeration
+  (memq val '(no yes downscale-big)))
+(define-opt
+  video-zoom
+  float
+  (>= val -20)
+  (<= val 20))
+(define-opt vlang list-of-string)
+(define-opt vo list-of-object-setting)
+(define-opt vo-image-avif-encoder string)
+(define-opt vo-image-avif-opts list-of-key-value)
+(define-opt vo-image-avif-pixfmt string)
+(define-opt
+  vo-image-format
+  enumeration
+  (memq val '(jpg jpeg png webp jxl avif)))
+(define-opt vo-image-high-bit-depth boolean)
+(define-opt
+  vo-image-jpeg-quality
+  integer
+  (>= val 0)
+  (<= val 100))
+(define-opt vo-image-jpeg-source-chroma boolean)
+(define-opt
+  vo-image-jxl-distance
+  double
+  (>= val 0)
+  (<= val 15))
+(define-opt
+  vo-image-jxl-effort
+  integer
+  (>= val 1)
+  (<= val 9))
+(define-opt vo-image-outdir string)
+(define-opt
+  vo-image-png-compression
+  integer
+  (>= val 0)
+  (<= val 9))
+(define-opt
+  vo-image-png-filter
+  integer
+  (>= val 0)
+  (<= val 5))
+(define-opt vo-image-tag-colorspace boolean)
+(define-opt
+  vo-image-webp-compression
+  integer
+  (>= val 0)
+  (<= val 6))
+(define-opt vo-image-webp-lossless boolean)
+(define-opt
+  vo-image-webp-quality
+  integer
+  (>= val 0)
+  (<= val 100))
+(define-opt vo-kitty-alt-screen boolean)
+(define-opt vo-kitty-cols integer)
+(define-opt vo-kitty-config-clear boolean)
+(define-opt vo-kitty-height integer)
+(define-opt vo-kitty-left integer)
+(define-opt vo-kitty-rows integer)
+(define-opt vo-kitty-top integer)
+(define-opt vo-kitty-use-shm boolean)
+(define-opt vo-kitty-width integer)
+(define-opt
+  vo-null-fps
+  double
+  (>= val 0)
+  (<= val 10000))
+(define-opt vo-sixel-alt-screen boolean)
+(define-opt vo-sixel-buffered boolean)
+(define-opt vo-sixel-cols integer)
+(define-opt vo-sixel-config-clear boolean)
+(define-opt
+  vo-sixel-dither
+  enumeration
+  (memq val
+        '(auto none
+               atkinson
+               fs
+               jajuni
+               stucki
+               burkes
+               arithmetic
+               xor)))
+(define-opt vo-sixel-fixedpalette boolean)
+(define-opt vo-sixel-height integer)
+(define-opt vo-sixel-left integer)
+(define-opt vo-sixel-pad-x integer)
+(define-opt vo-sixel-pad-y integer)
+(define-opt vo-sixel-reqcolors integer)
+(define-opt vo-sixel-rows integer)
+(define-opt vo-sixel-threshold integer)
+(define-opt vo-sixel-top integer)
+(define-opt vo-sixel-width integer)
+(define-opt vo-tct-256 boolean)
+(define-opt
+  vo-tct-algo
+  enumeration
+  (memq val '(plain half-blocks)))
+(define-opt
+  vo-tct-buffering
+  enumeration
+  (memq val '(pixel line frame)))
+(define-opt vo-tct-height integer)
+(define-opt vo-tct-width integer)
+(define-opt vo-vaapi-scaled-osd boolean)
+(define-opt
+  vo-vaapi-scaling
+  enumeration
+  (memq val '(default fast hq nla)))
+(define-opt vo-vdpau-chroma-deint boolean)
+(define-opt vo-vdpau-colorkey color)
+(define-opt vo-vdpau-composite-detect boolean)
+(define-opt
+  vo-vdpau-denoise
+  float
+  (>= val 0)
+  (<= val 1))
+(define-opt vo-vdpau-force-yuv boolean)
+(define-opt vo-vdpau-fps double)
+(define-opt
+  vo-vdpau-hqscaling
+  integer
+  (>= val 0)
+  (<= val 9))
+(define-opt
+  vo-vdpau-output-surfaces
+  integer
+  (>= val 2)
+  (<= val 15))
+(define-opt vo-vdpau-pullup boolean)
+(define-opt vo-vdpau-queuetime-fs integer)
+(define-opt vo-vdpau-queuetime-windowed integer)
+(define-opt
+  vo-vdpau-sharpen
+  float
+  (>= val -1)
+  (<= val 1))
+(define-opt
+  volume
+  float
+  (>= val -1)
+  (<= val 1000))
+(define-opt
+  volume-gain
+  float
+  (>= val -150)
+  (<= val 150))
+(define-opt
+  volume-gain-max
+  float
+  (>= val 0)
+  (<= val 150))
+(define-opt
+  volume-gain-min
+  float
+  (>= val -150)
+  (<= val 0))
+(define-opt
+  volume-max
+  float
+  (>= val 100)
+  (<= val 1000))
+(define-opt vulkan-async-compute boolean)
+(define-opt vulkan-async-transfer boolean)
+(define-opt vulkan-device string)
+(define-opt vulkan-display-display integer)
+(define-opt vulkan-display-mode integer)
+(define-opt vulkan-display-plane integer)
+(define-opt
+  vulkan-queue-count
+  integer
+  (>= val 1)
+  (<= val 8))
+(define-opt
+  vulkan-swap-mode
+  enumeration
+  (memq val
+        '(auto fifo fifo-relaxed mailbox immediate)))
+(define-opt watch-later-directory string)
+(define-opt watch-later-options list-of-string)
+(define-opt wayland-app-id string)
+(define-opt
+  wayland-configure-bounds
+  enumeration
+  (memq val '(auto no yes)))
+(define-opt
+  wayland-content-type
+  enumeration
+  (memq val '(auto none photo video game)))
+(define-opt wayland-disable-vsync boolean)
+(define-opt
+  wayland-edge-pixels-pointer
+  integer
+  (>= val 0)
+  (<= val 2147483647))
+(define-opt
+  wayland-edge-pixels-touch
+  integer
+  (>= val 0)
+  (<= val 2147483647))
+(define-opt wayland-present boolean)
+(define-opt wid integer64)
+(define-opt window-dragging boolean)
+(define-opt window-maximized boolean)
+(define-opt window-minimized boolean)
+(define-opt
+  window-scale
+  double
+  (>= val 0.001)
+  (<= val 100))
+(define-opt
+  write-filename-in-watch-later-config
+  boolean)
+(define-opt
+  x11-bypass-compositor
+  enumeration
+  (memq val '(no yes fs-only never)))
+(define-opt x11-name string)
+(define-opt
+  x11-netwm
+  enumeration
+  (memq val '(auto no yes)))
+(define-opt
+  x11-present
+  enumeration
+  (memq val '(no auto yes)))
+(define-opt x11-wid-title boolean)
+(define-opt xv-adaptor integer (>= val -1))
+(define-opt
+  xv-buffers
+  integer
+  (>= val 1)
+  (<= val 10))
+(define-opt
+  xv-ck
+  enumeration
+  (memq val '(use set cur)))
+(define-opt
+  xv-ck-method
+  enumeration
+  (memq val '(none bg man auto)))
+(define-opt xv-colorkey integer)
+(define-opt xv-port integer (>= val 0))
+(define-opt ytdl boolean)
+(define-opt ytdl-format string)
+(define-opt ytdl-raw-options list-of-key-value)
+(define-opt
+  zimg-dither
+  enumeration
+  (memq val '(no ordered random error-diffusion)))
+(define-opt zimg-fast boolean)
+(define-opt
+  zimg-scaler
+  enumeration
+  (memq val
+        '(point bilinear
+                bicubic
+                spline16
+                spline36
+                lanczos)))
+(define-opt
+  zimg-scaler-chroma
+  enumeration
+  (memq val
+        '(point bilinear
+                bicubic
+                spline16
+                spline36
+                lanczos)))
+(define-opt zimg-scaler-chroma-param-a double)
+(define-opt zimg-scaler-chroma-param-b double)
+(define-opt zimg-scaler-param-a double)
+(define-opt zimg-scaler-param-b double)
+(define-opt
+  zimg-threads
+  enumeration
+  (or (memq val '(auto))
+      (and (integer? val) (>= val 1) (<= val 64))))
+;;; Generated code - END.
+
+(define-record-type <mpv-profile-configuration>
+  (%make-mpv-profile-configuration data)
+  mpv-profile-configuration?
+  (data %mpv-profile-configuration-data))
+
+(define (make-mpv-profile-configuration . args)
+  ;; I am not sure how can I copy a hash-map.  Documentation does not mention
+  ;; anything.
+  (let ((new (make-hash-table)))
+    (let loop ((args args))
+      (match args
+        ((#:inherit cfg . tail)
+         (hash-for-each (lambda (key val)
+                          (hashq-set! new key val))
+                        (%mpv-profile-configuration-data cfg))
+         (loop tail))
+        (((? keyword? key) val . tail)
+         (let* ((key (keyword->symbol key))
+                (opt (hashq-ref %opts key)))
+           (unless opt
+             (throw 'bad-config "Option not found" key))
+           (unless ((profile-option-type-check opt) val)
+             (throw 'bad-config "Invalid value for" key val))
+           (hashq-set! new key (cons val (profile-option-serializer opt))))
+         (loop tail))
+        (()
+         (%make-mpv-profile-configuration new))))))
+
+(define (serialize-mpv-profile-configuration _ cfg)
+  (let ((sorted (sort
+                 (hash-map->list cons (%mpv-profile-configuration-data cfg))
+                 (lambda (a b)
+                   (string<? (symbol->string (car a))
+                             (symbol->string (car b)))))))
+    #~(string-append
+       #$@(map (match-lambda
+                 ((field-name . value)
+                  ((cdr value) field-name (car value))))
+               sorted))))
+
+
+
+
+;;;
+;;; Configuration base.
+;;;
+(define (serialize-type/mpv-profile-configurations _ profiles)
+  #~(string-append
+     #$@(map (match-lambda
+               ((name . config)
+                #~(string-append
+                   #$(format #f "[~a]~%" name)
+                   #$(serialize-mpv-profile-configuration _ config))))
+             profiles)))
+(define (type/mpv-profile-configurations? alist)
+  (every (match-lambda
+           (((? symbol?) . (? mpv-profile-configuration?)) #t)
+           (_ #f))
+         alist))
+
+(define (serialize-type/extra _ value)
+  (if value
+      #~(string-append #$value
+                       ;; Ensure the extra content ends in a new line.
+                       #$(if (string-suffix? "\n" value)
+                             "" "\n"))
+      #~""))
+(define (type/extra? val)
+  (or (string? val)
+      (gexp? val)))
+
+(define-record-type <home-mpv-configuration>
+  (%make-home-mpv-configuration global profiles extra-config)
+  home-mpv-configuration?
+  (global       home-mpv-configuration-global)
+  (profiles     home-mpv-configuration-profiles)
+  (extra-config home-mpv-configuration-extra-config))
+
+(define* (make-home-mpv-configuration
+          #:key
+          (inherit #f)
+          (global (if inherit
+                      (home-mpv-configuration-global inherit)
+                      (make-mpv-profile-configuration)))
+          (profiles (if inherit
+                        (home-mpv-configuration-profiles inherit)
+                        '()))
+          (extra-config (if inherit
+                            (home-mpv-configuration-extra-config inherit)
+                            #f)))
+  (unless (or (not global) (mpv-profile-configuration? global))
+    (throw 'bad-config "global must satisfy mpv-profile-configuration?"))
+  (unless (type/mpv-profile-configurations? profiles)
+    (throw 'bad-config "profiles must be an alist of mpv-profile-configuration?"))
+  (unless (or (not extra-config) (type/extra? extra-config))
+    (throw 'bad-config "extra-config must be a string or a gexp"))
+  (%make-home-mpv-configuration global profiles extra-config))
+
+(define (serialize-home-mpv-configuration cfg)
+  #~(string-append #$(serialize-mpv-profile-configuration
+                      'global
+                      (home-mpv-configuration-global cfg))
+                   #$(serialize-type/mpv-profile-configurations
+                      'profiles
+                      (home-mpv-configuration-profiles cfg))
+                   #$(serialize-type/extra
+                      'extra-config
+                      (home-mpv-configuration-extra-config cfg))))
+
+(define (mpv-configuration-files cfg)
+  `(("mpv/mpv.conf" ,(mixed-text-file "mpv.conf"
+                                      (serialize-home-mpv-configuration cfg)))))
+
+(define home-mpv-service-type
+  (service-type
+   (name 'home-mpv)
+   (extensions
+    (list (service-extension home-xdg-configuration-files-service-type
+                             mpv-configuration-files)))
+   (description
+    "Install configuration files for mpv into XDG configuration directory.")))
diff --git a/gnu/local.mk b/gnu/local.mk
index f03fcb14fc..c5e545fcb9 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -113,6 +113,7 @@ GNU_SYSTEM_MODULES =				\
   %D%/home/services/mail.scm			\
   %D%/home/services/media.scm			\
   %D%/home/services/messaging.scm		\
+  %D%/home/services/mpv.scm     		\
   %D%/home/services/music.scm			\
   %D%/home/services/pm.scm			\
   %D%/home/services/shells.scm			\
--
2.49.0