add dra-cla script

This commit is contained in:
CoolnsX
2022-03-05 17:38:17 +05:30
parent 1f563217dc
commit e674561798
3 changed files with 692 additions and 1 deletions

View File

@@ -1,2 +1,22 @@
# dra-cla
<p align=center>
<br>
<a href="http://makeapullrequest.com"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg"></a>
<img src="https://img.shields.io/badge/os-linux-brightgreen">
<img src="https://img.shields.io/badge/os-mac-brightgreen"></a>
<img src="https://img.shields.io/badge/os-windows-brightgreen"></a>
<img src="https://img.shields.io/badge/os-android-brightgreen"></a>
<br>
<a href="https://discord.gg/aqu7GpqVmR"><img src="https://invidget.switchblade.xyz/aqu7GpqVmR"></a>
<br>
<a href="https://github.com/ura43"><img src="https://img.shields.io/badge/lead-ura43-lightblue"></a>
<a href="https://github.com/CoolnsX"><img src="https://img.shields.io/badge/maintainer-CoolnsX-blue"></a>
<a href="https://github.com/RaynardGerraldo"><img src="https://img.shields.io/badge/maintainer-RayGL-blue"></a>
<br>
<a href="https://github.com/71zenith"><img src="https://img.shields.io/badge/maintainer-71zenith-blue"></a>
<a href="https://github.com/iamchokerman"><img src="https://img.shields.io/badge/maintainer-iamchokerman-blue"></a>
<a href="https://github.com/Derisis13"><img src="https://img.shields.io/badge/maintainer-Derisis13-blue"></a>
</p>
A cli tool to browse and play korean drama, chinese drama
This tool scrapes the site [dramacool](https://dramacool.fo).

47
disclaimer.md Normal file
View File

@@ -0,0 +1,47 @@
<h1 align="center">Disclaimer</h1>
<div align="center">
<h2>This project: ani-cli</h2>
<br>
The core aim of this project is to co-relate automation and efficiency to extract what is provided to an user on the internet. Every content available in the project is hosted by external non-affiliated sources.
<br>
<b>Any content served through this project is publicly accessible. If your site is listed in this project, the code is pretty much public. Take necessary measures to counter the exploits used to extract content in your site.</b>
Think of this project as your normal browser, but a bit more straight-forward and specific. While an average browser makes hundreds of requests to get everything from a site, this project goes on to make requests associated with only getting the content served by the sites.
<b>
This project is to be used at the user's own risk, based on their government and laws.
This project has no control on the content it is serving, using copyrighted content from the providers is not going to be accounted for by the developer. It is the user's own risk.
</b>
<br>
<h2>DMCA and Copyright Infrigements</h3>
<br>
<b>
A browser is a tool, and the maliciousness of the tool is directly based on the user.
</b>
This project uses client-side content access mechanisms. Hence, the copyright infrigements or DMCA in this project's regards are to be forwarded to the associated site by the associated notifier of any such claims. As of writing this is dramacool
<b>Do not harass the maintainer.</b>
<h2>
Contacting the maintainer
</h3>
<br>
Begin by making a GitHub issue or sending an email to ansari.tan20@gmail.com
</div>

624
dra-cla Executable file
View File

@@ -0,0 +1,624 @@
#!/bin/sh
# dra-cla
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Project repository: https://github.com/CoolnsX/dra-cla
# Version number
VERSION="1.0.0"
#######################
# AUXILIARY FUNCTIONS #
#######################
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 | -D | -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 history
-U fetch update from github
-V print version number and exit
Episode selection:
Add 'h' on beginning for episodes like '6.5' -> 'h6'
Multiple episodes can be chosen given a range
Choose episode [1-13]: 1 6
This would choose episodes 1 2 3 4 5 6
To select the last episode use -1
When selecting non-interactively, the first result will be
selected, if drama is passed
EOF
}
version_text () {
inf "Version: $VERSION" >&2
}
die () {
err "$*"
exit 1
}
update_script () {
# get the newest version of this script from github and replace it
update="$(curl -s "https://raw.githubusercontent.com/CoolnsX/dra-cla/master/dra-cla" | diff -u "$0" -)"
if [ -z "$update" ]; then
inf "Script is up to date :)"
else
if printf '%s\n' "$update" | patch "$0" - ; then
inf "Script has been updated"
else
die "Can't update for some reason!"
fi
fi
}
dep_ch () {
# checks if dependencies are present
for dep; do
if ! command -v "$dep" >/dev/null ; then
err "Program \"$dep\" not found. Please install it."
#aria2c is in the package aria2
[ "$dep" = "aria2c" ] && err "To install aria2c, Type <your_package_manager> aria2"
die
fi
done
}
#############
# SEARCHING #
#############
search_drama () {
# get drama name along with its id for search term
search=$(printf '%s' "$1" | tr ' ' '+' )
curl -s "$base_url/search?type=movies&keyword=$search" |
sed -n -E 's_^[[:space:]]*<a href="/drama-detail/([^"]*)".*_\1_p'
}
search_eps () {
# get available episodes for drama_id
drama_id="$1"
curl -s "$base_url/drama-detail/$drama_id" |
sed -nE "s/.*$id.*episode-(.*).html.*/\1/p" | head -1
}
search_for_unwatched () {
# compares history with dramacool, only shows unfinished drama
search_results="$*"
while read -r drama_id; do
current_ep_number=$(search_eps "$drama_id")
history_ep_number=$(sed -n -E "s/${drama_id}\t//p" "$logfile")
[ "$current_ep_number" -ge "$history_ep_number" ] && printf '%s\n' "$drama_id"
done <<-EOF
$search_results
EOF
}
search_another_drama () {
tput clear
prompt "Search Drama"
query="$REPLY $REPLY2"
process_search
}
search_history () {
tput clear
search_results=$(sed -n -E 's/\t[0-9]*//p' "$logfile")
[ -z "$search_results" ] && die "History is empty"
search_results=$(search_for_unwatched "$search_results")
[ -z "$search_results" ] && die "No unwatched episodes"
drama_selection "$search_results"
ep_choice_start=$(sed -n -E "s/${selection_id}\t//p" "$logfile")
}
##################
# URL PROCESSING #
##################
get_dpage_link() {
# get the download page url
drama_id="$1"
ep_no="$2"
for params in "-episode-$ep_no.html" "-$ep_no.html" "-episode-$ep_no-1.html" "-camrip-episode-$ep_no.html"; do
drama_page=$(curl -s "$base_url/$drama_id$params")
printf '%s' "$drama_page" | grep -q '<h1 class="entry-title">404</h1>' || break
done
printf '%s' "$drama_page" |
sed -n -E 's/.*class="Standard Server selected" rel="1" data-video="([^"]*)".*/\1/p' | sed 's/^/https:/g'
}
decrypt_link() {
secret_key='3933343232313932343333393532343839373532333432393038353835373532'
iv='39323632383539323332343335383235'
ajax_url="https://asianembed.io/encrypt-ajax.php"
crypto_data=$(curl -s "$1" | sed -nE 's/.*data-value="([^"]*)".*/\1/p')
id=$(printf '%s' "$crypto_data" | base64 -d | openssl enc -d -aes256 -K "$secret_key" -iv "$iv" | cut -d '&' -f1)
#encrypt and create the final ajax
ajax=$(printf "%s\010\016\003\010\t\003\004\t" "$id" | openssl enc -aes256 -K "$secret_key" -iv "$iv" -a)
data=$(curl -s -H "X-Requested-With:XMLHttpRequest" "$ajax_url" -d "id=$ajax" | sed -e 's/{"data":"//' -e 's/"}/\n/' -e 's/\\//g')
#decrypt the data to get final links
printf '%s' "$data" | base64 -d | openssl enc -d -aes256 -K "$secret_key" -iv "$iv" | sed -e 's/\].*/\]/' -e 's/\\//g' |
grep -Eo 'https:\/\/[-a-zA-Z0-9@:%._\+~#=][a-zA-Z0-9][-a-zA-Z0-9@:%_\+.~#?&\/\/=]*'
}
get_video_quality() {
# chooses the link for the set quality
dpage_url="$1"
video_links=$(decrypt_link "$dpage_url")
case $quality in
best)
video_link=$(printf '%s' "$video_links" | head -n 4 | tail -n 1)
;;
worst)
video_link=$(printf '%s' "$video_links" | head -n 1)
;;
*)
video_link=$(printf '%s' "$video_links" | grep -i "${quality}p" | head -n 1)
if [ -z "$video_link" ]; then
err "Current video quality is not available (defaulting to best quality)"
quality=best
video_link=$(printf '%s' "$video_links" | head -n 4 | tail -n 1)
fi
;;
esac
printf '%s' "$video_link"
}
###############
# TEXT OUTPUT #
###############
err () {
# display an error message to stderr (in red)
printf "\033[1;31m%s\033[0m\n" "$*" >&2
}
inf () {
# display an informational message (first argument in green, second in magenta)
printf "\033[1;32m%s \033[1;35m%s\033[0m\n" "$1" "$2"
}
prompt () {
# 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
printf "\033[1;34m%s\033[1;35m%s\033[1;34m: \033[0m" "$1" "$2"
read -r REPLY REPLY2
}
menu_line_even () {
# displays an even (cyan) line of a menu line with $2 as an indicator in [] and $1 as the option
printf "\033[1;34m[\033[1;36m%s\033[1;34m] \033[1;36m%s\033[0m\n" "$2" "$1"
}
menu_line_odd() {
# displays an odd (yellow) line of a menu line with $2 as an indicator in [] and $1 as the option
printf "\033[1;34m[\033[1;33m%s\033[1;34m] \033[1;33m%s\033[0m\n" "$2" "$1"
}
menu_line_alternate() {
menu_line_parity=${menu_line_parity:-0}
if [ "$menu_line_parity" -eq 0 ]; then
menu_line_odd "$1" "$2"
menu_line_parity=1
else
menu_line_even "$1" "$2"
menu_line_parity=0
fi
}
menu_line_strong() {
# displays a warning (red) line of a menu line with $2 as an indicator in [] and $1 as the option
printf "\033[1;34m[\033[1;31m%s\033[1;34m] \033[1;31m%s\033[0m\n" "$2" "$1"
}
#################
# INPUT PARSING #
#################
is_number () {
[ "$1" -eq "$1" ] 2>/dev/null || die 'Invalid number entered'
}
process_search () {
search_results=$(search_drama "$query")
while [ -z "$search_results" ]; do
err 'No search results found'
prompt 'Search Drama'
query="$REPLY $REPLY2"
search_results=$(search_drama "$query")
done
drama_selection "$search_results"
episode_selection
}
drama_selection () {
count=1
while read -r drama_id; do
menu_line_alternate "$drama_id" "$count"
: $((count+=1))
done <<-EOF
$search_results
EOF
if [ -n "$ep_choice_to_start" ] && [ -n "$select_first" ]; then
tput clear
choice=1
elif [ -z "$ep_choice_to_start" ] || { [ -n "$ep_choice_to_start" ] && [ -z "$select_first" ]; }; then
menu_line_strong "exit" "q"
prompt "Enter choice"
choice="$REPLY"
while ! [ "$choice" -eq "$choice" ] 2>/dev/null || [ "$choice" -lt 1 ] || [ "$choice" -ge "$count" ] || [ "$choice" = " " ]; do
[ "$choice" = "q" ] && exit 0
err "Invalid choice entered"
prompt "Enter choice"
choice="$REPLY"
done
fi
# Select respective drama_id
count=1
while read -r drama_id; do
if [ "$count" -eq "$choice" ]; then
selection_id="$drama_id"
break
fi
count=$((count+1))
done <<-EOF
$search_results
EOF
search_ep_result=$(search_eps "$selection_id")
read -r last_ep_number <<-EOF
$search_ep_result
EOF
}
episode_selection () {
# using get_dpage_link to get confirmation from episode 0 if it exists,else first_ep_number becomes "1"
first_ep_number=0
result=$(get_dpage_link "$drama_id" "$first_ep_number")
[ -z "$result" ] && first_ep_number=1
if [ "$last_ep_number" -gt "$first_ep_number" ]; then
inf "Range of episodes can be specified: start_number end_number"
if [ -z "$ep_choice_to_start" ]; then
prompt "Choose episode" "[$first_ep_number-$last_ep_number]"
ep_choice_start="$REPLY"
ep_choice_end="$REPLY2"
while [ "$ep_choice_start" -lt "$first_ep_number" ] 2> /dev/null || [ "$ep_choice_end" -gt "$last_ep_number" ] 2> /dev/null || [ "$ep_choice_start" -gt "$last_ep_number" ] 2> /dev/null || [ -z "$ep_choice_start" ] 2> /dev/null; do
if [ "$ep_choice_end" != -1 ]; then
err "Invalid number chosen"
prompt "Choose episode" "[$first_ep_number-$last_ep_number]"
ep_choice_start="$REPLY"
ep_choice_end="$REPLY2"
fi
done
else
ep_choice_start="$ep_choice_to_start" && unset ep_choice_to_start
fi
whether_half="$(printf '%s' "$ep_choice_start" | cut -c1-1)"
if [ "$whether_half" = "h" ]; then
half_ep=1
ep_choice_start="$(printf '%s' "$ep_choice_start" | cut -c2-)"
fi
else
# In case the drama contains only a single episode
ep_choice_start=1
fi
if [ -z "$ep_choice_end" ]; then
auto_play=0
else
auto_play=1
[ "$ep_choice_end" = "-1" ] && ep_choice_end="$last_ep_number"
fi
}
check_input() {
# checks if input is number, creates $episodes from $ep_choice_start and $ep_choice_end
is_number "$ep_choice_start"
episodes=$ep_choice_start
if [ -n "$ep_choice_end" ]; then
is_number "$ep_choice_end"
# create list of episodes to download/watch
episodes=$(seq "$ep_choice_start" "$ep_choice_end")
fi
}
##################
# VIDEO PLAYBACK #
##################
append_history () {
grep -q -w "${selection_id}" "$logfile" || printf "%s\t%s\n" "$selection_id" $((episode+1)) >> "$logfile"
}
open_selection() {
# opens selected episodes one-by-one
for ep in $episodes; do
open_episode "$selection_id" "$ep"
done
episode=${ep_choice_end:-$ep_choice_start}
}
open_episode () {
drama_id="$1"
episode="$2"
# cool way of clearing screen
tput clear
# checking if episode is in range
while [ "$episode" -gt "$last_ep_number" ] || [ -z "$episode" ]; do
is_number "$ep_choice_start"
if [ "$last_ep_number" -eq 0 ]; then
die "Episodes not released yet!"
else
err "Episode out of range"
fi
prompt "Choose episode" "[$first_ep_number-$last_ep_number]"
episode="$REPLY $REPLY2"
done
#processing half episodes
if [ "$half_ep" -eq 1 ]; then
temp_ep="$episode"
episode="${episode}-5"
fi
inf "Getting data for episode $episode"
# decrypting url
dpage_link=$(get_dpage_link "$drama_id" "$episode")
video_url=$(get_video_quality "$dpage_link")
if [ "$half_ep" -eq 1 ]; then
episode="$temp_ep"
half_ep=0
fi
# Download or play episodes
if [ "$is_download" -eq 0 ]; then
# write drama and episode number and save to temporary history
sed -E "
s/^${selection_id}\t[0-9]+/${selection_id}\t$((episode+1))/
" "$logfile" > "${logfile}.new"
[ "$PID" -ne 0 ] && kill "$PID" >/dev/null 2>&1
[ -z "$video_url" ] && die "Video URL not found"
case "$player_fn" in
vlc)
if [ "$auto_play" -eq 0 ]; then
nohup "$player_fn" --http-referrer="$dpage_link" "$video_url" > /dev/null 2>&1 &
else
inf "Currently playing $selection_id episode" "$episode/$last_ep_number, Range: $ep_choice_start-$ep_choice_end"
"$player_fn" --play-and-exit --http-referrer="$dpage_link" "$video_url" > /dev/null 2>&1
sleep 2
fi
;;
*)
if [ "$auto_play" -eq 0 ]; then
nohup "$player_fn" --referrer="$dpage_link" "$video_url" --force-media-title="dra-cla: $drama_id ep $episode" > /dev/null 2>&1 &
else
inf "Currently playing $selection_id episode" "$episode/$last_ep_number, Range: $ep_choice_start-$ep_choice_end"
"$player_fn" --referrer="$dpage_link" "$video_url" --force-media-title="dra-cla: $drama_id ep $episode" > /dev/null 2>&1
sleep 2
fi
;;
esac
PID=$!
mv "${logfile}.new" "$logfile"
else
mkdir -p "$download_dir"
inf "Downloading episode $episode ..."
# add 0 padding to the episode name
episode=$(printf "%03d" "$episode")
{
if aria2c -x 16 -s 16 --referer="$dpage_link" "$video_url" --dir="$download_dir" -o "${drama_id}-${episode}.mp4" --download-result=hide ; then
inf "Downloaded episode: $episode"
else
err "Download failed episode: $episode , please retry or check your internet connection"
fi
}
fi
}
############
# START UP #
############
# to clear the colors when exited using SIGINT
trap 'printf "\033[0m";[ -f "$logfile".new ] && rm "$logfile".new;exit 1' INT HUP
# default options
player_fn="mpv" #video player needs to be able to play urls
is_download=0
half_ep=0
PID=0
quality=best
scrape=query
download_dir="."
choice=
auto_play=0
# history file path
logfile="${XDG_CACHE_HOME:-$HOME/.cache}/dra-hsts"
logdir="${XDG_CACHE_HOME:-$HOME/.cache}"
# create history file and history dir if none found
[ -d "$logdir" ] || mkdir "$logdir"
[ -f "$logfile" ] || : > "$logfile"
while getopts 'vq:dp:chDUVa:' OPT; do
case $OPT in
h)
help_text
exit 0
;;
d)
is_download=1
select_first=1
;;
a)
ep_choice_to_start=$OPTARG
;;
D)
: > "$logfile"
exit 0
;;
p)
is_download=1
download_dir=$OPTARG
select_first=1
;;
q)
quality=$OPTARG
;;
c)
scrape=history
;;
v)
player_fn="vlc"
;;
U)
update_script
exit 0
;;
V)
version_text
exit 0
;;
*)
help_text
exit 1
;;
esac
done
shift $((OPTIND - 1))
# check for main dependencies
dep_ch "curl" "sed" "grep" "git" "openssl"
# check for optional dependencies
if [ "$is_download" -eq 0 ]; then
dep_ch "$player_fn"
else
dep_ch "aria2c"
fi
# dramacool likes to change domains but keep the olds as redirects
base_url="https://dramacool.fo"
case $scrape in
query)
if [ -z "$*" ]; then
prompt "Search Drama"
query="$REPLY $REPLY2"
else
if [ -n "$ep_choice_to_start" ]; then
REPLY=1
select_first=1
fi
query="$*"
fi
process_search
;;
history)
search_history
[ "$REPLY" = "q" ] && exit 0
first_ep_number=0
result=$(get_dpage_link "$drama_id" "$first_ep_number")
[ -z "$result" ] && first_ep_number=1
;;
*)
die "Unexpected scrape type"
esac
check_input
append_history
open_selection
########
# LOOP #
########
while :; do
if [ -z "$select_first" ]; then
if [ "$auto_play" -eq 0 ]; then
inf "Currently playing $selection_id episode" "$episode/$last_ep_number"
else
auto_play=0
fi
[ "$episode" -ne "$last_ep_number" ] && menu_line_alternate 'next episode' 'n'
[ "$episode" -ne "$first_ep_number" ] && menu_line_alternate 'previous episode' 'p'
[ "$last_ep_number" -ne "$first_ep_number" ] && menu_line_alternate 'select episode' 's'
menu_line_alternate "replay current episode" "r"
menu_line_alternate "search for another drama" "a"
menu_line_alternate "search history" "h"
menu_line_alternate "select quality (current: $quality)" "b"
menu_line_strong "exit" "q"
prompt "Enter choice"
# process user choice
choice="$REPLY"
case $choice in
n)
ep_choice_start=$((episode + 1))
ep_choice_end=
;;
b)
prompt "Select quality. Options (best|worst|360|480|720|1080)"
quality="$REPLY"
;;
p)
ep_choice_start=$((episode - 1))
ep_choice_end=
;;
s)
episode_selection
;;
r)
ep_choice_start=$((episode))
ep_choice_end=
;;
a)
search_another_drama
;;
h)
search_history
;;
q)
break
;;
*)
tput clear
err "Invalid choice"
continue
;;
esac
check_input
append_history
open_selection
else
wait $!
exit
fi
done