#!/data/data/com.termux/files/usr/bin/sh
export PATH="/data/data/com.termux/files/usr/opt/ani-cli/bin${PATH:+:}$PATH"

version_number="5.0.0"

# UI

# shellcheck disable=SC2086
# $1 = prompt, $2 = multi select flag (for fzf/rofi), $3 = extra flags by user
menu() {
    case "$menu_program" in
        fzf) fzf --reverse --cycle --prompt "$1" $2 $3 ;;
        rofi) rofi -sort -dmenu -i -p "$1" $2 $3 ;;
        dmenu) dmenu -l 20 -p "$1" $3 ;;
        *) "$menu_program" $3 "$1" ;;
    esac
}

# provide menu. input format is either (ep_list) or (number \t anime_id \t anime_name)
nth() {
    _stdin=$(cat -)
    [ -z "$_stdin" ] && return 1
    _line_count="$(printf "%s\n" "$_stdin" | wc -l | tr -d "[:space:]")"
    [ "$_line_count" -eq 1 ] && printf "%s" "$_stdin" | cut -f 2,3 && return 0
    _prompt="$1"
    [ $# -ne 1 ] && _multi_flag="$2"
    _line=$(printf "%s" "$_stdin" | cut -f 1,3 | tr '\t' ' ' | menu "$_prompt" "$_multi_flag" "$menu_extra_flags" | cut -d " " -f 1)
    _line_start=$(printf "%s" "$_line" | head -n 1)
    _line_end=$(printf "%s" "$_line" | tail -n 1)
    [ -n "$_line" ] || return 1
    if [ "$_line_start" = "$_line_end" ]; then
        printf "%s" "$_stdin" | grep -E '^'"${_line}"'($|[[:space:]])' | cut -f 2,3 || return 1
    else
        printf "%s" "$_stdin" | sed -n '/^'"${_line_start}"'$/,/^'"${_line_end}$"'/p' || return 1
    fi
}

die() {
    printf "\33[2K\r\033[1;31m%s\033[0m\n" "$*" >&2
    exit 1
}

info() {
    printf "\33[2K\r\033[1;34m%s\033[0m\n" "$*"
}

help_info() {
    printf "
    Usage:
    %s [options] [query]
    %s [query] [options]
    %s [options] [query] [options]

    Options:
      -c, --continue
        Continue watching from history
      -d, --download
        Download the video instead of playing it
      -D, --delete
        Delete history
      -l, --logview
        Show logs
      -s, --syncplay
        Use Syncplay to watch with friends
      -S, --select-nth
        Select nth entry
      -q, --quality
        Specify the video quality
      -v, --vlc
        Use VLC to play the video
      -V, --version
        Show the version of the script
      -h, --help
        Show this help message and exit
      -e, --episode, -r, --range
        Specify the number of episodes to watch
      --dub
        Play dubbed version
      --rofi
        Use rofi instead of fzf for the interactive menu
      --dmenu
        Use dmenu instead of fzf for the interactive menu
      --skip
        Use ani-skip to skip the intro of the episode (mpv only)
      --no-detach
        Don't detach the player (useful for in-terminal playback, mpv only)
      --exit-after-play
        Exit the player, and return the player exit code (useful for non interactive scenarios)
      -N, --nextep-countdown
        Display a countdown to the next episode
      -U, --update
        Update the script
    Some example usages:
      %s -q 720p banana fish
      %s --skip -S 2 one piece
      %s -d -e 2 cyberpunk edgerunners
      %s --vlc cyberpunk edgerunners -q 1080p -e 4
      %s blue lock -e 5-6
      %s -e \"5 6\" blue lock
    \n" "${0##*/}" "${0##*/}" "${0##*/}" "${0##*/}" "${0##*/}" "${0##*/}" "${0##*/}" "${0##*/}" "${0##*/}"
    exit 0
}

version_info() {
    printf "%s\n" "$version_number"
    exit 0
}

# Bookkeeping

update_script() {
    info "[branch:$branch] Checking for Update.."
    update="$($curl_exe --fail-with-body -sL -A "$agent" "https://raw.githubusercontent.com/pystardust/ani-cli/$branch/ani-cli")" || die "[branch:$branch] Connection error: $update"
    new_version="$(printf "%s" "$update" | sed -nE 's|^version_number="([^"]+)"$|\1|p')"
    [ -z "$new_version" ] && die "[branch:$branch] Invalid response."
    printf "%s" "$update" | grep -q "^version_number" || die "[branch:$branch] Invalid response."
    update="$(printf "%s\n" "$update" | diff -u "$0" -)"
    if [ -z "$update" ]; then
        info "[branch:$branch] Script is up to date :) ($version_number)"
    else
        if printf "%s\n" "$update" | patch "$0" -; then
            info "[branch:$branch] Updated: $version_number -> $new_version"
        else
            die "[branch:$branch] Failed to update. Read the above line!"
        fi
    fi
    exit 0
}

# checks if dependencies are present
dep_ch() {
    command -v "$1" >/dev/null || die "Program $1 not found. Please install it."
}

# checks for deps in order and returns the first available. format is "prog_a,prog_b,prog_c"
dep_ch_failover() {
    [ -z "$1" ] && return 1
    prog=$(printf "%s" "$1" | cut -d "," -f 1)
    rest=$(printf "%s" "$1" | cut -s -d "," -f 2-)
    command -v "$prog" >/dev/null 2>&1 && printf "%s" "$prog" && return 0
    [ -e "$prog" ] && printf "%s" "$prog" && return 0
    dep_ch_failover "$rest"
}

cleanup() {
    tput sgr0               # clears colors
    rm -f "${histfile}.new" # remove temp logfile
}

# SCRAPING

#shellcheck disable=SC2086
anidb_curl() {
    $curl_exe -sL -A "$agent" --max-time 10 $cipher_flag "$@"
}

# search the query and give results. format is (id \t name)
anidb_search() {
    #shellcheck disable=SC2059
    _page="$(anidb_curl "$(printf "$search_api" "$1")" | tr '\n' ' ' | sed 's|<a href|\n<a href|g')"
    if printf "%s" "$_page" | grep -qi "Just a moment"; then
        [ "$curl_exe" = "curl" ] && die "Blocked by cloudflare. Try installing curl-impersonate"
        die "Blocked by cloudflare."
    fi
    printf "%s" "$_page" | sed -nE 's|.*anime/([a-z0-9-]+-[0-9]+)".*alt="([^"]+)".*|\1\t\2|p' | sed -e "s|&#039;|'|g" -e 's|&quot;|"|g'
}

# extract mal_id and seasons metadata
anidb_desc() {
    #shellcheck disable=SC2059
    _page="$(anidb_curl "$(printf "$desc_api" "$1")" | tr '\n' ' ' | sed 's|<a href|\n<a href|g')"
    mal_id="$(printf "%s" "$_page" | sed -nE 's|.*https://myanimelist.net/anime/([0-9]+)/.*|\1|p')"
    seasons="$(printf "%s" "$_page" | sed -n '/>Seasons</,/>Details</p' | sed -nE 's|.*anime/([^"]+-[0-9]+)"[^>]*title="([^"]+)".*|\1\t\2|p' | sed -e "s|&#039;|'|g")"
    [ -n "$seasons" ] && seasons_option="\nchange_season"
}

# get the episodes list of the selected anime. format is (id \t ep_no)
anidb_episodes() {
    #shellcheck disable=SC2059
    _page="$(anidb_curl "$(printf "$episodes_api" "${1##*-}")")"
    printf "%s" "$_page" | sed 's|},{|}\n{|g' | sed -nE 's|.*"id":([0-9]+).*"number":([0-9]+).*|\1\t\2|p'
}

# extract the individual m3u8 links from response of embed urls
anidb_m3u8() {
    _ep_id=$(printf "%s" "$episode_maps" | sed -nE "s|^([0-9]+)\t${1}$|\1|p")
    _lang="jpn"
    [ "$2" = "dub" ] && _lang="eng"
    #shellcheck disable=SC2059
    _page="$(anidb_curl "$(printf "$m3u8_api" "${_ep_id}")")"
    _embed="$(printf "%s" "$_page" | sed 's|},{|}\n{|g' | sed -nE 's|.*'"${_lang}"'.*embed_url":"([^"]+)".*|\1|p' | sed 's|\\/|/|g' | head -n 1)"
    [ -z "$_embed" ] && return 1
    _embed_page="$(anidb_curl "$_embed")"
    _m3u8_master="$(printf "%s" "$_embed_page" | sed -nE "s|.*file: '([^']*)'.*|\1|p" | head -n 1)"
    anidb_curl "${_m3u8_master}" | sed 's|^#EXT-X-STREAM.*x||g; s|,.*|p|g; /^#/d; $!N; s|\n| >|;/EXT-X-I-FRAME/d'
}

