diff --git a/README.md b/README.md index ebe75a4..457bdf7 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # konversation-mpd - an mpd script for the Konversation IRC client -Currently only spams an IRC channel (or msg window) with some stats about what mpd is currently playing using whatever shortcut you assign it to. You can customize the output sent by editing the script; however I haven't generated a list of currently available variables. - -Future plans include doing nice things if you're not in playback mode; as well as basic playback control from within Konversation. +An mpd interface for Konversation. Functions as a scrobbler/announcer for a window, as well as allows control of MPD by passing commands. ## Requirements @@ -11,21 +9,101 @@ Future plans include doing nice things if you're not in playback mode; as well a mpd is obvious. bc is used to do math on sample rates. -## Installation/Usage +## Installation - Make any changes to the formatting of the output you wish, and copy the script to wherever Konversation looks for scripts on your system. - Assign `/exec mpdirc` to an alias of your choosing. -- Start playback in mpd. -- Issue your alias in the channel you wish to spam. -- Annoy your friends! -That's it. +## Usage + +The script functions as both a ~~spa~~announcer and as an MPD client. We'll assume you assigned it to `/mpd` in Konversation. + +### Playback Announcer + +Simply feeding `/mpd` will ~~spa~~announce your plaback information to the current window. + +`/me mpd: Song Title - Artist (From: Album) [ elapsed/duration | audioformat | bitrate | codec]` + +`[Paused]` will be appended to the song title if in paused state. `mpd: Not Playing` will be shown if in stop state. + +The format in which this is sent can be modified in the script itself. Simply rearrange and/or remove information you don't want. A list of variables are provided in this readme in case you want to add something. + +### MPD client + +The script can function as a "full" client by feeding commands/arguments to `/mpd`. Anything you send to the script will be passed to mpd as a command. + +``` +play [position] - Starts playback. Optional: Position to start playback at. Otherwise, uses current position. +pause - Toggles Pause. +next - skip track +previous - go back a track + +``` +These are just the commonly used examples. A full set of commands are available in mpd's command reference. If the command fails, the mpd error is returned to the chat window. If you want to type out the stupid long command to add a file to your playlist; it will take it and pass it. + +But it's mostly to be able to go `/mpd next`. ## How It Works The script talks to mpd (directly) using a file-handler to /dev/tcp/localhost/6600. After dropping it's banner response, we send it the `status` and `currentsong` commands; mpd responds with a ton of fields. We convert all of those fields in to a variable=value. We then check if the format is DSD or a sample rate and either specify a rate or divide by 1000. The extension of the file is obtained and some logic is done to determine which codec information we're going to display. We slap all of this in to a variable formatted the way we want; and send it to koversation over dBus. +Arguments passed to the script beyond Konversation's server and target are passed directly to mpd as a client command. + ## TODO -- List of variables, in case there's something you want I'm not already listing. -- Playback controls: start, stop, pause, skip...all from within IRC. +- ~~List of variables, in case there's something you want I'm not already listing.~~ +- ~~Playback controls: start, stop, pause, skip...all from within IRC.~~ +- Use, test, fix edge cases. + +## CHANGES + +``` +30-AUG-2025: Initial Release. Only announcer. +31-AUG-2025: Stop/Pause states. Added remote/client features. +``` + +## Variables + +Since mpd reports things in the `name: value` format, it's easy to convert everything in to a script variable. As a result we pull in some additional information that's not used; whether any of it is useful I don't know. I'm just getting a full look at this list myself. + +``` +repeat=0 +random=0 +single=0 +consume=0 +partition=default +playlist=14 +playlistlength=12 +mixrampdb=0 +state=play +song=0 +songid=1 +time=65:176 +elapsed=64.992 +bitrate=5644 # kbps +duration=176.360 +audio=44100:16:2 (dsdxx:2) # DSD content does not report a bit-depth, and it reports it's DSD rate as sample rate. Please don't use this directly. +nextsong=1 +nextsongid=2 +file=Path/To/File.ext +Added=2014-10-31T00:26:24Z +Track=1 # This is album track title. +Date=2014 +Album=Album Title +Artist=Artist +Title=Track Title +Performer=Performer +Time=176 +duration=176.360 +Pos=0 +Id=1 +``` + +Additionally, here are some script-specific variables you can use in the output: + +``` +audio_result - This generates samplerate khz/bitdepth-bit/stereo|format_part. It divides the sample rate by 1000, formats it from : to /, and it + also handles the DSD formatting. Inserts the MHz sample rate and appends the DSD format_part if it exists. +format_part - The audio format portion of audio_result containing sample rate, bith depth, and stereo. +codec_result - This determines what to show for codec, capitialized file extension or DSD stuff. Also reports Super Audio CD if ISO is detected. +``` diff --git a/mpdirc b/mpdirc index 5b1d494..ecb1033 100644 --- a/mpdirc +++ b/mpdirc @@ -1,8 +1,19 @@ #!/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 @@ -12,6 +23,10 @@ if ! [ "$(which $_qdbus 2> /dev/null)" ]; then fi fi +# Script Functions + +# Converts decimal seconds to "normal" format +# Arguments: seconds (floating point) seconds_to_mmss() { local total_seconds="$1" @@ -26,6 +41,8 @@ seconds_to_mmss() { 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" @@ -34,6 +51,7 @@ format_audio() { # 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" @@ -56,9 +74,10 @@ format_audio() { 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" - dsd="" ;; esac @@ -79,7 +98,9 @@ get_extension() { } get_mpd_data() { - # Send commands +# 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 @@ -87,29 +108,66 @@ get_mpd_data() { [[ "$name" == "" ]] && break # Empty line = end of response [[ "$name" == "OK" ]] && break - # Process the data + # 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 + 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" -# Open non-blocking connection MPD +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 -# Request Data +# 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 -# This is part of the global varible hack junk. +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) -# It splits the result in to new variables +# 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 | -# Generate codec - either extension, DSD??, or DSD64/Super Audio CD. +# Literally determines if it should display DSD, the extension, or DSD/SuperAudioCD fileext=$(get_extension "$file") if [[ -z "$dsd_part" ]]; then codec_result="$fileext" @@ -120,10 +178,6 @@ else fi -# Format output to send to konversation spam="/me mpd: $Artist - $Title (From: $Album) [$(seconds_to_mmss $elapsed)/$(seconds_to_mmss $duration) | $format_part | $bitrate kbps | $codec_result]" -# Spam that IRC channel! -$_qdbus org.kde.konversation /irc say $SERVER "$TARGET" "$spam" - -exec 3<&- +sendtokonversation