#!/bin/sh

# shellcheck disable=SC1091,SC1090

#fixed variables
config_file="$HOME/.jellyfin-cli-config"
VERSION="1.0.0"

info() {
	#shellcheck disable=SC2059
	printf "\033[2K\r\033[1;${2:-36}m${1}\033[0m"
}

success() {
	info "$1" "32"
}

ask() {
	info "$1" "33"
}

err() {
	info "$1\n" "31"
}

save_config() {
	if [ -f "$config_file" ] && grep -q "$1" "$config_file"; then
		sed -i "s|$1=.*|$1=$2|g" "$config_file" >/dev/null 2>&1
	else
		#shellcheck disable=SC2059
		printf "$1=$2\n" >>"$config_file"
		sed '/^$/d' "$config_file" >/dev/null 2>&1
	fi
	[ -z "$3" ] && success "$1 Saved in config, to override config values use it as envs\n"
}

auth_quick_connect() {
	info "Generating Quick Connect Code.."
	DEVICE_ID="$(uuidgen)"
	custom_auth='Authorization: MediaBrowser Client="jellyfin-cli", Device="jellyfin-cli", DeviceId="'"$DEVICE_ID"'", Version="'"$VERSION"'"'
	eval "$(curl -s "$JF_URL/QuickConnect/Initiate" -X POST -H "$custom_auth" | sed -nE 's|.*"Secret":"([^"]*)","Code":"([^"]*)",.*|SECRET=\1;CODE=\2|p')"
	info "Your Quick Connect Code: "
	printf '%s\n' "$CODE"
	info "Waiting for you to authorized."
	while curl -s "$JF_URL/QuickConnect/Connect?Secret=$SECRET" -H "$custom_auth" | grep -q '"Authenticated":false'; do
		printf '.'
		sleep 2
	done
	success "Authorized Successfully!!\n"

	# you authenticated YAY
	eval "$(curl -s "$JF_URL/Users/AuthenticateWithQuickConnect" -X POST -H "Content-Type: application/json" --data-raw '{"Secret":"'"$SECRET"'"}' -H "$custom_auth" | sed -nE 's|.*UserId":"([^"]*)".*"AccessToken":"([^"]*)",.*|JF_USER_ID=\1;JF_TOKEN=\2|p')"

	save_config "JF_USER_ID" "$JF_USER_ID"
	save_config "JF_TOKEN" "$JF_TOKEN"
}

check_config_auth() {
	info "Checking Config.."
	[ -f "$config_file" ] || return 1
	for i in JF_USER_ID JF_TOKEN JF_URL; do
		if ! grep -qE "$i=(.+)" "$config_file"; then
			return 1
		fi
	done
	info "Checking Auth..."
	. "$config_file"
	resp=$(curl -s "$JF_URL/Users/Me" -H 'Authorization: MediaBrowser Token="'"$JF_TOKEN"'"' | sed -nE 's|.*"Id":"([^"]*)".*|JF_USER_ID=\1|p')
	[ -z "$resp" ] && save_config "JF_TOKEN" "" "no_output" && return 1
	return 0
}

configure() {
	info "Welcome to Jellyfin CLI script, we will go through some configuration.\n"
	[ -f "$config_file" ] && . "$config_file"
	if ! [ -f "$config_file" ] || ! grep -qE "JF_URL=(.+)" "$config_file"; then
		ask "First, Where is Jellyfin hosted? : "
		read -r JF_URL
		save_config "JF_URL" "$JF_URL"
	fi
	if ! [ -f "$config_file" ] || ! grep -qE "JF_TOKEN=(.+)" "$config_file"; then
		auth_quick_connect
	fi
	if ! [ -f "$config_file" ] || ! grep -qE "JF_USER_ID=(.+)" "$config_file"; then
		eval "$(curl -s "$JF_URL/Users/Me" -H 'Authorization: MediaBrowser Token="'"$JF_TOKEN"'"' | sed -nE 's|.*"Id":"([^"]*)".*|JF_USER_ID=\1|p')"
		save_config "JF_USER_ID" "$JF_USER_ID"
	fi
	unset JF_USER_ID JF_TOKEN CODE SECRET JF_URL
	. "$config_file"
}

mpv_jellyfin() {
	[ -z "$1" ] && return 0
	[ -z "$2" ] && return 0

	success "Playing $2 on mpv"
	url="$JF_URL/Items/$1/Download?api_key=$JF_TOKEN"
	sub="$JF_URL/Videos/$1/$1/Subtitles/0/0/Stream.ass?api_key=$JF_TOKEN"
	! curl -s "$sub" | grep -q "Error processing request" && sub_arg="--sub-file=$sub"
	if uname -o | grep -q 'ndroid'; then
		text="Title: $2\nURL: $url"
		[ -n "$sub_arg" ] && text="$text\nSub URL: $sub"
		#shellcheck disable=SC2059
		printf "\n$text"
		#shellcheck disable=SC2059
		printf "$text" | termux-clipboard-set
		return 0
	fi
	#shellcheck disable=SC2086
	nohup mpv --input-ipc-server="$socket" --start="$((playbackPositionTicks / 10000000))" --force-media-title="$2" "$url" $sub_arg >/dev/null 2>&1 &
	skipPositions=$(curl -s "$JF_URL/Episode/$1/IntroSkipperSegments" -H 'Authorization: MediaBrowser Token="'"$JF_TOKEN"'"' -H "Accept: application/json" | sed 's|}|\n|g' | sed -nE 's|.*"Introduction".*"Start":([^\.,]*).*,"End":([^\.,]*).*|op_start=\1\nop_end=\2|p;s|.*"Credits".*"Start":([^\.,]*).*"End":([^\.,]*).*|ed_start=\1\ned_end=\2|p')
	track_progress "$1"
}

track_progress() {
	\cat <<EOF >"$progress_track_file"
#!/bin/sh

skipPos(){
	[ -z "\$3" ] && printf 1 && return 0
	[ -z "\$4" ] && printf 1 && return 0
	if [ "\$2" -ge "\$3" ] && [ "\$2" -lt "\$4" ]; then
		echo '{"command" :["seek" ,"'"\$4"'","absolute"]}' | socat - "$socket" >/dev/null
		echo '{"command": ["show-text", "'"\$5"'", 3000]}' | socat - "$socket" >/dev/null
		printf 1
		return 0
	fi
	printf 0
}

positionTicks=$playbackPositionTicks
$skipPositions
introSkipped=0
outroSkipped=0
while sleep 5;do
	position=\$(echo '{"command" :["get_property","playback-time"]}' | socat - "$socket" 2>/dev/null | sed -nE 's_.*data":([^,]*).*_\1_p' | tr -d '.' | sed 's|$|0|g')
	[ -z "\$position" ] && break
	positionTicks=\$position
	positionSec=\${position%???????}
	[ "\$introSkipped" -eq 0 ] && introSkipped=\$(skipPos "\$introSkipped" "\$positionSec" "\$op_start" "\$op_end" "Intro Skipped")
	[ "\$outroSkipped" -eq 0 ] && outroSkipped=\$(skipPos "\$outroSkipped" "\$positionSec" "\$ed_start" "\$ed_end" "Outro Skipped")
done
[ -n "\$positionTicks" ] && curl -s "$JF_URL/Users/$JF_USER_ID/PlayingItems/${1}?positionTicks=\$positionTicks" -X DELETE -H 'Authorization: MediaBrowser Token="$JF_TOKEN"' -H 'Content-Type: application/json'
rm "$socket"
rm "\$0"
EOF

	chmod +x "$progress_track_file"
	setsid -f "$progress_track_file"
}

get_data() {
	curl -s "${JF_URL}/$1" -H 'Authorization: MediaBrowser Token="'"$JF_TOKEN"'"' -H "Accept: application/json" | sed 's|\[{|\n|g;s|},{|\n|g' | sed -nE 's|^"Name":"([^"]*)",.*,"Id":"([^"]*)".*"PlaybackPositionTicks":([^,]*),.*Primary":\{?"([^"]*)".*|\2\t\4\t\1\t\3|p' | menu "$2"
}

shows() {
	season=$(get_data "Shows/$id/Seasons?userId=$JF_USER_ID" "Select Season >")
	[ -z "$season" ] && exit 1
	season_title=$(printf "%s" "$season" | cut -f3)
	season_id=$(printf "%s" "$season" | cut -f1)
	episode=$(get_data "Shows/$id/Episodes?seasonId=$season_id&userId=$JF_USER_ID" "Select Episode >")
	[ -z "$episode" ] && exit 1
	episode_title=$(printf "%s" "$episode" | cut -f3)
	episode_id=$(printf "%s" "$episode" | cut -f1)
	title="$title $season_title ep: $episode_title"
	id=$episode_id
	playbackPositionTicks=$(printf '%s' "$episode" | cut -f4)
}

collection() {
	collection=$(get_data "UserViews?userId=$JF_USER_ID" "Select Collection >")

	[ -z "$collection" ] && exit 1
	collection_id=$(printf '%s' "$collection" | cut -f1)
	collection_title=$(printf '%s' "$collection" | cut -f3 | sed 's|.$||g')

	recursive="false"
	[ "$collection_title" = "Movie" ] && recursive="true"

	data=$(get_data "Items?IncludeItemTypes=$collection_title&Recursive=$recursive&ParentId=$collection_id" "Select $collection_title >")
	[ -z "$data" ] && exit 1
	id=$(printf "%s" "$data" | cut -f1)
	title=$(printf "%s" "$data" | cut -f3)
	playbackPositionTicks=$(printf '%s' "$data" | cut -f4)

	case "$collection_title" in
		Show) shows ;;
		Movie) ;; # the id and title already belongs to Movie.
	esac
}

resume() {
	resume=$(get_data "UserItems/Resume?enableImages=true" "Resume >")
	[ -z "$resume" ] && exit 1
	id=$(printf "%s" "$resume" | cut -f1)
	title=$(printf "%s" "$resume" | cut -f3)
	playbackPositionTicks=$(printf '%s' "$resume" | cut -f4)
}

nextUp() {
	nextup=$(get_data "Shows/NextUp?enableTotalRecordCount=true&disableFirstEpisode=false&enableResumable=true" "Next UP >")
	[ -z "$nextup" ] && exit 1
	id=$(printf "%s" "$nextup" | cut -f1)
	title=$(printf "%s" "$nextup" | cut -f3)
	playbackPositionTicks=$(printf '%s' "$nextup" | cut -f4)
}

menu() {
	fzf --prompt="$1" --layout=reverse --border -d'\t' --with-nth=3 --preview="curl -sL '$JF_URL/items/{1}/Images/Primary?fillHeight=450&quality=96' -o - | chafa -f sixels" --preview-window=right,70%
}

check_config_auth || configure

info ""

. "$config_file"

socket="/tmp/${0##*/}-mpvsocket"
progress_track_file="/tmp/${0##*/}-progress"

what_to_watch=$(printf "My Media\nResume\nNext Up" | fzf --prompt="Select >" --layout=reverse --border)

case "$what_to_watch" in
	'My Media') collection ;;
	Resume) resume ;;
	'Next Up') nextUp ;;
esac

mpv_jellyfin "$id" "$title"