# select the quality according to the setting
select_quality() {
    case "$1" in
        best) _result=$(printf "%s" "$links" | head -n 1) ;;
        worst) _result=$(printf "%s" "$links" | grep -E '^[0-9]{3,4}' | tail -n 1) ;;
        *) _result=$(printf "%s" "$links" | grep -m 1 "$1") ;;
    esac
    [ -z "$_result" ] && printf "\33[2K\r\033[1;33m%s\033[0m\n" "$1 not found, defaulting to best" >&2 && _result=$(printf "%s" "$links" | head -n 1)

    video_link=$(printf "%s" "$_result" | cut -d ">" -f 2)
}

# gets embed url, collects direct links and selects one with desired quality into $episode
get_video_link() {
    links=$(anidb_m3u8 "$ep_no" "$mode" | sort -g -r -s)
    [ -z "$links" ] && die "No sources found for $mode!"
    info "anidb.app links fetched"
    select_quality "$quality"
    # should never trigger but just in case
    if printf "%s" "$ep_list" | grep -q "^$ep_no$"; then
        [ -z "$video_link" ] && die "Episode is released, but no valid sources!"
    else
        [ -z "$video_link" ] && die "Episode not released!"
    fi
}

# provide countdown for the next episode release both sub and dub
time_until_next_ep() {
    animeschedule="https://animeschedule.net"
    _query="$(printf "%s" "$*" | tr ' ' '+')"
    $curl_exe -s -G "$animeschedule/api/v3/anime" --data "q=${_query}" | sed 's|},{"id"|\n|g' | while read -r _entry; do
        _route=$(printf "%s" "$_entry" | sed -nE 's|.*"route":"([^"]*)",.*|\1|p')
        _eng_title=$(printf '%s' "$_entry" | sed -nE 's|.*"english":"([^"]*)".*|\1|p')
        [ -z "$_eng_title" ] && _eng_title=$(printf '%s' "$_entry" | sed -nE 's|.*,"title":"([^"]*)".*|\1|p')
        [ -z "$_eng_title" ] && _eng_title="N/A"
        _jpn_title=$(printf '%s' "$_entry" | sed -nE 's|.*"romaji":"([^"]*)".*|\1|p')
        [ -z "$_jpn_title" ] && _jpn_title="N/A"
        _status=$(printf '%s' "$_entry" | sed -nE 's|.*"status":"([^"]*)".*|\1|p')
        [ -z "$_status" ] && _status="Unknown"

        case "$_status" in
            Ongoing) _color="33" ;;
            Finished) _color="32" ;;
            *) _color="36" ;;
        esac

        printf "Eng: %s\n" "$_eng_title"
        printf "Jpn: %s\n" "$_jpn_title"
        printf "Status: \033[1;%sm%s\033[0m\n" "$_color" "$_status"

        if [ "$_status" != "Finished" ]; then
            _page="$($curl_exe -s "$animeschedule/anime/$_route")"
            _sub_ep=$(printf "%s" "$_page" | sed -nE 's|.*release-time-type-subs"[^>]*><span class="release-time-episode-number">Episode ([0-9]+)</span>.*|\1|p' | head -n 1)
            _dub_ep=$(printf "%s" "$_page" | sed -nE 's|.*release-time-type-dub"[^>]*><span class="release-time-episode-number">Episode ([0-9]+)</span>.*|\1|p' | head -n 1)
            _sub_countdown=$(printf "%s" "$_page" | sed -nE 's|.*class="countdown-time" datetime="([^"]*)".*|\1|p' | head -n 1)
            _dub_countdown=$(printf "%s" "$_page" | sed -nE 's|.*class="countdown-time countdown-time-dub" datetime="([^"]*)".*|\1|p' | head -n 1)

            [ -n "$_sub_ep" ] && [ -n "$_sub_countdown" ] &&
                printf "Next Sub: Episode %s in \033[1;%sm%s\033[0m\n" "$_sub_ep" "$_color" "$_sub_countdown" || printf "Next Sub: N/A\n"
            [ -n "$_dub_ep" ] && [ -n "$_dub_countdown" ] &&
                printf "Next Dub: Episode %s in \033[1;%sm%s\033[0m\n" "$_dub_ep" "$_color" "$_dub_countdown" || printf "Next Dub: N/A\n"
        fi
        printf "\n"
    done
    exit 0
}

