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