pystardust / ani-cli

A cli tool to browse and play anime

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

No such file or directory.

DhruvSinha2003 opened this issue · comments

After installing ani-cli and all the dependencies on my Windows 11 machine using scoop, I get this error:
C:\Users\dhruv>ani-cli
/bin/bash: C:\Users\dhruv\scoop\apps\ani-cli\current\ani-cli: No such file or directory

I have reinstalled ani-cli many times and also removed all the scoop files and installed that again.

When I run ani-cli on powershell, i get this error:
PowerShell 7.4.2
PS C:\Users\dhruv> ani-cli
/bin/bash: C:\Users\dhruv\scoop\apps\ani-cli\current\ani-cli: No such file or directory
PS C:\Users\dhruv>

When I run ani-cli on git bash:
dhruv@DhruvSinha MINGW64 ~
$ ani-cli
Checking dependencies...
Search anime: naruto

but it gets stuck here no matter what you enter in the search anime prompt

Only way i got it to work is by going in the scoop shims folder and manually running the ani-cli Windows Command Script

this is what is see in C:\Users\dhruv\scoop\apps\ani-cli\current:
image

  1. In powershell or cmd, what happens when you run ani-cli.cmd?
  2. In git bash, what do you mean by stuck? Can you share a screenshot of what happens after you type naruto Enter?
  3. In git bash, what is the output of curl --version?
  1. In powershell or cmd, what happens when you run ani-cli.cmd?
  2. In git bash, what do you mean by stuck? Can you share a screenshot of what happens after you type naruto Enter?
  3. In git bash, what is the output of curl --version?

Thanks for the reply

image

image
I have pressed enter several times in the git bash above... waiting for a while does not resolve anything either..

image

It looks like there are two problems, one in powershell and one in git bash.

  1. Could you paste your scoop/shims/ani-cli.cmd file here? Open it with notepad and paste the contents here.

  2. If the ani-cli.cmd file's second like begins with @bash, it might be using wsl. You need to make it use Git's bash. Replace @bash with:
    @"C:\Users\dhruv\scoop\apps\git\current\bin\bash.exe" (if you installed git with scoop)
    or
    @"C:\Program Files\Git\bin\bash.exe" (if you installed git manually).

  3. Check if the fix in (2) works in powershell.

  4. I don't know what's going on with the git bash problem. Could it be a readline problem? In Git Bash, could you try running read -r query, then enter "naruto Enter", then print the query variable.
    image
    image

Also, make sure git for windows is up to date.

ani-cli.cmd:
@ rem C:\Users\dhruv\scoop\apps\ani-cli\current\ani-cli
@ bash "C:\Users\dhruv\scoop\apps\ani-cli\current\ani-cli" %*

i added the space after the "@" because it was tagging people

After replacing:
@ rem C:\Users\dhruv\scoop\apps\ani-cli\current\ani-cli
@"C:\Users\dhruv\scoop\apps\git\current\bin\bash.exe" "C:\Users\dhruv\scoop\apps\ani-cli\current\ani-cli" %*

It is working in powershell now!!

I don't need it to work in git bash anymore but just for the sake of understanding the problem:

image

Thank you for your help... I am cool with closing this issue unless you want to debug the bash problem....

It works when you run ani-cli in powershell, right? You shouldn't need to add the .cmd every time.
Also, please keep ani-cli up to date with ani-cli -U instead of scoop update ani-cli until the scoop install script for ani-cli is fixed here.

(Just to note, others on Windows 11 have had trouble with wsl hijacking the script.)

Can you try updating ani-cli in powershell and see if it works in git bash?

It does work with just ani-cli, I am not using ani-cli.cmd

image
:(

Did you edit the ani-cli script? It should work. It works for me on Win11 + pwsh.
Can you paste the .rej reject file in C:\Users\dhruv\scoop\apps\ani-cli\current\?

Try reinstalling ani-cli:

  1. scoop uninstall ani-cli
  2. scoop install ani-cli.
  3. Replace @bash with @"C:\Users\dhruv\scoop\apps\git\current\bin\bash.exe" in the ani-cli.cmd file.
  4. Update ani-cli: ani-cli -U.
ani-cli.rej

--- ani-cli 2024-05-18 18:49:24.438424100 +0530
+++ - 2024-05-20 19:42:34.341551800 +0530
@@ -1,508 +1,508 @@
-#!/bin/sh

-version_number="4.8.6"

-# UI

-external_menu() {

  • rofi "$1" -sort -dmenu -i -width 1500 -p "$2"
    -}

-launcher() {

  • [ "$use_external_menu" = "0" ] && [ -z "$1" ] && set -- "+m" "$2"
  • [ "$use_external_menu" = "0" ] && fzf "$1" --reverse --cycle --prompt "$2"
  • [ "$use_external_menu" = "1" ] && external_menu "$1" "$2"
    -}

-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 -f2,3 && return 0
  • prompt="$1"
  • multi_flag=""
  • [ $# -ne 1 ] && shift && multi_flag="$1"
  • line=$(printf "%s" "$stdin" | cut -f1,3 | tr '\t' ' ' | launcher "$multi_flag" "$prompt" | cut -d " " -f 1)
  • [ -n "$line" ] && printf "%s" "$stdin" | grep -E '^'"${line}"'($|[[:space:]])' | cut -f2,3 || exit 1
    -}

-die() {

  • printf "\33[2K\r\033[1;31m%s\033[0m\n" "$*" >&2
  • exit 1
    -}

-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
    
  •  -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
    
  •  --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)
    
  •  --skip-title <title>
    
  •    Use given title as ani-skip query
    
  •  -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 --skip-title \"one piece\" -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
    -}

-update_script() {

  • update="$(curl -s -A "$agent" "https://raw.githubusercontent.com/pystardust/ani-cli/master/ani-cli")" || die "Connection error"
  • update="$(printf '%s\n' "$update" | diff -u "$0" -)"
  • if [ -z "$update" ]; then
  •    printf "Script is up to date :)\n"
    
  • else
  •    if printf '%s\n' "$update" | patch "$0" -; then
    
  •        printf "Script has been updated\n"
    
  •    else
    
  •        die "Can't update for some reason!"
    
  •    fi
    
  • fi
  • exit 0
    -}

-# checks if dependencies are present
-dep_ch() {

  • for dep; do
  •    command -v "$dep" >/dev/null || die "Program \"$dep\" not found. Please install it."
    
  • done
    -}

-# SCRAPING

-# extract the video links from response of embed urls, extract mp4 links form m3u8 lists
-get_links() {

  • episode_link="$(curl -e "$allanime_refr" -s "https://${allanime_base}$" -A "$agent" | sed 's|},{|
    -|g' | sed -nE 's|.link":"([^"])".
    "resolutionStr":"([^"])".|\2 >\1|p;s|.hls","url":"([^"])"."hardsub_lang":"en-US".|\1|p')"
  • case "$episode_link" in
  •    *repackager.wixmp.com*)
    
  •        extract_link=$(printf "%s" "$episode_link" | cut -d'>' -f2 | sed 's|repackager.wixmp.com/||g;s|\.urlset.*||g')
    
  •        for j in $(printf "%s" "$episode_link" | sed -nE 's|.*/,([^/]*),/mp4.*|\1|p' | sed 's|,|\
    

-|g'); do

  •            printf "%s >%s\n" "$j" "$extract_link" | sed "s|,[^/]*|${j}|g"
    
  •        done | sort -nr
    
  •        ;;
    
  •    *vipanicdn* | *anifastcdn*)
    
  •        if printf "%s" "$episode_link" | head -1 | grep -q "original.m3u"; then
    
  •            printf "%s" "$episode_link"
    
  •        else
    
  •            extract_link=$(printf "%s" "$episode_link" | head -1 | cut -d'>' -f2)
    
  •            relative_link=$(printf "%s" "$extract_link" | sed 's|[^/]*$||')
    
  •            curl -e "$allanime_refr" -s "$extract_link" -A "$agent" | sed 's|^#.*x||g; s|,.*|p|g; /^#/d; $!N; s|\
    

