From e5523a9b480f67ee878a0cc075043313cc58e07d Mon Sep 17 00:00:00 2001 From: justchokingaround Date: Wed, 22 Apr 2026 18:05:58 +0200 Subject: [PATCH 1/7] fix: update allanime key and ct_len MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Allanime API changed encryption on 2026-04-22. - Base key: SimtVuagFbGR2K7P -> Xot36i3lK3:v1 (now includes ":v1" suffix, derived via SHA-256) - Blob format: [version:1][IV:12][ciphertext][auth_tag:16] (was: [IV:12][plaintext] — version byte was skipped) - Ciphertext length: explicit ct_len = file_size - 13 - 16 (was: read entire rest, including GCM auth tag) - Version bump: 4.12.0 -> 4.13.0 --- ani-cli | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ani-cli b/ani-cli index 36da3afda..b2a966e38 100755 --- a/ani-cli +++ b/ani-cli @@ -1,6 +1,6 @@ #!/bin/sh -version_number="4.12.0" +version_number="4.13.0" # UI @@ -211,9 +211,11 @@ select_quality() { decode_tobeparsed() { tmp="$(mktemp)" printf '%s' "$1" | base64 -d >"$tmp" - iv="$(dd if="$tmp" bs=1 count=12 2>/dev/null | od -A n -t x1 | tr -d ' \n')" + file_size="$(wc -c < "$tmp")" + iv="$(dd if="$tmp" bs=1 skip=1 count=12 2>/dev/null | od -A n -t x1 | tr -d ' \n')" ctr="${iv}00000002" - plain="$(dd if="$tmp" bs=1 skip=12 2>/dev/null | openssl enc -d -aes-256-ctr -K "$allanime_key" -iv "$ctr" -nosalt -nopad 2>/dev/null)" + ct_len=$((file_size - 13 - 16)) + plain="$(dd if="$tmp" bs=1 skip=13 count="$ct_len" 2>/dev/null | openssl enc -d -aes-256-ctr -K "$allanime_key" -iv "$ctr" -nosalt -nopad 2>/dev/null)" rm -f "$tmp" printf '%s' "$plain" | tr '{}' '\n' | sed -nE 's|.*"sourceUrl":"--([^"]*)".*"sourceName":"([^"]*)".*|\2 :\1|p' } @@ -403,7 +405,7 @@ agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefo allanime_refr="https://allmanga.to" allanime_base="allanime.day" allanime_api="https://api.${allanime_base}" -allanime_key="$(printf '%s' 'SimtVuagFbGR2K7P' | openssl dgst -sha256 -binary | od -A n -t x1 | tr -d ' \n')" +allanime_key="$(printf '%s' 'Xot36i3lK3:v1' | openssl dgst -sha256 -binary | od -A n -t x1 | tr -d ' \n')" mode="${ANI_CLI_MODE:-sub}" download_dir="${ANI_CLI_DOWNLOAD_DIR:-.}" log_episode="${ANI_CLI_LOG:-1}" From 967821592a52bf6d0481672b961f8ccae5d67cac Mon Sep 17 00:00:00 2001 From: justchokingaround Date: Wed, 22 Apr 2026 18:18:01 +0200 Subject: [PATCH 2/7] chore: shellcheck --- ani-cli | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ani-cli b/ani-cli index b2a966e38..33c504c39 100755 --- a/ani-cli +++ b/ani-cli @@ -211,7 +211,7 @@ select_quality() { decode_tobeparsed() { tmp="$(mktemp)" printf '%s' "$1" | base64 -d >"$tmp" - file_size="$(wc -c < "$tmp")" + file_size="$(wc -c <"$tmp")" iv="$(dd if="$tmp" bs=1 skip=1 count=12 2>/dev/null | od -A n -t x1 | tr -d ' \n')" ctr="${iv}00000002" ct_len=$((file_size - 13 - 16)) From 156bf9b7bd7876b228613e314fadc6bc494e3f3a Mon Sep 17 00:00:00 2001 From: justchokingaround Date: Sat, 25 Apr 2026 18:56:39 +0200 Subject: [PATCH 3/7] feat: add filemoon provider --- ani-cli | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/ani-cli b/ani-cli index 33c504c39..06e183ddf 100755 --- a/ani-cli +++ b/ani-cli @@ -1,6 +1,6 @@ #!/bin/sh -version_number="4.13.0" +version_number="4.13.1" # UI @@ -181,9 +181,14 @@ generate_link() { 1) provider_init "wixmp" "/Default :/p" ;; # wixmp(default)(m3u8)(multi) -> (mp4)(multi) 2) provider_init "youtube" "/Yt-mp4 :/p" ;; # youtube(mp4)(single) 3) provider_init "sharepoint" "/S-mp4 :/p" ;; # sharepoint(mp4)(single) + 5) provider_init "filemoon" "/Fm-mp4 :/p" ;; # filemoon(m3u8)(single) *) provider_init "hianime" "/Luf-Mp4 :/p" ;; # hianime(m3u8)(multi) esac - [ -n "$provider_id" ] && get_links "$provider_id" + if [ "$1" = "5" ] && [ -n "$provider_id" ]; then + get_filemoon_links "$provider_id" + else + [ -n "$provider_id" ] && get_links "$provider_id" + fi } select_quality() { @@ -220,6 +225,44 @@ decode_tobeparsed() { printf '%s' "$plain" | tr '{}' '\n' | sed -nE 's|.*"sourceUrl":"--([^"]*)".*"sourceName":"([^"]*)".*|\2 :\1|p' } +b64url_to_hex() { + _len=$(printf '%s' "$1" | wc -c | tr -d ' ') + _mod=$((_len % 4)) + case $_mod in + 2) _pad="==" ;; + 3) _pad="=" ;; + *) _pad="" ;; + esac + printf '%s%s' "$1" "$_pad" | tr -- '-_' '+/' | base64 -d | od -A n -t x1 | tr -d ' \n' +} + +get_filemoon_links() { + response="$(curl -e "$allanime_refr" -s "https://${allanime_base}$1" -A "$agent")" + _fm_json="$(printf '%s' "$response" | tr -d '\n ' | tr ',' '\n')" + iv="$(printf '%s' "$_fm_json" | sed -nE 's|^"iv":"([^"]*)"$|\1|p')" + payload="$(printf '%s' "$_fm_json" | sed -nE 's|^"payload":"([^"]*)"$|\1|p')" + kp1="$(printf '%s' "$_fm_json" | sed -nE 's|^"key_parts":\["([^"]*)"$|\1|p')" + kp2="$(printf '%s' "$_fm_json" | sed -nE 's|^"([A-Za-z0-9_-]+)"\]$|\1|p' | head -1)" + key_hex="$(b64url_to_hex "$kp1")$(b64url_to_hex "$kp2")" + iv_hex="$(b64url_to_hex "$iv")00000002" + tmp="$(mktemp)" + _fm_len=$(printf '%s' "$payload" | wc -c | tr -d ' ') + _fm_mod=$((_fm_len % 4)) + case $_fm_mod in + 2) _fm_pad="==" ;; + 3) _fm_pad="=" ;; + *) _fm_pad="" ;; + esac + printf '%s%s' "$payload" "$_fm_pad" | tr -- '-_' '+/' | base64 -d >"$tmp" + ct_len=$(($(wc -c <"$tmp") - 16)) + plain="$(dd if="$tmp" bs=1 count="$ct_len" 2>/dev/null | openssl enc -d -aes-256-ctr -K "$key_hex" -iv "$iv_hex" -nosalt -nopad 2>/dev/null)" + rm -f "$tmp" + printf '%s' "$plain" | tr '{}[]' '\n' | + sed -nE 's|.*"url":"([^"]*)".*"height":([0-9]+).*|\2 >\1|p;s|.*"height":([0-9]+).*"url":"([^"]*)".*|\1 >\2|p' | + sed 's|\\u0026|\&|g;s|\\u003D|=|g' | sort -rn + printf "\033[1;32m%s\033[0m Links Fetched\n" "Filemoon" 1>&2 +} + # 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 @@ -235,7 +278,7 @@ get_episode_url() { fi # 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 From 1ccbf71ff83dd63e5beebdfbf04a2d8c1df3672b Mon Sep 17 00:00:00 2001 From: justchokingaround Date: Mon, 27 Apr 2026 12:51:48 +0200 Subject: [PATCH 4/7] fix: update api_resp req including query_hash and origin --- ani-cli | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/ani-cli b/ani-cli index 06e183ddf..6e3382596 100755 --- a/ani-cli +++ b/ani-cli @@ -1,6 +1,6 @@ #!/bin/sh -version_number="4.13.1" +version_number="4.14.0" # UI @@ -184,6 +184,7 @@ generate_link() { 5) provider_init "filemoon" "/Fm-mp4 :/p" ;; # filemoon(m3u8)(single) *) provider_init "hianime" "/Luf-Mp4 :/p" ;; # hianime(m3u8)(multi) esac + [ -n "$provider_id" ] && provider_id="${provider_id#/https://${allanime_base}}" if [ "$1" = "5" ] && [ -n "$provider_id" ]; then get_filemoon_links "$provider_id" else @@ -265,11 +266,26 @@ get_filemoon_links() { # 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 #shellcheck disable=SC2016 episode_embed_gql='query ($showId: String!, $translationType: VaildTranslationTypeEnumType!, $episodeString: String!) { episode( showId: $showId translationType: $translationType episodeString: $episodeString ) { episodeString sourceUrls }}' - api_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")" + #shellcheck disable=SC2016 + query_hash="d405d0edd690624b66baba3068e0edc3ac90f1597d898a1ec8db4e5c43c00fec" + query_vars="{\"showId\":\"$id\",\"translationType\":\"$mode\",\"episodeString\":\"$ep_no\"}" + query_ext="{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"$query_hash\"}}" + + #shellcheck disable=SC2016 + encoded_vars=$(printf '%s' "$query_vars" | sed 's/"/%22/g; s/:/%3A/g; s/{/%7B/g; s/}/%7D/g; s/,/%2C/g') + encoded_ext=$(printf '%s' "$query_ext" | sed 's/"/%22/g; s/:/%3A/g; s/{/%7B/g; s/}/%7D/g; s/,/%2C/g; s/ /%20/g') + + api_url="${allanime_api}/api?variables=${encoded_vars}&extensions=${encoded_ext}" + + api_resp="$(curl -e "$allanime_refr" -s -A "$agent" -H "Origin: https://youtu-chan.com" "$api_url")" + + if [ -z "$api_resp" ] || ! printf "%s" "$api_resp" | grep -q "tobeparsed"; then + api_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")" + fi + if printf "%s" "$api_resp" | grep -q '"tobeparsed"'; then blob="$(printf "%s" "$api_resp" | sed -nE 's|.*"tobeparsed":"([^"]*)".*|\1|p')" resp="$(decode_tobeparsed "$blob")" From 3620be56144a9de1a544cc3773392d71ef9c5130 Mon Sep 17 00:00:00 2001 From: justchokingaround Date: Mon, 27 Apr 2026 13:02:38 +0200 Subject: [PATCH 5/7] style: apply shfmt formatting From 9b46d3183321144641847df932dee2541ba0f672 Mon Sep 17 00:00:00 2001 From: justchokingaround Date: Mon, 27 Apr 2026 13:05:25 +0200 Subject: [PATCH 6/7] fix: correct pattern expansion and add shellcheck disable --- ani-cli | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ani-cli b/ani-cli index 6e3382596..443f9597b 100755 --- a/ani-cli +++ b/ani-cli @@ -184,7 +184,7 @@ generate_link() { 5) provider_init "filemoon" "/Fm-mp4 :/p" ;; # filemoon(m3u8)(single) *) provider_init "hianime" "/Luf-Mp4 :/p" ;; # hianime(m3u8)(multi) esac - [ -n "$provider_id" ] && provider_id="${provider_id#/https://${allanime_base}}" + [ "${provider_id#https://}" != "$provider_id" ] || provider_id="https://${allanime_base}${provider_id}" if [ "$1" = "5" ] && [ -n "$provider_id" ]; then get_filemoon_links "$provider_id" else @@ -244,6 +244,7 @@ get_filemoon_links() { payload="$(printf '%s' "$_fm_json" | sed -nE 's|^"payload":"([^"]*)"$|\1|p')" kp1="$(printf '%s' "$_fm_json" | sed -nE 's|^"key_parts":\["([^"]*)"$|\1|p')" kp2="$(printf '%s' "$_fm_json" | sed -nE 's|^"([A-Za-z0-9_-]+)"\]$|\1|p' | head -1)" + # shellcheck disable=SC2312 key_hex="$(b64url_to_hex "$kp1")$(b64url_to_hex "$kp2")" iv_hex="$(b64url_to_hex "$iv")00000002" tmp="$(mktemp)" From 9415864942f9097d6ce0fad2176f32331d377113 Mon Sep 17 00:00:00 2001 From: ikanop <113450482+ikanop@users.noreply.github.com> Date: Wed, 6 May 2026 09:19:55 +0200 Subject: [PATCH 7/7] organise downloads into per-show folders in home --- ani-cli | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ani-cli b/ani-cli index 443f9597b..7efded7cc 100755 --- a/ani-cli +++ b/ani-cli @@ -467,7 +467,7 @@ allanime_base="allanime.day" allanime_api="https://api.${allanime_base}" allanime_key="$(printf '%s' 'Xot36i3lK3:v1' | openssl dgst -sha256 -binary | od -A n -t x1 | tr -d ' \n')" mode="${ANI_CLI_MODE:-sub}" -download_dir="${ANI_CLI_DOWNLOAD_DIR:-.}" +download_dir="$HOME/ani-cli-downloads/$title" log_episode="${ANI_CLI_LOG:-1}" quality="${ANI_CLI_QUALITY:-best}" case "$(uname -a | cut -d " " -f 1,3-)" in