#!/usr/bin/env bash MPVTV_DATA_DIR=${XDG_DATA_HOME:-$HOME/.local/share}/mpvtv apiurl="https://epg.pw" RESPONSE1_FILE="${MPVTV_DATA_DIR}/response1.txt" RESPONSE2_FILE="${MPVTV_DATA_DIR}/response2.txt" RESPONSE3_FILE="${MPVTV_DATA_DIR}/response3.txt" COOKIES_FILE="${MPVTV_DATA_DIR}/cookies.txt" CHANNELS_FILE="${MPVTV_DATA_DIR}/channels.txt" SCHEDULE_FILE="${MPVTV_DATA_DIR}/schedule.json" CORRECT_SCHEDULE_FILE="${MPVTV_DATA_DIR}/correct_schedule.json" M3U8_FILE="${MPVTV_DATA_DIR}/m3u8.txt" mkdir -p "${MPVTV_DATA_DIR}" function usage { echo "Usage: $(basename "$0") [stream|schedule]" exit 0 } function clearFiles { [[ -f "$RESPONSE2_FILE" ]] && rm "$RESPONSE2_FILE" [[ -f "$RESPONSE3_FILE" ]] && rm "$RESPONSE3_FILE" [[ -f "$SCHEDULE_FILE" ]] && rm "$SCHEDULE_FILE" [[ -f "$CORRECT_SCHEDULE_FILE" ]] && rm "$CORRECT_SCHEDULE_FILE" } [[ "$#" -lt 1 ]] && usage [[ "$#" -gt 1 ]] && usage if [[ "$#" -eq 1 ]]; then if [[ "$1" != "stream" ]] && [[ "$1" != "schedule" ]]; then usage fi fi if [[ ! -f "$RESPONSE1_FILE" ]]; then response="$(curl -s -L -c "$COOKIES_FILE" -b "$COOKIES_FILE" \ -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0" \ -H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" \ "$apiurl/areas/gb.html?lang=en" )" echo "$response" > "$RESPONSE1_FILE" fi # shellcheck disable=SC1143 if [[ ! -f "$CHANNELS_FILE" ]]; then CHANNELS="$( sed '1,//d' "$RESPONSE1_FILE" | \ sed '/<\/table>/,$d' | \ awk '// {block = ""} {block = block $0 "\n"} /<\/tr>/ {if (!(block ~ /0<\/td>/)) print block}' | \ sed '/^[[:space:]]*$/d' | \ awk 'NF {print $0}' | \ sed 's/^[[:space:]]*//' | \ sed 'N;/\n<\/tr>/!P;D' | \ # awk '// {block=""; count=0} {block=block $0 "\n"} /<\/tr>/ {if (count >= 2) block=""; else printf "%s", block; block=""; next} /<\/td>/ {count++}' | \ # awk 'NR==1 {prev=$0; next} /<\/td>/ {prev=""; next} {if (prev) print prev; prev=$0} END {if (prev) print prev}' | \ sed '/SkyTV<\/td>/d' | \ sed -n '/href=/ {s/.*href="\([^"]*\)".*/\1/p; b}; p' | \ sed -n '/title=/ {s/.*>\(.*\)<\/a>/\1/p; b}; p' | \ sed '//d; /<\/tr>/d; //d' | \ sed 's/<\/td>//g' | \ awk 'NR%2{printf "%s ", $0; next} 1' | \ awk '!seen[$2]++' )" echo "$CHANNELS" > "$CHANNELS_FILE" fi function getSchedule { if [[ ! -f "$CORRECT_SCHEDULE_FILE" ]]; then echo "Nothing to get" exit 0 fi channel_name="$(jq -r '.name' "$CORRECT_SCHEDULE_FILE")" echo -e "Schedule for $channel_name\n" # Get the current time in your local time zone in the format used in start_date current_time=$(date +"%d-%m-%Y %H:%M") # Print the current time echo "Current Time: $current_time" # Use jq to find the item with the closest start_date and calculate time differences in a readable format closest_item=$(jq --arg current_time "$current_time" ' .epg_list | map( .start_date |= sub(" \\+0200"; "") | .current_time_parsed = ($current_time | strptime("%d-%m-%Y %H:%M") | mktime) | .start_time_parsed = (try (.start_date | strptime("%d-%m-%Y %H:%M") | mktime) catch 99999999) | .time_diff = (.start_time_parsed - .current_time_parsed) | .abs_time_diff = (if .time_diff < 0 then -(.time_diff) else .time_diff end) ) | sort_by(.abs_time_diff) | map( .hours_diff = (.time_diff / 3600 | floor) | .minutes_diff = ((.time_diff % 3600) / 60 | floor) | .seconds_diff = (.time_diff % 60 | floor) | .time_diff_readable = (.hours_diff | tostring) + " hours, " + (.minutes_diff | tostring) + " minutes, " + (.seconds_diff | tostring) + " seconds" ) | .[0] ' "$CORRECT_SCHEDULE_FILE") echo "Closest Item:" echo "$closest_item" exit 0 } function getChannel { CHANNEL_SELECTED="$(awk '{for (i=2; i<=NF; i++) printf "%s ", $i; print ""}' "$CHANNELS_FILE" | fuzzel -d -p "Channel? ")" if [[ -z "$CHANNEL_SELECTED" ]]; then echo "Nothing selected" exit 0 else CHANNEL_SELECTED="$(echo "$CHANNEL_SELECTED" | awk '{$1=$1};1')" CHANNEL_LINE="$(grep -n "$CHANNEL_SELECTED" "$CHANNELS_FILE" | awk -F: '{print $1}')" CHANNEL_URL="$(sed -n "${CHANNEL_LINE}"p "$CHANNELS_FILE" | cut -d' ' -f1)" CHANNEL_URL="${apiurl}${CHANNEL_URL}" fi if [[ -f "$CORRECT_SCHEDULE_FILE" ]]; then PREVIOUS_CHANNEL="$(jq -r '.name' "$CORRECT_SCHEDULE_FILE")" if [[ "$PREVIOUS_CHANNEL" == "$CHANNEL_SELECTED" ]]; then echo "No need for new stuff" play exit 0 else clearFiles fi fi if [[ -f "$CORRECT_SCHEDULE_FILE" ]]; then mydate="$(date '+%Y-%m-%d')" schedule_end_date="$(jq -r '.end_date' "$CORRECT_SCHEDULE_FILE")" timestamp1="$(date -d "$mydate" +%s)" timestamp2="$(date -d "$schedule_end_date" +%s)" if [[ "$timestamp1" -gt "$timestamp2" ]]; then clearFiles fi fi if [[ ! -f "$RESPONSE2_FILE" ]]; then response2="$(curl -s -L -c "$COOKIES_FILE" -b "$COOKIES_FILE" \ -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0" \ -H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" \ "$CHANNEL_URL" )" echo "$response2" > "$RESPONSE2_FILE" fi CHANNEL_LIVE="$(grep livestream "$RESPONSE2_FILE" | sed 's/^[[:space:]]*//' | sed -n '/href=/ {s/.*href="\([^"]*\)".*/\1/p; b}; p' )" CHANNEL_LIVE="${apiurl}${CHANNEL_LIVE}" if [[ ! -f "$RESPONSE3_FILE" ]]; then response3="$(curl -s -L -c "$COOKIES_FILE" -b "$COOKIES_FILE" \ -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0" \ -H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" \ "$CHANNEL_LIVE" )" echo "$response3" > "$RESPONSE3_FILE" fi M3U8_LINK="$(grep m3u8 "$RESPONSE3_FILE" | sed 's/^[[:space:]]*//' | grep -v href | head -n1 | sed -n 's/.*"\([^"]*\)".*/\1/p')" echo "$M3U8_LINK" > "$M3U8_FILE" SCHEDULE="$(grep json "$RESPONSE2_FILE" | sed 's/^[[:space:]]*//' | grep -v "Content-Type" | grep -v "class" | sed 's/\(.*\)<\/a.*/\1/')" if [[ ! -f "$SCHEDULE_FILE" ]]; then response4="$(curl -s -L -c "$COOKIES_FILE" -b "$COOKIES_FILE" \ -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0" \ -H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" \ "$SCHEDULE" )" echo "$response4" > "$SCHEDULE_FILE" fi if [[ ! -f "$CORRECT_SCHEDULE_FILE" ]]; then jq '.epg_list |= map(if .start_date then .start_date |= (sub(" +0000"; "") | strptime("%Y%m%d%H%M%S") | mktime | . + 7200 | strftime("%d-%m-%Y %H:%M +0200")) else . end)' "$SCHEDULE_FILE" > "$CORRECT_SCHEDULE_FILE" fi play } function play { STREAM_LINK="$(cat "$M3U8_FILE")" MPV_OPTS="--vo=gpu \ --gpu-api=opengl \ --opengl-es=yes \ --really-quiet \ --msg-level=all=no \ --msg-level=ffmpeg/demuxer=no \ --msg-level=ffmpeg=no \ --no-load-scripts \ --profile=sw-fast \ --no-ytdl" notify-send -t 2000 "Loading $CHANNEL_SELECTED" MPVPID="$(pidof mpv | cut -d' ' -f1)" [[ -n "$MPVPID" ]] && kill -s SIGTERM "$MPVPID" eval setsid -f mpv "${MPV_OPTS}" "${STREAM_LINK}" } [[ "$1" == "schedule" ]] && getSchedule [[ "$1" == "stream" ]] && getChannel exit 0