Skip to content

Commit ad7b874

Browse files
justchokingaround71zenithPlexTDM
authored andcommitted
fix: update api_resp req including query_hash and origin, and add filemoon provider (#1691)
Co-authored-by: zen <71zenith@proton.me> Co-authored-by: PlexTDM <tengisteka0631@gmail.com>
1 parent 766795b commit ad7b874

1 file changed

Lines changed: 126 additions & 26 deletions

File tree

ani-cli

Lines changed: 126 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/bin/sh
22

3-
version_number="4.13.0"
3+
version_number="4.14.0"
44

55
# UI
66

@@ -181,9 +181,14 @@ generate_link() {
181181
1) provider_init "wixmp" "/Default :/p" ;; # wixmp(default)(m3u8)(multi) -> (mp4)(multi)
182182
2) provider_init "youtube" "/Yt-mp4 :/p" ;; # youtube(mp4)(single)
183183
3) provider_init "sharepoint" "/S-mp4 :/p" ;; # sharepoint(mp4)(single)
184+
5) provider_init "filemoon" "/Fm-mp4 :/p" ;; # filemoon(m3u8)(single)
184185
*) provider_init "hianime" "/Luf-Mp4 :/p" ;; # hianime(m3u8)(multi)
185186
esac
186-
[ -n "$provider_id" ] && get_links "$provider_id"
187+
if [ "$1" = "5" ] && [ -n "$provider_id" ]; then
188+
get_filemoon_links "$provider_id"
189+
else
190+
[ -n "$provider_id" ] && get_links "$provider_id"
191+
fi
187192
}
188193