# HISTORY

backup_old_hist() {
    backupfile="${histfile}.v4"
    while IFS="	" read -r ep_no anime_id anime_title; do
        case "$anime_id" in
            *-*) printf "%s\t%s\t%s\n" "$ep_no" "$anime_id" "$anime_title" >>"${histfile}.new" ;;
            *) printf "%s\t%s\t%s\n" "$ep_no" "$anime_id" "$anime_title" >>"$backupfile" ;;
        esac
    done <"$histfile"
    mv "${histfile}.new" "$histfile"
}

process_hist_entry() {
    ep_list=$(anidb_episodes "$anime_id" | cut -f 2)
    ep_no=$(printf "%s" "$ep_list" | sed -n "/^${ep_no}$/{n;p;}") 2>/dev/null
    [ -n "$ep_no" ] && printf "%s\t%s - episode %s\n" "$anime_id" "$anime_title" "$ep_no"
}

update_history() {
    if grep -q "	${anime_id}	" "$histfile"; then
        # escape sed special chars in replacement: & and \ and delimiter |
        safe_title=$(printf "%s" "$anime_title" | sed 's|[&\|]|\\&|g')
        sed -E "s|^[^	]+	${anime_id}	[^	]+$|${ep_no}	${anime_id}	${safe_title}|" "$histfile" >"${histfile}.new"
    else
        cp "$histfile" "${histfile}.new"
        printf "%s\t%s\t%s\n" "$ep_no" "$anime_id" "$anime_title" >>"${histfile}.new"
    fi
    mv "${histfile}.new" "$histfile"
}

