Closed hrwtech closed 3 years ago
Hi, I'll look into it soon and see if I can integrate something similar to the Spotify or Music/iTunes widget or link the more basic Browser Track widget!
Here is how I did that:
ncmpcpp --current-song="%a - %t" 2>/dev/null
Could be improved by offering to customize the current-song format in simple-bar settings.
As suggested in #176 this could be handled in a future extensible custom widget system! I'll keep you posted here.
Thank you @kvndrsslr for your research.
That (#176) is a great idea indeed!
In case @hrwtech wants to use my approach in the meantime.
In the end I opted for mpc
(installable through brew install mpc
) instead of ncmpcpp
for obtaining track info because it also allows to toggle play/pause among other stuff and ncmpcpp
is more of a ncurses client than a command line swiss knife.
Instead of creating a new widget I just hacked the music/iTunes widget as I do not use Apple Music and if you're using MPD the chance is you do neither.
Here are the two files you need to replace:
lib/components/Music.jsx
import { React, run } from 'uebersicht'
import Specter from './Specter.jsx'
import { PlayingIcon, PausedIcon } from './Icons.jsx'
import { refreshData, clickEffect, classnames } from '../utils'
import { getSettings } from '../settings.js'
const { useRef } = React
const Music = ({ output }) => {
const ref = useRef()
const settings = getSettings()
const { widgets, musicWidgetOptions } = settings
const { musicWidget } = widgets
if (!musicWidget || !output) return null
const { playerState, trackInfo } = output
const { showSpecter } = musicWidgetOptions
if (trackInfo === '') return null
const isPlaying = playerState === 'playing'
const Icon = isPlaying ? PlayingIcon : PausedIcon
const onClick = (e) => {
clickEffect(e)
run(`mpc toggle`).then(refreshData)
}
const onMouseEnter = () => {
const target = ref.current
if (!target) return
const inner = target.querySelector('.music__inner')
const slider = target.querySelector('.music__slider')
const delta = inner.clientWidth - slider.clientWidth
if (delta > 0) return
const timing = Math.round((Math.abs(delta) * 100) / 4)
Object.assign(slider.style, {
transform: `translateX(${delta}px)`,
transition: `transform ${timing}ms linear`
})
}
const onMouseLeave = () => {
const target = ref.current
target && target.querySelector('.music__slider').removeAttribute('style')
}
const classes = classnames('music', {
'music--playing': isPlaying
})
return (
<div ref={ref} className={classes} onClick={onClick} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
<Icon className="music__icon" />
{showSpecter && isPlaying && <Specter />}
<div className="music__inner">
<div className="music__slider">
{trackInfo}
</div>
</div>
</div>
)
}
export default Music
lib/scripts/get_data.sh
ACTIVE_WIDGETS="$1"
NETWORK_DEVICE="$2"
WEATHER_LOCATION="$3"
VPN_CONNECTION_NAME="$4"
contains() {
if printf '%s\n' "$1" | grep -Fqe "$2"; then
return 0
else
return 1
fi
}
ZOOM_MIC=""
ZOOM_VIDEO=""
if contains "$ACTIVE_WIDGETS" "zoomWidget"; then
ZOOM_MIC=$(osascript ./simple-bar/lib/scripts/zoom-mute-status.scpt)
ZOOM_VIDEO=$(osascript ./simple-bar/lib/scripts/zoom-video-status.scpt)
fi
WEATHER="{}"
if contains "$ACTIVE_WIDGETS" "weatherWidget"; then
if [ "$WEATHER_LOCATION" != "" ]; then
WEATHER=$(curl -s "wttr.in/$WEATHER_LOCATION?format=j1" 2>/dev/null || echo "{}")
if contains "$WEATHER" "Unknown"; then
WEATHER="{}"
fi
fi
fi
if contains "$ACTIVE_WIDGETS" "batteryWidget"; then
BATTERY_PERCENTAGE=$(pmset -g batt | egrep '([0-9]+\%).*' -o --colour=auto | cut -f1 -d'%')
BATTERY_STATUS=$(pmset -g batt | grep "'.*'" | sed "s/'//g" | cut -c 18-19)
CAFFEINATE=caffeinate
CAFFEINATE_PID=""
if pgrep $CAFFEINATE 2>&1 >/dev/null; then
CAFFEINATE_PID=$(pgrep $CAFFEINATE)
fi
BATTERY_CHARGING=""
if [ "$BATTERY_STATUS" = "Ba" ]; then
BATTERY_CHARGING="false"
elif [ "$BATTERY_STATUS" = "AC" ]; then
BATTERY_CHARGING="true"
fi
fi
if contains "$ACTIVE_WIDGETS" "vpnWidget"; then
VPN_IS_RUNNING=$(osascript -e 'tell application "System Events" to (name of processes) contains "Viscosity"' 2>&1)
if [ "$VPN_IS_RUNNING" = true ]; then
VPN_STATUS=$(osascript -e "tell application \"Viscosity\" to return state of the first connection where name is equal to \"$VPN_CONNECTION_NAME\"" 2>/dev/null)
fi
fi
if contains "$ACTIVE_WIDGETS" "wifiWidget"; then
WIFI_STATUS=$(ifconfig $NETWORK_DEVICE | grep status | cut -c 10-)
WIFI_SSID=$(networksetup -getairportnetwork $NETWORK_DEVICE | cut -c 24-)
fi
if contains "$ACTIVE_WIDGETS" "soundWidget"; then
VOLUME=$(osascript -e 'set ovol to output volume of (get volume settings)')
MUTED=$(osascript -e 'set ovol to output muted of (get volume settings)')
fi
if contains "$ACTIVE_WIDGETS" "micWidget"; then
MIC=$(osascript -e 'set ovol to input volume of (get volume settings)')
fi
if contains "$ACTIVE_WIDGETS" "keyboardWidget"; then
KEYBOARD=$(defaults read ~/Library/Preferences/com.apple.HIToolbox.plist AppleSelectedInputSources | egrep -w 'KeyboardLayout Name' | sed 's/"//g' | sed 's/KeyboardLayout Name = //g')
fi
if contains "$ACTIVE_WIDGETS" "spotifyWidget"; then
SPOTIFY_IS_RUNNING=$(osascript -e 'tell application "System Events" to (name of processes) contains "Spotify"' 2>&1)
if [ "$SPOTIFY_IS_RUNNING" = true ]; then
SPOTIFY_PLAYER_STATE=$(osascript -e 'tell application "Spotify" to player state as string' 2>/dev/null || echo "stopped")
SPOTIFY_TRACK_NAME=$(osascript -e 'tell application "Spotify" to name of current track as string' 2>/dev/null | tr \" \' || echo "unknown track")
SPOTIFY_ARTIST_NAME=$(osascript -e 'tell application "Spotify" to artist of current track as string' 2>/dev/null | tr \" \' || echo "unknown artist")
fi
fi
if contains "$ACTIVE_WIDGETS" "musicWidget"; then
MUSIC_TRACK_INFO=$(mpc --format "%title%[ - %artist%]|[%file%]" | head -n 1)
MUSIC_PLAYER_STATE=$(mpc | head -n 2 | tail -n 1 | awk '{print substr($1,2,length($1)-2)}')
fi
BROWSER_TRACK="{}"
if contains "$ACTIVE_WIDGETS" "browserTrackWidget"; then
if GET_BROWSER_TRACK=$(osascript ./simple-bar/lib/scripts/browser_audio.applescript 2>&1); then
BROWSER_TRACK=$GET_BROWSER_TRACK
fi
fi
echo $(cat <<-EOF
{
"weather": {
"data": $WEATHER
},
"battery": {
"percentage": "$BATTERY_PERCENTAGE",
"charging": "$BATTERY_CHARGING",
"caffeinate": "$CAFFEINATE_PID"
},
"zoom": {
"mic": "$ZOOM_MIC",
"video": "$ZOOM_VIDEO"
},
"vpn": {
"status": "$VPN_STATUS"
},
"wifi": {
"status": "$WIFI_STATUS",
"ssid": "$WIFI_SSID"
},
"sound": {
"volume": "$VOLUME",
"muted": "$MUTED"
},
"mic": {
"volume": "$MIC"
},
"keyboard" : {
"layout": "$KEYBOARD"
},
"spotify": {
"spotifyIsRunning": "$SPOTIFY_IS_RUNNING",
"playerState": "$SPOTIFY_PLAYER_STATE",
"trackName": "$SPOTIFY_TRACK_NAME",
"artistName": "$SPOTIFY_ARTIST_NAME"
},
"music": {
"playerState": "$MUSIC_PLAYER_STATE",
"trackInfo": "$MUSIC_TRACK_INFO"
},
"browserTrack": $BROWSER_TRACK
}
EOF
)
In case you are running your mpd server on another host, just search/replace "mpc" with "mpc --host YOUR_HOSTNAME_OR_IP".
Thanks to everyone for their feedback! Unfortunately, this does not work whatsoever.
Do you actually have this working with the newest simple-bar?
Hey @hrwtech, sorry I did only update to the latest version just now! I did however do things right this time and created a new Widget for mpc complete with a section in the simple-bar settings to set the host/port of your MPD instance and the format string you like to display. You can try out PR #182 to see it in action.
I don't have much to offer by way of how but could you offer some some assistance