You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
5.5 KiB
Bash
184 lines
5.5 KiB
Bash
#!/bin/bash
|
|
# mpd announcer for Konversation - dewdude/Jay - dewdude@pickmy.org
|
|
# requires mpd and bc
|
|
#
|
|
# makes direct connection to mpd, polls for information
|
|
# spams it as an action to the current channel
|
|
# does some sample rate converstion - detects SACD playback
|
|
|
|
# Kompozer's always passed arguements
|
|
SERVER=$1
|
|
TARGET=$2
|
|
shift
|
|
shift
|
|
[[ -n "$@" ]] && COMMAND="$@"
|
|
|
|
# Initialize dbus
|
|
_qdbus=${KONVERSATION_DBUS_BIN:-qdbus-qt6}
|
|
if ! [ "$(which $_qdbus 2> /dev/null)" ]; then
|
|
_qdbus=qdbus
|
|
if ! [ "$(which $_qdbus 2> /dev/null)" ]; then
|
|
echo "Error: The qdbus (or qdbus-qt6) utility is missing."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Script Functions
|
|
|
|
# Converts decimal seconds to "normal" format
|
|
# Arguments: seconds (floating point)
|
|
seconds_to_mmss() {
|
|
local total_seconds="$1"
|
|
|
|
# Convert to integer (truncate decimal part)
|
|
local int_seconds=$(printf "%.0f" "$total_seconds")
|
|
|
|
# Calculate minutes and seconds
|
|
local minutes=$((int_seconds / 60))
|
|
local seconds=$((int_seconds % 60))
|
|
|
|
# Format with leading zeros
|
|
printf "%02d:%02d" "$minutes" "$seconds"
|
|
}
|
|
|
|
# Reparses the audio format tag, converts it to khz, and does stuff for DSD/SACD
|
|
# Argument: number:number:number (44100:16:2 - usually $audio)
|
|
format_audio() {
|
|
local audio_format="$1"
|
|
|
|
# Split the format string on colons
|
|
IFS=':' read -r samplerate bitdepth channels <<< "$audio_format"
|
|
|
|
# Fix it all to stereo!
|
|
local channel_text="Stereo"
|
|
# DSD is silly, but I still <3 it.
|
|
case $samplerate in
|
|
dsd64)
|
|
local samplerate="2.822MHz"
|
|
local bitdepth="1"
|
|
dsd="DSD64"
|
|
;;
|
|
dsd128)
|
|
local samplerate="5.644MHz"
|
|
local bitdepth="1"
|
|
dsd="DSD128"
|
|
;;
|
|
dsd256)
|
|
local samplerate="11.288MHz"
|
|
local bitdepth="1"
|
|
dsd="DSD256"
|
|
;;
|
|
dsd512)
|
|
local samplerate="22.576MHz"
|
|
local bitdepth="1"
|
|
dsd="DSD512"
|
|
;;
|
|
*)
|
|
# Converts from Hz to kHz
|
|
local trate="$(echo "scale=1; $samplerate / 1000" | bc)"
|
|
# Drops the trailing zero on sample rates like 192khz
|
|
samplerate="${trate%.0}kHz"
|
|
;;
|
|
esac
|
|
|
|
# Return formatted string - we can't set global variables here so we have to split it out later. Thanks bash!
|
|
echo "${samplerate}/${bitdepth}-bit/${channel_text}|${dsd}"
|
|
}
|
|
|
|
|
|
get_extension() {
|
|
local filepath="$1"
|
|
|
|
# Get just the filename without the path
|
|
local filename="${filepath##*/}"
|
|
|
|
# Extract extension and convert to uppercase
|
|
local extension="${filename##*.}"
|
|
echo "${extension^^}"
|
|
}
|
|
|
|
get_mpd_data() {
|
|
# This calls status and currentsong from mpd. writes result as a variable with it's value
|
|
# performs some sanitization. TODO: Get you a list of what's used.
|
|
# Send commands to mpd
|
|
printf "command_list_begin\r\nstatus\r\ncurrentsong\r\ncommand_list_end\r\n" >&3
|
|
|
|
# Read responses until we get empty line or OK
|
|
while IFS=': ' read -r name value <&3; do
|
|
[[ "$name" == "" ]] && break # Empty line = end of response
|
|
[[ "$name" == "OK" ]] && break
|
|
|
|
# Read each response and convert it in to variable=value
|
|
if [[ -n "$name" && -n "$value" && "$name" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then
|
|
declare -g "$name=$value" # Use -g for global scope - which works here.
|
|
fi
|
|
done
|
|
}
|
|
|
|
sendtokonversation() {
|
|
# Send output to channel and leave
|
|
$_qdbus org.kde.konversation /irc say $SERVER "$TARGET" "$spam"
|
|
|
|
exec 3<&-
|
|
exit
|
|
}
|
|
|
|
# We need (or I needed) non-blocking raw TCP. I don't think MPD has a command to close the client connection. I can send Quit or QUIT; and
|
|
# it works, but only ineractively. Any attempts to automatically script the commands to nc fail. It's like it doesn't care it saw 5 commands
|
|
# before quit...sent in order...or even in command list; you'll get the OK MPD banner and nothing. But this trick right here doesn't care.
|
|
# It's just raw TCP directly in shell. All I have to do is remember to read from it.
|
|
exec 3<>/dev/tcp/localhost/6600
|
|
|
|
# Clears the connection string from the buffer
|
|
read -r greeting <&3
|
|
|
|
# Control MPD
|
|
# If we're just sending a command, we can just do it here without polling for data.
|
|
#
|
|
if [[ -n "$COMMAND" ]]; then
|
|
printf "$COMMAND\r\n" >&3
|
|
read -r response <&3
|
|
if [[ $response != "OK" ]]; then
|
|
$_qdbus org.kde.konversation /irc error "mpd: $response"
|
|
fi
|
|
exec 3<&-
|
|
exit
|
|
fi
|
|
|
|
# It's all a giant work around for the fact format_audio can't set globals!
|
|
#
|
|
# Get the data from MPD
|
|
get_mpd_data
|
|
case $state in
|
|
stop)
|
|
spam="/me mpd: Not Playing"
|
|
sendtokonversation
|
|
;;
|
|
pause)
|
|
Artist="[Paused] $Artist"
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
|
|
# Send $audio to format_audio so it can do it's magic. Also is here now due to variable hack.
|
|
audio_result=$(format_audio $audio)
|
|
# Splits audio_result since we couldn't directly set variables from the function. For some reason. I hate bash.
|
|
format_part="${audio_result%|*}" # Everything before the |
|
|
dsd_part="${audio_result#*|}" # Everything after the |
|
|
|
|
# Literally determines if it should display DSD, the extension, or DSD/SuperAudioCD
|
|
fileext=$(get_extension "$file")
|
|
if [[ -z "$dsd_part" ]]; then
|
|
codec_result="$fileext"
|
|
elif [[ -n "dsd_part" && "$fileext" == "ISO" ]]; then
|
|
codec_result="$dsd_part/Super Audio CD"
|
|
else
|
|
codec_result="$dsd_part"
|
|
fi
|
|
|
|
|
|
spam="/me mpd: $Artist - $Title (From: $Album) [$(seconds_to_mmss $elapsed)/$(seconds_to_mmss $duration) | $format_part | $bitrate kbps | $codec_result]"
|
|
|
|
sendtokonversation
|