# PLAYING

# shellcheck disable=SC2086
# $1 = video link, $2 = video name, $3 = extra flags
download() {
    command -v "yt-dlp" >/dev/null && yt-dlp "$1" --no-skip-unavailable-fragments --fragment-retries infinite -N 16 -o "$download_dir/$2.mp4" $3 && return 0
    ffmpeg -extension_picky 0 -loglevel error -stats -i "$1" -c copy "$download_dir/$2.mp4" $3
}

play_episode() {
    [ "$log_episode" = 1 ] && [ "$player_function" != "debug" ] && [ "$player_function" != "download" ] && command -v logger >/dev/null && logger -t ani-cli "${anime_title} ${ep_no}"
    [ "$skip_intro" = 1 ] && skip_flag="$(ani-skip -i "$mal_id" -e "$canon_ep_no")"
    [ -z "$video_link" ] && get_video_link
    # wait for the previous player to close (in range selection)
    wait
    # shellcheck disable=SC2086
    case "$player_function" in
        debug) printf "All links:\n%s\nSelected link:\n%s\n" "$links" "$video_link" ;;
        android_mpv) nohup am start --user 0 -a android.intent.action.VIEW -d "$video_link" -n is.xyz.mpv/.MPVActivity -e "title" "${anime_title} Episode ${ep_no}" $player_extra_flags >/dev/null 2>&1 & ;;
        android_vlc) nohup am start --user 0 -a android.intent.action.VIEW -d "$video_link" -n org.videolan.vlc/org.videolan.vlc.gui.video.VideoPlayerActivity -e "title" "${anime_title} Episode ${ep_no}" $player_extra_flags >/dev/null 2>&1 & ;;
        "$HOME"/.local/share/flatpak/app/io.mpv/Mpv/) flatpak run io.mpv.Mpv $skip_flag $player_extra_flags --force-media-title="${anime_title} Episode ${ep_no}" "$video_link" >/dev/null 2>&1 & ;;
        *mpv*)
            if [ "$no_detach" = 0 ]; then
                nohup $player_function $skip_flag $player_extra_flags --force-media-title="${anime_title} Episode ${ep_no}" "$video_link" >/dev/null 2>&1 &
            else
                $player_function $skip_flag $player_extra_flags --force-media-title="${anime_title} Episode ${ep_no}" "$video_link"
                mpv_exitcode=$?
                [ "$exit_after_play" = 1 ] && [ -z "$_range" ] && exit "$mpv_exitcode"
            fi
            ;;
        *iina*)
            if pgrep -f "IINA" >/dev/null 2>&1; then
                # omit --keep-running when an IINA instance exists to prevent hanging
                nohup $player_function $player_extra_flags --no-stdin --mpv-force-media-title="${anime_title} Episode ${ep_no}" "$video_link" >/dev/null 2>&1 &
            else
                nohup $player_function $player_extra_flags --no-stdin --keep-running --mpv-force-media-title="${anime_title} Episode ${ep_no}" "$video_link" >/dev/null 2>&1 &
            fi
            ;;
        *vlc*) nohup $player_function $player_extra_flags --play-and-exit --meta-title="${anime_title} Episode ${ep_no}" "$video_link" >/dev/null 2>&1 & ;;
        *yncpla*) nohup $player_function $player_extra_flags "$video_link" -- --force-media-title="${anime_title} Episode ${ep_no}" >/dev/null 2>&1 & ;;
        download) "$player_function" "$video_link" "${anime_title} Episode ${ep_no}" $player_extra_flags ;;
        catt) nohup catt cast $player_extra_flags "$video_link" >/dev/null 2>&1 & ;;
        iSH)
            printf "\033]8;;vlc://%s\a~~~~~~~~~~~~~~~~~~~~\n~ Tap to open VLC ~\n~~~~~~~~~~~~~~~~~~~~\033]8;;\a\n" "$video_link"
            sleep 5
            ;;
        *) nohup $player_function $player_extra_flags "$video_link" >/dev/null 2>&1 & ;;
    esac
    replay="$video_link"
    unset video_link
    update_history
    [ "$menu_program" != "fzf" ] && wait
}

