ani-cli-npm 1.0.7 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,676 @@
1
+ #!/bin/sh
2
+
3
+ # License preamble at the end of the file
4
+ # Version number
5
+ VERSION="3.4.1"
6
+
7
+
8
+ #######################
9
+ # AUXILIARY FUNCTIONS #
10
+ #######################
11
+
12
+ help_text () {
13
+ while read -r line; do
14
+ printf "%s\n" "$line"
15
+ done <<-EOF
16
+
17
+ Usage:
18
+ ${0##*/} [-f] [-s] [-v] [-x] [-q <quality>] [-a <episode>] [-d | -p <download_dir>] [<query>] [-r <provider_no.>]
19
+ ${0##*/} [-f] [-s] [-v] [-x] [-q <quality>] -c
20
+ ${0##*/} -h | -D | -U | -V
21
+
22
+ Options:
23
+ -v use VLC as the media player
24
+ -q set video quality (best|worst|360|480|720|1080)
25
+ -s watch anime together with friends, using Syncplay (works with mpv only)
26
+ -f use fzf for anime selection
27
+ -a specify episode to watch
28
+ -d download episode
29
+ -p download episode to specified directory
30
+ -c continue watching anime from history
31
+ -h show helptext
32
+ -D delete history
33
+ -U fetch update from github
34
+ -V print version number and exit
35
+ -r select provider to scrape first [1-3]
36
+ -x print all video links from all providers to stdout (for debugging purpose)
37
+
38
+ Episode selection:
39
+ Multiple episodes can be chosen given a range
40
+ Choose episode [1-13]: 1 6
41
+ This would choose episodes 1 2 3 4 5 6
42
+ To select the last episode use -1
43
+
44
+ When selecting non-interactively, the first result will be
45
+ selected, if anime is passed
46
+ EOF
47
+ }
48
+
49
+ retry () {
50
+ err "$*"
51
+ prompt
52
+ }
53
+
54
+ # display an error message to stderr (in red)
55
+ err () {
56
+ printf "\33[2K\r\033[1;31m%s\033[0m\n" "$*" >&2
57
+ }
58
+
59
+ #display error message and exit
60
+ die () {
61
+ err "$*"
62
+ exit 1
63
+ }
64
+
65
+ # display an informational message (first argument in green, second in magenta)
66
+ inf () {
67
+ printf "\33[2K\r\033[1;35m%s \033[1;35m%s\033[0m\n" "$1" "$2"
68
+ }
69
+
70
+ progress() {
71
+ printf "\33[2K\r\033[1;34m%s\033[0m" "$1"
72
+ }
73
+
74
+ debug () {
75
+ printf "\n\033[1;32mReferrer :\033[0m %s\n\033[1;32mlinks >>\n\033[0m%s\n" "$1" "$2"
76
+ }
77
+
78
+ # 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
79
+ prompt () {
80
+ [ -n "$*" ] && printf "\33[2K\r\033[1;35m%s\n" "$*"
81
+ printf "\033[1;35m> \033[0m"
82
+ read -r REPLY REPLY2
83
+ }
84
+
85
+ selection_menu() {
86
+ menu_line_parity=0
87
+ while read -r option line; do
88
+ if [ "$option" = "q" ]; then
89
+ printf "\033[1;31m(\033[1;31m%s\033[1;31m) \033[1;31m%s\033[0m\n" "$option" "$line"
90
+ else
91
+ if [ "$menu_line_parity" -eq 0 ]; then
92
+ printf "\033[1;33m(\033[1;33m%s\033[1;33m) \033[1;33m%s\033[0m\n" "$option" "$line"
93
+ menu_line_parity=1
94
+ else
95
+ printf "\033[1;36m(\033[1;36m%s\033[1;36m) \033[1;36m%s\033[0m\n" "$option" "$line"
96
+ menu_line_parity=0
97
+ fi
98
+ fi
99
+ done <<-EOF
100
+ $*
101
+ EOF
102
+ prompt
103
+ }
104
+
105
+ selection_menu_fzf() {
106
+ printf "%s\n%s" "$1" "$2" | fzf --height=30% --border -1 --layout=reverse --header-first --header-lines=1 --cycle --with-nth 2.. | cut -f1 -d' '
107
+ }
108
+
109
+ version_text () {
110
+ inf "Version: $VERSION"
111
+ }
112
+
113
+ # get the newest version of this script from github and replace it
114
+ update_script () {
115
+ update="$(curl -A "$agent" -s "https://raw.githubusercontent.com/pystardust/ani-cli/master/ani-cli")" || die "Connection error"
116
+ update="$(printf '%s\n' "$update" | diff -u "$0" -)"
117
+ if [ -z "$update" ]; then
118
+ inf "Script is up to date :)"
119
+ else
120
+ if printf '%s\n' "$update" | patch "$0" - ; then
121
+ inf "Script has been updated"
122
+ else
123
+ die "Can't update for some reason!"
124
+ fi
125
+ fi
126
+ exit 0
127
+ }
128
+
129
+ # checks if dependencies are present
130
+ dep_ch () {
131
+ for dep; do
132
+ if ! command -v "$dep" >/dev/null ; then
133
+ die "Program \"$dep\" not found. Please install it."
134
+ fi
135
+ done
136
+ }
137
+
138
+ download () {
139
+ case $2 in
140
+ *m3u8*)
141
+ ffmpeg -loglevel error -stats -referer "$1" -i "$2" -c copy "$download_dir/$3.mp4" ;;
142
+ *)
143
+ axel -a -k -n 10 --header=Referer:"$1" "$2" -o "$download_dir/$3.mp4" ;;
144
+ esac
145
+ }
146
+
147
+ #############
148
+ # SEARCHING #
149
+ #############
150
+
151
+ # gets anime names along with its id for search term
152
+ search_anime () {
153
+ search=$(printf '%s' "$1" | tr ' ' '-' )
154
+ curl -s "https://gogoanime.lu//search.html?keyword=$search" -L |
155
+ sed -nE 's_^[[:space:]]*<a href="/category/([^"]*)" title.*">$_\1_p'
156
+ }
157
+
158
+ #fetches all the episodes embed links in an anime from gogoanime server
159
+ episode_list () {
160
+ 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')
161
+ echo $select_ep_results
162
+
163
+ first_ep_number=1
164
+ [ -z "$select_ep_result" ] && last_ep_number=0 || last_ep_number=$(printf "%s\n" "$select_ep_result" | wc -l)
165
+ }
166
+
167
+ process_hist_entry () {
168
+ temp_anime_id=$(printf "%s" "$anime_id" | sed 's/\t[0-9]*.$//')
169
+ current_ep=$(printf "%s" "$anime_id" | sed "s/$temp_anime_id\t//g")
170
+ episode_list "$temp_anime_id"
171
+ latest_ep=$last_ep_number
172
+ if [ -n "$latest_ep" ] && [ "$latest_ep" -ge "$current_ep" ]; then
173
+ printf "%s : %s / %s\n" "$temp_anime_id" "$current_ep" "$latest_ep"
174
+ fi
175
+ }
176
+
177
+ # compares history with gogoplay, only shows unfinished anime
178
+ search_history () {
179
+ [ ! -s "$logfile" ] && die "History is empty"
180
+ progress "Processing $scrape.."
181
+ search_results=$(while read -r anime_id; do process_hist_entry & done < "$logfile"; wait)
182
+ [ -z "$search_results" ] && die "No unwatched episodes"
183
+ one_hist=$(printf '%s\n' "$search_results" | grep -e "$" -c)
184
+ [ "$one_hist" = 1 ] && select_first=1
185
+ anime_selection "$search_results"
186
+ ep_choice_start=$(sed -n -E "s/${selection_id}\t(.*)/\1/p" "$logfile")
187
+ }
188
+
189
+ ##################
190
+ # URL PROCESSING #
191
+ ##################
192
+
193
+ generate_link() {
194
+ case $1 in
195
+ 1)
196
+ provider_name='Xstreamcdn'
197
+ progress "Fetching $provider_name links.."
198
+ fb_id=$(printf "%s" "$resp" | sed -n "s_.*fembed.*/v/__p")
199
+ refr="https://fembed-hd.com/v/$fb_id"
200
+ [ -z "$fb_id" ] && return 0
201
+ result_links="$(curl -A "$agent" -s -X POST "https://fembed-hd.com/api/source/$fb_id" -H "x-requested-with:XMLHttpRequest" |
202
+ sed -e 's/\\//g' -e 's/.*data"://' | tr "}" "\n" | sed -nE 's/.*file":"(.*)","label":"(.*)","type.*/\2>\1/p')"
203
+ echo $result_links
204
+ ;;
205
+ 2)
206
+ provider_name='Animixplay'
207
+ progress "Fetching $provider_name Direct link.."
208
+ refr="$base_url"
209
+ [ -z "$id" ] && return 0
210
+ enc_id=$(printf "%s" "$id" | base64)
211
+ ani_id=$(printf "%sLTXs3GrU8we9O%s" "$id" "$enc_id" | base64)
212
+ echo $id
213
+ echo $enc_id
214
+ echo $ani_id
215
+ #echo $base_url/api/live${ani_id}
216
+ #echo $ani_id
217
+
218
+ result_links="$(curl -s "$base_url/api/live${ani_id}" -A "$agent" -I | sed -nE 's_location: (.*)_\1_p' | cut -d"#" -f2 | base64 -d)"
219
+ echo $result_links
220
+ ;;
221
+
222
+ *)
223
+ provider_name='Gogoanime'
224
+ progress "Fetching $provider_name Direct link.."
225
+ refr="$gogohd_url"
226
+ [ -z "$id" ] && return 0
227
+ secret_key=$(printf "%s" "$resp" | sed -n '2p' | tr -d "\n" | od -A n -t x1 | tr -d " |\n")
228
+ iv=$(printf "%s" "$resp" | sed -n '3p' | tr -d "\n" | od -A n -t x1 | tr -d " |\n")
229
+ second_key=$(printf "%s" "$resp" | sed -n '4p' | tr -d "\n" | od -A n -t x1 | tr -d " |\n")
230
+ token=$(printf "%s" "$resp" | head -1 | base64 -d | openssl enc -d -aes256 -K "$secret_key" -iv "$iv" | sed -nE 's/.*&(token.*)/\1/p')
231
+ ajax=$(printf '%s' "$id" | openssl enc -e -aes256 -K "$secret_key" -iv "$iv" -a)
232
+ 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')
233
+ result_links="$(printf '%s' "$data" | base64 -d 2>/dev/null | openssl enc -d -aes256 -K "$second_key" -iv "$iv" 2>/dev/null |
234
+ sed -e 's/\].*/\]/' -e 's/\\//g' | grep -Eo 'https:\/\/[-a-zA-Z0-9@:%._\+~#=][a-zA-Z0-9][-a-zA-Z0-9@:%_\+.~#?&\/\/=]*')"
235
+ ;;
236
+ esac
237
+ }
238
+
239
+ # chooses the link for the set quality
240
+ get_video_link() {
241
+ dpage_url="$1"
242
+ id=$(printf "%s" "$dpage_url" | sed -nE 's/.*id=([^&]*).*/\1/p')
243
+ #multiple sed are used (regex seperated by ';') for extracting only required data from response of embed url
244
+ resp="$(curl -A "$agent" -sL "${gogohd_url}streaming.php?id=$id" |
245
+ sed -nE 's/.*class="container-(.*)">/\1/p ;
246
+ s/.*class="wrapper container-(.*)">/\1/p ;
247
+ s/.*class=".*videocontent-(.*)">/\1/p ;
248
+ s/.*data-value="(.*)">.*/\1/p ;
249
+ s/.*data-status="1".*data-video="(.*)">.*/\1/p')"
250
+ provider=1
251
+ [ -n "$select_provider" ] && provider="$select_provider"
252
+ i=0
253
+ while [ "$i" -lt 3 ] && [ -z "$result_links" ];do
254
+ generate_link "$provider"
255
+ provider=$((provider % 3 + 1))
256
+ if [ "$debug" -eq 1 ]; then
257
+ debug "$refr" "$result_links"
258
+ unset result_links
259
+ fi
260
+ : $((i+=1))
261
+ done
262
+ [ "$debug" -eq 1 ] && return 0
263
+ if printf '%s' "$result_links" | grep -q "m3u8"; then
264
+ get_video_quality_m3u8 "$result_links"
265
+ else
266
+ video_url=$(get_video_quality_mp4 "$result_links")
267
+ fi
268
+ echo $video_url
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
+ echo $selection_id
371
+ progress "Searching Episodes.."
372
+ episode_list "$selection_id"
373
+ }
374
+
375
+ # gets episode number from user, makes sure it's in range, skips input if only one episode exists
376
+ episode_selection () {
377
+ [ "$last_ep_number" -eq 0 ] && die "Episodes not released yet!"
378
+ if [ "$last_ep_number" -gt "$first_ep_number" ]; then
379
+ [ "$ep_choice_to_start" = "-1" ] && ep_choice_to_start="$last_ep_number"
380
+ if [ -z "$ep_choice_to_start" ]; then
381
+ # if branches, because order matters this time
382
+ while : ; do
383
+ last_ep_number=$(printf '%s' "$last_ep_number"|tr -d "[:space:]")
384
+ prompt "To specify a range, use: start_number end_number (Episodes: $first_ep_number-$last_ep_number)"
385
+ ep_choice_start="$REPLY"
386
+ ep_choice_end="$REPLY2"
387
+ [ "$REPLY" = q ] && exit 0
388
+ [ "$ep_choice_start" = "-1" ] && ep_choice_start="$last_ep_number" || [ -z "$ep_choice_start" ] && ep_choice_start="$last_ep_number"
389
+ [ "$ep_choice_end" = "-1" ] && ep_choice_end="$last_ep_number"
390
+ 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
391
+ err "Invalid number(s)"
392
+ continue
393
+ fi
394
+ 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
395
+ err "Episode out of range"
396
+ continue
397
+ fi
398
+ if [ -n "$ep_choice_end" ] && [ "$ep_choice_end" -le "$ep_choice_start" ]; then
399
+ err "Invalid range"
400
+ continue
401
+ fi
402
+ break
403
+ done
404
+ else
405
+ ep_choice_start="$ep_choice_to_start" && unset ep_choice_to_start
406
+ fi
407
+ else
408
+ # In case the anime contains only a single episode
409
+ ep_choice_start=1
410
+ fi
411
+ [ -n "$ep_choice_end" ] && auto_play=1
412
+ }
413
+
414
+ # creates $episodes from $ep_choice_start and $ep_choice_end
415
+ generate_ep_list() {
416
+ episodes=$ep_choice_start
417
+ [ -n "$ep_choice_end" ] && episodes=$(seq "$ep_choice_start" "$ep_choice_end")
418
+ }
419
+
420
+
421
+ ##################
422
+ # VIDEO PLAYBACK #
423
+ ##################
424
+
425
+ # opens selected episodes one-by-one
426
+ open_selection() {
427
+ for ep in $episodes; do
428
+ open_episode "$selection_id" "$ep"
429
+ done
430
+ episode=${ep_choice_end:-$ep_choice_start}
431
+ }
432
+
433
+ open_episode () {
434
+ anime_id="$1"
435
+ episode="$2"
436
+ tput clear
437
+ progress "Loading episode $episode..."
438
+ # decrypting url
439
+ dpage_link=$(printf "%s" "$select_ep_result" | sed -n "${episode}p")
440
+ if [ -z "$dpage_link" ];then
441
+ err "Episode doesn't exist!!"
442
+ else
443
+ get_video_link "$dpage_link"
444
+ fi
445
+ [ "$debug" -eq 1 ] && exit 0
446
+ # write anime and episode number and save to temporary history
447
+ grep -q "$selection_id" "$logfile" || printf "%s\t%s\n" "$selection_id" $((episode+1)) >> "$logfile"
448
+ sed -E "s/^${selection_id}\t[0-9]*/${selection_id}\t$((episode+1))/" "$logfile" > "${logfile}.new"
449
+ [ ! "$PID" = "0" ] && kill "$PID" >/dev/null 2>&1
450
+ [ -z "$video_url" ] && die "Video URL not found"
451
+ 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')"
452
+ if [ "$auto_play" -eq 0 ]; then
453
+ play_episode "$video_url" "$refr" "$trackma_title"
454
+ else
455
+ printf "\n"
456
+ play_episode "$video_url" "$refr" "$trackma_title"
457
+ wait
458
+ sleep 2
459
+ fi
460
+ PID=$!
461
+ # overwrite history with temporary history
462
+ mv "${logfile}.new" "$logfile"
463
+ }
464
+
465
+ play_episode () {
466
+ video_url="$1"; refr="$2" trackma_title="$3"
467
+ if [ "$player_fn" = "download" ];then
468
+ inf "Currently downloading $trackma_title ($provider_name)"
469
+ else
470
+ inf "Currently playing $trackma_title ($provider_name)"
471
+ fi
472
+ case "$player_fn" in
473
+ download)
474
+ if download "$refr" "$video_url" "$trackma_title"; then
475
+ inf "Downloaded episode: $trackma_title"
476
+ else
477
+ err "Download failed episode: $trackma_title , please retry or check your internet connection"
478
+ fi
479
+ ;;
480
+ iina)
481
+ nohup "$player_fn" "$video_url" --no-stdin --keep-running --mpv-referrer="$refr" --mpv-force-media-title="$trackma_title" > /dev/null 2>&1 & ;;
482
+ vlc)
483
+ if uname -a | grep -qE '[Aa]ndroid';then
484
+ 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 &
485
+ else
486
+ nohup "$player_fn" "$video_url" --http-referrer="$refr" --meta-title "$trackma_title" --play-and-exit > /dev/null 2>&1 &
487
+ fi
488
+ ;;
489
+ "syncplay"|"/Applications/Syncplay.app/Contents/MacOS/syncplay"|"/c/Program Files (x86)/Syncplay/Syncplay.exe")
490
+ nohup "$player_fn" "$video_url" -- --referrer="$refr" --force-media-title="$trackma_title" > /dev/null 2>&1 & ;;
491
+ *)
492
+ if uname -a | grep -qE '[Aa]ndroid';then
493
+ am start --user 0 -a android.intent.action.VIEW -d "$video_url" -n is.xyz.mpv/.MPVActivity > /dev/null 2>&1 &
494
+ else
495
+ nohup "$player_fn" "$video_url" --referrer="$refr" --force-media-title="$trackma_title" > /dev/null 2>&1 &
496
+ fi
497
+ ;;
498
+ esac
499
+ }
500
+
501
+ ############
502
+ # START UP #
503
+ ############
504
+
505
+ # clears the colors and deletes temporary logfile when exited using SIGINT
506
+ trap 'printf "\033[0m";rm -f "$logfile".new;exit 1' INT HUP
507
+
508
+ # default options
509
+ agent="Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/100.0"
510
+ PID=0
511
+ quality=best
512
+ scrape=Query
513
+ debug=0
514
+ choice=
515
+ fzf=0
516
+ auto_play=0
517
+ download_dir="$(pwd)"
518
+ curl curl -A "$agent" -s "$base_url/v1/sword-art-online"
519
+ pause 10000
520
+ case "$(uname)" in
521
+ Darwin*) player_fn='iina';;
522
+ *) player_fn='mpv';;
523
+ esac
524
+ # history file path
525
+ logdir="${XDG_CACHE_HOME:-$HOME/.cache}"
526
+ logfile="$logdir/ani-hsts"
527
+ # create history file and history dir if none found
528
+ [ -d "$logdir" ] || mkdir "$logdir"
529
+ [ -f "$logfile" ] || : > "$logfile"
530
+
531
+ while getopts 'svq:dp:chDUVa:xr:fn' OPT; do
532
+ case $OPT in
533
+ d) player_fn='download' ;;
534
+ a) ep_choice_to_start=$OPTARG ;;
535
+ U) update_script ;;
536
+ D)
537
+ : > "$logfile"
538
+ exit 0
539
+ ;;
540
+ p)
541
+ player_fn='download'
542
+ download_dir="$OPTARG"
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