mirror of
https://github.com/ksyasuda/aniwrapper.git
synced 2024-10-28 04:44:11 -07:00
40202b7c65
move skip intro script into scripts directory change setup.sh to reflect new directory and theme file
568 lines
14 KiB
Bash
Executable File
568 lines
14 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Set config directory if not already set
|
|
if [[ -z "$XDG_CONFIG_HOME" ]]; then
|
|
XDG_CONFIG_HOME="$HOME/.config"
|
|
fi
|
|
|
|
CFG_DIR="$XDG_CONFIG_HOME/ani-cli"
|
|
CFG_FILE="meh.rasi"
|
|
|
|
HISTORY_DB="$XDG_CONFIG_HOME/ani-cli/history.sqlite3"
|
|
|
|
# dependencies: grep sed curl video_player
|
|
# video_player ( needs to be able to play urls )
|
|
player_fn="mpv"
|
|
|
|
prog="ani-cli"
|
|
logfile="${XDG_CACHE_HOME:-$HOME/.cache}/ani-hsts"
|
|
|
|
# sql=$(sqlite3 -noheader "$HISTORY_DB")
|
|
|
|
c_red="\033[1;31m"
|
|
c_green="\033[1;32m"
|
|
c_yellow="\033[1;33m"
|
|
c_blue="\033[1;34m"
|
|
c_magenta="\033[1;35m"
|
|
c_cyan="\033[1;36m"
|
|
c_reset="\033[0m"
|
|
|
|
VERBOSE=1
|
|
|
|
help_text() {
|
|
while IFS= read line; do
|
|
printf "%s\n" "$line"
|
|
done <<-EOF
|
|
USAGE: $prog <query>
|
|
-h show this help text
|
|
-d download episode
|
|
-H continue where you left off
|
|
EOF
|
|
}
|
|
|
|
die() {
|
|
printf "$c_red%s$c_reset\n" "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
err() {
|
|
printf "$c_red%s$c_reset\n" "$*" >&2
|
|
}
|
|
|
|
search_anime() {
|
|
# get anime name along with its id
|
|
search=$(printf '%s' "$1" | tr ' ' '-')
|
|
titlepattern='<a href="/category/'
|
|
|
|
curl -s "https://gogoanime.pe//search.html" \
|
|
-G \
|
|
-d "keyword=$search" |
|
|
sed -n -E '
|
|
s_^[[:space:]]*<a href="/category/([^"]*)" title="([^"]*)".*_\1_p
|
|
'
|
|
}
|
|
|
|
search_eps() {
|
|
# get available episodes for anime_id
|
|
anime_id=$1
|
|
|
|
curl -s "https://gogoanime.pe/category/$anime_id" |
|
|
sed -n -E '
|
|
/^[[:space:]]*<a href="#" class="active" ep_start/{
|
|
s/.* '\''([0-9]*)'\'' ep_end = '\''([0-9]*)'\''.*/\2/p
|
|
q
|
|
}
|
|
'
|
|
}
|
|
|
|
get_dpage_link() {
|
|
# get the download page url
|
|
anime_id=$1
|
|
ep_no=$2
|
|
|
|
curl -s "https://gogoanime.pe/$anime_id-episode-$ep_no" |
|
|
sed -n -E '
|
|
/^[[:space:]]*<li class="dowloads">/{
|
|
s/.*href="([^"]*)".*/\1/p
|
|
q
|
|
}'
|
|
}
|
|
|
|
get_links() {
|
|
dpage_url="$1"
|
|
|
|
curl -s "$dpage_url" |
|
|
sed -n -E '
|
|
/href="([^"]*)" download>Download/{
|
|
s/href="([^"]*)" download>Download/\1/p
|
|
q
|
|
}' | tr -d ' '
|
|
}
|
|
|
|
dep_ch() {
|
|
for dep; do
|
|
if ! command -v "$dep" >/dev/null; then
|
|
die "Program \"$dep\" not found. Please install it."
|
|
fi
|
|
done
|
|
}
|
|
|
|
check_anime_name() {
|
|
# Maybe change to query the db for a similar name
|
|
# Check to make sure passed in name is not empty
|
|
[ "$VERBOSE" -eq 1 ] && printf "%s\n" "VAR: $1"
|
|
if [[ "$1" == "" ]] || [[ "$1" == " " ]] || [[ "$1" == "\n" ]]; then
|
|
printf "%s\n" "Passed in name is null"
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
run_stmt() {
|
|
printf "%s\n" "$1" | sqlite3 -noheader "$HISTORY_DB"
|
|
}
|
|
|
|
check_db() {
|
|
# Return number of matches for anime/episode in db
|
|
# echo "$1 $2"
|
|
if [[ "$2" == "search" ]]; then
|
|
stmt="SELECT DISTINCT COUNT(*) \
|
|
FROM search_history \
|
|
WHERE anime_name = '$1';"
|
|
res=$(run_stmt "$stmt")
|
|
# echo "QUERY RESULT $res"
|
|
return "$res"
|
|
else
|
|
stmt="SELECT DISTINCT COUNT(*) \
|
|
FROM watch_history \
|
|
WHERE anime_name = '$1' \
|
|
AND episode_number = $2;"
|
|
res=$(run_stmt "$stmt")
|
|
# echo "QUERY RESULT $res"
|
|
return "$res"
|
|
fi
|
|
}
|
|
|
|
update_date() {
|
|
# updates search/watch date for passed in anime
|
|
datetime=$(date +'%Y-%m-%d %H:%M:%S')
|
|
stmt=""
|
|
if [[ "$2" == "search" ]]; then
|
|
stmt="UPDATE search_history SET search_date = '$datetime' \
|
|
WHERE anime_name = '$1';"
|
|
else
|
|
stmt="UPDATE watch_history SET watch_date = '$datetime' \
|
|
WHERE anime_name = '$1' \
|
|
AND episode_number = $2;"
|
|
fi
|
|
run_stmt "$stmt"
|
|
}
|
|
|
|
insert_history() {
|
|
# inserts into search/watch history db
|
|
# check the anime_name/id
|
|
if [[ ! $(check_anime_name "$1") ]]; then
|
|
printf "%s\n" "ERROR: Anime name is none... exiting"
|
|
return 1
|
|
fi
|
|
datetime=$(date +'%Y-%m-%d %H:%M:%S')
|
|
check_db "$@"
|
|
# echo "CHECKDB RETURNED: $num"
|
|
if [[ "$?" -gt 0 ]]; then
|
|
if [[ "$2" == "search" ]]; then
|
|
printf "%s\n" "Already in search db... Updating search_date"
|
|
else
|
|
printf "%s\n" "Already in search db... Updating watch_date"
|
|
fi
|
|
update_date "$@"
|
|
else
|
|
if [[ "$2" == "search" ]]; then
|
|
stmt="INSERT INTO search_history(anime_name, search_date) \
|
|
VALUES('$1', '$datetime');"
|
|
run_stmt "$stmt"
|
|
else
|
|
stmt="INSERT INTO \
|
|
watch_history(anime_name, episode_number, watch_date) \
|
|
VALUES('$1', '$2', '$datetime');"
|
|
run_stmt "$stmt"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# get query
|
|
get_search_query() {
|
|
# Query the anime to stream/download
|
|
|
|
# Get search history
|
|
stmt="SELECT DISTINCT anime_name \
|
|
FROM search_history \
|
|
ORDER BY search_date DESC;"
|
|
# hist=$(echo "$stmt" | sqlite3 -noheader "$HISTORY_DB")
|
|
hist=$(run_stmt "$stmt")
|
|
|
|
if [ -z "$*" ]; then
|
|
query=$(printf "%s\n" "${hist[@]}" |
|
|
rofi -dmenu -l 12 -p "Search Anime:" \
|
|
-config "$CFG_DIR/${CFG_FILE}")
|
|
# printf "Search Anime: "
|
|
# read -r query
|
|
else
|
|
query=$*
|
|
fi
|
|
}
|
|
|
|
# create history file
|
|
[ -f "$logfile" ] || : >"$logfile"
|
|
|
|
#####################
|
|
## Anime selection ##
|
|
#####################
|
|
|
|
anime_selection() {
|
|
# Select anime from query results
|
|
search_results=$*
|
|
menu_format_string='[%d] %s\n'
|
|
menu_format_string_c1="$c_blue[$c_cyan%d$c_blue] $c_reset%s\n"
|
|
menu_format_string_c2="$c_blue[$c_cyan%d$c_blue] $c_yellow%s$c_reset\n"
|
|
|
|
count=1
|
|
menu=()
|
|
res=()
|
|
while read anime_id; do
|
|
# alternating colors for menu
|
|
[ $((count % 2)) -eq 0 ] &&
|
|
menu_format_string=$menu_format_string_c1 ||
|
|
menu_format_string=$menu_format_string_c2
|
|
|
|
# printf "$menu_format_string" "$count" "$anime_id"
|
|
menu+="$count - $anime_id\n"
|
|
idx=$((count - 1))
|
|
res["$idx"]="$anime_id"
|
|
count=$((count + 1))
|
|
done <<-EOF
|
|
$search_results
|
|
EOF
|
|
|
|
searched=""
|
|
cnt=0
|
|
# Get the comma separated list of indexes of anime that has been searched before
|
|
for anime in "${res[@]}"; do
|
|
[ "$VERBOSE" -eq 1 ] && printf "%s\n" "ANIME: $anime"
|
|
check_db "$anime" "search"
|
|
if [[ $? -gt 0 ]]; then
|
|
[ "$VERBOSE" -eq 1 ] && printf "%s\n" "SEARCHED BEFORE"
|
|
if [[ "$searched" == "" ]]; then
|
|
searched="$((cnt++))"
|
|
else
|
|
searched="$searched, $((cnt++))"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
printf "%s\n" "SEARCHED: $searched"
|
|
|
|
# get the anime from indexed list
|
|
user_input=$(printf "${menu[@]}" |
|
|
rofi -dmenu -config "$CFG_DIR/${CFG_FILE}" \
|
|
-a "$searched" \
|
|
-l 12 -i -p "Enter number:")
|
|
[ "$?" -ne 0 ] && return 1
|
|
choice=$(printf '%s\n' "$user_input" | awk '{print $1}')
|
|
name=$(printf '%s\n' "$user_input" | awk '{print $NF}')
|
|
if [[ "$VERBOSE" -eq 1 ]]; then
|
|
printf "%s\n" "NAME: $name"
|
|
fi
|
|
insert_history "$name" "search"
|
|
echo "Number Chosen: $choice"
|
|
# User input
|
|
# printf "$c_blue%s$c_green" "Enter number: "
|
|
# read choice
|
|
printf "$c_reset"
|
|
|
|
# Check if input is a number
|
|
[ "$choice" -eq "$choice" ] 2>/dev/null || die "Invalid number entered"
|
|
|
|
# Select respective anime_id
|
|
count=1
|
|
while read anime_id; do
|
|
if [ $count -eq $choice ]; then
|
|
selection_id=$anime_id
|
|
break
|
|
fi
|
|
count=$((count + 1))
|
|
done <<-EOF
|
|
$search_results
|
|
EOF
|
|
|
|
[ -z "$selection_id" ] && die "Invalid number entered"
|
|
|
|
read last_ep_number <<-EOF
|
|
$(search_eps "$selection_id")
|
|
EOF
|
|
}
|
|
|
|
##################
|
|
## Ep selection ##
|
|
##################
|
|
|
|
episode_selection() {
|
|
# select episode number for anime
|
|
[ $is_download -eq 1 ] &&
|
|
printf "Range of episodes can be specified: start_number end_number\n"
|
|
printf "%s\n" "Anime ID: $anime_id"
|
|
stmt="SELECT DISTINCT episode_number \
|
|
FROM watch_history \
|
|
WHERE anime_name = '$anime_id';"
|
|
hist=$(run_stmt "$stmt")
|
|
if [[ "$VERBOSE" -eq 1 ]]; then
|
|
printf "%s\n" "HISTORY: ${hist[*]}"
|
|
fi
|
|
|
|
# Get Watch History for $anime_id as comma separated list
|
|
watch_history=""
|
|
for i in $hist; do
|
|
if [[ "$watch_history" == "" ]]; then
|
|
watch_history="$((--i))"
|
|
else
|
|
watch_history="$watch_history, $((--i))"
|
|
fi
|
|
done
|
|
|
|
[ "$VERBOSE" -eq 1 ] && printf "WATCH HISTORY: %s\n" "$watch_history"
|
|
# printf "NUM EPISODES: $last_ep_number"
|
|
# get user choice and set the start and end
|
|
msg='<span foreground="peachpuff" style="italic" size="small" weight="light">Range of episodes can be provided as: START_EPISODE - END_EPISODE</span>'
|
|
choice=$(
|
|
seq 1 "$last_ep_number" |
|
|
rofi -dmenu -l 12 \
|
|
-a "$watch_history" \
|
|
-p "Select Episode [1, $last_ep_number]:" \
|
|
-mesg "$msg" \
|
|
-config "$CFG_DIR/${CFG_FILE}"
|
|
)
|
|
ep_choice_start=$(printf '%s\n' "${choice}" | awk '{print $1}')
|
|
ep_choice_end=$(printf '%s\n' "${choice}" | awk '{print $NF}')
|
|
|
|
# if only one episode was entered, set ep_choice_end to empty string so only selected episode plays
|
|
# otherwise plays from ep 1 - ep_choice_start
|
|
if [[ "$ep_choice_start" -eq "$ep_choice_end" ]]; then
|
|
ep_choice_end=""
|
|
fi
|
|
|
|
[ "$VERBOSE" -eq 1 ] && printf "%s\n" "START: $ep_choice_start | END: $ep_choice_end"
|
|
# read ep_choice_start ep_choice_end
|
|
printf "$c_reset"
|
|
|
|
}
|
|
|
|
open_episode() {
|
|
anime_id=$1
|
|
episode=$2
|
|
ddir=$3
|
|
|
|
# clear the screen
|
|
printf '\x1B[2J\x1B[1;1H'
|
|
if [ $episode -lt 1 ] || [ $episode -gt $last_ep_number ]; then
|
|
err "Episode out of range"
|
|
stmt="SELECT DISTINCT episode_number \
|
|
FROM watch_history \
|
|
WHERE anime_name = '$anime_id' \
|
|
ORDER BY episode_number ASC;"
|
|
# hist=$(echo "$stmt" | sqlite3 "$HISTORY_DB" | awk '{ if ( NR > 2 ) { print } }')
|
|
hist=$(run_stmt "$stmt")
|
|
if [[ "$VERBOSE" -eq 1 ]]; then
|
|
echo "HISTORY: ${hist[*]}"
|
|
fi
|
|
episode=$(printf "%s\n" "${hist[@]}" |
|
|
rofi -dmenu -l 12 -p "Choose Episode:" \
|
|
-config "$CFG_DIR/${CFG_FILE}")
|
|
printf "$c_reset"
|
|
fi
|
|
|
|
[ "$VERBOSE" -eq 1 ] && printf "Getting data for episode %d\n" $episode
|
|
|
|
insert_history "$anime_id" "$episode"
|
|
|
|
dpage_url=$(get_dpage_link "$anime_id" "$episode")
|
|
video_url=$(get_links "$dpage_url")
|
|
|
|
case $video_url in
|
|
*streamtape*)
|
|
# If direct download not available then scrape streamtape.com
|
|
BROWSER=${BROWSER:-firefox}
|
|
printf "scraping streamtape.com\n"
|
|
video_url=$(curl -s "$video_url" | sed -n -E '
|
|
/^<script>document/{
|
|
s/^[^"]*"([^"]*)" \+ '\''([^'\'']*).*/https:\1\2\&dl=1/p
|
|
q
|
|
}
|
|
')
|
|
;;
|
|
esac
|
|
|
|
if [ $is_download -eq 0 ]; then
|
|
# write anime and episode number
|
|
sed -E "
|
|
s/^${selection_id}\t[0-9]+/${selection_id}\t$((episode + 1))/
|
|
" "$logfile" >"${logfile}.new" && mv "${logfile}.new" "$logfile"
|
|
|
|
setsid -f $player_fn --http-header-fields="Referer: $dpage_url" "$video_url" >/dev/null 2>&1
|
|
# $player_fn --http-header-fields="Referer: $dpage_url" "$video_url"
|
|
else
|
|
printf "Downloading episode $episode ...\n"
|
|
printf "%s\n" "$video_url"
|
|
# add 0 padding to the episode name
|
|
episode=$(printf "%03d" $episode)
|
|
{
|
|
(
|
|
echo "$DDIR"
|
|
cd "$ddir" || return 1
|
|
mkdir -p "$anime_id" && cd "$anime_id" || return 1
|
|
ffmpeg -headers "Referer: $dpage_url" -i "$video_url" \
|
|
-codec copy "${anime_id}-${episode}.mkv" >/dev/null 2>&1 &&
|
|
printf "${c_green}Downloaded episode: %s${c_reset}\n" "$episode" ||
|
|
printf "${c_red}Download failed episode: %s${c_reset}\n" "$episode"
|
|
)
|
|
}
|
|
fi
|
|
}
|
|
|
|
############
|
|
# Start Up #
|
|
############
|
|
|
|
# to clear the colors when exited using SIGINT
|
|
trap "printf '$c_reset'" INT HUP
|
|
|
|
dep_ch "$player_fn" "curl" "sed" "grep"
|
|
|
|
# option parsing
|
|
is_download=0
|
|
list_history=0
|
|
scrape=query
|
|
download_dir="."
|
|
while getopts 'hd:Hl' OPT; do
|
|
case $OPT in
|
|
h)
|
|
help_text
|
|
exit 0
|
|
;;
|
|
d)
|
|
is_download=1
|
|
download_dir="$OPTARG"
|
|
|
|
if [ "$VERBOSE" -eq 1 ]; then
|
|
echo "DOWNLOAD DIR: $download_dir"
|
|
fi
|
|
;;
|
|
H)
|
|
scrape=history
|
|
;;
|
|
l)
|
|
list_history=1
|
|
;;
|
|
esac
|
|
done
|
|
shift $((OPTIND - 1))
|
|
|
|
########
|
|
# main #
|
|
########
|
|
|
|
if [[ "$list_history" -eq 1 ]]; then
|
|
stmt="SELECT DISTINCT anime_name \
|
|
FROM search_history \
|
|
ORDER BY search_date DESC"
|
|
hist=$(run_stmt "$stmt")
|
|
printf "%s\n" "${hist[@]}" |
|
|
rofi -config "$CFG_DIR/${CFG_FILE}" \
|
|
-dmenu -l 12 -i -p "Search History"
|
|
exit 0
|
|
fi
|
|
|
|
case $scrape in
|
|
query)
|
|
|
|
get_search_query "$*"
|
|
search_results=$(search_anime "$query")
|
|
[ -z "$search_results" ] && die "No search results found"
|
|
anime_selection "$search_results"
|
|
episode_selection
|
|
;;
|
|
history)
|
|
# search_results=$(sed -n -E 's/\t[0-9]*//p' "$logfile")
|
|
stmt="SELECT DISTINCT anime_name FROM watch_history ORDER BY watch_date DESC"
|
|
search_results=$(printf "%s\n" "$stmt" | sqlite3 -noheader "$HISTORY_DB")
|
|
[ -z "$search_results" ] && die "History is empty"
|
|
anime_selection "${search_results[@]}"
|
|
stmt="SELECT episode_number FROM watch_history ORDER BY watch_date DESC LIMIT 1"
|
|
run_stmt "$stmt"
|
|
ep_choice_start=$?
|
|
echo "EPISODE: $ep_choice_start"
|
|
# ep_choice_start=$(sed -n -E "s/${selection_id}\t//p" "$logfile")
|
|
;;
|
|
esac
|
|
|
|
{ # checking input
|
|
[ "$ep_choice_start" -eq "$ep_choice_start" ] 2>/dev/null || die "Invalid number entered"
|
|
episodes=$ep_choice_start
|
|
|
|
if [ -n "$ep_choice_end" ]; then
|
|
[ "$ep_choice_end" -eq "$ep_choice_end" ] 2>/dev/null || die "Invalid number entered"
|
|
# create list of episodes to download/watch
|
|
episodes=$(seq $ep_choice_start $ep_choice_end)
|
|
fi
|
|
}
|
|
|
|
# add anime to history file
|
|
grep -q -w "${selection_id}" "$logfile" ||
|
|
printf "%s\t%d\n" "$selection_id" $((episode + 1)) >>"$logfile"
|
|
|
|
for ep in $episodes; do
|
|
open_episode "$selection_id" "$ep" "$download_dir"
|
|
done
|
|
episode=${ep_choice_end:-$ep_choice_start}
|
|
|
|
choice=''
|
|
while :; do
|
|
printf "\n${c_green}Currently playing %s episode ${c_cyan}%d/%d\n" "$selection_id" $episode $last_ep_number
|
|
printf "$c_blue[${c_cyan}%s$c_blue] $c_yellow%s$c_reset\n" "n" "next episode"
|
|
printf "$c_blue[${c_cyan}%s$c_blue] $c_magenta%s$c_reset\n" "p" "previous episode"
|
|
printf "$c_blue[${c_cyan}%s$c_blue] $c_yellow%s$c_reset\n" "s" "select episode"
|
|
printf "$c_blue[${c_cyan}%s$c_blue] $c_magenta%s$c_reset\n" "r" "replay current episode"
|
|
printf "$c_blue[${c_cyan}%s$c_blue] $c_red%s$c_reset\n" "q" "exit"
|
|
printf "${c_blue}Enter choice:${c_green} "
|
|
printf "$c_reset"
|
|
read choice
|
|
|
|
# choice=$(printf '%s\n' "${args[@]}" | rofi -dmenu -l 8 -i -p "Enter choice:")
|
|
# choice=$(printf '%s\n' "$choice" | awk '{print $1}')
|
|
printf "$c_reset"
|
|
case $choice in
|
|
n)
|
|
episode=$((episode + 1))
|
|
;;
|
|
p)
|
|
episode=$((episode - 1))
|
|
;;
|
|
|
|
s)
|
|
printf "${c_blue}Choose episode $c_cyan[1-%d]$c_reset:$c_green " $last_ep_number
|
|
read episode
|
|
printf "$c_reset"
|
|
[ "$episode" -eq "$episode" ] 2>/dev/null || die "Invalid number entered"
|
|
;;
|
|
|
|
r) ;;
|
|
|
|
q)
|
|
break
|
|
;;
|
|
|
|
*)
|
|
die "invalid choice"
|
|
;;
|
|
esac
|
|
open_episode "$selection_id" "$episode" "$download_dir"
|
|
done
|