play() {
    _start=$(printf "%s" "$ep_no" | grep -Eo '^(-1|[0-9]+(\.[0-9]+)?)')
    _end=$(printf "%s" "$ep_no" | grep -Eo '(-1|[0-9]+(\.[0-9]+)?)$')
    [ "$_start" = "-1" ] && ep_no=$(printf "%s" "$ep_list" | tail -n 1) && unset _start
    [ -z "$_end" ] || [ "$_end" = "$_start" ] && unset _start _end
    [ "$_end" = "-1" ] && _end=$(printf "%s" "$ep_list" | tail -n 1)
    _line_count=$(printf "%s\n" "$ep_no" | wc -l | tr -d "[:space:]")
    if [ "$_line_count" != 1 ] || [ -n "$_start" ]; then
        [ -z "$_start" ] && _start=$(printf "%s\n" "$ep_no" | head -n 1)
        [ -z "$_end" ] && _end=$(printf "%s\n" "$ep_no" | tail -n 1)
        _range=$(printf "%s\n" "$ep_list" | sed -nE "/^${_start}\$/,/^${_end}\$/p")
        [ -z "$_range" ] && die "Invalid range!"
        for i in $_range; do
            tput clear
            ep_no=$i
            canon_ep_no="$(printf "%s" "$ep_list" | sed -n "/^${ep_no}$/=")"
            info "Playing episode $ep_no..."
            [ "$i" = "$_end" ] && unset _range
            play_episode
        done
    else
        printf "%s" "$ep_list" | grep -q "^$ep_no$" || die "Invalid episode!"
        canon_ep_no="$(printf "%s" "$ep_list" | sed -n "/^${ep_no}$/=")"
        play_episode
    fi
    # moves up to stored position and deletes to end
    [ "$player_function" != "debug" ] && [ "$player_function" != "download" ] && tput rc && tput ed
}

