#!/bin/bash # cmusctl # # Allows executing 'cmus-remote' commands and writes the currently # playing song to a file so be consumed by e.g. i3status. SCRIPT_NAME="$(basename -- "$0")" function usage() { echo "Usage: $SCRIPT_NAME [OPTIONS]" echo echo "Options:" echo " -h Display help." echo " -e [COUNT] Run forever, every [COUNT] seconds. Disabled (0) by default." echo " -l Kill other $SCRIPT_NAME processes. Only allowed if running forever." } while getopts ":e:c:lh" arg; do case $arg in e) EVERY=$OPTARG ;; c) COMMAND=$OPTARG ;; l) AQUIRE_LEADER=true ;; h) usage exit 0 ;; :) echo "$SCRIPT_NAME: Must supply an argument to -$OPTARG." >&2 usage exit 1 ;; ?) echo "Invalid option: -${OPTARG}." echo usage exit 2 ;; esac done LOOP=false EVERY="${EVERY:-0}" [[ $EVERY -gt 0 ]] && LOOP=true AQUIRE_LEADER="${AQUIRE_LEADER:-false}" OUTPUT_FILE="/tmp/$SCRIPT_NAME.status" PREV_STATUS="" function multiple_instances_running() { [[ "$(pgrep -f "$SCRIPT_NAME" | grep -cv "^$$$")" -gt 1 ]] || return 1 } function aquire_leader() { echo "Aquiring leadership" if ! [[ "$EVERY" -gt 0 ]]; then echo "ERROR: -e [COUNT] must be a positive integer for leader aquisition." 1>&2 exit 11 fi while read -r pid; do [[ "$pid" == "$$" ]] && continue if ! kill "$pid"; then echo "ERROR: Unable to kill $pid." 1>&2 exit 12 fi done <<<"$(pgrep -f "$SCRIPT_NAME")" echo "Leadership aquired." } function write_status() { local status="$1" # Don't write if there's no update if [[ "$status" != "$PREV_STATUS" ]]; then echo "$status" | tee "$OUTPUT_FILE" killall -SIGUSR1 i3status export PREV_STATUS="$status" else echo "NOCHG" fi ! $LOOP && exit 0 sleep "$EVERY" } function get_field() { local row row="$(grep "^$1 " <<<"$QUERY_RESULT")" echo "${row#"$1 "}" } function get_status() { local tmp status tmp="$(get_field status)" status="$tmp" [ "$tmp" == "playing" ] && status="▶" [ "$tmp" == "paused" ] && status="⏸️" [ "$tmp" == "stopped" ] && status="⏹️" echo $status } function get_progress() { local duration position duration="$(get_field duration)" position="$(get_field position)" if [ -n "$duration" ] && [ -n "$position" ]; then echo "$(((position * 100 / duration * 100) / 100))%" fi } function get_artist_title() { local tag_artist tag_title tag_artist="$(get_field "tag artist")" tag_title="$(get_field "tag title")" if [ -n "$tag_artist" ] && [ -n "$tag_title" ]; then echo "$tag_artist - $tag_title" fi } function get_file_name() { local fn fn="$(get_field file)" fn="${fn##*/}" fn="${fn%.*}" echo "$fn" } if $LOOP && multiple_instances_running; then if $AQUIRE_LEADER; then echo "Other instances have been detected." aquire_leader else echo "ERROR: Other instances are running and leader aquisition not set." 1>&2 exit 10 fi fi # shellcheck disable=SC2086 [ -n "$COMMAND" ] && cmus-remote $COMMAND while true; do QUERY_RESULT="$(cmus-remote --query 2>/dev/null)" [ -z "$QUERY_RESULT" ] && write_status "🎵❌" && continue PROGRESS="$(get_progress)" STATUS="$(get_status)" NAME="$(get_artist_title)" [ -z "$NAME" ] && NAME="$(get_file_name)" OUT="${STATUS^}" [ -n "$NAME" ] && OUT+=" $NAME" [ -n "$PROGRESS" ] && [ "$STATUS" != "⏹️" ] && OUT+=" ($PROGRESS)" write_status "$OUT" done