-| >|' | sed "s|>|>${relative_link}|g" | sort -nr

  •        fi
    
  •        ;;
    
  •    *) [ -n "$episode_link" ] && printf "%s\n" "$episode_link" ;;
    
  • esac
  • [ -z "$ANI_CLI_NON_INTERACTIVE" ] && printf "\033[1;32m%s\033[0m Links Fetched\n" "$provider_name" 1>&2
    -}

-# innitialises provider_name and provider_id. First argument is the provider name, 2nd is the regex that matches that provider's link
-provider_init() {

  • provider_name=$1
  • provider_id=$(printf "%s" "$resp" | sed -n "$2" | head -1 | cut -d':' -f2 | sed 's/../&
    -/g' | sed 's/^01$/9/g;s/^08$/0/g;s/^05$/=/g;s/^0a$/2/g;s/^0b$/3/g;s/^0c$/4/g;s/^07$/?/g;s/^00$/8/g;s/^5c$/d/g;s/^0f$/7/g;s/^5e$/f/g;s/^17$///g;s/^54$/l/g;s/^09$/1/g;s/^48$/p/g;s/^4f$/w/g;s/^0e$/6/g;s/^5b$/c/g;s/^5d$/e/g;s/^0d$/5/g;s/^53$/k/g;s/^1e$/&/g;s/^5a$/b/g;s/^59$/a/g;s/^4a$/r/g;s/^4c$/t/g;s/^4e$/v/g;s/^57$/o/g;s/^51$/i/g;' | tr -d '\n' | sed "s//clock//clock.json/")
    -}

-# generates links based on given provider
-generate_link() {

  • case $1 in
  •    1) provider_init "wixmp" "/Default :/p" ;;     # wixmp(default)(m3u8)(multi) -> (mp4)(multi)
    
  •    2) provider_init "dropbox" "/Sak :/p" ;;       # dropbox(mp4)(single)
    
  •    3) provider_init "wetransfer" "/Kir :/p" ;;    # wetransfer(mp4)(single)
    
  •    4) provider_init "sharepoint" "/S-mp4 :/p" ;;  # sharepoint(mp4)(single)
    
  •    *) provider_init "gogoanime" "/Luf-mp4 :/p" ;; # gogoanime(m3u8)(multi)
    
  • esac
  • [ -n "$provider_id" ] && get_links "$provider_id"
    -}

-select_quality() {

  • case "$1" in
  •    best) result=$(printf "%s" "$links" | head -n1) ;;
    
  •    worst) result=$(printf "%s" "$links" | grep -E '^[0-9]{3,4}' | tail -n1) ;;
    
  •    *) result=$(printf "%s" "$links" | grep -m 1 "$1") ;;
    
  • esac
  • [ -z "$result" ] && printf "Specified quality not found, defaulting to best\n" 1>&2 && result=$(printf "%s" "$links" | head -n1)
  • printf "%s" "$result" | cut -d'>' -f2
    -}