# MAIN

# setup
base_api="https://anidb.app"
search_api="${base_api}/browse?q=%s"
# search_api_alt="${base_api}/search/suggestions?q=%s"
desc_api="${base_api}/anime/%s"
episodes_api="${base_api}/api/frontend/anime/%s/episodes"
m3u8_api="${base_api}/api/frontend/episode/%s/languages"

ciphers='ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305'
tls13_ciphers='TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256'
agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"

mode="${ANI_CLI_MODE:-sub}"
download_dir="${ANI_CLI_DOWNLOAD_DIR:-.}"
log_episode="${ANI_CLI_LOG:-1}"
quality="${ANI_CLI_QUALITY:-best}"

curl_exe=$(dep_ch_failover "curl_firefox135,curl_chrome136,curl_chrome116,curl_ff117,curl") || die "Program curl not found"

case "$(uname -a | cut -d " " -f 1,3-)" in
    *Darwin*)
        cipher_flag="--ciphers $ciphers --tls13-ciphers $tls13_ciphers"
        player_function="${ANI_CLI_PLAYER:-$(dep_ch_failover "iina,/Applications/IINA.app/Contents/MacOS/iina-cli,mpv,vlc")}" || die 'No player found. Looked for iina, mpv and vlc'
        ;;                                                            # mac OS
    *ndroid*) player_function="${ANI_CLI_PLAYER:-android_mpv}" ;;     # Android OS (termux)
    *MINGW* | *WSL2*) player_function="${ANI_CLI_PLAYER:-mpv.exe}" ;; # Windows OS
    *ish*)
        player_function="${ANI_CLI_PLAYER:-iSH}"
        curl_exe=$(dep_ch_failover "curl_safari260_ios,$curl_exe")
        ;;                                                                                                                                                              # iOS (iSH)
    *) player_function="${ANI_CLI_PLAYER:-$(dep_ch_failover "mpv,$HOME/.local/share/flatpak/app/io.mpv/Mpv/,vlc")}" || die 'No player found. Looked for mpv and vlc' ;; # Linux OS
esac

player_extra_flags="${ANI_CLI_PLAYER_FLAGS:-""}"
no_detach="${ANI_CLI_NO_DETACH:-0}"
exit_after_play="${ANI_CLI_EXIT_AFTER_PLAY:-0}"
skip_intro="${ANI_CLI_SKIP_INTRO:-0}"
menu_program="${ANI_CLI_MENU:-fzf}"
menu_extra_flags="${ANI_CLI_MENU_FLAGS:-""}"

# not opening from a terminal
if [ ! -t 0 ]; then
    command -v dmenu >/dev/null && menu_program=dmenu
    command -v rofi >/dev/null && menu_program=rofi
fi

hist_dir="${ANI_CLI_HIST_DIR:-${XDG_STATE_HOME:-$HOME/.local/state}/ani-cli}"
[ ! -d "$hist_dir" ] && mkdir -p "$hist_dir"
histfile="$hist_dir/ani-hsts"
[ ! -f "$histfile" ] && : >"$histfile"

source="${ANI_CLI_DEFAULT_SOURCE:-search}"
branch="${ANI_CLI_BRANCH:-master}"

