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
189194select_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
224269get_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
@@ -423,8 +481,7 @@ exit_after_play="${ANI_CLI_EXIT_AFTER_PLAY:-0}"
423481use_external_menu=" ${ANI_CLI_EXTERNAL_MENU:- 0} "
424482external_menu_normal_window=" ${ANI_CLI_EXTERNAL_MENU_NORMAL_WINDOW:- 0} "
425483skip_intro=" ${ANI_CLI_SKIP_INTRO:- 0} "
426- # shellcheck disable=SC2154
427- skip_title=" $ANI_CLI_SKIP_TITLE "
484+ skip_title=" ${ANI_CLI_SKIP_TITLE:- } "
428485[ -t 0 ] || (command -v dmenu && use_external_menu=2)
429486[ -t 0 ] || (command -v rofi && use_external_menu=1)
430487hist_dir=" ${ANI_CLI_HIST_DIR:- ${XDG_STATE_HOME:- $HOME / .local/ state} / ani-cli} "
0 commit comments