189194
select_quality() {
@@ -220,13 +225,66 @@ decode_tobeparsed() {
220225
printf '%s' "$plain" | tr '{}' '\n' | sed -nE 's|.*"sourceUrl":"--([^"]*)".*"sourceName":"([^"]*)".*|\2 :\1|p'
221226
}
222227

228+
b64url_to_hex() {
229+
_len=$(printf '%s' "$1" | wc -c | tr -d ' ')
230+
_mod=$((_len % 4))
231+
case $_mod in
232+
2) _pad="==" ;;
233+
3) _pad="=" ;;
234+
*) _pad="" ;;
235+
esac
236+
printf '%s%s' "$1" "$_pad" | tr -- '-_' '+/' | base64 -d | od -A n -t x1 | tr -d ' \n'
237+
}
238+
239+
get_filemoon_links() {
240+
response="$(curl -e "$allanime_refr" -s "https://${allanime_base}$1" -A "$agent")"
241+
_fm_json="$(printf '%s' "$response" | tr -d '\n ' | tr ',' '\n')"
242+
iv="$(printf '%s' "$_fm_json" | sed -nE 's|^"iv":"([^"]*)"$|\1|p')"
243+
payload="$(printf '%s' "$_fm_json" | sed -nE 's|^"payload":"([^"]*)"$|\1|p')"
244+
kp1="$(printf '%s' "$_fm_json" | sed -nE 's|^"key_parts":\["([^"]*)"$|\1|p')"
245+
kp2="$(printf '%s' "$_fm_json" | sed -nE 's|^"([A-Za-z0-9_-]+)"\]$|\1|p' | head -1)"
246+
_kp1_hex="$(b64url_to_hex "$kp1")"
247+
_kp2_hex="$(b64url_to_hex "$kp2")"
248+
key_hex="$_kp1_hex$_kp2_hex"
249+
iv_hex="$(b64url_to_hex "$iv")00000002"
250+
tmp="$(mktemp)"
251+
_fm_len=$(printf '%s' "$payload" | wc -c | tr -d ' ')
252+
_fm_mod=$((_fm_len % 4))
253+
case $_fm_mod in
254+
2) _fm_pad="==" ;;
255+
3) _fm_pad="=" ;;
256+
*) _fm_pad="" ;;
257+
esac
258+
printf '%s%s' "$payload" "$_fm_pad" | tr -- '-_' '+/' | base64 -d >"$tmp"
259+
ct_len=$(($(wc -c <"$tmp") - 16))
260+
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)"
261+
rm -f "$tmp"
262+
printf '%s' "$plain" | tr '{}[]' '\n' |
263+
sed -nE 's|.*"url":"([^"]*)".*"height":([0-9]+).*|\2 >\1|p;s|.*"height":([0-9]+).*"url":"([^"]*)".*|\1 >\2|p' |
264+
sed 's|\\u0026|\&|g;s|\\u003D|=|g' | sort -rn
265+
printf "\033[1;32m%s\033[0m Links Fetched\n" "Filemoon" 1>&2
266+
}
267+
223268
# gets embed urls, collects direct links into provider files, selects one with desired quality into $episode
224269
get_episode_url() {
225-
# get the embed urls of the selected episode
226270
#shellcheck disable=SC2016
227271
episode_embed_gql='query ($showId: String!, $translationType: VaildTranslationTypeEnumType!, $episodeString: String!) { episode( showId: $showId translationType: $translationType episodeString: $episodeString ) { episodeString sourceUrls }}'
228272

229-
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")"
273+
query_hash="d405d0edd690624b66baba3068e0edc3ac90f1597d898a1ec8db4e5c43c00fec"
274+
query_vars="{\"showId\":\"$id\",\"translationType\":\"$mode\",\"episodeString\":\"$ep_no\"}"
275+
query_ext="{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"$query_hash\"}}"
276+
277+
encoded_vars=$(printf '%s' "$query_vars" | sed 's/"/%22/g; s/:/%3A/g; s/{/%7B/g; s/}/%7D/g; s/,/%2C/g')
278+
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')
279+
280+
api_url="${allanime_api}/api?variables=${encoded_vars}&extensions=${encoded_ext}"
281+
282+
api_resp="$(curl -e "https://youtu-chan.com" -s -A "$agent" -H "Origin: https://youtu-chan.com" "$api_url")"
283+
284+
if [ -z "$api_resp" ] || ! printf "%s" "$api_resp" | grep -q "tobeparsed"; then
285+
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")"
286+
fi
287+
230288
if printf "%s" "$api_resp" | grep -q '"tobeparsed"'; then
231289
blob="$(printf "%s" "$api_resp" | sed -nE 's|.*"tobeparsed":"([^"]*)".*|\1|p')"
232290
resp="$(decode_tobeparsed "$blob")"
@@ -235,7 +293,7 @@ get_episode_url() {
235293
fi
236294
# generate links into sequential files
237295
cache_dir="$(mktemp -d)"
238-
providers="1 2 3 4"
296+
providers="1 2 3 4 5"
239297
for provider in $providers; do
240298
generate_link "$provider" >"$cache_dir"/"$provider" &
241299
done
@@ -263,14 +321,39 @@ search_anime() {
263321
time_until_next_ep() {
264322
animeschedule="https://animeschedule.net"
265323
query="$(printf "%s\n" "$*" | tr ' ' '+')"
266-
curl -s -G "$animeschedule/api/v3/anime" --data "q=${query}" | sed 's|"id"|\n|g' | sed -nE 's|.*,"route":"([^"]*)","premier.*|\1|p' | while read -r anime; do
267-
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')
268-
status="Ongoing"
269-
color="33"
270-
printf "%s\n" "$data"
271-
! (printf "%s\n" "$data" | grep -q "Next Raw Release:") && status="Finished" && color="32"
272-
printf "Status: \033[1;%sm%s\033[0m\n---\n" "$color" "$status"
273-
done
324+
325+
curl -s -G "$animeschedule/api/v3/anime" --data "q=${query}" \
326+
| sed 's|"id"|\n|g' \
327+
| sed -nE 's|.*,"route":"([^"]*)","premier.*|\1|p' \
328+
| {
329+
found=0
330+
331+
while read -r anime; do
332+
data=$(curl -s "$animeschedule/anime/$anime" \
333+
| sed '1,/"anime-header-list-buttons-wrapper"/d' \
334+
| sed -nE '
335+
s|.*countdown-time-raw" datetime="([^"]*)">.*|Next Raw Release: \1|p;
336+
s|.*countdown-time" datetime="([^"]*)">.*|Next Sub Release: \1|p;
337+
s|.*english-title">([^<]*)<.*|English Title: \1|p;
338+
s|.*main-title".*>([^<]*)<.*|Japanese Title: \1|p
339+
')
340+
341+
if printf "%s\n" "$data" | grep -q "Next Sub Release:"; then
342+
printf "%s\n" "$data"
343+
printf "Status: \033[1;33mOngoing\033[0m\n---\n"
344+
found=1
345+
break
346+
fi
347+
348+
if [ "$found" -eq 0 ]; then
349+
printf "%s\n" "$data"
350+
printf "Status: \033[1;32mFinished/Unknown\033[0m\n---\n"
351+
found=1
352+
break
353+
fi
354+
done
355+
}
356+
274357
exit 0
275358
}
276359

@@ -288,9 +371,14 @@ episodes_list() {
288371
process_hist_entry() {
289372
ep_list=$(episodes_list "$id")
290373
latest_ep=$(printf "%s\n" "$ep_list" | tail -n1)
374+
# Update episode count in title
291375
title=$(printf "%s\n" "$title" | sed "s|[0-9]\+ episodes|${latest_ep} episodes|")
292-
ep_no=$(printf "%s" "$ep_list" | sed -n "/^${ep_no}$/{n;p;}") 2>/dev/null
293-
[ -n "$ep_no" ] && printf "%s\t%s - episode %s\n" "$id" "$title" "$ep_no"
376+
next_ep=$(printf "%s" "$ep_list" | sed -n "/^${ep_no}$/{n;p;}")
377+
if [ -n "$next_ep" ]; then
378+
printf "%s\t%s - episode %s\n" "$id" "$title" "$next_ep"
379+
else
380+
printf "%s\t%s - no new episode\n" "$id" "$title"
381+
fi
294382
}
295383

296384
update_history() {
@@ -329,10 +417,6 @@ play_episode() {
329417
[ -z "$episode" ] && get_episode_url
330418
# shellcheck disable=SC2086
331419
case "$player_function" in
332-
debug)
333-
printf "All links:\n%s\nSelected link:\n" "$links"
334-
printf "%s\n" "$episode"
335-
;;
336420
mpv*)
337421
if [ "$no_detach" = 0 ]; then
338422
nohup $player_function $skip_flag --force-media-title="${allanime_title}Episode ${ep_no}" "$episode" $subs_flag $refr_flag >/dev/null 2>&1 &
@@ -423,8 +507,7 @@ exit_after_play="${ANI_CLI_EXIT_AFTER_PLAY:-0}"
423507
use_external_menu="${ANI_CLI_EXTERNAL_MENU:-0}"
424508
external_menu_normal_window="${ANI_CLI_EXTERNAL_MENU_NORMAL_WINDOW:-0}"
425509
skip_intro="${ANI_CLI_SKIP_INTRO:-0}"
426-
# shellcheck disable=SC2154
427-
skip_title="$ANI_CLI_SKIP_TITLE"
510+
skip_title="${ANI_CLI_SKIP_TITLE:-}"
428511
[ -t 0 ] || (command -v dmenu && use_external_menu=2)
429512
[ -t 0 ] || (command -v rofi && use_external_menu=1)
430513
hist_dir="${ANI_CLI_HIST_DIR:-${XDG_STATE_HOME:-$HOME/.local/state}/ani-cli}"
@@ -526,16 +609,33 @@ esac
526609

527610
# searching
528611
case "$search" in
529-
history)
530-
anime_list=$(while read -r ep_no id title; do process_hist_entry & done <"$histfile")
531-
wait
612+
history)
613+
anime_list=$(while read -r ep_no id title; do
614+
process_hist_entry
615+
done <"$histfile")
532616
[ -z "$anime_list" ] && die "No unwatched series in history!"
617+
618+
# selection
533619
[ -z "${index##*[!0-9]*}" ] && id=$(printf "%s" "$anime_list" | nl -w 2 | sed 's/^[[:space:]]//' | nth "Select anime: " | cut -f1)
534620
[ -z "${index##*[!0-9]*}" ] || id=$(printf "%s" "$anime_list" | sed -n "${index}p" | cut -f1)
621+
535622
[ -z "$id" ] && exit 1
536-
title=$(printf "%s" "$anime_list" | grep "$id" | cut -f2 | sed 's/ - episode.*//')
623+
# get original entry from history file (correct source of truth)
624+
hist_entry=$(awk -F '\t' -v id="$id" '$2 == id {print; exit}' "$histfile")
625+
626+
title=$(printf "%s" "$hist_entry" | cut -f3)
627+
ep_no=$(printf "%s" "$hist_entry" | cut -f1)
628+
537629
ep_list=$(episodes_list "$id")
538-
ep_no=$(printf "%s" "$anime_list" | grep "$id" | cut -f2 | sed -nE 's/.*- episode (.+)$/\1/p')
630+
next_ep=$(printf "%s" "$ep_list" | sed -n "/^${ep_no}$/{n;p;}")
631+
if [ "$search" = "history" ] && [ -z "$next_ep" ]; then
632+
echo ""
633+
echo "Checking next episode for: $title"
634+
echo "-------------------------------------"
635+
time_until_next_ep "$title"
636+
exit 0
637+
fi
638+
539639
allanime_title="$(printf "%s" "$title" | cut -d'(' -f1 | tr -d '[:punct:]')"
540640
;;
541641
*)

0 commit comments

Comments
 (0)