#!/bin/sh

# Depends: GNU getopt, mpv, socat, streamlink, xclip

SOCK="/tmp/umpv-fifo"

help() {
	B=$(tput bold)
	U=$(tput smul)
	N=$(tput sgr0)

	cat << EOF
${B}NAME${N}
	play - mpv playback functions

${B}SYNOPSIS${N}
	${B}play${N} [${U}OPTION${N}] [${U}ARGS${N}...]

${B}DESCRIPTION${N}
	play is a script to manage different mpv viewing bahavior.
	If no ${U}URLS${N} argument is provided, it is read from the clipboard instead.
	The queue option starts a mpv window with a playlist, which all videos of
	subsequent queue calls get added to.

${B}OPTIONS${N}
	${B}-h${N}, ${B}--help${N}
		Display usage message and exit.

	${B}-q${N}, ${B}--quality${N} ${U}QUALITY${N}
		Set the video quality, example: ${U}720p60${N}.

	${B}-f${N}, ${B}--shuffle${N} [${U}URLS${N}...]
		Shuffle audio playlist (disables video playback).

	${B}-u${N}, ${B}--queue${N} [${U}URLS${N}...]
		Add multiple videos to the unique mpv's queue.

	${B}-s${N}, ${B}--stream${N} [${U}URLS${N}...]
		Play video(s) using streamlink.

	${B}-l${N}, ${B}--low-latency${N}
		Enable twitch low-latency mode in streamlink.
EOF
}

# --------------------------------------

qualityFormat() {
	url="$1"

	# Twitch urls dont support fancy matching
	if echo "$url" | grep -q "twitch\.tv"; then
		if [ -z "$quality" ]; then
			echo "Source"
		else
			echo "$quality"
		fi
		return
	fi

	# , separator = download several formats
	# + separator = merge several formats into a single file
	# / separator = or
	if [ -z "$quality" ]; then
		echo "bestvideo[height<=?1080]+bestaudio/best"
	else
		height="$(echo "$quality" | awk -F 'p' '{ print $1 }')"
		fps="$(echo "$quality" | awk -F 'p' '{ print $2 }')"

		format="bestvideo[height<=?$height]"
		if [ -n "$fps" ]; then
			format="${format}[fps<=?$fps]"
		fi
		format="$format+bestaudio/best"

		echo "$format"
	fi
}

play() {
	url="$1"

	notify-send -t 2500 "Loading video: $url"
	setsid -f mpv --no-terminal \
		   --ytdl-format="$(qualityFormat "$url")" \
		   --ytdl-raw-options=add-metadata=,external-downloader=aria2c \
		   "$url"
}

shuffle() {
	urls="$*"

	mpv --no-video --shuffle \
		--ytdl-format='bestaudio[ext=m4a]' \
		--ytdl-raw-options=add-metadata=,external-downloader=aria2c \
		"$urls"
}

queue() {
	urls="$*"

	options="--no-terminal --force-window --input-ipc-server=$SOCK"

	# Create mpv cache directory
	dir="$(dirname "$SOCK")"
	[ ! -d "$dir" ] && mkdir -p "$dir"

	# Delete socket if no umpv is running
	if ! pgrep -f "mpv $options" > /dev/null; then
		rm -f "$SOCK"
	fi

	if [ -S "$SOCK" ]; then
		notify-send -t 2500 "Added video to queue.."
		# Add video to named pipe
		echo "$urls" | awk -v RS=' ' '{ print "raw loadfile "$1" append" }' \
			| socat UNIX-CONNECT:"$SOCK" -
	else
		# Play video
		notify-send -t 2500 "Loading video: $urls"
		# shellcheck disable=2086
		setsid -f mpv $options \
			   --ytdl-format="$(qualityFormat $urls)" \
			   --ytdl-raw-options=add-metadata=,external-downloader=aria2c \
			   $urls
	fi
}

stream() {
	channel="$1"
	quality="$2"
	lowLatency="$3"

	if [ -z "$quality" ]; then
		if ! streamlink --quiet --config /dev/null "$channel"; then
			return 1
		fi

		printf "Select stream quality: "
		read -r quality
	fi

	if [ -z "$lowLatency" ]; then
		arguments="\
			--player-args '--force-window'"
	else
		arguments="\
			--twitch-low-latency \
			--player-args '--force-window --cache=yes --demuxer-max-bytes=750k'"
	fi

	echo "Starting stream $channel @ $quality"
	command="setsid -f streamlink \
		--twitch-disable-hosting \
		--twitch-disable-reruns \
		--player mpv \
		--stream-sorting-excludes '<480p,>=1080p' \
		$arguments \
		$channel $quality > /dev/null 2>&1"
	eval "$command"
}

# Option parsing
# --------------------------------------

script="$(basename "$0")"
parsed="$(getopt --options "hslquf" \
				 --longoptions "help,stream,quality,queue,shuffle" \
				 -n "$script" -- "$@" 2>&1)"
result="$?"

# Exit if invalid option is provided
if [ "$result" -ne 0 ]; then
	echo "$parsed" | head -n 1 >&2
	echo "Try './$script --help' for more information." >&2
	exit 1
fi

eval set -- "$parsed"

streamOption=0
qualityOption=0
lowLatencyOption=0
queueOption=0
shuffleOption=0
while true; do
	case "$1" in
		-h | --help)
			help
			exit
			;;
		-s | --stream)
			streamOption=1
			shift
			;;
		-l | --low-latency)
			lowLatencyOption=1
			shift
			;;
		-q | --quality)
			qualityOption=1
			shift
			;;
		-u | --queue)
			queueOption=1
			shift
			;;
		-f | --shuffle)
			shuffleOption=1
			shift
			;;
		--)
			shift
			break
			;;
		*)
			break
			;;
	esac
done

# Target parsing
# --------------------------------------

# Incompatible flags
result=$((streamOption + queueOption + shuffleOption))
if [ $result -gt 1 ]; then
	echo "Incompatible flags." >&2
	echo "Try './$script --help' for more information." >&2
	exit 1;
fi

# Get quality
if [ $qualityOption -eq 1 ]; then
	quality="$1"
	shift
fi

# Set url to clipboard if none provided
# >>> session=xorg
clip="$(xclip -selection clipboard -out)"
# <<<
# >>> session=wayland
# clip="$(wl-paste)"
# <<<
if [ "$#" -eq 0 ]; then
	eval set -- "$clip"
fi

[ $lowLatencyOption -eq 1 ] && lowLatency="1"

# Execute
# --------------------------------------

if [ $streamOption -eq 1 ]; then
	for url in "$@"; do
		stream "$url" "$quality" "$lowLatency"
	done
elif [ $shuffleOption -eq 1 ]; then
	shuffle "$*"
elif [ $queueOption -eq 1 ]; then
	queue "$*"
else
	if [ "$*" = "" ]; then
		# >>> session=xorg
		play "$(xclip -o)"
		# <<<
		# >>> session=wayland
		# play "$(wl-paste)"
		# <<<
	else
		for url in "$@"; do
			play "$url"
		done
	fi
fi