-# gets embed urls, collects direct links into provider files, selects one with desired quality into $episode
-get_episode_url() {

  • get the embed urls of the selected episode

  • episode_embed_gql="query ($showId: String!, $translationType: VaildTranslationTypeEnumType!, $episodeString: String!) { episode( showId: $showId translationType: $translationType episodeString: $episodeString ) { episodeString sourceUrls }}"
  • resp=$(curl -e "$allanime_refr" -s -G "${allanime_api}/api" --data-urlencode "variables={"showId":"$id","translationType":"$mode","episodeString":"$ep_no"}" --data-urlencode "query=$episode_embed_gql" -A "$agent" | tr '{}' '\n' | sed 's|\u002F|/|g;s|\||g' | sed -nE 's|.sourceUrl":"--([^"])".sourceName":"([^"])".*|\2 :\1|p')
  • generate links into sequential files

  • cache_dir="$(mktemp -d)"
  • providers="1 2 3 4 5"
  • for provider in $providers; do
  •    generate_link "$provider" >"$cache_dir"/"$provider" &
    
  • done
  • wait
  • select the link with matching quality

  • links=$(cat "$cache_dir"/* | sed 's|^Mp4-||g;/http/!d' | sort -g -r -s)
  • rm -r "$cache_dir"
  • episode=$(select_quality "$quality")
  • [ -z "$episode" ] && die "Episode not released!"
    -}

-# search the query and give results
-search_anime() {

  • search_gql="query( $search: SearchInput $limit: Int $page: Int $translationType: VaildTranslationTypeEnumType $countryOrigin: VaildCountryOriginEnumType ) { shows( search: $search limit: $limit page: $page translationType: $translationType countryOrigin: $countryOrigin ) { edges { _id name availableEpisodes __typename } }}"
  • curl -e "$allanime_refr" -s -G "${allanime_api}/api" --data-urlencode "variables={"search":{"allowAdult":false,"allowUnknown":false,"query":"$1"},"limit":40,"page":1,"translationType":"$mode","countryOrigin":"ALL"}" --data-urlencode "query=$search_gql" -A "$agent" | sed 's|Show|
    -|g' | sed -nE "s|._id":"([^\"])","name":"([^\"])".${mode}":([1-9][^,]).|\1 \2 (\3 episodes)|p"
    -}

-time_until_next_ep() {

  • animeschedule="https://animeschedule.net"
  • curl -s -G "$animeschedule/api/v3/anime" --data-urlencode "q=$1" | sed 's|"id"|\n|g' | sed -nE 's|.,"route":"([^"])","premier.*|\1|p' | while read -r anime; do
  •    data=$(curl -s "$animeschedule/anime/$anime" | sed '1,/"anime-header-list-buttons-wrapper"/d' | sed -nE 's|.*countdown-time-raw" datetime="([^"]*)">.*|Next Raw Release: \1|p;s|.*countdown-time" datetime="([^"]*)">.*|Next Sub Release: \1|p;s|.*english-title">([^<]*)<.*|English Title: \1|p;s|.*main-title".*>([^<]*)<.*|Japanese Title: \1|p')
    
  •    status="Ongoing"
    
  •    color="33"
    
  •    printf "%s\n" "$data"
    
  •    ! (printf "%s\n" "$data" | grep -q "Next Raw Release:") && status="Finished" && color="32"
    
  •    printf "Status:  \033[1;%sm%s\033[0m\n---\n" "$color" "$status"
    
  • done
  • exit 0
    -}

-# get the episodes list of the selected anime
-episodes_list() {

  • episodes_list_gql="query ($showId: String!) { show( _id: $showId ) { _id availableEpisodesDetail }}"
  • curl -e "$allanime_refr" -s -G "${allanime_api}/api" --data-urlencode "variables={"showId":"$"}" --data-urlencode "query=$episodes_list_gql" -A "$agent" | sed -nE "s|.$mode":[([0-9.",])].|\1|p" | sed 's|,|
    -|g; s|"||g' | sort -n -k 1
    -}

-# PLAYING

-process_hist_entry() {

  • ep_list=$(episodes_list "$id")
  • 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" "$id" "$title" "$ep_no"
    -}

-update_history() {

  • if grep -q -- "$id" "$histfile"; then
  •    sed -E "s/^[^\t]+\t${id}\t/${ep_no}\t${id}\t/" "$histfile" >"${histfile}.new"
    
  • else
  •    cp "$histfile" "${histfile}.new"
    
  •    printf "%s\t%s\t%s\n" "$ep_no" "$id" "$title" >>"${histfile}.new"
    
  • fi
  • mv "${histfile}.new" "$histfile"
    -}

-download() {

  • case $1 in
  •    *m3u8*)
    
  •        if command -v "yt-dlp" >/dev/null; then
    
  •            yt-dlp "$1" --no-skip-unavailable-fragments --fragment-retries infinite -N 16 -o "$download_dir/$2.mp4"
    
  •        else
    
  •            ffmpeg -loglevel error -stats -i "$1" -c copy "$download_dir/$2.mp4"
    
  •        fi
    
  •        ;;
    
  •    *)
    
  •        aria2c --enable-rpc=false --check-certificate=false --continue --summary-interval=0 -x 16 -s 16 "$1" --dir="$download_dir" -o "$2.mp4" --download-result=hide
    
  •        ;;
    
  • esac
    -}

-play_episode() {

  • [ "$skip_intro" = 1 ] && skip_flag="$(ani-skip -q "$mal_id" -e "$ep_no")"
  • [ -z "$episode" ] && get_episode_url
  • shellcheck disable=SC2086

  • case "$player_function" in
  •    debug)
    
  •        [ -z "$ANI_CLI_NON_INTERACTIVE" ] && printf "All links:\n%s\nSelected link:\n" "$links"
    
  •        printf "%s\n" "$episode"
    
  •        ;;
    
  •    mpv*)
    
  •        if [ "$no_detach" = 0 ]; then
    
  •            nohup "$player_function" $skip_flag --force-media-title="${allanime_title}Episode ${ep_no}" "$episode" >/dev/null 2>&1 &
    
  •        else
    
  •            "$player_function" $skip_flag --force-media-title="${allanime_title}Episode ${ep_no}" "$episode"
    
  •        fi
    
  •        ;;
    
  •    android_mpv) nohup am start --user 0 -a android.intent.action.VIEW -d "$episode" -n is.xyz.mpv/.MPVActivity >/dev/null 2>&1 & ;;
    
  •    android_vlc) nohup am start --user 0 -a android.intent.action.VIEW -d "$episode" -n org.videolan.vlc/org.videolan.vlc.gui.video.VideoPlayerActivity -e "title" "${allanime_title}Episode ${ep_no}" >/dev/null 2>&1 & ;;
    
  •    iina) nohup "$player_function" --no-stdin --keep-running --mpv-force-media-title="${allanime_title}Episode ${ep_no}" "$episode" >/dev/null 2>&1 & ;;
    
  •    flatpak_mpv) flatpak run io.mpv.Mpv --force-media-title="${allanime_title}Episode ${ep_no}" "$episode" >/dev/null 2>&1 & ;;
    
  •    vlc*) nohup "$player_function" --play-and-exit --meta-title="${allanime_title}Episode ${ep_no}" "$episode" >/dev/null 2>&1 & ;;
    
  •    *yncpla*) nohup "$player_function" "$episode" -- --force-media-title="${allanime_title}Episode ${ep_no}" >/dev/null 2>&1 & ;;
    
  •    download) "$player_function" "$episode" "${allanime_title}Episode ${ep_no}" ;;
    
  •    catt) nohup catt cast "$episode" >/dev/null 2>&1 & ;;
    
  •    iSH)
    
  •        printf "\e]8;;vlc://%s\a~~~~~~~~~~~~~~~~~~~~\n~ Tap to open VLC ~\n~~~~~~~~~~~~~~~~~~~~\e]8;;\a\n" "$episode"
    
  •        sleep 5
    
  •        ;;
    
  •    *) nohup "$player_function" "$episode" >/dev/null 2>&1 & ;;
    
  • esac
  • replay="$episode"
  • unset episode
  • update_history
  • [ "$use_external_menu" = "1" ] && 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 -n1) && unset start
  • [ -z "$end" ] || [ "$end" = "$start" ] && unset start end
  • [ "$end" = "-1" ] && end=$(printf "%s" "$ep_list" | tail -n1)
  • 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 -n1)
    
  •    [ -z "$end" ] && end=$(printf "%s\n" "$ep_no" | tail -n1)
    
  •    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
    
  •        printf "\33[2K\r\033[1;34mPlaying episode %s...\033[0m\n" "$ep_no"
    
  •        play_episode
    
  •    done
    
  • else
  •    play_episode
    
  • fi
  • moves upto stored positon and deletes to end

  • [ "$player_function" != "debug" ] && [ "$player_function" != "download" ] && tput rc && tput ed
    -}

-# MAIN

-# setup
-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/121.0"
-allanime_refr="https://allanime.to"
-allanime_base="allanime.day"
-allanime_api="https://api.${allanime_base}"
-mode="${ANI_CLI_MODE:-sub}"
-download_dir="${ANI_CLI_DOWNLOAD_DIR:-.}"
-quality="${ANI_CLI_QUALITY:-best}"
-case "$(uname -a)" in

  • Darwin) player_function="${ANI_CLI_PLAYER:-iina}" ;; # mac OS
  • ndroid) player_function="${ANI_CLI_PLAYER:-android_mpv}" ;; # Android OS (termux)
  • steamdeck) player_function="${ANI_CLI_PLAYER:-flatpak_mpv}" ;; # steamdeck OS
  • MINGW | WSL2) player_function="${ANI_CLI_PLAYER:-mpv.exe}" ;; # Windows OS
  • ish) player_function="${ANI_CLI_PLAYER:-iSH}" ;; # iOS (iSH)
  • *) player_function="${ANI_CLI_PLAYER:-mpv}" ;; # Linux OS
    -esac

-no_detach="${ANI_CLI_NO_DETACH:-0}"
-use_external_menu="${ANI_CLI_EXTERNAL_MENU:-0}"
-skip_intro="${ANI_CLI_SKIP_INTRO:-0}"
-# shellcheck disable=SC2154
-skip_title="$ANI_CLI_SKIP_TITLE"
-[ -t 0 ] || use_external_menu=1
-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"
-search="${ANI_CLI_DEFAULT_SOURCE:-scrape}"

-while [ $# -gt 0 ]; do

  • case "$1" in
  •    -v | --vlc)
    
  •        case "$(uname -a)" 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) search=history ;;
    
  •    -d | --download) player_function=download ;;
    
  •    -D | --delete)
    
  •        : >"$histfile"
    
  •        exit 0
    
  •        ;;
    
  •    -V | --version) version_info ;;
    
  •    -h | --help) help_info ;;
    
  •    -e | --episode | -r | --range)
    
  •        [ $# -lt 2 ] && die "missing argument!"
    
  •        ep_no="$2"
    
  •        [ -n "$index" ] && ANI_CLI_NON_INTERACTIVE=1 #Checks for -S presence
    
  •        shift
    
  •        ;;
    
  •    --dub) mode="dub" ;;
    
  •    --no-detach) no_detach=1 ;;
    
  •    --rofi) use_external_menu=1 ;;
    
  •    --skip) skip_intro=1 ;;
    
  •    --skip-title)
    
  •        [ $# -lt 2 ] && die "missing argument!"
    
  •        skip_title="$2"
    
  •        shift
    
  •        ;;
    
  •    -N | --nextep-countdown) search=nextep ;;
    
  •    -U | --update) update_script ;;
    
  •    *) query="$(printf "%s" "$query $1" | sed "s|^ ||;s| |+|g")" ;;
    
  • esac
  • shift
    -done
    -[ "$use_external_menu" = "0" ] && multi_selection_flag="${ANI_CLI_MULTI_SELECTION:-"-m"}"
    -[ "$use_external_menu" = "1" ] && multi_selection_flag="${ANI_CLI_MULTI_SELECTION:-"-multi-select"}"
    -printf "\33[2K\r\033[1;34mChecking dependencies...\033[0m\n"
    -dep_ch "curl" "sed" "grep" || true
    -[ "$skip_intro" = 1 ] && (dep_ch "ani-skip" || true)
    -if [ -z "$ANI_CLI_NON_INTERACTIVE" ]; then dep_ch fzf || true; fi
    -case "$player_function" in
  • debug) ;;
  • download) dep_ch "ffmpeg" "aria2c" ;;
  • flatpak*)
  •    dep_ch "flatpak"
    
  •    flatpak info io.mpv.Mpv >/dev/null 2>&1 || die "Program \"mpv (flatpak)\" not found. Please install it."
    
  •    ;;
    
  • 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

-# searching
-case "$search" in

  • history)
  •    anime_list=$(while read -r ep_no id title; do process_hist_entry & done <"$histfile")
    
  •    wait
    
  •    [ -z "$anime_list" ] && die "No unwatched series in history!"
    
  •    result=$(printf "%s" "$anime_list" | nl -w 2 | sed 's/^[[:space:]]//' | nth "Select anime: " | cut -f1)
    
  •    [ -z "$result" ] && exit 1
    
  •    resfile="$(mktemp)"
    
  •    grep "$result" "$histfile" >"$resfile"
    
  •    read -r ep_no id title <"$resfile"
    
  •    ep_list=$(episodes_list "$id")
    
  •    ep_no=$(printf "%s" "$ep_list" | sed -n "/^${ep_no}$/{n;p;}") 2>/dev/null
    
  •    allanime_title="$(printf "%s" "$title" | cut -d'(' -f1 | tr -d '[:punct:]')"
    
  •    ;;
    
  • *)
  •    if [ "$use_external_menu" = "0" ]; then
    
  •        while [ -z "$query" ]; do
    
  •            printf "\33[2K\r\033[1;36mSearch anime: \033[0m" && read -r query
    
  •        done
    
  •    else
    
  •        [ -z "$query" ] && query=$(printf "" | external_menu "" "Search anime: ")
    
  •        [ -z "$query" ] && exit 1
    
  •    fi
    
  •    # for checking new releases by specifying anime name
    
  •    [ "$search" = "nextep" ] && time_until_next_ep "$query"
    
  •    query=$(printf "%s" "$query" | sed "s| |+|g")
    
  •    anime_list=$(search_anime "$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" ] && exit 1
    
  •    title=$(printf "%s" "$result" | cut -f2)
    
  •    allanime_title="$(printf "%s" "$title" | cut -d'(' -f1 | tr -d '[:punct:]')"
    
  •    id=$(printf "%s" "$result" | cut -f1)
    
  •    ep_list=$(episodes_list "$id")
    
  •    [ -z "$ep_no" ] && ep_no=$(printf "%s" "$ep_list" | nth "Select episode: " "$multi_selection_flag")
    
  •    [ -z "$ep_no" ] && exit 1
    
  •    ;;
    

-esac
-[ "$skip_intro" = 1 ] && mal_id="$(ani-skip -q "${skip_title:-${title}}")"

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

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

-while cmd=$(printf "next\nreplay\nprevious\nselect\nchange_quality\nquit" | nth "Playing episode $ep_no of $title... "); do

  • case "$cmd" in
  •    next) ep_no=$(printf "%s" "$ep_list" | sed -n "/^${ep_no}$/{n;p;}") 2>/dev/null ;;
    
  •    replay) episode="$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: " "$multi_selection_flag") ;;
    
  •    change_quality)
    
  •        episode=$(printf "%s" "$links" | launcher)
    
  •        quality=$(printf "%s" "$episode" | grep -oE "^[0-9]+")
    
  •        episode=$(printf "%s" "$episode" | cut -d'>' -f2)
    
  •        ;;
    
  •    *) 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
+#!/bin/sh
+
+version_number="4.8.6"
+
+# UI
+
+external_menu() {

  • rofi "$1" -sort -dmenu -i -width 1500 -p "$2"
    +}

+launcher() {

  • [ "$use_external_menu" = "0" ] && [ -z "$1" ] && set -- "+m" "$2"
  • [ "$use_external_menu" = "0" ] && fzf "$1" --reverse --cycle --prompt "$2"
  • [ "$use_external_menu" = "1" ] && external_menu "$1" "$2"
    +}

+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 -f2,3 && return 0
  • prompt="$1"
  • multi_flag=""
  • [ $# -ne 1 ] && shift && multi_flag="$1"
  • line=$(printf "%s" "$stdin" | cut -f1,3 | tr '\t' ' ' | launcher "$multi_flag" "$prompt" | cut -d " " -f 1)
  • [ -n "$line" ] && printf "%s" "$stdin" | grep -E '^'"${line}"'($|[[:space:]])' | cut -f2,3 || exit 1
    +}

+die() {

  • printf "\33[2K\r\033[1;31m%s\033[0m\n" "$*" >&2
  • exit 1
    +}

+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
    
  •  -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
    
  •  --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)
    
  •  --skip-title <title>
    
  •    Use given title as ani-skip query
    
  •  -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 --skip-title \"one piece\" -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
    +}

+update_script() {

  • update="$(curl -s -A "$agent" "https://raw.githubusercontent.com/pystardust/ani-cli/master/ani-cli")" || die "Connection error"
  • update="$(printf '%s\n' "$update" | diff -u "$0" -)"
  • if [ -z "$update" ]; then
  •    printf "Script is up to date :)\n"
    
  • else
  •    if printf '%s\n' "$update" | patch "$0" -; then
    
  •        printf "Script has been updated\n"
    
  •    else
    
  •        die "Can't update for some reason!"
    
  •    fi
    
  • fi
  • exit 0
    +}

+# checks if dependencies are present
+dep_ch() {

  • for dep; do
  •    command -v "$dep" >/dev/null || die "Program \"$dep\" not found. Please install it."
    
  • done
    +}

+# SCRAPING
+
+# extract the video links from response of embed urls, extract mp4 links form m3u8 lists
+get_links() {

  • episode_link="$(curl -e "$allanime_refr" -s "https://${allanime_base}$" -A "$agent" | sed 's|},{|
    +|g' | sed -nE 's|.link":"([^"])".
    "resolutionStr":"([^"])".|\2 >\1|p;s|.hls","url":"([^"])"."hardsub_lang":"en-US".|\1|p')"
  • case "$episode_link" in
  •    *repackager.wixmp.com*)
    
  •        extract_link=$(printf "%s" "$episode_link" | cut -d'>' -f2 | sed 's|repackager.wixmp.com/||g;s|\.urlset.*||g')
    
  •        for j in $(printf "%s" "$episode_link" | sed -nE 's|.*/,([^/]*),/mp4.*|\1|p' | sed 's|,|\
    

+|g'); do

  •            printf "%s >%s\n" "$j" "$extract_link" | sed "s|,[^/]*|${j}|g"
    
  •        done | sort -nr
    
  •        ;;
    
  •    *vipanicdn* | *anifastcdn*)
    
  •        if printf "%s" "$episode_link" | head -1 | grep -q "original.m3u"; then
    
  •            printf "%s" "$episode_link"
    
  •        else
    
  •            extract_link=$(printf "%s" "$episode_link" | head -1 | cut -d'>' -f2)
    
  •            relative_link=$(printf "%s" "$extract_link" | sed 's|[^/]*$||')
    
  •            curl -e "$allanime_refr" -s "$extract_link" -A "$agent" | sed 's|^#.*x||g; s|,.*|p|g; /^#/d; $!N; s|\
    

+| >|' | sed "s|>|>${relative_link}|g" | sort -nr

  •        fi
    
  •        ;;
    
  •    *) [ -n "$episode_link" ] && printf "%s\n" "$episode_link" ;;
    
  • esac
  • [ -z "$ANI_CLI_NON_INTERACTIVE" ] && printf "\033[1;32m%s\033[0m Links Fetched\n" "$provider_name" 1>&2
    +}

