ani-cli-npm 2.1.4 → 2.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. package/.idea/ani-cli-npm.iml +11 -11
  2. package/.idea/discord.xml +6 -6
  3. package/.idea/git_toolbox_prj.xml +15 -0
  4. package/.idea/inspectionProfiles/Project_Default.xml +10 -0
  5. package/.idea/jsLibraryMappings.xml +5 -5
  6. package/.idea/modules.xml +7 -7
  7. package/.idea/vcs.xml +5 -5
  8. package/README.MD +79 -77
  9. package/bin/Anime.js +409 -393
  10. package/bin/IO/help.js +59 -0
  11. package/bin/IO/input.js +89 -0
  12. package/bin/cache.js +79 -0
  13. package/bin/change_config.js +99 -0
  14. package/bin/core_utils/curl.js +35 -35
  15. package/bin/core_utils/interfaces.js +2 -2
  16. package/bin/core_utils/libs.js +12 -12
  17. package/bin/core_utils/regex.js +8 -8
  18. package/bin/cover_manager.js +3 -0
  19. package/bin/curl.js +35 -0
  20. package/bin/download.js +36 -36
  21. package/bin/file_managment/cache.js +87 -87
  22. package/bin/file_managment/change_config.js +122 -121
  23. package/bin/file_managment/load_config.js +111 -110
  24. package/bin/generate_link.js +47 -47
  25. package/bin/help.js +59 -59
  26. package/bin/index.js +164 -159
  27. package/bin/input.js +89 -89
  28. package/bin/interfaces.js +2 -0
  29. package/bin/libs.js +12 -0
  30. package/bin/load_config.js +106 -0
  31. package/bin/regex.js +8 -0
  32. package/bin/search_anime.js +39 -39
  33. package/bin/url_genoration/generate_link.js +47 -0
  34. package/bin/url_genoration/search_anime.js +39 -0
  35. package/bin/video_quality.js +6 -0
  36. package/package.json +45 -45
  37. package/src/Anime.ts +427 -0
  38. package/src/IO/help.ts +64 -0
  39. package/src/IO/input.ts +92 -0
  40. package/src/core_utils/curl.ts +32 -0
  41. package/src/core_utils/interfaces.ts +25 -0
  42. package/src/core_utils/libs.ts +13 -0
  43. package/src/core_utils/regex.ts +5 -0
  44. package/src/cover_manager.ts +9 -0
  45. package/src/download.ts +35 -0
  46. package/src/file_managment/cache.ts +58 -0
  47. package/src/file_managment/change_config.ts +126 -0
  48. package/src/file_managment/load_config.ts +79 -0
  49. package/src/index.ts +143 -0
  50. package/src/url_genoration/generate_link.ts +53 -0
  51. package/src/url_genoration/search_anime.ts +41 -0
  52. package/src/video_quality.ts +6 -0
  53. package/temp.sh +676 -0
  54. package/tsconfig.json +109 -109
