diff --git a/.config/eww/eww.yuck b/.config/eww/eww.yuck index e6c87d8..a004283 100644 --- a/.config/eww/eww.yuck +++ b/.config/eww/eww.yuck @@ -75,7 +75,7 @@ ;; name) wouldn't match either open instance; both were opened under ;; distinct --id values instead, so the close button has to close by ;; that same id, and each instance needs to know its own. -(defwidget mpd-player-widget [win-id] +(defwidget mpd-player-widget [win-id screen_id] ;; halign/valign "end" so whichever branch is showing hugs the ;; window's own bottom-right anchor instead of centering in it. (box :orientation "v" :halign "end" :valign "end" :space-evenly false @@ -112,13 +112,13 @@ (box :visible {player_expanded} (revealer :transition "slideup" :duration "300ms" :reveal {player_expanded} (overlay - (mpd-dashboard-widget) + (mpd-dashboard-widget :screen_id screen_id) (box :orientation "h" :halign "end" :valign "start" :class "player-card-actions" (button :class "mpd-close" :onclick "eww update player_expanded=false" "⌄") (button :class "mpd-close" :onclick "eww close ${win-id}" "✕"))))))) (defwindow mpd-player-window - [win-id] + [win-id screen_id] :monitor 0 ;; Both width and height auto-size to content (not just height, like ;; lyrics-window) -- the collapsed circle and expanded card are very @@ -129,4 +129,4 @@ :stacking "fg" :windowtype "normal" :focusable true - (mpd-player-widget :win-id win-id)) + (mpd-player-widget :win-id win-id :screen_id screen_id)) diff --git a/.config/eww/mpd-dashboard.scss b/.config/eww/mpd-dashboard.scss index 4af35a7..2dfde43 100644 --- a/.config/eww/mpd-dashboard.scss +++ b/.config/eww/mpd-dashboard.scss @@ -213,5 +213,45 @@ } .dashboard-track-add:hover { - color: white; + color: #ffffff; +} + +.dashboard-tabs-bar { + margin-top: 10px; + margin-bottom: 10px; } + +.dashboard-modes-bar { + margin-right: 5px; +} + +.mpd-mode-shuffle, .mpd-mode-shuffle-active, +.mpd-mode-repeat, .mpd-mode-repeat-active, +.mpd-mode-consume, .mpd-mode-consume-active, +.mpd-mode-single, .mpd-mode-single-active { + padding: 2px 10px; + font-size: 10px; + transition: all 0.2s ease; + border-radius: 12px; +} + +.mpd-mode-shuffle, .mpd-mode-repeat, .mpd-mode-consume, .mpd-mode-single { + background-color: rgba(255, 255, 255, 0.05); + color: #888888; +} + +/* Shuffle: muted orange */ +.mpd-mode-shuffle:hover { background-color: rgba(211, 84, 0, 0.2); color: #ffffff; } +.mpd-mode-shuffle-active { background-color: rgba(211, 84, 0, 0.7); color: white; font-weight: bold; } + +/* Repeat: muted brown */ +.mpd-mode-repeat:hover { background-color: rgba(160, 64, 0, 0.2); color: #ffffff; } +.mpd-mode-repeat-active { background-color: rgba(160, 64, 0, 0.7); color: white; font-weight: bold; } + +/* Consume: muted red */ +.mpd-mode-consume:hover { background-color: rgba(192, 57, 43, 0.2); color: #ffffff; } +.mpd-mode-consume-active { background-color: rgba(192, 57, 43, 0.7); color: white; font-weight: bold; } + +/* Single: muted purple */ +.mpd-mode-single:hover { background-color: rgba(142, 68, 173, 0.2); color: #ffffff; } +.mpd-mode-single-active { background-color: rgba(142, 68, 173, 0.7); color: white; font-weight: bold; } diff --git a/.config/eww/mpd-dashboard.yuck b/.config/eww/mpd-dashboard.yuck index a760516..4f1e9d8 100644 --- a/.config/eww/mpd-dashboard.yuck +++ b/.config/eww/mpd-dashboard.yuck @@ -12,29 +12,39 @@ (deflisten dashboard_search_results :initial "[]" "~/.config/eww/scripts/dashboard-search-listen.sh") -(defwidget mpd-dashboard-widget [] +(defwidget mpd-dashboard-widget [screen_id] (box :class "dashboard-container" :orientation "h" :space-evenly false ;; Left Pane: Now Playing & Lyrics (box :class "dashboard-left" :orientation "v" :space-evenly false :width 450 - (box :class "dashboard-now-playing" :orientation "h" :space-evenly false - (image :class "dashboard-albumart" :path {mpd_status.albumart} :image-width 160 :image-height 160) - (box :orientation "v" :space-evenly false :vexpand true :class "dashboard-meta" - (label :class "dashboard-title" :text {mpd_status.title == "" ? "Nothing playing" : mpd_status.title} :limit-width 30 :halign "start") - (label :class "dashboard-album" :text "👤 ${mpd_status.artist}" :limit-width 30 :halign "start") - (label :class "dashboard-year" :text "📅 ${mpd_status.year}" :halign "start" :visible {mpd_status.year != ""}) - (label :class "dashboard-composer" :text "🎼 ${mpd_status.composer}" :limit-width 30 :halign "start" :visible {mpd_status.composer != ""}) - (box :vexpand true) - (box :orientation "v" :space-evenly false :class "dashboard-progress-container" - (label :class "dashboard-time" :text {mpd_status.time} :halign "end") - (scale :class "dashboard-progress" :value {mpd_status.progress} :min 0 :max 101 :onchange "mpc seek {}%")) - (box :orientation "h" :space-evenly false :halign "start" :class "dashboard-controls" - (button :class "mpd-btn" :onclick "mpc prev" "⏮") - (button :class "mpd-btn" :onclick "mpc toggle" {mpd_status.state == "playing" ? "⏸" : "▶"}) - (button :class "mpd-btn" :onclick "mpc stop" "⏹") - (button :class "mpd-btn" :onclick "mpc next" "⏭")))) - (box :class "dashboard-tabs" :orientation "h" :space-evenly false :spacing 10 - (button :class {dashboard_left_tab == "lyrics" ? "dashboard-tab-active" : "dashboard-tab"} :onclick "eww update dashboard_left_tab='lyrics'" "Lyrics") - (button :class {dashboard_left_tab == "queue" ? "dashboard-tab-active" : "dashboard-tab"} :onclick "eww update dashboard_left_tab='queue'" "Queue")) + (overlay + (box :class "dashboard-now-playing" :orientation "h" :space-evenly false + (image :class "dashboard-albumart" :path {mpd_status.albumart} :image-width 160 :image-height 160) + (box :orientation "v" :space-evenly false :vexpand true :class "dashboard-meta" + (label :class "dashboard-title" :text {mpd_status.title == "" ? "Nothing playing" : mpd_status.title} :limit-width 30 :halign "start") + (label :class "dashboard-album" :text "👤 ${mpd_status.artist}" :limit-width 30 :halign "start") + (label :class "dashboard-year" :text "📅 ${mpd_status.year}" :halign "start" :visible {mpd_status.year != ""}) + (label :class "dashboard-composer" :text "🎼 ${mpd_status.composer}" :limit-width 30 :halign "start" :visible {mpd_status.composer != ""}) + (box :vexpand true) + (box :orientation "v" :space-evenly false :class "dashboard-progress-container" + (label :class "dashboard-time" :text {mpd_status.time} :halign "end") + (scale :class "dashboard-progress" :value {mpd_status.progress} :min 0 :max 101 :onchange "mpc seek {}%")) + (box :orientation "h" :space-evenly false :halign "start" :class "dashboard-controls" + (button :class "mpd-btn" :onclick "mpc prev" "⏮") + (button :class "mpd-btn" :onclick "mpc toggle" {mpd_status.state == "playing" ? "⏸" : "▶"}) + (button :class "mpd-btn" :onclick "mpc stop" "⏹") + (button :class "mpd-btn" :onclick "mpc next" "⏭")))) + (box :halign "end" :valign "start" :class "dashboard-lyrics-toggle-box" + (button :class "mpd-close" :onclick "eww open --toggle --screen ${screen_id} lyrics-window" "🎤"))) + (box :class "dashboard-tabs-bar" :orientation "h" :space-evenly false :hexpand true + (box :class "dashboard-tabs" :orientation "h" :space-evenly false :spacing 10 + (button :class {dashboard_left_tab == "lyrics" ? "dashboard-tab-active" : "dashboard-tab"} :onclick "eww update dashboard_left_tab='lyrics'" "Lyrics") + (button :class {dashboard_left_tab == "queue" ? "dashboard-tab-active" : "dashboard-tab"} :onclick "eww update dashboard_left_tab='queue'" "Queue")) + (box :hexpand true) + (box :class "dashboard-modes-bar" :orientation "h" :space-evenly false :spacing 5 :valign "center" + (button :class {mpd_status.random == "on" ? "mpd-mode-shuffle-active" : "mpd-mode-shuffle"} :onclick "mpc random" "Shuffle") + (button :class {mpd_status.repeat == "on" ? "mpd-mode-repeat-active" : "mpd-mode-repeat"} :onclick "mpc repeat" "Repeat") + (button :class {mpd_status.consume == "on" ? "mpd-mode-consume-active" : "mpd-mode-consume"} :onclick "mpc consume" "Consume") + (button :class {mpd_status.single == "on" ? "mpd-mode-single-active" : "mpd-mode-single"} :onclick "mpc single" "Single"))) (box :class "dashboard-left-content" :orientation "v" :space-evenly false :vexpand true (box :visible {dashboard_left_tab == "lyrics"} :class "dashboard-lyrics" :orientation "v" :space-evenly false :vexpand true @@ -93,4 +103,4 @@ :geometry (geometry :x "0" :y "0" :width "750px" :height "450px" :anchor "center") :stacking "fg" :windowtype "normal" - (mpd-dashboard-widget)) + (mpd-dashboard-widget :screen_id 0)) diff --git a/.config/eww/scripts/mpd-player-status.sh b/.config/eww/scripts/mpd-player-status.sh index f759415..be559db 100755 --- a/.config/eww/scripts/mpd-player-status.sh +++ b/.config/eww/scripts/mpd-player-status.sh @@ -21,15 +21,21 @@ MUSIC_DIR=$(grep -E "^music_directory" ~/.config/mpd/mpd.conf 2>/dev/null | sed prev="" while true; do - state=$(mpc status 2>/dev/null | grep -oP '\[\K[^\]]+' || echo "stop") + status_text=$(mpc status 2>/dev/null) + state=$(echo "$status_text" | grep -oP '\[\K[^\]]+' || echo "stop") artist=$(mpc current -f '%artist%' 2>/dev/null) title=$(mpc current -f '%title%' 2>/dev/null) file=$(mpc current -f '%file%' 2>/dev/null) year=$(mpc current -f '%date%' 2>/dev/null) composer=$(mpc current -f '%composer%' 2>/dev/null) queue_length=$(mpc playlist 2>/dev/null | wc -l) - progress=$(mpc status 2>/dev/null | grep -oP '\(\K[0-9]+(?=%\))' || echo "0") - time_str=$(mpc status 2>/dev/null | grep -oP '\d+:\d+/\d+:\d+' | sed 's|/| / |' || echo "0:00 / 0:00") + progress=$(echo "$status_text" | grep -oP '\(\K[0-9]+(?=%\))' || echo "0") + time_str=$(echo "$status_text" | grep -oP '\d+:\d+/\d+:\d+' | sed 's|/| / |' || echo "0:00 / 0:00") + + repeat_mode=$(echo "$status_text" | grep -oP 'repeat: \K(on|off)' || echo "off") + random_mode=$(echo "$status_text" | grep -oP 'random: \K(on|off)' || echo "off") + single_mode=$(echo "$status_text" | grep -oP 'single: \K(on|off)' || echo "off") + consume_mode=$(echo "$status_text" | grep -oP 'consume: \K(on|off)' || echo "off") if [ -n "$file" ]; then # Only re-extract when the track actually changed -- ffmpeg+convert @@ -53,10 +59,10 @@ while true; do albumart="$PLACEHOLDER_PATH" [ -s "$ALBUMART_PATH" ] && albumart="$ALBUMART_PATH" - line="${state}|${artist}|${title}|${file}|${year}|${composer}|${queue_length}|${progress}|${time_str}" + line="${state}|${artist}|${title}|${file}|${year}|${composer}|${queue_length}|${progress}|${time_str}|${repeat_mode}|${random_mode}|${single_mode}|${consume_mode}" if [ "$line" != "$prev" ]; then - jq -cn --arg state "$state" --arg artist "$artist" --arg title "$title" --arg albumart "$albumart" --arg year "$year" --arg composer "$composer" --arg queue "$queue_length" --arg progress "$progress" --arg time "$time_str" \ - '{state: $state, artist: $artist, title: $title, albumart: $albumart, year: $year, composer: $composer, queue_length: $queue, progress: $progress, time: $time}' + jq -cn --arg state "$state" --arg artist "$artist" --arg title "$title" --arg albumart "$albumart" --arg year "$year" --arg composer "$composer" --arg queue "$queue_length" --arg progress "$progress" --arg time "$time_str" --arg repeat "$repeat_mode" --arg random "$random_mode" --arg single "$single_mode" --arg consume "$consume_mode" \ + '{state: $state, artist: $artist, title: $title, albumart: $albumart, year: $year, composer: $composer, queue_length: $queue, progress: $progress, time: $time, repeat: $repeat, random: $random, single: $single, consume: $consume}' prev="$line" fi diff --git a/.config/systemd/user/eww.service b/.config/systemd/user/eww.service index 00cb5fc..131bdd7 100644 --- a/.config/systemd/user/eww.service +++ b/.config/systemd/user/eww.service @@ -11,7 +11,6 @@ Type=simple Environment=PATH=/home/linuxbrew/.linuxbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin ExecStart=/usr/bin/eww daemon --no-daemonize ExecStartPost=/usr/bin/sleep 2 -ExecStartPost=/usr/bin/eww open lyrics-window # One instance per monitor -- "--id" lets the same mpd-player-window # definition be opened more than once simultaneously (normally opening # a window name that's already open just no-ops/replaces it); "--screen" @@ -19,8 +18,8 @@ ExecStartPost=/usr/bin/eww open lyrics-window # "--arg win-id=..." matches each instance's own --id so its close # button (eww.yuck) can close itself specifically, not the other # monitor's copy or the (unmatched) bare "mpd-player-window" name. -ExecStartPost=/usr/bin/eww open --id mpd-player-screen0 --screen 0 --arg win-id=mpd-player-screen0 mpd-player-window -ExecStartPost=/usr/bin/eww open --id mpd-player-screen1 --screen 1 --arg win-id=mpd-player-screen1 mpd-player-window +ExecStartPost=/usr/bin/eww open --id mpd-player-screen0 --screen 0 --arg win-id=mpd-player-screen0 --arg screen_id=0 mpd-player-window +ExecStartPost=/usr/bin/eww open --id mpd-player-screen1 --screen 1 --arg win-id=mpd-player-screen1 --arg screen_id=1 mpd-player-window Restart=on-failure [Install]