+# innitialises provider_name and provider_id. First argument is the provider name, 2nd is the regex that matches that provider's link
+provider_init() {

  • provider_name=$1
  • provider_id=$(printf "%s" "$resp" | sed -n "$2" | head -1 | cut -d':' -f2 | sed 's/../&
    +/g' | sed 's/^01$/9/g;s/^08$/0/g;s/^05$/=/g;s/^0a$/2/g;s/^0b$/3/g;s/^0c$/4/g;s/^07$/?/g;s/^00$/8/g;s/^5c$/d/g;s/^0f$/7/g;s/^5e$/f/g;s/^17$///g;s/^54$/l/g;s/^09$/1/g;s/^48$/p/g;s/^4f$/w/g;s/^0e$/6/g;s/^5b$/c/g;s/^5d$/e/g;s/^0d$/5/g;s/^53$/k/g;s/^1e$/&/g;s/^5a$/b/g;s/^59$/a/g;s/^4a$/r/g;s/^4c$/t/g;s/^4e$/v/g;s/^57$/o/g;s/^51$/i/g;' | tr -d '\n' | sed "s//clock//clock.json/")
    +}

+# generates links based on given provider
+generate_link() {

  • case $1 in
  •    1) provider_init "wixmp" "/Default :/p" ;;     # wixmp(default)(m3u8)(multi) -> (mp4)(multi)
    
  •    2) provider_init "dropbox" "/Sak :/p" ;;       # dropbox(mp4)(single)
    
  •    3) provider_init "wetransfer" "/Kir :/p" ;;    # wetransfer(mp4)(single)
    
  •    4) provider_init "sharepoint" "/S-mp4 :/p" ;;  # sharepoint(mp4)(single)
    
  •    *) provider_init "gogoanime" "/Luf-mp4 :/p" ;; # gogoanime(m3u8)(multi)
    
  • esac
  • [ -n "$provider_id" ] && get_links "$provider_id"
    +}