package/temp.sh ADDED
@@ -0,0 +1,676 @@
1
+
2
+ #!/bin/sh
3
+
4
+ #---
5
+ #dependencies:
6
+ # curl.se: ^7.8
7
+ # openssl.org: ^1.1
8
+ # ffmpeg.org: ^5.1
9
+ #---
10
+
11
+ # License preamble at the end of the file
12
+ # Version number
13
+ VERSION="3.4.7"
14
+
15
+
16
+ #######################
17
+ # AUXILIARY FUNCTIONS #
18
+ #######################
19
+
20
+ help_text () {
21
+ while read -r line; do
22
+ printf "%s\n" "$line"
23
+ done <<-EOF
24
+ Usage:
25
+ ${0##*/} [-f] [-s] [-v] [-x] [-q <quality>] [-a <episode>] [-d | -p <download_dir>] [<query>] [-r <provider_no.>]
26
+ ${0##*/} [-f] [-s] [-v] [-x] [-q <quality>] -c
27
+ ${0##*/} -h | -D | -U | -V
28
+ Options:
29
+ -v use VLC as the media player
30
+ -q set video quality (best|worst|360|480|720|1080)
31
+ -s watch anime together with friends, using Syncplay (works with mpv only)
32
+ -f use fzf for anime selection
33
+ -a specify episode to watch
34
+ -d download episode
35
+ -p download episode to specified directory
36
+ -c continue watching anime from history
37
+ -h show helptext
38
+ -D delete history
39
+ -U fetch update from github
40
+ -V print version number and exit
41
+ -r select provider to scrape first [1-3]
42
+ -x print all video links from all providers to stdout (for debugging purpose)
43
+ Episode selection:
44
+ Multiple episodes can be chosen given a range
45
+ Choose episode [1-13]: 1 6
46
+ This would choose episodes 1 2 3 4 5 6
47
+ To select the last episode use -1
48
+ When selecting non-interactively, the first result will be
49
+ selected, if anime is passed
50
+ EOF
51
+ }
52
+
53
+ retry () {
54
+ err "$*"
55
+ prompt
56
+ }
57
+
58
+ # display an error message to stderr (in red)
59
+ err () {
60
+ printf "\33[2K\r\033[1;31m%s\033[0m\n" "$*" >&2
61
+ }
62
+
63
+ #display error message and exit
64
+ die () {
65
+ err "$*"
66
+ exit 1
67
+ }
68
+
69
+ # display an informational message (first argument in green, second in magenta)
70
+ inf () {
71
+ printf "\33[2K\r\033[1;35m%s \033[1;35m%s\033[0m\n" "$1" "$2"
72
+ }
73
+
74
+ progress() {
75
+ printf "\33[2K\r\033[1;34m%s\033[0m" "$1"
76
+ }
77
+
78
+ debug () {
79
+ printf "\n\033[1;32mReferrer :\033[0m %s\n\033[1;32mlinks >>\n\033[0m%s\n" "$1" "$2"
80
+ }
81
+
82
+ # prompts the user with message in $1-2 ($1 in blue, $2 in magenta) and saves the input to the variables in $REPLY and $REPLY2
83
+ prompt () {
84
+ [ -n "$*" ] && printf "\33[2K\r\033[1;35m%s\n" "$*"
85
+ printf "\033[1;35m> \033[0m"
86
+ read -r REPLY REPLY2
87
+ }
88
+
89
+ selection_menu() {
90
+ menu_line_parity=0
91
+ while read -r option line; do
92
+ if [ "$option" = "q" ]; then
93
+ printf "\033[1;31m(\033[1;31m%s\033[1;31m) \033[1;31m%s\033[0m\n" "$option" "$line"
94
+ else
95
+ if [ "$menu_line_parity" -eq 0 ]; then
96
+ printf "\033[1;33m(\033[1;33m%s\033[1;33m) \033[1;33m%s\033[0m\n" "$option" "$line"
97
+ menu_line_parity=1
98
+ else
99
+ printf "\033[1;36m(\033[1;36m%s\033[1;36m) \033[1;36m%s\033[0m\n" "$option" "$line"
100
+ menu_line_parity=0
101
+ fi
102
+ fi
103
+ done <<-EOF
104
+ $*
105
+ EOF
106
+ prompt
107
+ }
108
+
109
+ selection_menu_fzf() {
110
+ printf "%s\n%s" "$1" "$2" | fzf --height=30% --border -1 --layout=reverse --header-first --header-lines=1 --cycle --with-nth 2.. | cut -d\ -f1
111
+ }
112
+
113
+ version_text () {
114
+ inf "Version: $VERSION"
115
+ }
116
+
117
+ # get the newest version of this script from github and replace it
118
+ update_script () {
119
+ update="$(curl -A "$agent" -s "https://raw.githubusercontent.com/pystardust/ani-cli/master/ani-cli")" || die "Connection error"
120
+ update="$(printf '%s\n' "$update" | diff -u "$0" -)"
121
+ if [ -z "$update" ]; then
122
+ inf "Script is up to date :)"
123
+ else
124
+ if printf '%s\n' "$update" | patch "$0" - ; then
125
+ inf "Script has been updated"
126
+ else
127
+ die "Can't update for some reason!"
128
+ fi
129
+ fi
130
+ exit 0
131
+ }
132
+
133
+ # checks if dependencies are present
134
+ dep_ch () {
135
+ for dep; do
136
+ if ! command -v "$dep" >/dev/null ; then
137
+ die "Program \"$dep\" not found. Please install it."
138
+ fi
139
+ done
140
+ }
141
+
142
+ download () {
143
+ case $2 in
144
+ *m3u8*)
145
+ ffmpeg -loglevel error -stats -referer "$1" -i "$2" -c copy "$download_dir/$3.mp4" ;;
146
+ *)
147
+ axel -a -k -n 10 --header=Referer:"$1" "$2" -o "$download_dir/$3.mp4" ;;
148
+ esac
149
+ }
150
+
151
+ #############
152
+ # SEARCHING #
153
+ #############
154
+
155
+ # gets anime names along with its id for search term
156
+ search_anime () {
157
+ search=$(printf '%s' "$1" | tr ' ' '-' )
158
+ curl -s "https://gogoanime.dk//search.html?keyword=$search" -L |
159
+ sed -nE "s_^[[:space:]]*<a href=\"/category/([^\"]*)\" title.*\">\$_\1_p"
160
+ }
161
+
162
+ #fetches all the episodes embed links in an anime from gogoanime server
163
+ episode_list () {
164
+ select_ep_result=$(curl -A "$agent" -s "$base_url/v1/$1" | sed -nE "s_.*epslistplace.*>(.*)</div>_\1_p" | tr "," "\n" | sed -e '/extra/d' -e '/PV/d' | sed -nE 's_".*":"(.*)".*_\1_p')
165
+ first_ep_number=1
166
+ [ -z "$select_ep_result" ] && last_ep_number=0 || last_ep_number=$(printf "%s\n" "$select_ep_result" | wc -l)
167
+ }
168
+
169
+ process_hist_entry () {
170
+ temp_anime_id=$(printf "%s" "$anime_id" | sed 's/\t[0-9]*.$//')
171
+ current_ep=$(printf "%s" "$anime_id" | sed "s/$temp_anime_id\t//g")
172
+ episode_list "$temp_anime_id"
173
+ latest_ep=$last_ep_number
174
+ if [ -n "$latest_ep" ] && [ "$latest_ep" -ge "$current_ep" ]; then
175
+ printf "%s : %s / %s\n" "$temp_anime_id" "$current_ep" "$latest_ep"
176
+ fi
177
+ }
178
+
179
+ # compares history with gogoplay, only shows unfinished anime
180
+ search_history () {
181
+ [ ! -s "$logfile" ] && die "History is empty"
182
+ progress "Processing $scrape.."
183
+ search_results=$(while read -r anime_id; do process_hist_entry & done < "$logfile"; wait)
184
+ [ -z "$search_results" ] && die "No unwatched episodes"
185
+ one_hist=$(printf '%s\n' "$search_results" | grep -e "$" -c)
186
+ [ "$one_hist" = 1 ] && select_first=1
187
+ anime_selection "$search_results"
188
+ ep_choice_start=$(sed -n -E "s/${selection_id}\t(.*)/\1/p" "$logfile")
189
+ }
190
+
191
+ ##################
192
+ # URL PROCESSING #
193
+ ##################
194
+
195
+ generate_link() {
196
+ case $1 in
197
+ 2)
198
+ provider_name='Xstreamcdn'
199
+ progress "Fetching $provider_name links.."
200
+ fb_id=$(printf "%s" "$resp" | sed -n "s_.*fembed.*/v/__p")
201
+ refr="https://fembed-hd.com/v/$fb_id"
202
+ [ -z "$fb_id" ] && return 0
203
+ result_links="$(curl -A "$agent" -s -X POST "https://fembed-hd.com/api/source/$fb_id" -H "x-requested-with:XMLHttpRequest" |
204
+ sed -e 's/\\//g' -e 's/.*data"://' | tr "}" "\n" | sed -nE 's/.*file":"(.*)","label":"(.*)","type.*/\2>\1/p')"
205
+ ;;
206
+ 1)
207
+ provider_name='Animixplay'
208
+ progress "Fetching $provider_name Direct link.."
209
+ refr="$base_url"
210
+ [ -z "$id" ] && return 0
211
+ enc_id=$(printf "%s" "$id" | base64)
212
+ ani_id=$(printf "%sLTXs3GrU8we9O%s" "$id" "$enc_id" | base64)
213
+ result_links="$(curl -s "$base_url/api/cW9${ani_id}" -A "$agent" -I | sed -nE 's_[L|l]ocation: https?://[^#]*#([^#]*).*_\1_p' | base64 -d)"
214
+ ;;
215
+ *)
216
+ provider_name='Gogoanime'
217
+ progress "Fetching $provider_name Direct link.."
218
+ refr="$gogohd_url"
219
+ [ -z "$id" ] && return 0
220
+ secret_key=$(printf "%s" "$resp" | sed -n '2p' | tr -d "\n" | od -A n -t x1 | tr -d " |\n")
221
+ echo "secret_key: $secret_key"
222
+ iv=$(printf "%s" "$resp" | sed -n '3p' | tr -d "\n" | od -A n -t x1 | tr -d " |\n")
223
+ echo "iv: $iv"
224
+ second_key=$(printf "%s" "$resp" | sed -n '4p' | tr -d "\n" | od -A n -t x1 | tr -d " |\n")
225
+ echo "second_key: $second_key"
226
+ token=$(printf "%s" "$resp" | head -1 | base64 -d | openssl enc -d -aes256 -K "$secret_key" -iv "$iv" | sed -nE 's/.*&(token.*)/\1/p')
227
+ echo "token: $token"
228
+ ajax=$(printf '%s' "$id" | openssl enc -e -aes256 -K "$secret_key" -iv "$iv" -a)
229
+ echo "ajax: $ajax"
230
+ data=$(curl -A "$agent" -sL -H "X-Requested-With:XMLHttpRequest" "${gogohd_url}encrypt-ajax.php?id=${ajax}&alias=${id}&${token}" | sed -e 's/{"data":"//' -e 's/"}/\n/' -e 's/\\//g')
231
+ echo "data: $data"
232
+ result_links="$(printf '%s' "$data" | base64 -d 2>/dev/null | openssl enc -d -aes256 -K "$second_key" -iv "$iv" 2>/dev/null |
233
+ tr -d \\\\ | sed -nE "s_.*file\":\"([^\"]*)\".*source.*_\1_p")"
234
+ echo "result_links: $result_links"
235
+ ;;
236
+
237
+ esac
238
+ }
239
+
240
+ # chooses the link for the set quality
241
+ get_video_link() {
242
+ dpage_url="$1"
243
+ id=$(printf "%s" "$dpage_url" | sed -nE 's/.*id=([^&]*).*/\1/p')
244
+ #multiple sed are used (regex seperated by ';') for extracting only required data from response of embed url
245
+ resp="$(curl -A "$agent" -sL "${gogohd_url}streaming.php?id=$id" |
246
+ sed -nE 's/.*class="container-(.*)">/\1/p ;
247
+ s/.*class="wrapper container-(.*)">/\1/p ;
248
+ s/.*class=".*videocontent-(.*)">/\1/p ;
249
+ s/.*data-value="(.*)">.*/\1/p ;
250
+ s/.*data-status="1".*data-video="(.*)">.*/\1/p')"
251
+ provider=1
252
+ [ -n "$select_provider" ] && provider="$select_provider"
253
+ i=0
254
+ while [ "$i" -lt 3 ] && [ -z "$result_links" ];do
255
+ generate_link "$provider"
256
+ provider=$((provider % 3 + 1))
257
+ if [ "$debug" -eq 1 ]; then
258
+ debug "$refr" "$result_links"
259
+ unset result_links
260
+ fi
261
+ : $((i+=1))
262
+ done
263
+ [ "$debug" -eq 1 ] && return 0
264
+ if printf '%s' "$result_links" | grep -q "m3u8"; then
265
+ get_video_quality_m3u8 "$result_links"
266
+ else
267
+ video_url=$(get_video_quality_mp4 "$result_links")
268
+ fi
269
+ unset result_links
270
+ }
271
+
272
+ get_video_quality_mp4() {
273
+ case $quality in
274
+ best)
275
+ video_url=$(printf '%s' "$1" | tail -n 1 | cut -d">" -f2) ;;
276
+ worst)
277
+ video_url=$(printf '%s' "$1" | head -n 1 | cut -d">" -f2) ;;
278
+ *)
279
+ video_url=$(printf '%s' "$1" | grep -i "${quality}p" | head -n 1 | cut -d">" -f2)
280
+ if [ -z "$video_url" ]; then
281
+ err "Current video quality is not available (defaulting to best quality)"
282
+ video_url=$(printf '%s' "$1" | tail -n 1 | cut -d">" -f2)
283
+ fi
284
+ ;;
285
+ esac
286
+ printf '%s' "$video_url"
287
+ }
288
+
289
+ get_video_quality_m3u8() {
290
+ printf '%s' "$1" | grep -qE "manifest.*m3u.*" && video_url=$1 && return 0
291
+ m3u8_links=$(curl -A "$agent" -s --referer "$dpage_link" "$1")
292
+ case $quality in
293
+ best)
294
+ res_selector=$(printf "%s" "$m3u8_links" | sed -nE 's_.*RESOLUTION=.*x([^,]*).*_\1_p' | sort -nr | head -1);;
295
+ worst)
296
+ res_selector=$(printf "%s" "$m3u8_links" | sed -nE 's_.*RESOLUTION=.*x([^,]*).*_\1_p' | sort -nr | tail -1);;
297
+ *)
298
+ res_selector=$quality
299
+ if ! (printf '%s' "$m3u8_links" | grep -q "x$quality"); then
300
+ err "Current video quality is not available (defaulting to best quality)"
301
+ res_selector=$(printf "%s" "$m3u8_links" | sed -nE 's_.*RESOLUTION=.*x([^,]*).*_\1_p' | sort -nr | head -1)
302
+ fi
303
+ ;;
304
+ esac
305
+ video_url=$(printf '%s' "$m3u8_links" | sed -n "/x$res_selector/{n;p;}" | tr -d '\r')
306
+ printf "%s" "$m3u8_links" | grep -q "http" || video_url="$(printf "%s" "$1" | sed 's|[^/]*$||')$video_url" || true
307
+ }
308
+
309
+
310
+ #################
311
+ # INPUT PARSING #
312
+ #################
313
+
314
+ append () {
315
+ [ -z "$1" ] || printf "%s\n" "$1"
316
+ printf "%s %s" "$3" "$2"
317
+ }
318
+
319
+ # only lets the user pass in case of a valid search
320
+ process_search () {
321
+ progress "Searching $scrape.."
322
+ search_results=$(search_anime "$query")
323
+ while [ -z "$search_results" ]; do
324
+ retry 'No search results found'
325
+ query="$REPLY $REPLY2"
326
+ progress "Searching $scrape.."
327
+ search_results=$(search_anime "$query")
328
+ done
329
+ anime_selection "$search_results"
330
+ episode_selection
331
+ }
332
+
333
+ # anime-selection menu handling function
334
+ anime_selection () {
335
+ if [ "$fzf" -eq 0 ];then
336
+ inf "$scrape Results >>"
337
+ else
338
+ progress ""
339
+ fi
340
+ count=1
341
+ unset selection_list
342
+ while read -r anime_id; do
343
+ displayed_title=$(printf '%s' "$anime_id" | tr '-' ' ')
344
+ selection_list=$(append "$selection_list" "$displayed_title" "$count")
345
+ : $((count+=1))
346
+ done <<-EOF
347
+ $search_results
348
+ EOF
349
+ if [ -n "$select_first" ]; then
350
+ tput clear
351
+ choice=1
352
+ elif [ -z "$ep_choice_to_start" ] || { [ -n "$ep_choice_to_start" ] && [ -z "$select_first" ]; }; then
353
+ selection_list=$(append "$selection_list" "quit" "q")
354
+ if [ "$fzf" -eq 1 ]; then
355
+ choice=$(selection_menu_fzf ". $scrape Results>>" "$selection_list")
356
+ [ -z "$choice" ] && exit 0
357
+ else
358
+ selection_menu "$selection_list"
359
+ choice="$REPLY"
360
+ [ -z "$choice" ] && choice=1
361
+ fi
362
+ while ! [ "$choice" -eq "$choice" ] 2>/dev/null || [ "$choice" -lt 1 ] || [ "$choice" -ge "$count" ] || [ "$choice" = " " ]; do
363
+ [ "$choice" = "q" ] && exit 0
364
+ retry "Invalid choice entered"
365
+ choice="$REPLY"
366
+ done
367
+ fi
368
+ # Select respective anime_id
369
+ selection_id="$(printf "%s" "$search_results" | sed -n "${choice}p" | cut -d':' -f1 | tr -d ' ')"
370
+ progress "Searching Episodes.."
371
+ episode_list "$selection_id"
372
+ }
373
+
374
+ # gets episode number from user, makes sure it's in range, skips input if only one episode exists
375
+ episode_selection () {
376
+ [ "$last_ep_number" -eq 0 ] && die "Episodes not released yet!"
377
+ if [ "$last_ep_number" -gt "$first_ep_number" ]; then
378
+ [ "$ep_choice_to_start" = "-1" ] && ep_choice_to_start="$last_ep_number"
379
+ if [ -z "$ep_choice_to_start" ]; then
380
+ # if branches, because order matters this time
381
+ while : ; do
382
+ last_ep_number=$(printf '%s' "$last_ep_number"|tr -d "[:space:]")
383
+ prompt "To specify a range, use: start_number end_number (Episodes: $first_ep_number-$last_ep_number)"
384
+ ep_choice_start="$REPLY"
385
+ ep_choice_end="$REPLY2"
386
+ [ "$REPLY" = q ] && exit 0
387
+ [ "$ep_choice_start" = "-1" ] && ep_choice_start="$last_ep_number" || [ -z "$ep_choice_start" ] && ep_choice_start="$last_ep_number"
388
+ [ "$ep_choice_end" = "-1" ] && ep_choice_end="$last_ep_number"
389
+ if ! [ "$ep_choice_start" -eq "$ep_choice_start" ] 2>/dev/null || { [ -n "$ep_choice_end" ] && ! [ "$ep_choice_end" -eq "$ep_choice_end" ] 2>/dev/null; }; then
390
+ err "Invalid number(s)"
391
+ continue
392
+ fi
393
+ if [ "$ep_choice_start" -gt "$last_ep_number" ] 2>/dev/null || [ "$ep_choice_end" -gt "$last_ep_number" ] 2>/dev/null || [ "$ep_choice_start" -lt "$first_ep_number" ] 2>/dev/null; then
394
+ err "Episode out of range"
395
+ continue
396
+ fi
397
+ if [ -n "$ep_choice_end" ] && [ "$ep_choice_end" -le "$ep_choice_start" ]; then
398
+ err "Invalid range"
399
+ continue
400
+ fi
401
+ break
402
+ done
403
+ else
404
+ ep_choice_start="$ep_choice_to_start" && unset ep_choice_to_start
405
+ fi
406
+ else
407
+ # In case the anime contains only a single episode
408
+ ep_choice_start=1
409
+ fi
410
+ [ -n "$ep_choice_end" ] && auto_play=1
411
+ }
412
+
413
+ # creates $episodes from $ep_choice_start and $ep_choice_end
414
+ generate_ep_list() {
415
+ episodes=$ep_choice_start
416
+ [ -n "$ep_choice_end" ] && episodes=$(seq "$ep_choice_start" "$ep_choice_end")
417
+ }
418
+
419
+
420
+ ##################
421
+ # VIDEO PLAYBACK #
422
+ ##################
423
+
424
+ # opens selected episodes one-by-one
425
+ open_selection() {
426
+ for ep in $episodes; do
427
+ open_episode "$selection_id" "$ep"
428
+ done
429
+ episode=${ep_choice_end:-$ep_choice_start}
430
+ }
431
+
432
+ open_episode () {
433
+ anime_id="$1"
434
+ episode="$2"
435
+ tput clear
436
+ progress "Loading episode $episode..."
437
+ # decrypting url
438
+ dpage_link=$(printf "%s" "$select_ep_result" | sed -n "${episode}p")
439
+ if [ -z "$dpage_link" ];then
440
+ die "Episode doesn't exist!!"
441
+ else
442
+ get_video_link "$dpage_link"
443
+ fi
444
+ [ "$debug" -eq 1 ] && exit 0
445
+ # write anime and episode number and save to temporary history
446
+ grep -q -- "$selection_id" "$logfile" || printf "%s\t%s\n" "$selection_id" $((episode+1)) >> "$logfile"
447
+ sed -E "s/^${selection_id}\t[0-9]*/${selection_id}\t$((episode+1))/" "$logfile" > "${logfile}.new"
448
+ [ ! "$PID" = "0" ] && kill "$PID" >/dev/null 2>&1
449
+ [ -z "$video_url" ] && die "Video URL not found"
450
+ trackma_title="$(printf '%s' "$anime_id Episode $episode" | tr '-' ' ' | awk '{for(i=1;i<=NF;i++){ $i=toupper(substr($i,1,1)) substr($i,2) }}1')"
451
+ if [ "$auto_play" -eq 0 ]; then
452
+ play_episode "$video_url" "$refr" "$trackma_title"
453
+ else
454
+ printf "\n"
455
+ play_episode "$video_url" "$refr" "$trackma_title"
456
+ wait
457
+ sleep 2
458
+ fi
459
+ PID=$!
460
+ # overwrite history with temporary history
461
+ mv "${logfile}.new" "$logfile"
462
+ }
463
+
464
+ play_episode () {
465
+ video_url="$1"; refr="$2" trackma_title="$3"
466
+ if [ "$player_fn" = "download" ];then
467
+ inf "Currently downloading $trackma_title ($provider_name)"
468
+ else
469
+ inf "Currently playing $trackma_title ($provider_name)"
470
+ fi
471
+ case "$player_fn" in
472
+ download)
473
+ if download "$refr" "$video_url" "$trackma_title"; then
474
+ inf "Downloaded episode: $trackma_title"
475
+ else
476
+ err "Download failed episode: $trackma_title , please retry or check your internet connection"
477
+ fi
478
+ ;;
479
+ iina)
480
+ nohup "$player_fn" "$video_url" --no-stdin --keep-running --mpv-referrer="$refr" --mpv-force-media-title="$trackma_title" > /dev/null 2>&1 & ;;
481
+ vlc)
482
+ if uname -a | grep -qE '[Aa]ndroid';then
483
+ am start --user 0 -a android.intent.action.VIEW -d "$video_url" -n org.videolan.vlc/org.videolan.vlc.gui.video.VideoPlayerActivity -e "title" "$trackma_title" > /dev/null 2>&1 &
484
+ else
485
+ nohup "$player_fn" "$video_url" --http-referrer="$refr" --meta-title "$trackma_title" --play-and-exit > /dev/null 2>&1 &
486
+ fi
487
+ ;;
488
+ "syncplay"|"/Applications/Syncplay.app/Contents/MacOS/syncplay"|"/c/Program Files (x86)/Syncplay/Syncplay.exe")
489
+ nohup "$player_fn" "$video_url" -- --referrer="$refr" --force-media-title="$trackma_title" > /dev/null 2>&1 & ;;
490
+ *)
491
+ if uname -a | grep -qE '[Aa]ndroid';then
492
+ am start --user 0 -a android.intent.action.VIEW -d "$video_url" -n is.xyz.mpv/.MPVActivity > /dev/null 2>&1 &
493
+ else
494
+ nohup "$player_fn" "$video_url" --referrer="$refr" --force-media-title="$trackma_title" > /dev/null 2>&1 &
495
+ fi
496
+ ;;
497
+ esac
498
+ }
499
+
500
+ ############
501
+ # START UP #
502
+ ############
503
+
504
+ # clears the colors and deletes temporary logfile when exited using SIGINT
505
+ trap 'printf "\033[0m";rm -f "$logfile".new;exit 1' INT HUP
506
+
507
+ # default options
508
+ agent="Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/100.0"
509
+ PID=0
510
+ quality=best
511
+ scrape=Query
512
+ debug=0
513
+ choice=
514
+ fzf=0
515
+ auto_play=0
516
+ download_dir="$(pwd)"
517
+ case "$(uname)" in
518
+ Darwin*) player_fn='iina';;
519
+ *) player_fn='mpv';;
520
+ esac
521
+ # history file path
522
+ logdir="${XDG_CACHE_HOME:-$HOME/.cache}"
523
+ logfile="$logdir/ani-hsts"
524
+ # create history file and history dir if none found
525
+ [ -d "$logdir" ] || mkdir "$logdir"
526
+ [ -f "$logfile" ] || : > "$logfile"
527
+
528
+ while getopts 'svq:dp:chDUVa:xr:fn' OPT; do
529
+ case $OPT in
530
+ d) player_fn='download' ;;
531
+ a) ep_choice_to_start=$OPTARG ;;
532
+ U) update_script ;;
533
+ D)
534
+ : > "$logfile"
535
+ exit 0
536
+ ;;
537
+ p)
538
+ player_fn='download'
539
+ download_dir="$OPTARG"
540
+ if [ ! -d "$download_dir" ] ; then
541
+ mkdir -p "$download_dir" || die "Couldn't create $download_dir"
542
+ fi
543
+ ;;
544
+ n) scrape=New ;;
545
+ s)
546
+ case "$(uname -s)" in
547
+ Darwin*) player_fn="/Applications/Syncplay.app/Contents/MacOS/syncplay" ;;
548
+ MINGW*|*Msys) player_fn="/c/Program Files (x86)/Syncplay/Syncplay.exe" ;;
549
+ *) player_fn="syncplay" ;;
550
+ esac
551
+ ;;
552
+ q) quality=$OPTARG ;;
553
+ x) debug=1 ;;
554
+ r) select_provider=$OPTARG ;;
555
+ f) fzf=1 ;;
556
+ c) scrape=History ;;
557
+ v) player_fn='vlc';;
558
+ V)
559
+ version_text
560
+ exit 0
561
+ ;;
562
+ h)
563
+ help_text
564
+ exit 0
565
+ ;;
566
+ *)
567
+ help_text
568
+ exit 1
569
+ ;;
570
+ esac
571
+ done
572
+ shift $((OPTIND - 1))
573
+ progress "Checking dependencies.."
574
+ # shellcheck disable=SC2046
575
+ dep_ch "curl" "sed" "grep" "openssl" || true
576
+
577
+ if [ "$player_fn" = "download" ];then
578
+ dep_ch "ffmpeg" "axel"
579
+ elif ! (uname -a | grep -qE '[Aa]ndroid');then
580
+ dep_ch "$player_fn"
581
+ fi
582
+
583
+ gogohd_url="https://gogohd.net/"
584
+ base_url="https://animixplay.to"
585
+ if [ "$scrape" = "Query" ];then
586
+ if [ -z "$*" ]; then
587
+ prompt "Search Anime"
588
+ query="$REPLY $REPLY2"
589
+ else
590
+ if [ -n "$ep_choice_to_start" ]; then
591
+ REPLY=1
592
+ select_first=1
593
+ fi
594
+ query="$*"
595
+ fi
596
+ process_search
597
+ elif [ "$scrape" = "New" ];then
598
+ progress ""
599
+ selection_id="$(curl -s "https://animixplay.to/rss.xml" | sed -nE 's_.*link.*animixplay.to/v1/([^<]*)/ep([^<]*)<.*_\1 episode \2_p' | tr '-' ' ' | fzf --height=30% --border -1 --layout=reverse --cycle)"
600
+ [ -z "$selection_id" ] && die "No anime Selected"
601
+ ep=$(printf "%s" "$selection_id" | sed 's_.*episode __')
602
+ selection_id=$(printf "%s" "$selection_id" | sed 's_ episode.*__' | tr ' ' '-')
603
+ episode_list "$selection_id"
604
+ open_episode "$selection_id" "$ep"
605
+ exit 0
606
+ else
607
+ search_history
608
+ fi
609
+
610
+ generate_ep_list
611
+ open_selection
612
+
613
+ ########
614
+ # LOOP #
615
+ ########
616
+
617
+ while : ; do
618
+ auto_play=0
619
+ unset menu
620
+ unset options
621
+ [ "$episode" -ne "$last_ep_number" ] && menu=$(append "$menu" 'next' 'n')
622
+ [ "$episode" -ne "$first_ep_number" ] && menu=$(append "$menu" 'previous' 'p')
623
+ menu=$(append "$menu" 'replay' 'r')
624
+ [ "$first_ep_number" -ne "$last_ep_number" ] && menu=$(append "$menu" 'select' 's')
625
+ menu=$(append "$menu" 'quit' 'q')
626
+ if [ "$fzf" -eq 1 ];then
627
+ progress ""
628
+ choice="$(selection_menu_fzf ". Menu>>" "$menu")"
629
+ [ -z "$choice" ] && die "No anime Selected"
630
+ else
631
+ selection_menu "$menu"
632
+ choice="$REPLY"
633
+ fi
634
+ case $choice in
635
+ n|'')
636
+ ep_choice_start=$((episode + 1))
637
+ unset ep_choice_end
638
+ ;;
639
+ p)
640
+ ep_choice_start=$((episode - 1))
641
+ unset ep_choice_end
642
+ ;;
643
+ r)
644
+ ep_choice_start="$episode"
645
+ unset ep_choice_end
646
+ ;;
647
+ s)
648
+ episode_selection ;;
649
+ q)
650
+ break ;;
651
+ *)
652
+ tput clear
653
+ err "Invalid choice"
654
+ continue
655
+ ;;
656
+ esac
657
+ generate_ep_list
658
+ open_selection
659
+ done
660
+
661
+ # ani-cli
662
+ #
663
+ # This program is free software: you can redistribute it and/or modify
664
+ # it under the terms of the GNU General Public License as published by
665
+ # the Free Software Foundation, either version 3 of the License, or
666
+ # (at your option) any later version.
667
+ #
668
+ # This program is distributed in the hope that it will be useful,
669
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
670
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
671
+ # GNU General Public License for more details.
672
+ #
673
+ # You should have received a copy of the GNU General Public License
674
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
675
+ #
676
+ # Project repository: https://github.com/pystardust/ani-cli