while [ $# -gt 0 ]; do
    case "$1" in
        -v | --vlc)
            case "$(uname -a | cut -d " " -f 1,3-)" in
                *ndroid*) player_function="android_vlc" ;;
                MINGW* | *WSL2*) player_function="vlc.exe" ;;
                *ish*) player_function="iSH" ;;
                *) player_function="vlc" ;;
            esac
            ;;
        -s | --syncplay)
            case "$(uname -s)" in
                Darwin*) player_function="/Applications/Syncplay.app/Contents/MacOS/syncplay" ;;
                MINGW* | *Msys)
                    export PATH="$PATH":"/c/Program Files (x86)/Syncplay/"
                    player_function="syncplay.exe"
                    ;;
                *) player_function="syncplay" ;;
            esac
            ;;
        -q | --quality)
            [ $# -lt 2 ] && die "missing argument!"
            quality="$2"
            shift
            ;;
        -S | --select-nth)
            [ $# -lt 2 ] && die "missing argument!"
            index="$2"
            shift
            ;;
        -c | --continue) source=history ;;
        -d | --download)
            player_function=download
            ;;
        -D | --delete)
            : >"$histfile"
            exit 0
            ;;
        -l | --logview)
            case "$(uname -s)" in
                Darwin*) log show --predicate 'process == "logger"' ;;
                Linux*) journalctl -t ani-cli ;;
                *) die "Logger not implemented for your platform" ;;
            esac
            exit 0
            ;;
        -V | --version) version_info ;;
        -h | --help) help_info ;;
        -e | --episode | -r | --range)
            [ $# -lt 2 ] && die "missing argument!"
            ep_no="$2"
            shift
            ;;
        --dub) mode="dub" ;;
        --no-detach) no_detach=1 ;;
        --exit-after-play) exit_after_play=1 && no_detach=1 ;;
        --rofi) menu_program=rofi ;;
        --dmenu) menu_program=dmenu ;;
        --skip) skip_intro=1 ;;
        -N | --nextep-countdown) source=nextep ;;
        -U | --update)
            dep_ch "patch"
            branch="${2:-$branch}"
            update_script
            ;;
        *) query="$(printf "%s" "$query $1" | sed 's|^ ||;s| |+|g')" ;;
    esac
    shift
done

[ "$menu_program" = "fzf" ] && menu_multi_flag="-m"
[ "$menu_program" = "rofi" ] && menu_multi_flag="-multi-select"

info "Checking dependencies..."
dep_ch "sed"
dep_ch "grep"
[ "$skip_intro" = 1 ] && dep_ch "ani-skip"
dep_ch "$menu_program" # TODO: use dep_ch_failover to iterate through options

case "$player_function" in
    debug) ;;
    download) dep_ch_failover "yt-dlp,ffmpeg" >/dev/null || die 'Neither yt-dlp nor ffmpeg found' ;;
    android*) printf "\33[2K\rChecking of players on Android is disabled.\n" ;;
    *iSH*) printf "\33[2K\rChecking of players on iOS is disabled\n" ;;
    *) dep_ch "$player_function" ;;
esac

# idk where to put this, so I put it here...
trap 'cleanup; exit 1' INT HUP TERM

