diff --git a/.github/workflows/ani-cli.yml b/.github/workflows/ani-cli.yml
index 884fc4376..69292b5a4 100644
--- a/.github/workflows/ani-cli.yml
+++ b/.github/workflows/ani-cli.yml
@@ -4,7 +4,7 @@ on:
branches:
- master
pull_request:
- paths:
+ paths:
- "**ani-cli"
jobs:
@@ -12,18 +12,20 @@ jobs:
name: Shellcheck + Shfmt
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Run the sh-checker
uses: luizm/action-sh-checker@master
env:
SHELLCHECK_OPTS: -s sh -o all -e 2250
SHFMT_OPTS: -i 4 -ci -d
+ with:
+ sh_checker_exclude: "_ani-cli-bash _ani-cli-zsh"
check-exec:
name: Executable Bit
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: test exec bit
run: test -x "./ani-cli"
@@ -31,6 +33,6 @@ jobs:
name: No Awk Allowed
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: verify that noone added awk
run: '! grep awk "./ani-cli"'
diff --git a/.github/workflows/inverse-ani.yml b/.github/workflows/inverse-ani.yml
index c19f9cd2a..75bb5076a 100644
--- a/.github/workflows/inverse-ani.yml
+++ b/.github/workflows/inverse-ani.yml
@@ -5,7 +5,7 @@ name: 'ani-cli checks'
on:
pull_request:
paths-ignore:
- - "**ani-cli"
+ - "/ani-cli"
jobs:
sh-checker:
name: Shellcheck + Shfmt
diff --git a/.github/workflows/markdown.yml b/.github/workflows/markdown.yml
index 0dacb020b..6bc210753 100644
--- a/.github/workflows/markdown.yml
+++ b/.github/workflows/markdown.yml
@@ -22,5 +22,5 @@ jobs:
name: Find Trailing Whitespace
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: ocular-d/trailing-spaces@0.0.2
diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml
index d8ce20d21..5bdb93046 100644
--- a/.github/workflows/version.yml
+++ b/.github/workflows/version.yml
@@ -2,14 +2,14 @@ name: 'ani-cli checks'
on:
pull_request:
paths:
- - "**ani-cli"
+ - "/ani-cli"
jobs:
version-bump:
name: Version Bump
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- name: check version bump
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7e3919dec..7eeb31147 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -20,32 +20,3 @@
- Take part in troubleshooting and testing
- Star the repo
- Follow the maintainers
-
-## Development with nix
-
-When you develop with nix you can use the [dev shell](https://github.com/pystardust/ani-cli#nix-shell).
-
-To run the dev shell you can run the following command in the repository root:
-```shell
-nix-shell
-```
-
-The dev shell includes the following packages:
-- runtime dependencies of ani-cli
-- shfmt
-- shellcheck
-
-Its also possible to use alternative packages for the video player or add features with this command:
-```shell
-nix-shell --arg true
-```
-These are the packages available in the dev shell:
-- `withVlc`
-- `withIina`
-- `chromecastSupport`
-- `syncSupport`
-
-Just chain these commands together when you wanna multiple features for example:
-```shell
-nix-shell --arg withVlc true --arg chromecastSupport true
-```
diff --git a/README.md b/README.md
index 7225be8ca..23f700f0a 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@
-A cli to browse and watch anime (alone AND with friends). This tool scrapes the site allanime.
+A cli to browse and watch anime (alone AND with friends). This tool scrapes the site allmanga.
@@ -39,8 +39,12 @@ A cli to browse and watch anime (alone AND with friends). This tool scrapes the
- [Tier 2: Windows, WSL, iOS, Steam Deck, FreeBSD](#tier-2-support-windows-wsl-ios-steam-deck-FreeBSD)
- [From Source](#installing-from-source)
- [Uninstall](#uninstall)
+- [Completion](#completion)
+ - [bash](#bash)
+ - [zsh](#zsh)
- [Dependencies](#dependencies-1)
- [Ani-Skip](#ani-skip)
+- [FAQ](#faq)
- [Homies](#homies)
- [Contribution Guidelines](./CONTRIBUTING.md)
- [Disclaimer](./disclaimer.md)
@@ -495,6 +499,24 @@ apk del grep sed curl fzf git aria2 ffmpeg ncurses
+## Completion
+
+### bash
+
+To add tab completions using bash run the following command inside the ani-cli directory
+```
+cp _ani-cli-bash /path/to/your/completions
+echo "source /path/to/your/completions/_ani-cli-bash" >> ~/.bashrc
+```
+
+### zsh
+
+To add tab completions using zsh run the following command inside the ani-cli directory
+```
+cp _ani-cli-zsh /path/to/your/completions
+echo "source /path/to/your/completions/_ani-cli-zsh" >> ~/.zshrc
+```
+
## Dependencies
- grep
@@ -521,9 +543,26 @@ Ani-skip uses the external lua script function of mpv and as such – for now
**Note:** It may be, that ani-skip won't know the anime you're trying to watch. Try using the `--skip-title ` command line argument. (It uses the [aniskip API](https://github.com/lexesjan/typescript-aniskip-extension/tree/main/src/api/aniskip-http-client) and you can contribute missing anime or ask for including it in the database on their [discord server](https://discord.com/invite/UqT55CbrbE)).
+## FAQ
+
+
+* Can I change subtitle language or turn them off? - No, the subtitles are baked into the video.
+* Can I watch dub? - Yes, use `--dub`.
+* Can I change dub language? - No.
+* Can I change media source? - No (unless you can scrape that source yourself).
+* Can I use vlc? - Yes, use `--vlc` or `export ANI_CLI_PLAYER=vlc`.
+* Can I adjust resolution? - Yes, use `-q resolution`, for example `ani-cli -q 1080`.
+* How can I download? - Use `-d`, it will download into your working directory.
+* Can i change download folder? - Yes, set the `ANI_CLI_DOWNLOAD_DIR` to your desired location.
+* How can I bulk download? - `Use -d -e firstepisode-lastepisode`, for example `ani-cli onepiece -d -e 1-1000`.
+
+**Note:** All features are documented in `ani-cli --help`.
+
+
+
## Homies
-* [animdl](https://github.com/justfoolingaround/animdl): Ridiculously efficient, fast and light-weight (supports most sources: allanime, zoro ... (Python)
+* [animdl](https://github.com/justfoolingaround/animdl): Ridiculously efficient, fast and light-weight (supports most sources: allmanga, zoro ... (Python)
* [jerry](https://github.com/justchokingaround/jerry): stream anime with anilist tracking and syncing, with discord presence (Shell)
* [anipy-cli](https://github.com/sdaqo/anipy-cli): ani-cli rewritten in python (Python)
* [Dantotsu](https://github.com/rebelonion/Dantotsu): Rebirth of Saikou, Best android app for anime/manga/LN with anilist integration (Kotlin)
@@ -534,3 +573,5 @@ Ani-skip uses the external lua script function of mpv and as such – for now
* [redqu](https://github.com/port19x/redqu): A media centric reddit client (Clojure)
* [doccli](https://github.com/TowarzyszFatCat/doccli): A cli to watch anime with POLISH subtitles (Python)
* [GoAnime](https://github.com/alvarorichard/GoAnime): A CLI tool to browse, play, and download anime in Portuguese(Go)
+* [Curd](https://github.com/Wraient/curd): A CLI tool to watch anime with Anilist, Discord RPC, Skip Intro/Outro/Filler/Recap (Go)
+- [FastAnime](https://github.com/Benex254/FastAnime): browser anime experience from the terminal (Python)
diff --git a/ani-cli b/ani-cli
index 7eadcefdd..0458eaa5a 100755
--- a/ani-cli
+++ b/ani-cli
@@ -1,6 +1,6 @@
#!/bin/sh
-version_number="4.9.0"
+version_number="4.9.6"
# UI
@@ -116,10 +116,13 @@ dep_ch() {
}
where_iina() {
- [ -n "$ANI_CLI_PLAYER" ] && printf "%s" "$ANI_CLI_PLAYER" && return 0
- command -v iina >/dev/null && printf "iina" && return 0
[ -e "/Applications/IINA.app/Contents/MacOS/iina-cli" ] && echo "/Applications/IINA.app/Contents/MacOS/iina-cli" && return 0
- dep_ch iina # exit with formating
+ printf "%s" "iina" && return 0
+}
+
+where_mpv() {
+ command -v "flatpak" >/dev/null && flatpak info io.mpv.Mpv >/dev/null 2>&1 && printf "%s" "flatpak_mpv" && return 0
+ printf "%s" "mpv" && return 0
}
# SCRAPING
@@ -130,6 +133,13 @@ get_links() {
|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"
@@ -145,7 +155,7 @@ get_links() {
[ -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
+# initialises 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/../&\
@@ -155,9 +165,10 @@ provider_init() {
# generates links based on given provider
generate_link() {
case $1 in
- 1) provider_init "dropbox" "/Sak :/p" ;; # dropbox(mp4)(single)
- 2) provider_init "wetransfer" "/Kir :/p" ;; # wetransfer(mp4)(single)
- 3) provider_init "sharepoint" "/S-mp4 :/p" ;; # sharepoint(mp4)(single)
+ 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"
@@ -181,7 +192,7 @@ get_episode_url() {
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"
+ providers="1 2 3 4 5"
for provider in $providers; do
generate_link "$provider" >"$cache_dir"/"$provider" &
done
@@ -190,7 +201,11 @@ get_episode_url() {
links=$(cat "$cache_dir"/* | sed 's|^Mp4-||g;/http/!d;/Alt/d' | sort -g -r -s)
rm -r "$cache_dir"
episode=$(select_quality "$quality")
- [ -z "$episode" ] && die "Episode not released!"
+ if printf "%s" "$ep_list" | grep -q "^$ep_no$"; then
+ [ -z "$episode" ] && die "Episode is released, but no valid sources!"
+ else
+ [ -z "$episode" ] && die "Episode not released!"
+ fi
}
# search the query and give results
@@ -198,12 +213,12 @@ 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"
+| g' | sed -nE "s|.*_id\":\"([^\"]*)\",\"name\":\"(.+)\",.*${mode}\":([1-9][^,]*).*|\1 \2 (\3 episodes)|p" | sed 's/\\"//g'
}
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
+ curl -s -G "$animeschedule/api/v3/anime" --data "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"
@@ -234,7 +249,7 @@ process_hist_entry() {
update_history() {
if grep -q -- "$id" "$histfile"; then
- sed -E "s|^[^\t]+\t${id}\t[^\t]+$|${ep_no}\t${id}\t${title}|" "$histfile" >"${histfile}.new"
+ sed -E "s|^[^ ]+ ${id} [^ ]+$|${ep_no} ${id} ${title}|" "$histfile" >"${histfile}.new"
else
cp "$histfile" "${histfile}.new"
printf "%s\t%s\t%s\n" "$ep_no" "$id" "$title" >>"${histfile}.new"
@@ -317,7 +332,7 @@ play() {
else
play_episode
fi
- # moves upto stored positon and deletes to end
+ # moves up to stored position and deletes to end
[ "$player_function" != "debug" ] && [ "$player_function" != "download" ] && tput rc && tput ed
}
@@ -325,20 +340,19 @@ play() {
# 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_refr="https://allmanga.to"
allanime_base="allanime.day"
allanime_api="https://api.${allanime_base}"
mode="${ANI_CLI_MODE:-sub}"
download_dir="${ANI_CLI_DOWNLOAD_DIR:-.}"
log_episode="${ANI_CLI_LOG:-1}"
quality="${ANI_CLI_QUALITY:-best}"
-case "$(uname -a)" in
- *Darwin*) player_function="$(where_iina)" ;; # mac OS
+case "$(uname -a | cut -d " " -f 1,3-)" in
+ *Darwin*) player_function="${ANI_CLI_PLAYER:-$(where_iina)}" ;; # mac OS
*ndroid*) player_function="${ANI_CLI_PLAYER:-android_mpv}" ;; # Android OS (termux)
- *neptune*) 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
+ *) player_function="${ANI_CLI_PLAYER:-$(where_mpv)}" ;; # Linux OS
esac
no_detach="${ANI_CLI_NO_DETACH:-0}"
@@ -357,7 +371,7 @@ search="${ANI_CLI_DEFAULT_SOURCE:-scrape}"
while [ $# -gt 0 ]; do
case "$1" in
-v | --vlc)
- case "$(uname -a)" in
+ case "$(uname -a | cut -d " " -f 1,3-)" in
*ndroid*) player_function="android_vlc" ;;
MINGW* | *WSL2*) player_function="vlc.exe" ;;
*ish*) player_function="iSH" ;;
@@ -431,13 +445,10 @@ 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" ;;
- *iina*) true ;; # handled out of band in where_iina
+ *IINA*) true ;; # handled out of band in where_iina
+ flatpak_mpv) true ;; # handled out of band in where_mpv
*) dep_ch "$player_function" ;;
esac
@@ -485,7 +496,7 @@ esac
# moves the cursor up one line and clears that line
tput cuu1 && tput el
-# stores the positon of cursor
+# stores the position of cursor
tput sc
# playback & loop
diff --git a/hacking.md b/hacking.md
index f361a4dc7..e291a2e4e 100644
--- a/hacking.md
+++ b/hacking.md
@@ -3,7 +3,7 @@ Ani-cli is set up to scrape one platform - currently allanime. Supporting multip
However ani-cli being open-source and the pirate anime streaming sites being so similar you can hack ani-cli to support any site that follows a few conventions.
-## Prequisites
+## Prerequisites
Here's the of skills you'll need and the guide will take for granted:
- basic shell scripting
- understanding of http(s) requests and proficiency with curl
@@ -33,7 +33,7 @@ An adblocker can help with reducing traffic from the site, but beware of extensi
Once you have the pages (urls) that you're interested in, it's easier to inspect them from less/an editor.
The debugger's inspector can help you with finding what's what but finding patterns/urls is much easier in an editor.
-Additionally the debugger doesn't always show you the html faithfully - I've experineced some escape sequences being rendered, capitalization changing - so be sure you see the response of the servers in raw format before you write your regexes.
+Additionally the debugger doesn't always show you the html faithfully - I've experienced some escape sequences being rendered, capitalization changing - so be sure you see the response of the servers in raw format before you write your regexes.
### Core concepts
If you navigate the site normally from the browser, you'll see that each anime is represented with an URL that compromises from an ID (that identifies a series/season of series) and an episode number.
@@ -50,7 +50,7 @@ Just try searching for a few series and see how the URL changes (most of the tim
If the site uses a POST request or a more roundabout way, use the debugger to analyze the traffic.
Once you figured out how searching works, you'll have to replicate it in the `search_anime` function.
-The `curl` in this function is responsible for the search request, and the following `sed` regexes mold the respons into many lines of `id\ttitle` format.
+The `curl` in this function is responsible for the search request, and the following `sed` regexes mold the response into many lines of `id\ttitle` format.
The reason for this is the `nth` function, see it for more details.
You'll have to change some variables in the process (eg. allanime_base) too.
@@ -83,7 +83,7 @@ From here they are separated and parsed by `provider_init` and the first half on
Some sites (like allanime) have these urls not in plaintext but "encrypted". The decrypt allanime function does this post-processing, it might need to be changed or discarded completely.
If there's only one embed source, the `generate links..` block can be reduced to a single call to `generate_link`.
-The current structure does the agregation of many providers asynchronously, but this is not needed if there's only one source.
+The current structure does the aggregation of many providers asynchronously, but this is not needed if there's only one source.
### Extracting the media links
diff --git a/shell.nix b/shell.nix
deleted file mode 100644
index 5d1624704..000000000
--- a/shell.nix
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- pkgs ? import {},
- withMpv ? true,
- withVlc ? false,
- withIina ? false,
- chromecastSupport ? false,
- syncSupport ? false
-}:
-
-# To start the dev shell use the comment nix-shell
-# use --arg withVlc true to use VLC
-# use --arg withIina true to use Iina
-# use --arg chromecastSupport true to use chromecastSupport
-# use --arg syncSupport true to use syncSupport
-
-assert withMpv || withVlc || withIina;
-
-with pkgs;
-mkShell {
- name = "ani-cli dev shell";
- buildInputs = [ shfmt shellcheck (ani-cli.override ({ withMpv = withMpv; withVlc = withVlc; withIina = withIina; chromecastSupport = chromecastSupport; syncSupport = syncSupport; })).runtimeDependencies ];
-}