summaryrefslogtreecommitdiff
path: root/iptv.sh
diff options
context:
space:
mode:
authorLi Zhineng <[email protected]>2024-07-04 19:23:31 +0800
committerGitHub <[email protected]>2024-07-04 19:23:31 +0800
commit9aec9bfbd4d6370423927fdd7b8bc0bb0f8aa811 (patch)
treed79819566c994042a9563221788999ece475715a /iptv.sh
parentd45b437498614d23d2a817e66549818006a64146 (diff)
parent6de6d14533b10ed83feff05d79115ac2659ae594 (diff)
downloadchina-unicom-iptv-gd-9aec9bfbd4d6370423927fdd7b8bc0bb0f8aa811.tar.gz
china-unicom-iptv-gd-9aec9bfbd4d6370423927fdd7b8bc0bb0f8aa811.zip
Merge pull request #1 from lizhineng/epg
Supports building EPG file
Diffstat (limited to 'iptv.sh')
-rwxr-xr-xiptv.sh330
1 files changed, 200 insertions, 130 deletions
diff --git a/iptv.sh b/iptv.sh
index da80728..c91c824 100755
--- a/iptv.sh
+++ b/iptv.sh
@@ -1,169 +1,239 @@
#!/usr/bin/env bash
-# Default values
-ip_address="127.0.0.1"
-udpxy_endpoint="http://127.0.0.1:4022"
-output_file="iptv.M3U8"
-curl_args=""
-endpoint="http://eds1.unicomgd.com:8082"
+step () { echo -e "\033[32m[-]\033[0m $1"; }
-while [ $# -gt 0 ]; do
- case "$1" in
- -u | --user) user_id="$2"; shift 2;;
- -p | --password) password="$2"; shift 2;;
- -d | --device) device_id="$2"; shift 2;;
- --ip) ip_address="$2"; shift 2;;
- --mac) mac_address="$2"; shift 2;;
- --udpxy) udpxy_endpoint="$2"; shift 2;;
- -o | --output) output_file="$2"; shift 2;;
- --curl) curl_args="$2"; shift 2;;
- *) echo "Unknown option: $1"; exit 1;;
- esac
-done
-
-##
-## Validate user input
-##
-
-if [[ -z "$user_id" ]]; then
- echo "Requires an IPTV user ID with -u or --user"
- exit 1
-fi
+fatal () { echo -e "\033[31m[!]\033[0m $1"; exit 1; }
-if [[ -z "$password" ]]; then
- echo "Requires an IPTV password with -p or --password"
- exit 1
-fi
+ensure_curl_is_installed () {
+ if ! command -v curl &>/dev/null; then
+ fatal "The cURL package that handles HTTP requests is not installed."
+ fi
+}
-if [[ -z "$device_id" ]]; then
- echo "Requires a device ID with -d or --device"
- exit 1
-fi
+ensure_jq_is_installed () {
+ if ! command -v jq &>/dev/null; then
+ fatal "The jq package that handles HTTP JSON response is not installed."
+ fi
+}
-if [[ -z "$mac_address" ]]; then
- echo "Requires a device MAC address with --mac"
- exit 1
-fi
+ensure_openssl_is_installed () {
+ if ! command -v openssl &>/dev/null; then
+ fatal "The OpenSSL package that handles token computation is not installed."
+ fi
+}
-##
-## Check dependencies
-##
+categorize_by_channel_name () {
+ result="720P"
-if ! command -v jq &>/dev/null; then
- echo "The jq package that handles HTTP JSON response is not installed."
- exit 1
-fi
+ case "$1" in
+ *4K*) result="4K" ;;
+ *"超清"*|*"高清"*) result="1080P" ;;
+ esac
-if ! command -v openssl &>/dev/null; then
- echo "The OpenSSL package that handles token computation is not installed."
- exit 1
-fi
+ echo "$result"
+}
+
+make_epg () {
+ # Check dependencies
+ ensure_curl_is_installed
+ ensure_jq_is_installed
+
+ # Default variables
+ output_file="epg.xml"
+ endpoint="http://120.87.12.38:8083/epg/api/page/biz_59417088.json"
+ curl_args=""
+
+ while [ $# -gt 0 ]; do
+ case "$1" in
+ -o | --output ) output_file="$2"; shift 2;;
+ --endpoint ) endpoint="$2"; shift 2;;
+ --curl ) curl_args="$2"; shift 2;;
+ *) echo "Unknown option: $1"; exit 1;;
+ esac
+ done
+
+ step "Request channel index"
+ response=$(curl --silent $curl_args "$endpoint")
+
+ step "Create the EPG XML file"
+ echo '<?xml version="1.0" encoding="UTF-8"?>' > $output_file
+ echo '<!DOCTYPE tv SYSTEM "xmltv.dtd">' >> $output_file
+ echo "<tv date=\"$(date +"%Y%m%d%H%M%S %z")\">" >> $output_file
+
+ while read -r item; do
+ item_title=$(echo "$item" | jq -r '.itemTitle')
+ item_type=$(echo "$item" | jq -r '.itemType')
+ data_link=$(echo "$item" | jq -r '.dataLink')
+
+ if [[ "$item_type" == "channel" ]]; then
+ step "Process: $item_title"
+
+ response=$(curl --silent --interface eth0 "$data_link")
+ channel_icon=$(echo "$response" | jq -r '.channel.icon')
+ channel_title=$(echo "$response" | jq -r '.channel.title')
+ hwcode=$(echo "$response" | jq -r '.channel.params.hwcode')
+
+ echo " <channel id=\"$hwcode\">" >> $output_file
+ echo " <display-name lang=\"zh\">$channel_title</display-name>" >> $output_file
+ echo " <icon src=\"$channel_icon\"/>" >> $output_file
+ echo " </channel>" >> $output_file
+
+ while read -r schedule; do
+ schedule_title=$(echo "$schedule" | jq -r '.title')
+ schedule_starttime=$(echo "$schedule" | jq -r '.starttime')
+ schedule_endtime=$(echo "$schedule" | jq -r '.endtime')
+
+ echo " <programme start=\"$schedule_starttime +0800\" stop=\"$schedule_endtime +0800\" channel=\"$hwcode\">" >> $output_file
+ echo " <title lang=\"zh\">$schedule_title</title>" >> $output_file
+ echo " </programme>" >> $output_file
+ done < <(echo "$response" | jq -c '.schedules[]')
+ fi
+ done < <(echo "$response" | jq -c '.areaDatas[].items[]')
+
+ echo '</tv>' >> $output_file
+
+ step "EPG built sucessfully!"
+
+ exit 0
+}
+
+make_playlist () {
+ # Check dependencies
+ ensure_curl_is_installed
+ ensure_jq_is_installed
+ ensure_openssl_is_installed
+
+ # Default values
+ ip_address="127.0.0.1"
+ udpxy_endpoint="http://127.0.0.1:4022"
+ output_file="playlist.M3U8"
+ curl_args=""
+ endpoint="http://eds1.unicomgd.com:8082"
+
+ while [ $# -gt 0 ]; do
+ case "$1" in
+ -u | --user) user_id="$2"; shift 2;;
+ -p | --password) password="$2"; shift 2;;
+ -d | --device) device_id="$2"; shift 2;;
+ --ip) ip_address="$2"; shift 2;;
+ --mac) mac_address="$2"; shift 2;;
+ --udpxy) udpxy_endpoint="$2"; shift 2;;
+ -o | --output) output_file="$2"; shift 2;;
+ --curl) curl_args="$2"; shift 2;;
+ *) echo "Unknown option: $1"; exit 1;;
+ esac
+ done
-##
-## Execute the main script
-##
+ # Validate user input
+ if [[ -z "$user_id" ]]; then
+ fatal "Requires an IPTV user ID with -u or --user"
+ fi
-echo "[-] Authenticate"
+ if [[ -z "$password" ]]; then
+ fatal "Requires an IPTV password with -p or --password"
+ fi
-##
-## Retreive Authentication URL
-##
+ if [[ -z "$device_id" ]]; then
+ fatal "Requires a device ID with -d or --device"
+ fi
-response=$(curl --silent $curl_args \
- "$endpoint/EDS/jsp/AuthenticationURL?Action=Login&UserID=$user_id&return_type=1")
+ if [[ -z "$mac_address" ]]; then
+ fatal "Requires a device MAC address with --mac"
+ fi
-epgurl=$(echo "$response" | jq -r '.epgurl')
-host="${epgurl#*//}"
-host="${host%%/*}"
+ # Retreive Authentication URL
+ step "Authenticate"
-##
-## Retreive token
-##
+ response=$(curl --silent $curl_args \
+ "$endpoint/EDS/jsp/AuthenticationURL?Action=Login&UserID=$user_id&return_type=1")
-response=$(curl --silent $curl_args \
- "http://$host/EPG/oauth/v2/authorize?response_type=EncryToken&client_id=jiulian&userid=$user_id")
+ epgurl=$(echo "$response" | jq -r '.epgurl')
+ host="${epgurl#*//}"
+ host="${host%%/*}"
-encry_token=$(echo "$response" | jq -r '.EncryToken')
+ # Retreive challenge token
+ response=$(curl --silent $curl_args \
+ "http://$host/EPG/oauth/v2/authorize?response_type=EncryToken&client_id=jiulian&userid=$user_id")
-##
-## Authenticate
-##
+ encry_token=$(echo "$response" | jq -r '.EncryToken')
-pass=$(printf "%-024s" "$password" | tr ' ' 0 | xxd -p)
+ # Authenticate
+ pass=$(printf "%-024s" "$password" | tr ' ' 0 | xxd -p)
-authinfo=(
- $(shuf -i 1-99999999 -n 1) $encry_token
- $user_id $device_id
- $ip_address $mac_address
- "Reserved" "OTT"
-)
+ authinfo=(
+ $(shuf -i 1-99999999 -n 1) $encry_token
+ $user_id $device_id
+ $ip_address $mac_address
+ "Reserved" "OTT"
+ )
-authinfo=$(IFS='$'; echo "${authinfo[*]}")
+ authinfo=$(IFS='$'; echo "${authinfo[*]}")
-authinfo=$(echo -n $authinfo | \
+ authinfo=$(echo -n $authinfo | \
openssl enc -e -des-ede3 -K $pass -nosalt 2>/dev/null | \
xxd -p -u -c 0)
-response=$(curl --silent $curl_args \
+ response=$(curl --silent $curl_args \
"http://$host/EPG/oauth/v2/token?grant_type=EncryToken&client_id=jiulian&UserID=$user_id&DeviceType=UNT400G&DeviceVersion=5.5.021&authinfo=$authinfo&issmarthomestb=1&tvdesktopid=")
-access_token=$(echo "$response" | jq -r '.access_token')
-
-echo "[-] Request channel metas"
+ access_token=$(echo "$response" | jq -r '.access_token')
-declare -A logos
+ step "Request channel metas"
+ declare -A logos
-response=$(curl --silent $curl_args \
- http://120.87.12.38:8083/epg/api/custom/getAllChannel.json)
+ response=$(curl --silent $curl_args \
+ http://120.87.12.38:8083/epg/api/custom/getAllChannel.json)
-while read -r channel; do
- hwcode=$(echo "$channel" | jq -r '.params.hwcode')
- icon=$(echo "$channel" | jq -r '.icon')
+ while read -r channel; do
+ hwcode=$(echo "$channel" | jq -r '.params.hwcode')
+ icon=$(echo "$channel" | jq -r '.icon')
- logos["$hwcode"]="$icon"
-done < <(echo "$response" | jq -c '.channels[]')
+ logos["$hwcode"]="$icon"
+ done < <(echo "$response" | jq -c '.channels[]')
-echo "[-] Request channels from the batch API"
-
-response=$(curl --silent $curl_args \
+ step "Request channels from the batch API"
+ response=$(curl --silent $curl_args \
--data '{"channelcodes":""}' \
--header 'Content-Type: application/json;charset=utf-8' \
--header "Authorization: $access_token" \
http://$host/EPG/interEpg/channellist/batch)
-echo "[-] Decode channels from the HTTP response"
-
-echo "#EXTM3U" > $output_file
-echo "#EXT-X-VERSION:3" >> $output_file
-
-echo "$response" | jq -c '.channellist[]' | while read -r channel; do
- channelcode=$(echo "$channel" | jq -r '.channelcode')
- channelname=$(echo "$channel" | jq -r '.channelname')
- channelurl=$(echo "$channel" | jq -r '.channelurl')
- IFS='|' read -ra channelurls <<< "$channelurl"
-
- echo "[-] Process: $channelname"
-
- pattern="://([^/]+)"
- if [[ "${channelurls[0]}" =~ $pattern ]]; then
- host=${BASH_REMATCH[1]}
-
- group="720P"
- case "$channelname" in
- *"4K"*)
- group="4K"
- ;;
- *"超清"*|*"高清"*)
- group="1080P"
- ;;
- \?)
- group="720P"
- ;;
- esac
+ step "Decode channels from the HTTP response"
+ echo "#EXTM3U" > $output_file
+ echo "#EXT-X-VERSION:3" >> $output_file
- echo "#EXTINF:-1 tvg-id=\"$channelcode\" tvg-name=\"$channelname\" tvg-logo=\"${logos[$channelcode]}\" group-name=\"$group\",$channelname" >> $output_file
- echo "$udpxy_endpoint/udp/$host" >> $output_file
- fi
-done
+ echo "$response" | jq -c '.channellist[]' | while read -r channel; do
+ channelcode=$(echo "$channel" | jq -r '.channelcode')
+ channelname=$(echo "$channel" | jq -r '.channelname')
+ channelurl=$(echo "$channel" | jq -r '.channelurl')
+ IFS='|' read -ra channelurls <<< "$channelurl"
+
+ step "Process: $channelname"
+
+ pattern="://([^/]+)"
+ if [[ "${channelurls[0]}" =~ $pattern ]]; then
+ host=${BASH_REMATCH[1]}
-echo "[-] Extract IPTV channels successfully!"
+ group=$(categorize_by_channel_name "$channelname")
+
+ echo "#EXTINF:-1 tvg-id=\"$channelcode\" tvg-name=\"$channelname\" tvg-logo=\"${logos[$channelcode]}\" group-name=\"$group\",$channelname" >> $output_file
+ echo "$udpxy_endpoint/udp/$host" >> $output_file
+ fi
+ done
+
+ step "Extract IPTV channels successfully!"
+
+ exit 0
+}
+
+##
+## Main
+##
+
+while [ $# -gt 0 ]; do
+ case "$1" in
+ make:playlist) shift 1; make_playlist "$@";;
+ make:epg) shift 1; make_epg "$@";;
+ *) echo "Unknown command: $1"; exit 1;;
+ esac
+done