# searching
case "$source" in
    history)
        backup_old_hist
        anime_list=$(while read -r ep_no anime_id anime_title; do process_hist_entry & done <"$histfile")
        wait
        [ -z "$anime_list" ] && die "No unwatched series in history!"
        [ -z "${index##*[!0-9]*}" ] && anime_id=$(printf "%s" "$anime_list" | nl -w 2 | sed 's/^[[:space:]]//' | nth "Select anime: " | cut -f 1)
        [ -z "${index##*[!0-9]*}" ] || anime_id=$(printf "%s" "$anime_list" | sed -n "${index}p" | cut -f 1)
        [ -z "$anime_id" ] && exit 1
        anime_title=$(printf "%s" "$anime_list" | grep "^$anime_id	" | cut -f 2 | sed 's| - episode.*||')
        anidb_desc "$anime_id" || true
        episode_maps="$(anidb_episodes "$anime_id")"
        ep_list="$(printf "%s" "$episode_maps" | cut -f 2)"
        ep_no=$(printf "%s" "$anime_list" | grep "^$anime_id	" | sed -nE 's/.*- episode (.+)$/\1/p')
        ;;
    *)
        if [ "$menu_program" = "fzf" ]; then
            while [ -z "$query" ]; do
                printf "\33[2K\r\033[1;36mSearch anime: \033[0m" && read -r query
            done
        else
            [ -z "$query" ] && query=$(: | menu "Search anime: " "" "$menu_extra_flags")
            [ -z "$query" ] && exit 1
        fi
        # for checking new releases by specifying anime name
        [ "$source" = "nextep" ] && time_until_next_ep "$query"

        query=$(printf "%s" "$query" | sed 's| |+|g')

        anime_list=$(anidb_search "$query")
        [ -z "$anime_list" ] && die "No results found!"
        [ "$index" -eq "$index" ] 2>/dev/null && result=$(printf "%s" "$anime_list" | sed -n "${index}p")
        [ -z "$index" ] && result=$(printf "%s" "$anime_list" | nl -w 2 | sed 's/^[[:space:]]//' | nth "Select anime: ")
        [ -z "$result" ] && die "Invalid anime selection"
        anime_title="$(printf "%s" "$result" | cut -f 2)"
        anime_id="$(printf "%s" "$result" | cut -f 1)"
        anidb_desc "$anime_id" || true
        episode_maps="$(anidb_episodes "$anime_id")"
        ep_list="$(printf '%s' "$episode_maps" | cut -f 2)"
        [ -z "$ep_no" ] && ep_no=$(printf "%s" "$ep_list" | nth "Select episode: " "$menu_multi_flag")
        [ -z "$ep_no" ] && die "Invalid episode selection"
        ;;
esac

# moves the cursor up one line and clears that line
tput cuu1 && tput el
# stores the position of cursor
tput sc

# playback & loop
play
[ "$player_function" = "download" ] || [ "$player_function" = "debug" ] && exit 0

#shellcheck disable=SC2059
while cmd=$(printf "next\nreplay\nprevious\nselect$seasons_option\nchange_quality\nquit" | nth "Playing episode $ep_no of $anime_title... "); do
    case "$cmd" in
        next) ep_no=$(printf "%s" "$ep_list" | sed -n "/^${ep_no}$/{n;p;}") 2>/dev/null ;;
        replay) video_link="$replay" ;;
        previous) ep_no=$(printf "%s" "$ep_list" | sed -n "/^${ep_no}$/{g;1!p;};h") 2>/dev/null ;;
        select) ep_no=$(printf "%s" "$ep_list" | nth "Select episode: " "$menu_multi_flag") ;;
        change_season)
            new_anime="$(printf "%s" "$seasons" | nl -w 2 | sed 's/^[[:space:]]//' | nth "Select season: ")"
            [ -z "$new_anime" ] && die "Invalid season selection"
            anime_title="$(printf "%s" "$new_anime" | cut -f 2)"
            anime_id="$(printf "%s" "$new_anime" | cut -f 1)"
            anidb_desc "$anime_id" || true
            episode_maps="$(anidb_episodes "$anime_id")"
            ep_list="$(printf '%s' "$episode_maps" | cut -f 2)"
            ep_no=$(printf "%s" "$ep_list" | nth "Select episode: " "$menu_multi_flag")
            [ -z "$ep_no" ] && die "Invalid episode selection"
            ;;
        change_quality)
            new_quality="$(printf "%s" "$links" | menu "Select Quality: " "" "$menu_extra_flags" | cut -d ">" -f 1)"
            [ -z "$new_quality" ] && die "No quality selected"
            select_quality "$new_quality"
            ;;
        *)
            cleanup
            exit 0
            ;;
    esac
    [ -z "$ep_no" ] && die "Out of range"
    play
done

# ani-cli
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Project repository: https://github.com/pystardust/ani-cli
