diff --git a/hosts/common/programs/default.nix b/hosts/common/programs/default.nix index 729e0575..e09ee632 100644 --- a/hosts/common/programs/default.nix +++ b/hosts/common/programs/default.nix @@ -45,6 +45,7 @@ ./nix-index.nix ./obsidian.nix ./offlineimap.nix + ./playerctl.nix ./rhythmbox.nix ./ripgrep.nix ./sfeed.nix diff --git a/hosts/common/programs/playerctl.nix b/hosts/common/programs/playerctl.nix new file mode 100644 index 00000000..bada691e --- /dev/null +++ b/hosts/common/programs/playerctl.nix @@ -0,0 +1,15 @@ +{ config, lib, pkgs, ... }: +{ + # TODO: give `sane.programs` native support for defining services + systemd.user.services.playerctld = lib.mkIf config.sane.programs.playerctl.enabled { + description = "playerctl daemon to keep track of which MPRIS players were recently active"; + documentation = [ "https://github.com/altdesktop/playerctl/issues/161" ]; + wantedBy = [ "default.target" ]; + serviceConfig.ExecStart = "${config.sane.programs.playerctl.package}/bin/playerctld"; + # serviceConfig.Type = "dbus"; + # serviceConfig.BusName = "org.mpris.MediaPlayer2.Player"; + serviceConfig.Type = "simple"; # playerctl also supports a --daemon option, idk if that's better + serviceConfig.Restart = "on-failure"; + serviceConfig.RestartSec = "10s"; + }; +} diff --git a/hosts/modules/gui/sway/default.nix b/hosts/modules/gui/sway/default.nix index 78f4aea6..54ce1953 100644 --- a/hosts/modules/gui/sway/default.nix +++ b/hosts/modules/gui/sway/default.nix @@ -171,6 +171,7 @@ in "swayidle" "wl-clipboard" "blueberry" # GUI bluetooth manager + "playerctl" # for waybar & particularly to have playerctld running # "mako" # notification daemon "swaynotificationcenter" # notification daemon # # "pavucontrol" diff --git a/hosts/modules/gui/sway/waybar-media b/hosts/modules/gui/sway/waybar-media new file mode 100755 index 00000000..4c30e7a2 --- /dev/null +++ b/hosts/modules/gui/sway/waybar-media @@ -0,0 +1,17 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i bash -p jq -p playerctl +status=$(playerctl status 2> /dev/null | tr 'A-Z' 'a-z') +if [ -z "$status" ]; then + status="inactive" +fi + +artist=$(playerctl metadata artist 2> /dev/null) +title=$(playerctl metadata title 2> /dev/null) + +text= +if [ -n "$title" ]; then + text="$artist - $title" +fi +# waybar requires output to be on a single line. +# `alt` key determines the icon +jq --null-input --compact-output --arg status "$status" --arg text "$text" '{ "text": $text, "alt": $status }' diff --git a/hosts/modules/gui/sway/waybar-top.nix b/hosts/modules/gui/sway/waybar-top.nix index 566ee1ff..da336406 100644 --- a/hosts/modules/gui/sway/waybar-top.nix +++ b/hosts/modules/gui/sway/waybar-top.nix @@ -1,6 +1,14 @@ # docs: -# format specifiers: +# - custom modules: +# - format specifiers: { lib, pkgs }: +let + waybar-media = pkgs.static-nix-shell.mkBash { + pname = "waybar-media"; + src = ./.; + pkgs = [ "jq" "playerctl" ]; + }; +in { height = lib.mkDefault 40; modules-left = lib.mkDefault [ "sway/workspaces" ]; @@ -19,28 +27,36 @@ max-length = 50; }; - # include song artist/title. - # source: "custom/media" = { - exec = pkgs.writeShellScript "waybar-mediaplayer" '' - player_status=$(${pkgs.playerctl}/bin/playerctl status 2> /dev/null) - if [ "$player_status" = "Playing" ]; then - echo " $(${pkgs.playerctl}/bin/playerctl metadata artist) - $(${pkgs.playerctl}/bin/playerctl metadata title)" - elif [ "$player_status" = "Paused" ]; then - echo " $(${pkgs.playerctl}/bin/playerctl metadata artist) - $(${pkgs.playerctl}/bin/playerctl metadata title)" - fi - ''; + # this module shows the actively playing song + # - source: + # - alternative: + # - alternative: + # + # N.B.: for this to behave well with multiple MPRIS clients, + # `playerctld` must be enabled. see: + exec = "${waybar-media}/bin/waybar-media"; + return-type = "json"; interval = 2; - format = "{}"; - # return-type = "json"; - on-click = "${pkgs.playerctl}/bin/playerctl play-pause"; - on-scroll-up = "${pkgs.playerctl}/bin/playerctl next"; - on-scroll-down = "${pkgs.playerctl}/bin/playerctl previous"; + format = "{icon}{}"; + max-length = 50; + format-icons = { + playing = " "; + paused = " "; + inactive = ""; + }; + tooltip = false; + on-click = "playerctl play-pause"; + on-scroll-up = "playerctl next"; + on-scroll-down = "playerctl previous"; }; "custom/swaync" = { # source: - tooltip = false; - format = "{icon}"; # or "{icon} {}" to inclde notif count + exec-if = "which swaync-client"; + exec = "swaync-client -swb"; + return-type = "json"; + escape = true; + format = "{icon}"; # or "{icon} {}" to include notif count format-icons = { notification = ""; none = ""; @@ -51,12 +67,9 @@ dnd-inhibited-notification = ""; dnd-inhibited-none = ""; }; - return-type = "json"; - exec-if = "which swaync-client"; - exec = "swaync-client -swb"; + tooltip = false; on-click = "swaync-client -t -sw"; on-click-right = "swaync-client -d -sw"; - escape = true; }; network = { # docs: