From dbf55614cd4f864e908f00d4f8c88ab90fcf9138 Mon Sep 17 00:00:00 2001 From: woniuzfb <47843848+woniuzfb@users.noreply.github.com> Date: Wed, 8 Dec 2021 02:15:59 +0800 Subject: [PATCH] feat: soccer tv schedules --- docs/iptv.sh | 1558 ++++++++++++++++++++++++++++++----------- i18n/iptv.sh.pot | 490 ++++++------- i18n/po/iptv.sh-en.mo | Bin 27383 -> 27383 bytes iptv.sh | 1558 ++++++++++++++++++++++++++++++----------- 4 files changed, 2505 insertions(+), 1101 deletions(-) diff --git a/docs/iptv.sh b/docs/iptv.sh index 8e17d0c..6464915 100755 --- a/docs/iptv.sh +++ b/docs/iptv.sh @@ -5,7 +5,7 @@ set -euo pipefail -sh_ver="1.87.2" +sh_ver="1.87.3" sh_debug=0 export LANGUAGE= export LC_ALL= @@ -84,39 +84,39 @@ indent_20='\r\033[20C' Println() { - printf '%b' "\n$1\n" + printf '\n%b\n' "$1" } -ReleaseCheck() +DistCheck() { - [ -n "${release:-}" ] && return 0 + [ -n "${dist:-}" ] && return 0 - release_files=( /etc/issue /etc/os-release /proc/version ) - release="" + dist_files=( /etc/issue /etc/os-release /proc/version ) + dist="" - for release_file in "${release_files[@]}" + for dist_file in "${dist_files[@]}" do - if [ ! -s "$release_file" ] + if [ ! -s "$dist_file" ] then continue fi - if grep -Eqi "Red Hat|redhat|CentOS|Fedora|Amazon" < "$release_file" + if grep -Eqi "Red Hat|redhat|CentOS|Fedora|Amazon" < "$dist_file" then - release="rpm" + dist="rpm" break - elif grep -qi "Ubuntu" < "$release_file" + elif grep -qi "Ubuntu" < "$dist_file" then - release="ubu" + dist="ubu" break - elif grep -qi "Debian" < "$release_file" + elif grep -qi "Debian" < "$dist_file" then - release="deb" + dist="deb" break fi done - if [ -z "$release" ] + if [ -z "$dist" ] then Println "${red}[ERROR]${normal} not support yet...\n" exit 1 @@ -210,13 +210,13 @@ DepInstall() [[ -x $(command -v $dependency) ]] && return 0 - ReleaseCheck + DistCheck if [ "$dependency" == "gettext" ] || [ "$dependency" == "wget" ] then Println "${green}[INFO]${normal} Installing $dependency, it takes awhile..." - if [ "$release" == "rpm" ] + if [ "$dist" == "rpm" ] then if [[ -x $(command -v getenforce) ]] && [ "$(getenforce)" != "Disabled" ] then @@ -232,7 +232,7 @@ DepInstall() exit 1 fi else - if [ "$release" == "deb" ] + if [ "$dist" == "deb" ] then DebFixSources fi @@ -253,7 +253,7 @@ DepInstall() Println "`eval_gettext \"\\\$info 安装 \\\$dependency, 请稍等...\"`" - if [ "$release" == "rpm" ] + if [ "$dist" == "rpm" ] then if [[ -x $(command -v getenforce) ]] && [ "$(getenforce)" != "Disabled" ] then @@ -274,7 +274,7 @@ DepInstall() exit 1 fi else - if [ "$release" == "deb" ] + if [ "$dist" == "deb" ] then DebFixSources fi @@ -478,11 +478,11 @@ i18nGetMsg() LocaleFix() { - ReleaseCheck + DistCheck Println "${green}[INFO]${normal} Installing language (locale) support, it takes awhile..." - if [ "$release" == "rpm" ] + if [ "$dist" == "rpm" ] then if [[ -x $(command -v getenforce) ]] && [ "$(getenforce)" != "Disabled" ] then @@ -492,7 +492,7 @@ LocaleFix() yum -y install glibc-common glibc-locale-source glibc-all-langpacks glibc-langpack-en glibc-langpacks-zh langpacks-zh_CN >/dev/null 2>&1 || true else - if [ "$release" == "deb" ] + if [ "$dist" == "deb" ] then DebFixSources fi @@ -520,11 +520,9 @@ LocaleFix() fi } -# eval_gettext MSGID -# looks up the translation of MSGID and substitutes shell variables in the -# result. -eval_gettext () { - gettext "$1" | (export PATH `envsubst --variables "$1"`; envsubst "$1") +eval_gettext() +{ + gettext "$1" | (export PATH `envsubst --variables "$1"`; envsubst "$1") } TEXTDOMAIN=iptv @@ -579,7 +577,7 @@ i18nGetMsg DepsCheck() { - ReleaseCheck + DistCheck DepInstall tput @@ -588,7 +586,7 @@ DepsCheck() DepsInstall() { - if [ "$release" == "rpm" ] + if [ "$dist" == "rpm" ] then if [[ -x $(command -v getenforce) ]] && [ "$(getenforce)" != "Disabled" ] then @@ -629,7 +627,7 @@ DepsInstall() yum -y update ca-certificates >/dev/null 2>&1 || yum -y reinstall ca-certificates >/dev/null 2>&1 else - if [ "$release" == "deb" ] + if [ "$dist" == "deb" ] then DebFixSources fi @@ -1704,7 +1702,7 @@ inquirer() var_name=$2 date_pick_regex_failed_msg=${3:-$(gettext "时间验证错误")} date_pick_validator=${4:-inquirer:date_pick_default_validator} - date_pick=$(printf '%(%Y-%m-%d %H:%M:%S)T' -1) + date_pick=$(printf '%(%Y-%m-%d %H:%M:%S)T' "${!var_name:--1}") current_pos=12 failed_count=0 first_keystroke=true @@ -2116,7 +2114,17 @@ ShFileUpdate() Progress() { - echo -ne "\n`eval_gettext \"\\\$info 安装中, 请等待...\"`" + local msg + + if [ -z "${1:-}" ] + then + msg="`eval_gettext \"\\\$info 安装中, 请等待...\"`" + else + msg="$info $1..." + fi + + echo -ne "\n$msg" + while true do echo -n "." @@ -2158,18 +2166,18 @@ PythonInstall() return 0 fi - ReleaseCheck + DistCheck Println "`eval_gettext \"\\\$info 安装 python3 ...\"`" + Progress & + progress_pid=$! + trap ' kill $progress_pid 2> /dev/null ' EXIT - Progress & - progress_pid=$! - - if [ "$release" == "rpm" ] + if [ "$dist" == "rpm" ] then if ! yum -y install python3 python3-pip > /dev/null 2>&1 then @@ -2191,7 +2199,7 @@ PythonInstall() kill $progress_pid trap - EXIT - echo -n "...100%" && echo + echo "...100%" } CrossplaneInstall() @@ -2309,7 +2317,7 @@ FFmpegCompile() { DepsCheck - if [ "$release" == "rpm" ] + if [ "$dist" == "rpm" ] then Println "`eval_gettext \"\\\$error 不支持 centos\"`\n" exit 1 @@ -2443,7 +2451,7 @@ Cflags: -I\${includedir} # nasm # uname -mpi | grep -qE 'x86|i386|i686' - if [ "$release" != "arm" ] + if [ "$dist" != "arm" ] then cd ~/ffmpeg_sources if [ ! -d nasm-2.15.05 ] @@ -2656,7 +2664,7 @@ Cflags: -I\${includedir} fi cd lame-3.100 # uname -a | grep -q 'aarch64' - if [ "$release" == "arm" ] + if [ "$dist" == "arm" ] then lame_build_target="--build=arm-linux" else @@ -3405,7 +3413,7 @@ Update() reinstall_ffmpeg_yn="Y" fi - ReleaseCheck + DistCheck if [[ ${reinstall_ffmpeg_yn:-N} == [Yy] ]] then @@ -3458,7 +3466,7 @@ YoutubeDlInstall() if [ "$monitor" = true ] then - MonitorError "无法安装 youtube-dl" + MonitorErr "无法安装 youtube-dl" return 0 fi @@ -3507,7 +3515,7 @@ YtDlpInstall() if [ "$monitor" = true ] then - MonitorError "无法安装 yt-dlp" + MonitorErr "无法安装 yt-dlp" return 0 fi @@ -3800,8 +3808,8 @@ OpensslInstall() trap ' kill $progress_pid 2> /dev/null ' EXIT - ReleaseCheck - if [ "$release" == "rpm" ] + DistCheck + if [ "$dist" == "rpm" ] then yum -y install openssl openssl-devel >/dev/null 2>&1 else @@ -3820,8 +3828,8 @@ ImageMagickInstall() kill $progress_pid 2> /dev/null ' EXIT rm -f "$IPTV_ROOT/magick" - ReleaseCheck - if [ "$release" == "rpm" ] + DistCheck + if [ "$dist" == "rpm" ] then yum -y install ImageMagick >/dev/null 2>&1 else @@ -3852,13 +3860,13 @@ Pdf2htmlInstall() exit 1 fi - ReleaseCheck + DistCheck Progress & progress_pid=$! trap ' kill $progress_pid 2> /dev/null ' EXIT - if [ "$release" == "rpm" ] + if [ "$dist" == "rpm" ] then yum install cmake gcc gnu-getopt java-1.8.0-openjdk libpng-devel fontforge-devel cairo-devel poppler-devel libspiro-devel freetype-devel libtiff-devel openjpeg libxml2-devel giflibgiflib-devel libjpeg-turbo-devel libuninameslist-devel pango-devel make gcc-c++ >/dev/null 2>&1 else @@ -3939,7 +3947,7 @@ Pdf2htmlInstall() kill $progress_pid trap - EXIT - echo -n "...100%" && echo + echo "...100%" if grep -q "profile.d" < "/etc/profile" then @@ -3963,12 +3971,12 @@ TesseractInstall() DepsCheck - if [ "$release" == "ubu" ] + if [ "$dist" == "ubu" ] then add-apt-repository ppa:alex-p/tesseract-ocr -y AptUpdate apt-get -y install tesseract - elif [ "$release" == "deb" ] + elif [ "$dist" == "deb" ] then Println "$info 参考 https://notesalexp.org/tesseract-ocr/ ...\n" else @@ -3978,7 +3986,7 @@ TesseractInstall() PostfixInstall() { - if [ "$release" == "rpm" ] + if [ "$dist" == "rpm" ] then yum -y install postfix > /dev/null else @@ -4121,7 +4129,8 @@ GetServerIp() echo "$ip" } -GetFreePort() { +GetFreePort() +{ if [ -n "${1:-}" ] && [ -n "${2:-}" ] then lport=$1 @@ -4486,7 +4495,7 @@ JQ() esac { - flock -x 200 || { MonitorError "`eval_gettext \"\\\$FILE JQ fd 200 失败\"`"; exit 1; } + flock -x 200 || { MonitorErr "`eval_gettext \"\\\$FILE JQ fd 200 失败\"`"; exit 1; } if ! $JQ_FILE "${jq_args[@]}" "${jq_commands[*]}" "$FILE" > "$TMP_FILE" || [ ! -s "$TMP_FILE" ] then @@ -6094,7 +6103,7 @@ HlsStreamCreatorPlus() then for play_list in "$output_dir_root/"*.m3u8 do - echo "#EXT-X-ENDLIST" >> "$play_list" + echo "#EXT-X-ENDLIST" >> "$play_list" || exit 1 done sleep "$seg_length" fi @@ -6840,7 +6849,7 @@ HlsStreamCreatorPlus() then for play_list in "$chnl_output_dir_root/"*.m3u8 do - echo "#EXT-X-ENDLIST" >> "$play_list" + echo "#EXT-X-ENDLIST" >> "$play_list" || exit 1 done sleep "$chnl_seg_length" fi @@ -7980,7 +7989,7 @@ GetChannel() if [ -z "$chnl_pid" ] then Println "$error $i18n_channel_try_again\n" - MonitorError "获取频道信息 $select_json" + MonitorErr "获取频道信息 $select_json" return 1 fi @@ -12304,7 +12313,7 @@ StartChannel() if [ -z "${formats_indices:-}" ] then Println "$error [ $chnl_channel_name ] 解析发生错误, 直播链接不存在?\n" - MonitorError "$chnl_channel_name 解析发生错误, 直播链接不存在?" + MonitorErr "$chnl_channel_name 解析发生错误, 直播链接不存在?" return 0 fi fi @@ -12332,7 +12341,7 @@ StartChannel() if ! parse_urls=($(yt-dlp --no-warnings -f "$code" -g "$chnl_stream_link")) && ! parse_urls=($(youtube-dl -f "$code" -g "$chnl_stream_link")) then Println "$error [ $chnl_channel_name ] 解析 $code 发生错误" - MonitorError "$chnl_channel_name 解析 $code 发生错误" + MonitorErr "$chnl_channel_name 解析 $code 发生错误" return 0 fi @@ -13030,7 +13039,7 @@ StartChannel() done if [ "$monitor" = true ] then - MonitorError "$chnl_channel_name 请重新选择音轨" + MonitorErr "$chnl_channel_name 请重新选择音轨" return 0 fi choose=1 @@ -13195,7 +13204,7 @@ StartChannel() done if [ "$monitor" = true ] then - MonitorError "$chnl_channel_name 请重新选择字幕" + MonitorErr "$chnl_channel_name 请重新选择字幕" return 0 fi choose=1 @@ -13710,7 +13719,7 @@ StopChannel() rm -rf "$FFMPEG_LOG_ROOT/$chnl_pid.pid" else kill "$chnl_pid" 2> /dev/null || true - if ! flock -E 1 -w 30 -x "$FFMPEG_LOG_ROOT/$chnl_pid.pid" rm -f "$FFMPEG_LOG_ROOT/$chnl_pid.pid" + if ! flock -E 1 -w 30 -x "$FFMPEG_LOG_ROOT/$chnl_pid.pid" rm -f "$FFMPEG_LOG_ROOT/$chnl_pid.pid" 2> /dev/null then MonitorLog "频道 [ $chnl_channel_name ] 进程 $chnl_pid 不存在" jq_path='["channels"]' @@ -13735,13 +13744,13 @@ StopChannel() rm -f "$FFMPEG_LOG_ROOT/$chnl_pid.pid" else kill "$chnl_pid" 2> /dev/null || true - if ! flock -E 1 -w $((30+chnl_seg_length)) -x "$FFMPEG_LOG_ROOT/$chnl_pid.pid" rm -f "$FFMPEG_LOG_ROOT/$chnl_pid.pid" + if ! flock -E 1 -w $((30+chnl_seg_length)) -x "$FFMPEG_LOG_ROOT/$chnl_pid.pid" rm -f "$FFMPEG_LOG_ROOT/$chnl_pid.pid" 2> /dev/null then if [ "$chnl_hls_end_list" = true ] && ls -A "$chnl_output_dir_root/$chnl_seg_dir_path${chnl_seg_name}"*.ts > /dev/null 2>&1 then for play_list in "$chnl_output_dir_root/"*.m3u8 do - echo "#EXT-X-ENDLIST" >> "$play_list" + echo "#EXT-X-ENDLIST" >> "$play_list" || true done sleep "$chnl_seg_length" fi @@ -13987,85 +13996,825 @@ ListChannelsSchedule() fi } -AddChannelsSchedule() +ListChannelSchedules() { - echo - add_options=( '手动添加' '选择足球比赛' ) - inquirer list_input_index "选择操作" add_options add_options_index + chnl_schedules_list="${indent_6}${dim_underlined}${chnls_channel_name[chnls_index]} [${chnls_output_dir_name[chnls_index]}]${normal}\n\n" + chnl_schedules_count=0 - if [ "$add_options_index" -eq 1 ] + if [ -n "${chnls_schedule_status[chnls_index]}" ] then + IFS="${delimiters[1]}" read -ra chnl_schedules_start_time <<< "${chnls_schedule_start_time[chnls_index]}" + IFS="${delimiters[1]}" read -ra chnl_schedules_end_time <<< "${chnls_schedule_end_time[chnls_index]}" + IFS="${delimiters[1]}" read -ra chnl_schedules_loop <<< "${chnls_schedule_loop[chnls_index]}" + IFS="${delimiters[1]}" read -ra chnl_schedules_auto_remove <<< "${chnls_schedule_auto_remove[chnls_index]}" + IFS="${delimiters[1]}" read -ra chnl_schedules_hls_change <<< "${chnls_schedule_hls_change[chnls_index]}" + IFS="${delimiters[1]}" read -ra chnl_schedules_hls_change_once <<< "${chnls_schedule_hls_change_once[chnls_index]}" + IFS="${delimiters[1]}" read -ra chnl_schedules_status <<< "${chnls_schedule_status[chnls_index]}" - return 0 + chnl_schedules_if_null="${chnls_schedule_hls_change[chnls_index]//false/}" + chnl_schedules_if_null="${chnl_schedules_if_null//true/}" + + IFS="${delimiters[1]}" read -ra chnl_schedules_channel_name <<< "${chnls_schedule_channel_name[chnls_index]:-$chnl_schedules_if_null}${delimiters[1]}" + + chnl_schedules_count=${#chnl_schedules_status[@]} + chnl_schedules_indices=("${!chnl_schedules_status[@]}") + + for chnl_schedules_index in "${chnl_schedules_indices[@]}" + do + if [ "${chnl_schedules_status[chnl_schedules_index]}" -eq 0 ] + then + chnl_schedule_status_list="${green}等待${normal}" + elif [ "${chnl_schedules_status[chnl_schedules_index]}" -eq 1 ] + then + chnl_schedule_status_list="${blue}进行${normal}" + else + chnl_schedule_status_list="${red}结束${normal}" + fi + if [ "${chnl_schedules_hls_change_once[chnl_schedules_index]}" = true ] + then + chnl_schedule_hls_change_list="${green}一次${normal}" + elif [ "${chnl_schedules_hls_change[chnl_schedules_index]}" = true ] + then + chnl_schedule_hls_change_list="${green}是${normal}" + else + chnl_schedule_hls_change_list="${red}否${normal}" + fi + if [ "${chnl_schedules_loop[chnl_schedules_index]}" = true ] + then + chnl_schedule_loop_list="${green}是${normal}" + else + chnl_schedule_loop_list="${red}否${normal}" + fi + if [ "${chnl_schedules_auto_remove[chnl_schedules_index]}" = true ] + then + chnl_schedule_auto_remove_list="${green}是${normal}" + else + chnl_schedule_auto_remove_list="${red}否${normal}" + fi + if [ -n "${chnl_schedules_channel_name[chnl_schedules_index]}" ] + then + chnl_schedule_channel_name_list="${indent_6}频道名称: ${blue}${chnl_schedules_channel_name[chnl_schedules_index]}${normal}\n" + else + chnl_schedule_channel_name_list="" + fi + chnl_schedules_list="$chnl_schedules_list ${green}$((chnl_schedules_index+1)).${normal}${indent_6}状态: $chnl_schedule_status_list${indent_20}防盗链: $chnl_schedule_hls_change_list\n${indent_6}循环: $chnl_schedule_loop_list${indent_20}自动清除: $chnl_schedule_auto_remove_list\n$chnl_schedule_channel_name_list${indent_6}开始时间: $(date +%c --date=@"${chnl_schedules_start_time[chnl_schedules_index]}")\n${indent_6}结束时间: $(date +%c --date=@"${chnl_schedules_end_time[chnl_schedules_index]}")\n\n" + done fi - ListChannels - InputChannelsIndex + Println "$chnl_schedules_list" +} - for chnls_index in "${chnls_indices[@]}" +ScheduleParse() +{ + schedule=$($JQ_FILE 'unique_by(.start_time)' <<< "$schedule") + + [ -z "${delimiters:-}" ] && delimiters=( $'\001' $'\002' $'\003' $'\004' $'\005' $'\006' ) + IFS=$'\003\t' read -r m_title m_time m_start_time m_end_time < <(JQs flat "$schedule" '' ' + . as $schedles | reduce ({title,time,start_time,end_time}|keys_unsorted[]) as $key ([]; + $schedles[$key] as $val | if $val then + . + [$val + "\u0002\u0003"] + else + . + ["\u0003"] + end + )|@tsv' "${delimiters[@]}") + + IFS="${delimiters[1]}" read -ra ${chnl_id}_title <<< "$m_title" + IFS="${delimiters[1]}" read -ra ${chnl_id}_time <<< "$m_time" + IFS="${delimiters[1]}" read -ra ${chnl_id}_start_time <<< "$m_start_time" + IFS="${delimiters[1]}" read -ra ${chnl_id}_end_time <<< "$m_end_time" + + schedule_title=("${chnl_id}_title"[@]) + schedule_title=("${!schedule_title}") + schedule_time=("${chnl_id}_time"[@]) + schedule_time=("${!schedule_time}") + schedule_start_time=("${chnl_id}_start_time"[@]) + schedule_start_time=("${!schedule_start_time}") + schedule_end_time=("${chnl_id}_end_time"[@]) + schedule_end_time=("${!schedule_end_time}") + schedule_indices=("${!schedule_title[@]}") + + for schedule_index in "${schedule_indices[@]}" + do + schedules_chnl_id+=("$chnl_id") + schedules_start_time+=("${schedule_start_time[schedule_index]}") + schedules_end_time+=("${schedule_end_time[schedule_index]}") + schedules_title+=("${schedule_title[schedule_index]}") + if [ "$((${schedule_end_time[schedule_index]}-${schedule_start_time[schedule_index]}))" -gt 5000 ] + then + mark=" ${red}*${normal}" + else + mark="" + fi + schedules_list+=("${schedule_title[schedule_index]} ${green}[$chnl_id]${normal} ${blue}[${schedule_time[schedule_index]}]${normal}$mark") + done +} + +SearchSoccerSchedules() +{ + astro_chnls=( + "astrobeinsports:236:beIN Sports HD" + "astrobeinsportsmax:313:beIN Sports MAX HD" + "astrosupersport:154:Astro SuperSport HD" + "astrosupersport2:138:Astro SuperSport 2 HD" + "astrosupersport3:164:Astro SuperSport 3 HD" + "astrosupersport4:241:Astro SuperSport 4 HD" + "astrosupersport5:455:Astro SuperSport 5 HD" + ) + + nbcsn_chnls=( + "nbcsn:NBCSN:NBCSN" + "nbcsnhd:NBCSNHD:NBCSN HD" + ) + + beinsports_chnls=( + "beinsports:1:beinsports" + "beinsportsenglish1:17:beinsports english 1" + "beinsportsenglish2:18:beinsports english 2" + "beinsportsenglish3:19:beinsports english 3" + ) + + beinsportsau_chnls=( + "beinsports1au:BEINSP1:beinsports 1 AU" + "beinsports2au:BEINSP2:beinsports 2 AU" + "beinsports3au:BEINSP3:beinsports 3 AU" + ) + + supersport_chnls=( + "supersportpremierleague:SuperSport Premier League" + "supersportfootball:SuperSport Football" + "supersportlaliga:SuperSport La Liga" + "supersportvariety1:SuperSport Variety 1" + "supersportvariety2:SuperSport Variety 2" + "supersportvariety3:SuperSport Variety 3" + "supersportvariety4:SuperSport Variety 4" + "supersportgrandstand:SuperSport Grandstand" + ) + + btsport_chnls=( + "btsportespn:BT Sport//ESPN" + "btsport1:BT Sport 1" + "btsport2:BT Sport 2" + "btsport3:BT Sport 3" + ) + + sky_chnls=( + "skysportspremierleague:1303:SkySp PL" + "skysportsmainevent:1301:SkySpMainEv" + "skysportsfootball:3838:SkySp F'ball" + "premiersports1:5153:Premier 1 HD" + "premiersports2:1634:Premier 2 HD" + "laligatv:1015:LaLigaTV HD" + ) + + printf -v today '%(%Y-%m-%d)T' -1 + today_time=$(date -d "today 0" +%s) + printf -v sys_time '%(%s)T' -1 + min_start_time=$((sys_time-5400)) + + if [ "$search_options_index" -eq 0 ] + then + max_start_time=$((sys_time+43200)) + + if [ "$sys_time" -gt $((today_time+43200)) ] + then + search_options_index=2 + fi + elif [ "$search_options_index" -eq 1 ] + then + max_start_time=$(date -d "today 23:59:59" +%s) + else + max_start_time=$(date -d "tomorrow 23:59:59" +%s) + fi + + yesterday=$(date -d "yesterday" +"%Y-%m-%d") + tomorrow=$(date -d "tomorrow" +"%Y-%m-%d") + schedules_chnl_id=() + schedules_start_time=() + schedules_end_time=() + schedules_title=() + schedules_list=() + + for chnl in "${astro_chnls[@]}" do - chnl_schedules_list="${indent_6}${dim_underlined}${chnls_channel_name[chnls_index]} [${chnls_output_dir_name[chnls_index]}] ${normal}\n\n" + chnl_id=${chnl%%:*} + astro_id=${chnl#*:} + chnl_name=${astro_id#*:} + astro_id=${astro_id%%:*} - if [ -n "${chnls_schedule_status[chnls_index]}" ] + today_schedule=$(curl -s -Lm 20 -H "User-Agent: $USER_AGENT_BROWSER" "https://contenthub-api.eco.astro.com.my/channel/$astro_id.json" | + $JQ_FILE --arg today "$today" --arg min "$min_start_time" --arg max "$max_start_time" --argjson keys '["title","time","start_time","end_time"]' '.response.schedule[$today] + | map(select(.title|test("(L).* vs ";"i")) + | .["start_time"] = (.datetimeInUtc|sub("(?.*) (?