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

#!/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