Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ cd .. && rm -rf ./ani-cli
*To install (with Homebrew) the dependencies required on Mac OS, you can run:*

```sh
brew install curl grep aria2 ffmpeg git fzf yt-dlp && \
brew install curl grep aria2 ffmpeg git fzf yt-dlp python3 && \
pip3 install pycryptodome && \
brew install --cask iina
```
*Why iina and not mpv? Drop-in replacement for mpv for MacOS. Integrates well with OSX UI. Excellent support for M1. Open Source.*
Expand Down Expand Up @@ -509,6 +510,8 @@ apk del grep sed curl fzf git aria2 ffmpeg ncurses
- fzf - User interface
- ani-skip (optional)
- patch - Self updating
- python3 - Decryption
- pycryptodome (python library) - Decryption

### Ani-Skip

Expand Down
56 changes: 52 additions & 4 deletions ani-cli
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/sh

version_number="4.11.0"
version_number="4.12.0"

# UI

Expand Down Expand Up @@ -214,7 +214,45 @@ get_episode_url() {
#shellcheck disable=SC2016
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 -H "Content-Type: application/json" -X POST "${allanime_api}/api" --data "{\"variables\":{\"showId\":\"$id\",\"translationType\":\"$mode\",\"episodeString\":\"$ep_no\"},\"query\":\"$episode_embed_gql\"}" -A "$agent" | tr '{}' '\n' | sed 's|\\u002F|\/|g;s|\\||g' | sed -nE 's|.*sourceUrl":"--([^"]*)".*sourceName":"([^"]*)".*|\2 :\1|p')
payload="{\"variables\":{\"showId\":\"$id\",\"translationType\":\"$mode\",\"episodeString\":\"$ep_no\"},\"query\":\"$episode_embed_gql\"}"
resp_raw=$(curl -e "$allanime_refr" -s -H "Content-Type: application/json" -X POST "${allanime_api}/api" --data "$payload" -A "$agent")

# Handle tobeparsed if present
if printf "%s" "$resp_raw" | grep -q "\"tobeparsed\""; then
tbp=$(printf "%s" "$resp_raw" | sed -nE 's/.*"tobeparsed":"([^"]*)".*/\1/p')
# AES-GCM decryption logic
# Key: sha256 of "SimtVaugFbGR2K7P"
# IV: first 12 bytes
# Tag: last 16 bytes
# Ciphertext: middle bytes

# We use python3 for decryption as it's more reliable for AES-GCM than raw openssl in shell
resp=$(python3 -c "
import base64, hashlib, json, sys
from Crypto.Cipher import AES
tbp = sys.stdin.read().strip()
raw = base64.b64decode(tbp)
key = hashlib.sha256(\"P7K2RGbFgauVtmiS\"[::-1].encode()).digest()
iv, ciphertext, tag = raw[:12], raw[12:-16], raw[-16:]
cipher = AES.new(key, AES.MODE_GCM, nonce=iv)
try:
decrypted = cipher.decrypt_and_verify(ciphertext, tag).decode('utf-8')
data = json.loads(decrypted)
for source in data.get('episode', {}).get('sourceUrls', []):
url = source['sourceUrl']
if url.startswith('--'):
url = url[2:]
print(f\"{source['sourceName']} :{url}\")
except Exception:
pass
" << EOF
$tbp
EOF
)
else
resp=$(printf "%s" "$resp_raw" | tr '{}' '\n' | sed 's|\\u002F|\/|g;s|\\||g' | sed -nE 's|.*sourceUrl":"--([^"]*)".*sourceName":"([^"]*)".*|\2 :\1|p')
fi

# generate links into sequential files
cache_dir="$(mktemp -d)"
providers="1 2 3 4"
Expand All @@ -238,8 +276,18 @@ search_anime() {
#shellcheck disable=SC2016
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 -H "Content-Type: application/json" -X POST "${allanime_api}/api" --data "{\"variables\":{\"search\":{\"allowAdult\":false,\"allowUnknown\":false,\"query\":\"$1\"},\"limit\":40,\"page\":1,\"translationType\":\"$mode\",\"countryOrigin\":\"ALL\"},\"query\":\"$search_gql\"}" -A "$agent" | sed 's|Show|\
| g' | sed -nE "s|.*_id\":\"([^\"]*)\",\"name\":\"(.+)\",.*${mode}\":([1-9][^,]*).*|\1 \2 (\3 episodes)|p" | sed 's/\\"//g'
search_tmp=$(mktemp)
curl -e "$allanime_refr" -s -H "Content-Type: application/json" -X POST "${allanime_api}/api" --data "{\"variables\":{\"search\":{\"allowAdult\":false,\"allowUnknown\":false,\"query\":\"$1\"},\"limit\":40,\"page\":1,\"translationType\":\"$mode\",\"countryOrigin\":\"ALL\"},\"query\":\"$search_gql\"}" -A "$agent" -o "$search_tmp"

python3 -c "
import json, sys
with open('$search_tmp', 'r') as f:
data = json.load(f)
mode = '$mode'
for edge in data.get('data', {}).get('shows', {}).get('edges', []):
print(f\"{edge['_id']}\t{edge['name']} ({edge['availableEpisodes'].get(mode, 0)} episodes)\")
"
rm "$search_tmp"
}

time_until_next_ep() {
Expand Down
Loading