Files
dra-cla/dra-cla
2024-05-25 21:43:50 +05:30

322 lines
9.8 KiB
Bash
Executable File

#!/bin/sh
#shellcheck disable=SC2154
# most important variables.
VERSION="3.0.1"
CHANNEL="main"
base_url="https://streamcool.pro"
logdir="${XDG_CACHE_HOME:-$HOME/.cache}"
logfile="$logdir/dra-hsts"
quality=best
scrape=query
agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/12$(head -5 /dev/urandom | tr -dc '0-2' | cut -c1).0.0.0 Safari/537.36"
trap 'rm -f '"$logfile"'.new' INT HUP
############
# help #
############
help_text() {
while IFS= read -r line; do
printf "%s\n" "$line"
done <<-EOF
Usage:
${0##*/} [-v] [-q <quality>] [-a <episode>] [-d | -p <download_dir>] [<query>]
${0##*/} [-v] [-q <quality>] -c
${0##*/} -h | -U | -V
Options:
-c continue watching drama from history
-a specify episode to watch
-h show helptext
-d download episode
-p download episode to specified directory
-q set video quality (best|worst|360|480|720|1080)
-v use VLC as the media player
-D Delete Entire history
-U fetch update from github
-V print version number and exit
Episode selection:
Multiple episodes can be chosen given a range
Choose episode [1-13]: 1 6
This would choose episodes 1 2 3 4 5 6
When selecting non-interactively (eg: -a <ep_no>), the first result will be
selected, if drama is passed as Args
EOF
}
############
# Update #
############
update_script() {
log "Checking For Updates.." >&2
update="$(curl -A "$agent" -s "https://raw.githubusercontent.com/CoolnsX/dra-cla/$CHANNEL/dra-cla" | diff -u "$0" -)"
if [ -z "$update" ]; then
log "Script is up to date :)\n" "32" >&2
exit 0
fi
#dry run
if [ "$1" -eq 0 ]; then
log "Update Available!!\n" "32" >&2
log "To Update, type: ${sudo}${0##*/} -U" "33" >&2
exit 0
fi
#warning: this updates the codebase of script.
if printf '%s\n' "$update" | patch "$0" -; then
log "Script has been updated\n" "32" >&2
exit 0
else
log "Can't update for some reason!\n" "31" >&2
exit 1
fi
}
############
# UI #
############
log() {
#shellcheck disable=SC2059
printf "\033[2K\r\033[1;${2:-36}m${1}\033[0m"
}
menu() {
fzf --prompt="$1 >> " --layout=reverse --border --height=20 -0 -1 -m
}
ask() {
log "$1" "33"
}
#############
# Logic #
#############
dep_ch() {
for dep in $(printf "%s" "$1" | tr ' ' '\n'); do
command -v "$dep" >/dev/null || {
log "Program $dep not found. Please install it\n" "31"
[ "$dep" = "aria2c" ] && log "To install $dep, Type <your_package_manager> aria2" "32"
exit 1
}
done
}
download() {
case "$1" in
*m3u8*)
log "Fetching Metadata"
data=$(curl -s -A "$agent" "$1" | sed '/#/d')
printf '%s' "$data" | nl -n'rz' | sed -E "s|^([0-9]*)[[:space:]]*(.*)|${3}\2\n\tout=\1.ts|g" | aria2c -x16 -s16 -j50 -d "$logdir/dra-hls" -i - --download-result=hide --summary-interval=0 --allow-overwrite=true
log "\nConcatenating Pieces..\n"
cat "$logdir/dra-hls"/* | ffmpeg -loglevel error -stats -i - -c copy "$download_dir/$2.mp4" -y
rm -f "$logdir/dra-hls"/*
;;
*)
aria2c --enable-rpc=false --check-certificate=false --continue --summary-interval=0 -x16 -s16 "$1" --dir="$download_dir" -o "$2.mp4" --download-result=hide
;;
esac
tput clear
log "Downloaded $2/$4"
}
open_episode() {
tput clear
log "Fetching $title Episode $episode.."
[ -z "$dpage_link" ] && dpage_link=$(curl -s -A "$agent" "$base_url/videos/${id}${episode}" | sed -nE 's_^[[:space:]]*<iframe src="([^"]*)".*_https:\1_p')
get_video_url
if grep -q "$id" "$logfile"; then
sed -E "s/^${id}.*/${id}$((episode + 1))/" "$logfile" >"${logfile}.new"
else
printf "%s%s\n" "$id" "$((episode + 1))" >>"$logfile"
fi
[ -z "$video_link" ] && log "Video URL not found" "31"
[ "$player_function" = "download" ] && display="Downloading" || display="Streaming"
log "$display $title Episode $episode/$total_eps\n" "32"
[ -z "$nohup" ] && ! printf "%s" "$player_function" | grep -q "android" && log "To play next Episode, quit the player."
#media Player
case "$player_function" in
mpv*) $nohup $player_function --force-media-title="${title} Episode ${episode}" "$video_link" >/dev/null 2>&1 ;;
android_mpv) am start --user 0 -a android.intent.action.VIEW -d "$video_link" -n is.xyz.mpv/.MPVActivity >/dev/null 2>&1 ;;
vlc*) $nohup $player_function --play-and-exit --meta-title="${title} Episode ${episode}" "$video_link" >/dev/null 2>&1 ;;
android_vlc) am start --user 0 -a android.intent.action.VIEW -d "$video_link" -n org.videolan.vlc/org.videolan.vlc.gui.video.VideoPlayerActivity -e "title" "${title} Episode ${episode}" >/dev/null 2>&1 ;;
download) "$player_function" "$video_link" "${title} Episode ${episode}" "$relative_link" "$total_eps";;
esac
dpage_link=""
[ -f "$logfile.new" ] && mv "${logfile}.new" "$logfile"
}
decrypt_link() {
secret_key='3933343232313932343333393532343839373532333432393038353835373532'
iv='39323632383539323332343335383235'
ajax_url="$base_url/encrypt-ajax.php"
ajax=$(printf "%s" "$1" | sed -nE 's/.*id=([^&]*)&.*/\1/p' | openssl enc -e -aes256 -K "$secret_key" -iv "$iv" -a)
video_url=$(curl -A "$agent" -s -H "X-Requested-With:XMLHttpRequest" "$ajax_url" -d "id=$ajax" | sed -e 's/{"data":"//' -e 's/"}/\n/' -e 's/\\//g' | base64 -d | openssl enc -d -aes256 -K "$secret_key" -iv "$iv" | sed -e 's/\].*/\]/' -e 's/\\//g' | tr '{|}' '\n' | sed -nE 's/\"file\":"([^"]*)".*label.*P.*/\1/p')
}
get_video_url() {
decrypt_link "$dpage_link"
relative_link=$(printf "%s" "$video_url" | sed 's|[^/]*$||')
video_links=$(curl -s -A "$agent" "$video_url" | sed "s|^#.*x||g; s|,.*|p|g; /^#/d; \$!N; s|\n| >${relative_link}|")
case $quality in
best)
video_link=$(printf '%s' "$video_links" | tail -n 1 | cut -d'>' -f2)
;;
worst)
video_link=$(printf '%s' "$video_links" | head -n 1 | cut -d'>' -f2)
;;
*)
video_link=$(printf '%s' "$video_links" | sed -n "/${quality}p >/p" | cut -d'>' -f2)
if [ -z "$video_link" ]; then
log "Current video quality is not available (defaulting to best quality)\n" "31"
quality=best
video_link=$(printf '%s' "$video_links" | tail -n 1 | cut -d'>' -f2)
fi
;;
esac
}
############
# Main #
############
#create history file
[ -d "$logdir" ] || mkdir "$logdir"
[ -f "$logfile" ] || : >"$logfile"
download_dir="."
# OS detection for player selection and default download location.
case "$(uname -a)" in
*MINGW* | *WSL2*)
player_function="mpv.exe"
alt_player="vlc.exe"
;;
*ndroid*)
player_function="android_mpv"
download_dir="/sdcard"
alt_player="android_vlc"
;;
*)
player_function="mpv"
alt_player="vlc"
command -v "doas" >/dev/null && sudo="doas " || sudo="sudo "
;;
esac
while getopts 'vq:dp:chDUVa:' OPT; do
case $OPT in
d)
player_function="download"
;;
a)
ep_start=$OPTARG
;;
D)
: >"$logfile"
exit 0
;;
p)
player_function="download"
download_dir=$OPTARG
;;
q)
quality=$OPTARG
;;
c)
scrape=history
;;
v)
player_function=$alt_player
;;
U)
update_script 1
;;
V)
log "Version: $VERSION\n" >&2
log "Channel: $CHANNEL\n" >&2
update_script 0
;;
*)
help_text
exit 1
;;
esac
done
shift $((OPTIND - 1))
#dependency checking
log "Checking Dependencies.."
dep_ch "curl sed grep openssl fzf"
if [ "$player_function" = "download" ]; then
dep_ch "aria2c ffmpeg"
elif ! printf "%s" "$player_function" | grep -q "android"; then
dep_ch "$player_function"
fi
if [ "$scrape" = "query" ]; then
[ -z "$*" ] && ask "Search Drama: " && read -r query || query=$*
log "Searching Drama.."
response=$(curl -A "$agent" -s "$base_url/search.html" -G --data-urlencode "keyword=$query" | sed -nE 's_^[[:space:]]*<a href="/videos/([^"]*)-episode-([0-9]*)">_\1 (\2 Episodes)_p')
[ -z "$response" ] && log "No Results Found" "31" && exit 0
log ""
id=$(printf "%s" "$response" | tr '-' ' ' | menu "Select Drama")
[ -z "$id" ] && log "No Drama Selected" "31" && exit 0
# sets $title and $total_eps variable
eval "$(printf %s "$id" | tr -s ' ' | sed -nE 's|(.*) \(([0-9]*) Episodes\)$|title="\1";total_eps="\2"|p')"
id=$(printf "%s" "$id" | sed 's| ([0-9]* Episodes)|-episode-|g' | tr ' ' '-')
else
log ""
[ ! -s "$logfile" ] && log "History is empty" "31" && exit 0
id=$(tr '-' ' ' <"$logfile" | menu "Continue" | tr ' ' '-')
[ -z "$id" ] && log "No Drama Selected" "31" && exit 0
ep_start=$(printf "%s" "$id" | sed -nE 's|.*-episode-([0-9]*)|\1|p')
log "Checking Episode $ep_start"
response=$(curl -s "$base_url/videos/$id" -A "$agent" | sed '/Latest Episodes/,$d' | sed -nE 's_^[[:space:]]*<a href.*/videos/.*-episode-([0-9]*)">.*_\1_p;s_^[[:space:]]*<iframe src="([^"]*)".*_https:\1_p')
[ -z "$response" ] && log "Episode Not Released" "31" && exit 0
id=$(printf "%s" "$id" | sed 's|-episode-.*|-episode-|g')
total_eps=$(printf "%s" "$response" | sed -n '2p')
title=$(printf "%s" "$id" | sed 's|-episode-.*||g' | tr '-' ' ' | tr -s ' ')
dpage_link=$(printf "%s" "$response" | head -1)
fi
#shows prompt if select episode is not specified via args
if [ -z "$ep_start" ]; then
log "Selected: $title\n" "32"
printf "%s" "$player_function" | grep -q "android" && display="Range is broken for android." || display="To specify a range, use: start_number end_number"
log "$display\n"
ask "Episodes [1-$total_eps]: "
read -r ep_start ep_end
fi
[ -z "$ep_start" ] && log "No Episode Selected" "31" && exit 1
if [ -n "$ep_end" ]; then
for episode in $(seq "$ep_start" "$ep_end"); do
open_episode
done
else
nohup="setsid -f"
episode="${ep_start}"
open_episode
fi
episode="${ep_end:-$ep_start}"
while cmd=$(printf "next\nreplay\nprevious\nselect\nchange_quality\nquit" | menu "Select Option"); do
case "$cmd" in
next) [ "$episode" -lt "$total_eps" ] && : $((episode += 1)) || flag=1 ;;
replay) ;;
previous) [ "$episode" -gt 1 ] && : $((episode -= 1)) || flag=1 ;;
select) ask "Episodes [1-$total_eps]: " && read -r episode ;;
*) log "" && exit 0 ;;
esac
[ -n "$flag" ] && log "Out of Range" "31" && flag="" && continue
open_episode
done