Skip to content

Commit

Permalink
Merge branch 'pystardust:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Lockl00p authored Jan 15, 2025
2 parents 6d7b43b + 2595908 commit 310a774
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 91 deletions.
10 changes: 6 additions & 4 deletions .github/workflows/ani-cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,35 @@ on:
branches:
- master
pull_request:
paths:
paths:
- "**ani-cli"

jobs:
sh-checker:
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"

check-no-awk:
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"'
2 changes: 1 addition & 1 deletion .github/workflows/inverse-ani.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name: 'ani-cli checks'
on:
pull_request:
paths-ignore:
- "**ani-cli"
- "/ani-cli"
jobs:
sh-checker:
name: Shellcheck + Shfmt
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/markdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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/[email protected]
4 changes: 2 additions & 2 deletions .github/workflows/version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 0 additions & 29 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <feature> 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
```
45 changes: 43 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
</p>

<h3 align="center">
A cli to browse and watch anime (alone AND with friends). This tool scrapes the site <a href="https://allanime.to/">allanime.</a>
A cli to browse and watch anime (alone AND with friends). This tool scrapes the site <a href="https://allmanga.to/">allmanga.</a>
</h3>

<h1 align="center">
Expand All @@ -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)
Expand Down Expand Up @@ -495,6 +499,24 @@ apk del grep sed curl fzf git aria2 ffmpeg ncurses

</details>

## 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
Expand All @@ -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 <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
<details>

* 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`.

</details>

## 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)
Expand All @@ -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)
63 changes: 37 additions & 26 deletions ani-cli
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/sh

version_number="4.9.0"
version_number="4.9.6"

# UI

Expand Down Expand Up @@ -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
Expand All @@ -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"
Expand All @@ -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/../&\
Expand All @@ -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"
Expand All @@ -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
Expand All @@ -190,20 +201,24 @@ 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
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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -317,28 +332,27 @@ 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
}

# 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_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}"
Expand All @@ -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" ;;
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions hacking.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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.

Expand Down Expand Up @@ -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

Expand Down
Loading

0 comments on commit 310a774

Please sign in to comment.