#!/bin/bash
#
# fetches list of episodes (with contents), upcoming broadcasts of
# tv series (-t and/or -T) or the very same for movies (-m) using
# www.wunschliste.de as online database. Tested with:
# - CYGWIN_NT-10.0 2.11.2(0.329/5/3) 2018-11-08 x86_64 Cygwin
# - Linux 3.2.40 #23824 SMP Fri Sep 7 12:48:46 CST 2018 armv7l
# GNU/Linux synology_armada375_ds215j
#
# (C) Josef Kleber 2017-2019 License: gplv3
#
# Environment variables
# WL_PAYTV=''
#
version="v2.1l (2019/07/06)"
copyright="(C) Josef Kleber 2017-2019"
license="gplv3"
tempfile=$(mktemp)
sopt=""
Sopt=""
Eopt=""
popt=""
eopt="MS-ANSI"
copt="false"
fopt="false"
zopt="false"
topt="false"
mopt="series"
number='^[0-9]*$'
scol=$'\E[41m'
ecol=$'\E[44m'
rcol=$'\E[49m'
toptarg=' '
Toptarg='#'
os=$(uname -o)
#
if [ -z "$WL_PAYTV" ]
then
WL_PAYTV="#"
fi
#
check_prog()
{
hash "$1" 2>/dev/null || { echo -e "\n$1 is not installed.\nAborting." >&2; exit 1; }
}
#
check_prog uname
check_prog curl
check_prog grep
check_prog cut
check_prog sed
check_prog cat
check_prog tr
check_prog date
check_prog wc
if [ "$os" = "Cygwin" ]
then
# only needed for Windows (MS-ANSI encoding)
check_prog iconv
fi
#
function pversion()
{
echo "This is version $version of $(basename $0)"
echo $copyright $license
exit 0;
}
#
function phelp()
{
echo -e "\n $(basename $0) [options]\n"\
"\n fetches list of episodes (with contents), upcoming broadcasts of tv series\n"\
" (-t and/or -T) or the very same for movies (-m) using\n"\
" www.wunschliste.de as online database.\n\n"\
" Options:\n\n\n"\
" EPG mode:\n\n"\
" -s \e[4mseries\e[24m or \e[4mmovie\e[24m (-m) in www.wunschliste.de URL notation, e.g. auf-achse\n"\
" (series) or iron-man (movie).\n"\
" The script is able to process input like 'Auf Achse'!\n\n"\
" -S lists episodes of season \e[4mseason\e[24m.\n\n"\
" -E lists episode(s) \e[4mepisode\e[24m of all seasons.\n\n"\
" -p lists episode(s) matching \e[4mpattern\e[24m.\n\n"\
" -c includes content in the list. (Implicit default for movies (-m))\n\n"\
" -f writes file(s) with \e[4mfile extension\e[24m. (ep_nr ep_name.ext)\n"\
" (default: '' -> no file(s))\n\n"\
" -e \e[4mfile encoding\e[24m (iconv) (default: MS-ANSI)\n"\
" only works for Cygwin (reencoding for Win10)\n\n"\
" -z 'sanitize' file name(s). ((german) substitution of special characters\n"\
" for file system)\n\n"\
" -P search series or movies (-m) matching \e[4mpattern\e[24m.\n\n\n"\
" Broadcast mode:\n\n"\
" -t lists upcoming broadcasts instead, matching \e[4mpattern\e[24m, e.g. 'zdf' (channel),\n"\
" 'Fr ' (Friday), '\.12' (December), '(6|7)x' (Season 6 or 7),\n"\
" '(0[6-7]|1[4-6]):' (broadcasts starting 06-07 or 14-16);\n"\
" '*', \* or ? will list all broadcasts!\n"\
" This matching uses Extended Regular Expressions (ERE)!\n\n"\
" -T lists upcoming broadcasts instead, not matching \e[4mpattern\e[24m.\n"\
" This can be combined with -t!\n\n"\
" -l \e[4mfile\e[24m; checks a list of series or movies (-m) in format\n"\
" series/movie,include_pattern,exclude_pattern (-s .. -t .. -T ..),\n"\
" e.g. die-simpsons,pro.*27x,#\n\n\n"\
" Movie mode:\n\n"\
" -m search movies instead of series!\n\n\n"\
" General options:\n\n"\
" -v print version info\n\n"\
" -h print help\n\n\n"\
" ENVIRONMENT VARIABLES:\n\n"\
" WL_PAYTV\n"\
" defines a list (ERE) of excluded channnels in Broadcast mode,\n"\
" e.g. '( sky | tnt )'\n\n\n"\
" EXAMPLES:\n\n"\
" wunschliste -s auf-achse -S 4\n"\
" lists all episodes of season 4 of 'Auf Achse'\n\n"\
" wunschliste -s auf-achse -E 2\n"\
" lists episode 2 of all 6 seasons of 'Auf Achse'\n\n"\
" wunschliste -cs auf-achse -S 1 -E 2\n"\
" lists title and content of episode 2 of season 1 of 'Auf Achse'\n\n"\
" wunschliste -s navy-cis -p Terror\n"\
" lists all episode(s) matching 'Terror' of 'Navy CIS'\n\n"\
" wunschliste -cs auf-achse -S 1 -f .txt\n"\
" creates files with content for all episodes of season 1 of 'Auf Achse'\n\n"\
" wunschliste -s navy-cis -t '(Sa|So).*\.07\..*1[01]:' -T Fox\n"\
" lists all episodes of 'Navy CIS' running on Saturday or Sunday in July\n"\
" starting at 10:xx or 11:xx, but not on Fox!\n\n"\
" wunschliste -mP 'iron man'\n"\
" lists all movies related to 'iron man'\n\n"\
" wunschliste -ms 'Iron Man 3'\n"\
" lists content of 'Iron Man 3'\n\n"\
" wunschliste -ml movie.rec\n"\
" lists all upcoming broadcasts of 'Iron Man 1 - 3', if movie.rec looks like:\n\n"\
" iron-man,?,#\n"\
" iron-man-2,?,#\n"\
" iron-man-3,?,#\n\n"\
" This file must be encoded in UTF-8 with UNIX file endings. Moreover it may\n"\
" contain other shell style comments!\n"\
" There must be seperate files for series and movies called with options -l or\n"\
" -m -l!"\
"\n"
exit 0;
}
#
function intv()
{
if [ "$mopt" = "movie" ]
then
curl 'https://www.wunschliste.de/spielfilm/'$sopt'' 2>/dev/null | sed -e 's#<span class="sf3"#\n<span class="sf3"#g' | grep -e 'class="l"' >"$tempfile"
if [ -s "$tempfile" ]
then
intvfile=$(mktemp)
# to avoid unnecessary and time-consuming date calculations
# we grep for $thismonth and $nextmonth
thismonth=$(date -d 'now' '+%m.%Y')
nextmonth=$(date -d 'next month' '+%m.%Y')
sed -e 's#.*class="smartphone">\([^<]*\).*class="d1">\([^<]*\).*class="d2">\([0-9\.]*\).*"no-smartphone"> \([0-9]*\)\:\([0-9]*\) h.*#\2 \3 \4:\5 \1#' "$tempfile" | \
grep -Eie "$toptarg" | grep -Eiv "$Toptarg" | grep -Eiv "$WL_PAYTV" | grep -e "$thismonth" -e "$nextmonth" >"$intvfile"
while read line
do
# So 23.04.2017 20:15h Das Erste
date_line=$(echo "$line" | cut -d ' ' -f2)
day=$(echo "$date_line" | cut -d '.' -f1)
month=$(echo "$date_line" | cut -d '.' -f2)
year=$(echo "$date_line" | cut -d '.' -f3)
time=$(echo "$line" | cut -d ' ' -f3 | sed -e 's/h$/:00/')
date_iso="$year-$month-$day"
date_unix=$(date -d "$date_iso $time" '+%s')
date_unix_now=$(date -d 'now' '+%s')
if [ "$date_unix" -gt "$date_unix_now" ]
then
echo "$line"
fi
done <"$intvfile"
rm "$intvfile"
fi
else
seriesnumber=$(curl https://www.wunschliste.de/serie/$sopt 2>/dev/null | grep -m 1 -o "atom.pl?s=[0-9]*" | cut -d '=' -f 2)
curl "https://api.wunschliste.de/print/$seriesnumber" 2>/dev/null | grep -e '<tr><td>' | sed -e "s#</td><td>#|#"g -e "s#<[^>]*>##g" | \
sed -e "s#\([^|]*\)|\([[:alpha:]][[:alpha:]]\)\([^|]*\)|\(..\).\(..\)[^|]*|\(..\).\(..\)[^|]*|(\([^)]*\))\(.*\)#\2 \3 \4:\5-\6:\7 \1 | \8\9#" \
-e "s#\([^|]*\)|\([^|]*\)|\(..\).\(..\)[^|]*|\(..\).\(..\)[^|]*|(\([^)]*\))\(.*\)# \2 \3:\4-\5:\6 \1 | \7\8#" \
-e "s#\([^|]*\)|\(..\)\([^|]*\)|\(..\).\(..\)[^|]*|\(..\).\(..\)[^|]*|\(.*\)#\2 \3 \4:\5-\6:\7 \1 | \8#" | \
grep -Eie "$toptarg" | grep -Eiv "$Toptarg" | grep -Eiv "$WL_PAYTV"
fi
rm "$tempfile"
exit 0
}
#
function search()
{
pattern="$1"
pattern_url=$(echo "$1" | sed -e 's/ /%20/g')
if [ "$mopt" = "movie" ]
then
# HTTP POST
curl --data "query=$pattern_url&query_art=spielfilm" https://www.wunschliste.de/suche >"$tempfile" 2>/dev/null
echo -e "\nSuchergebnisse für \"$pattern\":\n"
grep -e 'ul id="suchergebnisliste"' "$tempfile" | sed -e 's#</li>#\n#g' | grep -e '/spielfilm/' | sed -e 's#.*<li.*<a href="/spielfilm/\([^"]*\).*#\1#'
else
# HTTP POST
curl --data "query=$pattern_url&query_art=titel" https://www.wunschliste.de/suche >"$tempfile" 2>/dev/null
echo -e "\nSuchergebnisse für \"$pattern\":\n"
grep -e 'ul id="suchergebnisliste"' "$tempfile" | sed -e 's#</li>#\n#g' | grep -e '/serie/' | sed -e 's#.*<li.*<a href="/serie/\([^"]*\).*#\1#'
fi
rm "$tempfile"
exit 0
}
#
function check_list()
{
cache=$(mktemp -d)
list=$(mktemp)
optmovie=""
cp "$1" "$list"
echo -e "\n#" >>"$list"
sed -i -e '1i #' -e '/^$/d' "$list"
sed -i -e '/^[[:space:]]*#/d' "$list"
if [ "$mopt" = "movie" ]
then
optmovie="-m"
fi
while IFS=, read series include exclude
do
if [[ ! "$series" = *"#"* ]]
then
series=$(echo "$series" | tr 'A-Z' 'a-z' | sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/Ä/Ae/g' -e 's/Ö/Oe/g' -e 's/Ü/Ue/g' -e 's/ß/ss/g' | tr ' ' '-')
if [ ! -s "$cache/$series.tvc" ]
then
# "$optmovie" does not work ???
wunschliste $optmovie -s "$series" -t "?" >"$cache/$series.tvc"
fi
if [ "$include" = "?" ] || [ "$include" = "*" ]
then
ginclude=" "
else
ginclude="$include"
fi
grep -Eie "$ginclude" "$cache/$series.tvc" | grep -Eiv "$exclude" >"$tempfile"
if [ -s "$tempfile" ]
then
echo -e "\n$series <$include><$exclude>:\n"
cat "$tempfile"
fi
fi
done <"$list"
rm "$tempfile"
rm "$list"
rm -rf "$cache"
exit 0
}
#
function check_series()
{
if [ ! -s "$tempfile" ]
then
sopt_url=$(echo $sopt | sed -e 's/-/%20/g')
curl --data "query=$sopt_url&query_art=titel" https://www.wunschliste.de/suche >"$tempfile" 2>/dev/null
if [ -s "$tempfile" ]
then
if grep -qe 'war leider erfolglos' "$tempfile"
then
echo -e "\nKeine Suchergebnisse für \"$sopt\":\n"
echo "-> $(basename $0) -P pattern"
else
curl https://www.wunschliste.de/serie/$sopt >"$tempfile" 2>/dev/null
if [ -s "$tempfile" ]
then
echo -e "\nFür die Serie \"$sopt\" liegen keine Episodeninformationen vor!\n"
else
curl --data "query=$sopt_url&query_art=titel" https://www.wunschliste.de/suche >"$tempfile" 2>/dev/null
echo -e "\nSuchergebnisse für \"$sopt\":\n"
grep -e 'ul id="suchergebnisliste"' "$tempfile" | sed -e 's#</li>#\n#g' | grep -e '/serie/' | sed -e 's#.*<li.*<a href="/serie/\([^"]*\).*#\1#'
fi
fi
else
echo -e "\nKeine Suchergebnisse für \"$sopt\":\n"
echo "-> $(basename $0) -P pattern"
fi
rm "$tempfile"
exit 11
fi
}
#
printline()
{
series=$(echo $line | cut -d'|' -f1)
episode=$(echo $line | cut -d'|' -f2)
link=$(echo $line | cut -d'|' -f3)
# decode html entities
# recode available???
if hash recode >/dev/null 2>&1
then
title=$(echo $line | cut -d'|' -f4 | tr '_' ' ' | sed -e 's/<[^>]*>//g' | recode html..utf8)
else
title=$(echo $line | cut -d'|' -f4 | tr '_' ' ' | sed -e 's/<[^>]*>//g')
fi
if [ "$series" = "xx" ]
then
echo "${ecol}${episode}${rcol} $title"
filename="${episode} $title"
else
if [[ $series =~ $number ]]
then
echo "$(printf "${scol}%02d" ${series})${ecol}${episode}${rcol} $title"
filename="$(printf "%02d" ${series})x${episode} $title"
else
if [[ $episode =~ $number ]]
then
echo "${scol}${series}${ecol}${episode}${rcol} $title"
filename="${series}x${episode} $title"
else
echo "${scol}${series}${rcol} $title"
filename="${series} $title"
fi
fi
fi
if [ "$fopt" = "true" ]
then
sanitize_filename "$filename"
fi
if [ "$copt" = "true" ]
then
printcontent
else
if [ ! -z $Sopt ]
then
filename=$(echo $filename | sed -e 's#^[0-9]*x##')
fi
if [ ! -z $ofext ]
then
echo "" >"$filename"
fi
fi
}
#
printcontent()
{
curl "https://www.wunschliste.de$link" 2>/dev/null | sed -e 's#</div><div#</div>\n<div#g' >"$tempfile"
content=$(grep -e 'text form' "$tempfile" | sed -e 's#<p class="credits".*>##' -e 's#<[^>]*>##g')
echo "$content"
if [ "$fopt" = "true" ]
then
if [ ! -z $Sopt ]
then
filename=$(echo "$filename" | sed -e 's#^[0-9]*x##')
fi
if [ "$os" = "Cygwin" ]
then
echo "$content" | iconv -f UTF-8 -t "$eopt" >"$filename"
else
echo "$content" >"$filename"
fi
fi
}
#
sanitize_filename()
{
filename=$(echo "$1" | sed -e 's/\(.*\) ([a-zA-Z].*/\1/' -e 's/\(.*\ ([0-9]*)\) ([a-zA-Z0-9].*/\1/' | \
sed -e 's#"#"#g' -e 's#\(.*\)#\1'$ofext'#')
if [ "$zopt" = "true" ]
then
filename=$(echo $filename | sed -e 's/(//' -e 's/)//' | sed -e 's/, /_K_/g' | sed -e 's/\. /_P_/g' | \
sed -e 's/ \& /_AMP_/g' | sed -e 's/"/_AFZ_/g' | sed -e 's/!/_ARZ_/g' | sed -e 's/?/_FRZ_/g'| \
sed -e 's/:/_DP_/g' | sed -e 's/\x27/_AP_/g' | sed -e 's/\.\.\./_PPP_/g' | sed -e 's#_'$ofext'$#'$ofext'#' | \
tr ' ' '_' | sed -e 's#_\{2,\}#_#g')
fi
}
#
while getopts "s:S:E:cvhf:e:zp:P:t:T:l:m" flag
do
case "$flag" in
s) sopt="$OPTARG";;
S) Sopt="$OPTARG";;
E) Eopt="$OPTARG";;
e) eopt="$OPTARG";;
l) check_list "$OPTARG";;
c) copt="true";;
z) zopt="true";;
m) mopt="movie";;
t) topt="true";toptarg="$OPTARG";;
T) topt="true";Toptarg="$OPTARG";;
v) pversion;;
h) phelp;;
f) fopt="true";ofext="$OPTARG";;
p) popt="$OPTARG";;
P) search "$OPTARG";;
esac
done
#
sopt=$(echo $sopt | tr 'A-Z' 'a-z' | sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/Ä/Ae/g' -e 's/Ö/Oe/g' -e 's/Ü/Ue/g' -e 's/ß/ss/g' | tr ' ' '-')
Sopt=$(echo $Sopt | sed -e 's/^0*//')
if [ ! -z $Eopt ] && [ $(echo $Eopt | wc -c ) -lt 3 ]
then
Eopt="0$Eopt"
fi
if [ "$toptarg" = "?" ] || [ "$toptarg" = "*" ]
then
toptarg=" "
fi
#
if [ "$topt" = "true" ]
then
intv
fi
#
if [ "$mopt" = "movie" ]
then
url="https://www.wunschliste.de/spielfilm/$sopt"
curl "$url" 2>/dev/null | sed -e 's#</div><div#</div>\n<div#g' >"$tempfile"
grep -e 'text_inhalt' "$tempfile" | grep -e 'form' | \
sed -e 's#\(.*\)<div class="credits.*</div>#\1#' -e 's#<div id="text_inhalt_innen" class="form">##' \
-e 's#<div class="absatz"></div>##g'
else
url="https://www.wunschliste.de/serie/$sopt/episoden"
curl "$url" 2>/dev/null | sed -e '/Staffelnummer/d' >"$tempfile"
check_series
# create data set in season|episode|rellink|title (origtitle) format
data=$(grep -e 'class="epg_' "$tempfile" | sed -e 's#</li><li#</li>\n<li#g' | sed -e 's#</i></span></li>#</i></span></li>\n#g' | \
grep -ve 'Wiederholung' | grep -e 'epl1' | grep -ve 'getElementById' | \
sed -e 's#.*title="Staffel">\([^<]*\)<.*title="Episode">\([0-9]*\)</span>.*href="\([^"]*\)">\(.*\)</a>.*#\1|\2|\3|\4#' | \
sed -e 's#.*title="Episode">\([0-9]*\)</span>.*href="\([^"]*\)">\(.*\)</a>.*#xx|\1|\2|\3#' | \
sed -e 's#.*title="Staffel">\([A-Za-z]*\)</span>.*href="\([^"]*\)">\(.*\)</a>.*#\1|xx|\2|\3#' | \
sed -e 's#<span class="otitel">##' -e 's#</span>##' -e 's#"#\"#g' | sed -e 's#)(#) (#' -e 's#(# (#g' -e 's# # #g' | tr ' ' '_')
#
if [ -z $Sopt ]
then
if [ -z $Eopt ]
then
:
else
data=$(echo $data | tr ' ' '\n' | sed -e '/.*|'$Eopt'|.*/!d')
fi
else
if [ -z $Eopt ]
then
if [[ $Sopt =~ $number ]]
then
data=$(echo $data | tr ' ' '\n' | sed -e '/'^$Sopt'|[0-9]*|.*/!d')
else
data=$(echo $data | tr ' ' '\n' | sed -e '/'^$Sopt'|xx|.*/!d')
fi
else
data=$(echo $data | tr ' ' '\n' | sed -e '/'^$Sopt'|'$Eopt'|.*/!d')
fi
fi
if [ ! -z $popt ]
then
data=$(echo $data | tr ' ' '\n' | grep -ie "$popt")
fi
#
for line in $data
do
printline
done
fi
#
rm "$tempfile"
exit 0