+select_quality() {

  • case "$1" in
  •    best) result=$(printf "%s" "$links" | head -n1) ;;
    
  •    worst) result=$(printf "%s" "$links" | grep -E '^[0-9]{3,4}' | tail -n1) ;;
    
  •    *) result=$(printf "%s" "$links" | grep -m 1 "$1") ;;
    
  • esac
  • [ -z "$result" ] && printf "Specified quality not found, defaulting to best\n" 1>&2 && result=$(printf "%s" "$links" | head -n1)
  • printf "%s" "$result" | cut -d'>' -f2
    +}

+# gets embed urls, collects direct links into provider files, selects one with desired quality into $episode
+get_episode_url() {

  • get the embed urls of the selected episode

  • episode_embed_gql="query ($showId: String!, $translationType: VaildTranslationTypeEnumType!, $episodeString: String!) { episode( showId: $showId translationType: $translationType episodeString: $episodeString ) { episodeString sourceUrls }}"
  • resp=$(curl -e "$allanime_refr" -s -G "${allanime_api}/api" --data-urlencode "variables={"showId":"$id","translationType":"$mode","episodeString":"$ep_no"}" --data-urlencode "query=$episode_embed_gql" -A "$agent" | tr '{}' '\n' | sed 's|\u002F|/|g;s|\||g' | sed -nE 's|.sourceUrl":"--([^"])".sourceName":"([^"])".*|\2 :\1|p')
  • generate links into sequential files

  • cache_dir="$(mktemp -d)"
  • providers="1 2 3 4 5"
  • for provider in $providers; do
  •    generate_link "$provider" >"$cache_dir"/"$provider" &
    
  • done
  • wait
  • select the link with matching quality

  • links=$(cat "$cache_dir"/* | sed 's|^Mp4-||g;/http/!d' | sort -g -r -s)
  • rm -r "$cache_dir"
  • episode=$(select_quality "$quality")
  • [ -z "$episode" ] && die "Episode not released!"
    +}

+# search the query and give results
+search_anime() {

  • search_gql="query( $search: SearchInput $limit: Int $page: Int $translationType: VaildTranslationTypeEnumType $countryOrigin: VaildCountryOriginEnumType ) { shows( search: $search limit: $limit page: $page translationType: $translationType countryOrigin: $countryOrigin ) { edges { _id name availableEpisodes __typename } }}"
  • curl -e "$allanime_refr" -s -G "${allanime_api}/api" --data-urlencode "variables={"search":{"allowAdult":false,"allowUnknown":false,"query":"$1"},"limit":40,"page":1,"translationType":"$mode","countryOrigin":"ALL"}" --data-urlencode "query=$search_gql" -A "$agent" | sed 's|Show|
    +|g' | sed -nE "s|._id":"([^\"])","name":"([^\"])".${mode}":([1-9][^,]).|\1 \2 (\3 episodes)|p"
    +}

+time_until_next_ep() {

  • animeschedule="https://animeschedule.net"
  • curl -s -G "$animeschedule/api/v3/anime" --data-urlencode "q=$1" | sed 's|"id"|\n|g' | sed -nE 's|.,"route":"([^"])","premier.*|\1|p' | while read -r anime; do
  •    data=$(curl -s "$animeschedule/anime/$anime" | sed '1,/"anime-header-list-buttons-wrapper"/d' | sed -nE 's|.*countdown-time-raw" datetime="([^"]*)">.*|Next Raw Release: \1|p;s|.*countdown-time" datetime="([^"]*)">.*|Next Sub Release: \1|p;s|.*english-title">([^<]*)<.*|English Title: \1|p;s|.*main-title".*>([^<]*)<.*|Japanese Title: \1|p')
    
  •    status="Ongoing"
    
  •    color="33"
    
  •    printf "%s\n" "$data"
    
  •    ! (printf "%s\n" "$data" | grep -q "Next Raw Release:") && status="Finished" && color="32"
    
  •    printf "Status:  \033[1;%sm%s\033[0m\n---\n" "$color" "$status"
    
  • done
  • exit 0
    +}

+# get the episodes list of the selected anime
+episodes_list() {

  • episodes_list_gql="query ($showId: String!) { show( _id: $showId ) { _id availableEpisodesDetail }}"
  • curl -e "$allanime_refr" -s -G "${allanime_api}/api" --data-urlencode "variables={"showId":"$"}" --data-urlencode "query=$episodes_list_gql" -A "$agent" | sed -nE "s|.$mode":[([0-9.",])].|\1|p" | sed 's|,|
    +|g; s|"||g' | sort -n -k 1
    +}

+# PLAYING
+
+process_hist_entry() {

  • ep_list=$(episodes_list "$id")
  • 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" "$id" "$title" "$ep_no"
    +}

+update_history() {

  • if grep -q -- "$id" "$histfile"; then
  •    sed -E "s/^[^\t]+\t${id}\t/${ep_no}\t${id}\t/" "$histfile" >"${histfile}.new"
    
  • else
  •    cp "$histfile" "${histfile}.new"
    
  •    printf "%s\t%s\t%s\n" "$ep_no" "$id" "$title" >>"${histfile}.new"
    
  • fi
  • mv "${histfile}.new" "$histfile"
    +}

+download() {

  • case $1 in
  •    *m3u8*)
    
  •        if command -v "yt-dlp" >/dev/null; then
    
  •            yt-dlp "$1" --no-skip-unavailable-fragments --fragment-retries infinite -N 16 -o "$download_dir/$2.mp4"
    
  •        else
    
  •            ffmpeg -loglevel error -stats -i "$1" -c copy "$download_dir/$2.mp4"
    
  •        fi
    
  •        ;;
    
  •    *)
    
  •        aria2c --enable-rpc=false --check-certificate=false --continue --summary-interval=0 -x 16 -s 16 "$1" --dir="$download_dir" -o "$2.mp4" --download-result=hide
    
  •        ;;
    
  • esac
    +}

+play_episode() {

  • [ "$skip_intro" = 1 ] && skip_flag="$(ani-skip -q "$mal_id" -e "$ep_no")"
  • [ -z "$episode" ] && get_episode_url
  • shellcheck disable=SC2086

  • case "$player_function" in
  •    debug)
    
  •        [ -z "$ANI_CLI_NON_INTERACTIVE" ] && printf "All links:\n%s\nSelected link:\n" "$links"
    
  •        printf "%s\n" "$episode"
    
  •        ;;
    
  •    mpv*)
    
  •        if [ "$no_detach" = 0 ]; then
    
  •            nohup "$player_function" $skip_flag --force-media-title="${allanime_title}Episode ${ep_no}" "$episode" >/dev/null 2>&1 &
    
  •        else
    
  •            "$player_function" $skip_flag --force-media-title="${allanime_title}Episode ${ep_no}" "$episode"
    
  •        fi
    
  •        ;;
    
  •    android_mpv) nohup am start --user 0 -a android.intent.action.VIEW -d "$episode" -n is.xyz.mpv/.MPVActivity >/dev/null 2>&1 & ;;
    
  •    android_vlc) nohup am start --user 0 -a android.intent.action.VIEW -d "$episode" -n org.videolan.vlc/org.videolan.vlc.gui.video.VideoPlayerActivity -e "title" "${allanime_title}Episode ${ep_no}" >/dev/null 2>&1 & ;;
    
  •    iina) nohup "$player_function" --no-stdin --keep-running --mpv-force-media-title="${allanime_title}Episode ${ep_no}" "$episode" >/dev/null 2>&1 & ;;
    
  •    flatpak_mpv) flatpak run io.mpv.Mpv --force-media-title="${allanime_title}Episode ${ep_no}" "$episode" >/dev/null 2>&1 & ;;
    
  •    vlc*) nohup "$player_function" --play-and-exit --meta-title="${allanime_title}Episode ${ep_no}" "$episode" >/dev/null 2>&1 & ;;
    
  •    *yncpla*) nohup "$player_function" "$episode" -- --force-media-title="${allanime_title}Episode ${ep_no}" >/dev/null 2>&1 & ;;
    
  •    download) "$player_function" "$episode" "${allanime_title}Episode ${ep_no}" ;;
    
  •    catt) nohup catt cast "$episode" >/dev/null 2>&1 & ;;
    
  •    iSH)
    
  •        printf "\e]8;;vlc://%s\a~~~~~~~~~~~~~~~~~~~~\n~ Tap to open VLC ~\n~~~~~~~~~~~~~~~~~~~~\e]8;;\a\n" "$episode"
    
  •        sleep 5
    
  •        ;;
    
  •    *) nohup "$player_function" "$episode" >/dev/null 2>&1 & ;;
    
  • esac
  • replay="$episode"
  • unset episode
  • update_history
  • [ "$use_external_menu" = "1" ] && 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 -n1) && unset start
  • [ -z "$end" ] || [ "$end" = "$start" ] && unset start end
  • [ "$end" = "-1" ] && end=$(printf "%s" "$ep_list" | tail -n1)
  • 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 -n1)
    
  •    [ -z "$end" ] && end=$(printf "%s\n" "$ep_no" | tail -n1)
    
  •    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
    
  •        printf "\33[2K\r\033[1;34mPlaying episode %s...\033[0m\n" "$ep_no"
    
  •        play_episode
    
  •    done
    
  • else
  •    play_episode
    
  • fi
  • moves upto stored positon and deletes to end

  • [ "$player_function" != "debug" ] && [ "$player_function" != "download" ] && tput rc && tput ed
    +}

+# MAIN
+
+# setup
+agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/121.0"
+allanime_refr="https://allanime.to"
+allanime_base="allanime.day"
+allanime_api="https://api.${allanime_base}"
+mode="${ANI_CLI_MODE:-sub}"
+download_dir="${ANI_CLI_DOWNLOAD_DIR:-.}"
+quality="${ANI_CLI_QUALITY:-best}"
+case "$(uname -a)" in

  • Darwin) player_function="${ANI_CLI_PLAYER:-iina}" ;; # mac OS
  • ndroid) player_function="${ANI_CLI_PLAYER:-android_mpv}" ;; # Android OS (termux)
  • steamdeck) player_function="${ANI_CLI_PLAYER:-flatpak_mpv}" ;; # steamdeck OS
  • MINGW | WSL2) player_function="${ANI_CLI_PLAYER:-mpv.exe}" ;; # Windows OS
  • ish) player_function="${ANI_CLI_PLAYER:-iSH}" ;; # iOS (iSH)
  • *) player_function="${ANI_CLI_PLAYER:-mpv}" ;; # Linux OS
    +esac

+no_detach="${ANI_CLI_NO_DETACH:-0}"
+use_external_menu="${ANI_CLI_EXTERNAL_MENU:-0}"
+skip_intro="${ANI_CLI_SKIP_INTRO:-0}"
+# shellcheck disable=SC2154
+skip_title="$ANI_CLI_SKIP_TITLE"
+[ -t 0 ] || use_external_menu=1
+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"
+search="${ANI_CLI_DEFAULT_SOURCE:-scrape}"
+
+while [ $# -gt 0 ]; do

  • case "$1" in
  •    -v | --vlc)
    
  •        case "$(uname -a)" 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) search=history ;;
    
  •    -d | --download) player_function=download ;;
    
  •    -D | --delete)
    
  •        : >"$histfile"
    
  •        exit 0
    
  •        ;;
    
  •    -V | --version) version_info ;;
    
  •    -h | --help) help_info ;;
    
  •    -e | --episode | -r | --range)
    
  •        [ $# -lt 2 ] && die "missing argument!"
    
  •        ep_no="$2"
    
  •        [ -n "$index" ] && ANI_CLI_NON_INTERACTIVE=1 #Checks for -S presence
    
  •        shift
    
  •        ;;
    
  •    --dub) mode="dub" ;;
    
  •    --no-detach) no_detach=1 ;;
    
  •    --rofi) use_external_menu=1 ;;
    
  •    --skip) skip_intro=1 ;;
    
  •    --skip-title)
    
  •        [ $# -lt 2 ] && die "missing argument!"
    
  •        skip_title="$2"
    
  •        shift
    
  •        ;;
    
  •    -N | --nextep-countdown) search=nextep ;;
    
  •    -U | --update) update_script ;;
    
  •    *) query="$(printf "%s" "$query $1" | sed "s|^ ||;s| |+|g")" ;;
    
  • esac
  • shift
    +done
    +[ "$use_external_menu" = "0" ] && multi_selection_flag="${ANI_CLI_MULTI_SELECTION:-"-m"}"
    +[ "$use_external_menu" = "1" ] && multi_selection_flag="${ANI_CLI_MULTI_SELECTION:-"-multi-select"}"
    +printf "\33[2K\r\033[1;34mChecking dependencies...\033[0m\n"
    +dep_ch "curl" "sed" "grep" || true
    +[ "$skip_intro" = 1 ] && (dep_ch "ani-skip" || true)
    +if [ -z "$ANI_CLI_NON_INTERACTIVE" ]; then dep_ch fzf || true; fi
    +case "$player_function" in
  • debug) ;;
  • download) dep_ch "ffmpeg" "aria2c" ;;
  • flatpak*)
  •    dep_ch "flatpak"
    
  •    flatpak info io.mpv.Mpv >/dev/null 2>&1 || die "Program \"mpv (flatpak)\" not found. Please install it."
    
  •    ;;
    
  • 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

+# searching
+case "$search" in

  • history)
  •    anime_list=$(while read -r ep_no id title; do process_hist_entry & done <"$histfile")
    
  •    wait
    
  •    [ -z "$anime_list" ] && die "No unwatched series in history!"
    
  •    result=$(printf "%s" "$anime_list" | nl -w 2 | sed 's/^[[:space:]]//' | nth "Select anime: " | cut -f1)
    
  •    [ -z "$result" ] && exit 1
    
  •    resfile="$(mktemp)"
    
  •    grep "$result" "$histfile" >"$resfile"
    
  •    read -r ep_no id title <"$resfile"
    
  •    ep_list=$(episodes_list "$id")
    
  •    ep_no=$(printf "%s" "$ep_list" | sed -n "/^${ep_no}$/{n;p;}") 2>/dev/null
    
  •    allanime_title="$(printf "%s" "$title" | cut -d'(' -f1 | tr -d '[:punct:]')"
    
  •    ;;
    
  • *)
  •    if [ "$use_external_menu" = "0" ]; then
    
  •        while [ -z "$query" ]; do
    
  •            printf "\33[2K\r\033[1;36mSearch anime: \033[0m" && read -r query
    
  •        done
    
  •    else
    
  •        [ -z "$query" ] && query=$(printf "" | external_menu "" "Search anime: ")
    
  •        [ -z "$query" ] && exit 1
    
  •    fi
    
  •    # for checking new releases by specifying anime name
    
  •    [ "$search" = "nextep" ] && time_until_next_ep "$query"
    
  •    query=$(printf "%s" "$query" | sed "s| |+|g")
    
  •    anime_list=$(search_anime "$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" ] && exit 1
    
  •    title=$(printf "%s" "$result" | cut -f2)
    
  •    allanime_title="$(printf "%s" "$title" | cut -d'(' -f1 | tr -d '[:punct:]')"
    
  •    id=$(printf "%s" "$result" | cut -f1)
    
  •    ep_list=$(episodes_list "$id")
    
  •    [ -z "$ep_no" ] && ep_no=$(printf "%s" "$ep_list" | nth "Select episode: " "$multi_selection_flag")
    
  •    [ -z "$ep_no" ] && exit 1
    
  •    ;;
    

+esac
+[ "$skip_intro" = 1 ] && mal_id="$(ani-skip -q "${skip_title:-${title}}")"
+
+# moves the cursor up one line and clears that line
+tput cuu1 && tput el
+# stores the positon of cursor
+tput sc
+
+# playback & loop
+play
+[ "$player_function" = "download" ] || [ "$player_function" = "debug" ] && exit 0
+
+while cmd=$(printf "next\nreplay\nprevious\nselect\nchange_quality\nquit" | nth "Playing episode $ep_no of $title... "); do

  • case "$cmd" in
  •    next) ep_no=$(printf "%s" "$ep_list" | sed -n "/^${ep_no}$/{n;p;}") 2>/dev/null ;;
    
  •    replay) episode="$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: " "$multi_selection_flag") ;;
    
  •    change_quality)
    
  •        episode=$(printf "%s" "$links" | launcher)
    
  •        quality=$(printf "%s" "$episode" | grep -oE "^[0-9]+")
    
  •        episode=$(printf "%s" "$episode" | cut -d'>' -f2)
    
  •        ;;
    
  •    *) 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

After reinstalling and changing the cmd file, the update is working!!

Update

PowerShell 7.4.2
PS C:\Users\dhruv> scoop uninstall ani-cli
Uninstalling 'ani-cli' (4.8).
Removing shim 'ani-cli'.
Removing shim 'ani-cli.cmd'.
Unlinking ~\scoop\apps\ani-cli\current
'ani-cli' was uninstalled.
PS C:\Users\dhruv> scoop install ani-cli
Updating Scoop...
Updating Buckets...

  • d24c5fdd3134 watchman: Update to version 2024.05.20.00 main 3 hours ago
  • ce04d5b83a03 oh-my-posh: Update to version 20.0.1 main 3 hours ago
  • 68409b235e8e red: Update to version 20may24 main 7 hours ago
  • 665b1f8c36e5 red-view: Update to version 20may24 main 7 hours ago
  • bf05086aa52c red-toolchain: Update to version 20may24 main 7 hours ago
  • 0e91b06a3730 openapi-generator-cli: Update to version 7.6.0 main 7 hours ago
  • 49144b962e41 doxygen: Update to version 1.11.0 main 7 hours ago
  • 47e6bc1d6696 mihomo@1.18.5: Fix hash (Closes #5854) main 8 hours ago
  • 97a63c388d5e wstunnel: Update to version 9.5.1 main 11 hours ago
  • a0351ff69f6a tup: Update to version 0.8-7 main 11 hours ago
  • 319398f28d10 trivy: Update to version 0.51.2 main 11 hours ago
  • 32436fb8a92d sqldef: Update to version 0.17.10 main 11 hours ago
  • 9f1af27ff80f slang: Update to version 2024.1.17 main 11 hours ago
  • 30133a40d110 rust-analyzer: Update to version 2024-05-20 main 11 hours ago
  • 278e9343d9d2 python: Tweak manifest (#5850) main 13 hours ago
  • d0add1e4d8ac autocorrect: Update to version 2.9.3 main 15 hours ago
  • 7ab10179c9a6 unrar@7.0.1: Fix hash (#5839) main 17 hours ago
  • 36288e1e47ee chore: Replace deprecated env function with `(Set|Ge.. main 17 hours ago
  • 5f47f94129ea tesseract: Fix extraction (#5846) main 18 hours ago
  • 9e46b536534a static-web-server: Update to version 2.31.0 main 19 hours ago
  • 22fd315649ce realm: Update to version 2.6.0 main 19 hours ago
  • 8061e92d6509 mingw-mstorsjo-llvm-ucrt: Update to version 18.1.6-202.. main 19 hours ago
  • 7038ce57699f flaresolverr: Update to version 3.3.18 main 19 hours ago
  • 7d302aa68c11 win-acme: Update to version 2.2.8.1635 main 23 hours ago
  • 7577e64c1491 golangci-lint: Update to version 1.58.2 main 23 hours ago
  • ee1aa02f1524 sqlpage: Update to version 0.21.0 main 27 hours ago
  • 1e22c0bdee99 sing-box: Update to version 1.8.14 main 27 hours ago
  • 9a8f43b751a4 mediamtx: Update to version 1.8.2 main 27 hours ago
  • 4a1c2f804422 wstunnel: Update to version 9.5.0 main 31 hours ago
  • 9a1be8996d4d tesseract: Update to version 5.3.4.20240503 main 31 hours ago
  • 3f493355005d sqldef: Update to version 0.17.9 main 31 hours ago
  • 636e6d47bdc3 oh-my-posh: Update to version 20.0.0 main 31 hours ago
  • db05a3e5a20d luau-lsp: Update to version 1.29.1 main 31 hours ago
  • 6d1a8ee584bb whisper-cpp: Update to version 1.6.0 main 35 hours ago
  • a67fc913b32a redis: Update to version 7.2.5 main 35 hours ago
  • 2c8db14e6cbc oh-my-posh: Update to version 19.32.0 main 35 hours ago
  • 877ffb9d8237 gitql: Update to version 0.19.1 main 35 hours ago
  • 8ee8854a657e dbmate: Update to version 2.16.0 main 35 hours ago
  • 9db096f80903 red: Update to version 19may24 main 2 days ago
  • 53fd9a651ad0 red-view: Update to version 19may24 main 2 days ago
  • 651a4944590d red-toolchain: Update to version 19may24 main 2 days ago
  • be315069ddca mihomo@1.18.5: Fix hash (Closes #5845) main 2 days ago
  • 36ff212114d8 racket: Update to version 8.13 main 2 days ago
  • 901a9e40712b racket-minimal: Update to version 8.13 main 2 days ago
  • 3da535ecab37 pandoc-crossref: Update to version 0.3.17.1a main 2 days ago
  • c9873027777e aqua: Update to version 2.28.1 main 2 days ago
  • 9fbde7710587 terragrunt: Update to version 0.58.7 main 2 days ago
  • c453035109f8 vfox: Update to version 0.5.3 main 2 days ago
  • 84b0bd64b996 importexcel: Update to version 7.8.9 main 2 days ago
  • 1ae15e950f38 win-vind: Update to version 5.13.0 extras 3 hours ago
  • 2e32b4f8b5eb sidekick-browser: Update to version 122.59.1.38681-203.. extras 3 hours ago
  • 53e28477bf3d crunchy-cli: Update to version 3.6.3 extras 3 hours ago
  • 85ac3be63952 castle-view-image: Update to version 2.2.0 extras 3 hours ago
  • 72c209e87c85 zoom: Update to version 6.0.10.39647 extras 7 hours ago
  • 729c1a5931c3 xmedia-recode: Update to version 3.5.9.6 extras 7 hours ago
  • 5618603320ff sidekick-browser: Update to version 120.58.1.38488-aa4.. extras 7 hours ago
  • 0946e87940d9 s3browser: Update to version 11.7.5 extras 7 hours ago
  • abcc9ff80dba resizer: Update to version 2.2 extras 7 hours ago
  • c5fc7431eb2c microsip: Update to version 3.21.4 extras 7 hours ago
  • 5c376931d923 kdiff3: Update to version 1.11.1 extras 7 hours ago
  • 2d72dd2f81fc database.net: Update to version 36.0.8906.2 extras 7 hours ago
  • bbd062c123c8 cudatext: Update to version 1.214.6.4 extras 7 hours ago
  • f04e9444e02b sidekick-browser: Update to version 122.60.1.39616-113.. extras 11 hours ago
  • dbf1863f32d8 responsively: Update to version 1.11.1 extras 11 hours ago
  • 82db541422da jackett: Update to version 0.21.2644 extras 11 hours ago
  • 2d902c34015e glary-utilities: Update to version 6.10 extras 11 hours ago
  • 161c84ac14f5 sidekick-browser: Update to version 120.58.1.38488-aa4.. extras 15 hours ago
  • fa6e24a8f940 gui-for-clash: Update to version 1.7.2 extras 15 hours ago
  • 1bb57985dc16 qtemu@2.1: Fix hash (Closes #13316) extras 17 hours ago
  • 18f9932db3e7 windowtextextractor: Update to version 2.1.2 extras 19 hours ago
  • 4e3330168d2d stirling-pdf: Update to version 0.24.3 extras 19 hours ago
  • 8cbfd090d6f1 sidekick-browser: Update to version 122.60.1.39616-113.. extras 19 hours ago
  • 8217fd4af365 scrawler: Update to version 2024.5.19.0 extras 23 hours ago
  • 47bb35baa5b8 openark: Update to version 1.3.6 extras 23 hours ago
  • 605e72f748ac ventoy: Update to version 1.0.98 extras 27 hours ago
  • 2dc8db53a401 synfig-studio: Update to version 1.4.5 extras 27 hours ago
  • ae9fd64bc4f4 stirling-pdf: Update to version 0.24.2 extras 27 hours ago
  • 6ed30fbfe6ec oculante: Update to version 0.8.22 extras 27 hours ago
  • 7603a381cff4 hibit-uninstaller: Update to version 3.2.20 extras 27 hours ago
  • e7da581964a2 helm-ls: Update to version 0.0.17 extras 27 hours ago
  • 884c8140b5fb electerm: Update to version 1.39.18 extras 27 hours ago
  • a312d7c4c556 dbeaver: Update to version 24.0.5 extras 27 hours ago
  • c966702fb70e stirling-pdf: Update to version 0.24.1 extras 31 hours ago
  • a074065e7881 smartsystemmenu: Update to version 2.26.1 extras 31 hours ago
  • 40ef554ecdaa lazygit: Update to version 0.42.0 extras 31 hours ago
  • 2ff9f5f8e2a7 gui-for-clash: Update to version 1.7.1 extras 31 hours ago
  • 405d806bbee4 firemin@11.8.3.8398: Fix hash (Closes #13314) extras 34 hours ago
  • f497ea291d9f virtualhere-client: Update to version 5.6.4 extras 35 hours ago
  • 1866a9dbc4ad notepad2-zufuliu: Update to version 4.24.05r5242 extras 35 hours ago
  • 6355238debd9 magpie: Update to version 0.11.0 extras 35 hours ago
  • 1e7e361f3011 jackett: Update to version 0.21.2635 extras 35 hours ago
  • d3bdc7f526bf cudatext: Update to version 1.214.6.3 extras 35 hours ago
  • 4898b890d590 sidekick-browser: Update to version 120.58.1.38488-aa4.. extras 2 days ago
  • e038b06a0bdd infoqube: Update to version 125.6 extras 2 days ago
  • cb717e9bbd8c celestia@1.6.4: Fix homepage url extras 2 days ago
  • 0707d4dd1b13 mpv-git: Update to version 20240519 extras 2 days ago
  • 491302849a64 horizon-eda: Update to version 2.6.0 extras 2 days ago
  • 0de75c05f6a8 sidekick-browser: Update to version 122.59.1.38681-203.. extras 2 days ago
  • a4447a9a33dc librewolf: Update to version 126.0-1 extras 2 days ago
  • 80c26eec0c78 floorp: Update to version 11.13.1 extras 2 days ago
  • 3195e0ebb5f9 cider: Update to version 1.6.3 extras 2 days ago
  • d266624fea52 xpipe: Update to version 9.3 extras 2 days ago
  • a6f8c39ef080 ungoogled-chromium: Update to version 125.0.6422.60-1.1 extras 2 days ago
  • f21cd85fc9ee sidekick-browser: Update to version 120.58.1.38488-aa4.. extras 2 days ago
  • 0411a1f0a08d saber: Update to version 0.23.2 extras 2 days ago
  • 75898971c8c8 floorp: Update to version 11.13.0 extras 2 days ago
  • a74f161af28c fancontrol: Update to version 191 extras 2 days ago
    Scoop was updated successfully!
    WARN Scoop uses 'aria2c' for multi-connection downloads.
    WARN Should it cause issues, run 'scoop config aria2-enabled false' to disable it.
    WARN To disable this warning, run 'scoop config aria2-warning-enabled false'.
    Installing 'ani-cli' (4.8) [64bit] from 'extras' bucket
    Loading ani-cli from cache.
    Checking hash of ani-cli ... ok.
    Linking ~\scoop\apps\ani-cli\current => ~\scoop\apps\ani-cli\4.8
    Creating shim for 'ani-cli'.
    'ani-cli' (4.8) was installed successfully!
    PS C:\Users\dhruv> ani-cli -U
    patching file 'C:\Users\dhruv\scoop\apps\ani-cli\current\ani-cli'
    Script has been updated
    PS C:\Users\dhruv>

still same problem with bash even after updating:
image

again as long as its working in powershell, i am happy but if you want to debug the git bash for future references lemme know

...
PS C:\Users\dhruv> ani-cli -U
patching file 'C:\Users\dhruv\scoop\apps\ani-cli\current\ani-cli'
Script has been updated
...

Your ani-cli -U works now, right? Great.

Just remember to ani-cli -U to update the script every once in a while. Don't use scoop update ani-cli to update it unless the scoop install script is fixed.

As for the Git Bash problem, could you raise a new issue? We can try to fix it there. Someone else had this issue but it was unresolved #1097.