ani-cli-npm 1.0.7 → 1.1.0

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