Last active
August 8, 2025 23:26
-
-
Save OutOfThisPlanet/a7133fb05d7a1fd4d3667609238e9ef7 to your computer and use it in GitHub Desktop.
Multi-threaded IPTV stream checker
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Variables | |
| path=$(pwd) | |
| sname=$0 | |
| wfile="$path/working.m3u" | |
| # Setup colors | |
| cyan='\e[0;36m' | |
| green='\033[92m' | |
| red='\e[1;31m' | |
| yellow='\e[0;33m' | |
| orange='\e[38;5;166m' | |
| # Check if temp directory exists | |
| if [[ ! -d $path/temp ]]; then | |
| mkdir "$path/temp" >/dev/null 2>&1 | |
| fi | |
| # Clean any files from previous run in temp folder | |
| rm -rf "$path/temp/*" >/dev/null 2>&1 | |
| # Function to handle process cleanup on exit or Ctrl+C | |
| function cleanup() { | |
| # Kill all background processes | |
| echo "Cleaning up orphaned processes..." | |
| for pid in $(cat "$path/temp/pids.txt" 2>/dev/null); do | |
| if ps -p "$pid" > /dev/null; then | |
| kill "$pid" >/dev/null 2>&1 | |
| fi | |
| done | |
| rm -f "$path/temp/pids.txt" # Clean the pid list file | |
| exit 1 | |
| } | |
| # Trap cleanup function to run on script exit or interrupt (Ctrl+C) | |
| trap cleanup EXIT INT | |
| # Multi-threaded stream checking | |
| function check_stream() { | |
| local chkf=$1 | |
| local i=$2 | |
| local srvnmb=$3 | |
| local wfile=$4 | |
| local unique_id=$5 # unique identifier for each stream check | |
| # Generate a unique temp file for each process | |
| local temp_stream_file="$path/temp/stream_$unique_id" | |
| local temp_pid_file="$path/temp/pid_$unique_id" | |
| chkurl=$(echo "$chkf" | head -c 4) | |
| case "$chkurl" in | |
| http|rtmp|HTTP) | |
| wget -q "$chkf" -O "$temp_stream_file" & | |
| pid=$! | |
| echo $pid >> "$path/temp/pids.txt" # Save pid to file | |
| sleep 10 | |
| rpid=$(ps -p "$pid" -o pid= | awk '{print$1}') | |
| if [[ "$rpid" == "$pid" ]]; then | |
| kill $pid | |
| fi | |
| if [[ ! -f "$temp_stream_file" ]]; then | |
| echo -e "$yellow" "Error reading captured file" | |
| else | |
| stsz=$(wc -c "$temp_stream_file" | awk '{print$1}') | |
| if [[ "$stsz" -le "100" ]]; then | |
| echo -e "$green" "Link:$yellow $i$green of :$yellow$srvnmb$green is$red OFF" | |
| else | |
| echo -e "$green" "Link:$yellow $i$green of :$yellow$srvnmb$green is$green ON" | |
| writefile "$chkf" "$wfile" | |
| fi | |
| fi | |
| esac | |
| # Cleanup | |
| rm -rf "$temp_stream_file" >/dev/null 2>&1 | |
| rm -rf "$temp_pid_file" >/dev/null 2>&1 | |
| } | |
| # Function that processes and writes results to file | |
| function writefile() { | |
| local chkf=$1 | |
| local wfile=$2 | |
| # checks if tool already created previously an m3u file | |
| if [[ -f "$wfile" ]]; then | |
| gturlline=$(grep -n "$chkf" < $path/temp/1 | tr ":" "\n" | sed -n 1p) | |
| defline=$((gturlline-1)) | |
| stdata=$(sed -n "$defline p" < $path/temp/1) | |
| echo "$stdata" >> "$wfile" | |
| echo "$chkf" >> "$wfile" | |
| echo "" >> "$wfile" | |
| else | |
| echo "#EXTM3U" > "$wfile" | |
| echo "" >> "$wfile" | |
| gturlline=$(grep -n "$chkf" < $path/temp/1 | tr ":" "\n" | sed -n 1p) | |
| defline=$((gturlline-1)) | |
| stdata=$(sed -n "$defline p" < $path/temp/1) | |
| echo "$stdata" >> "$wfile" | |
| echo "$chkf" >> "$wfile" | |
| echo "" >> "$wfile" | |
| fi | |
| } | |
| # Function to test stream with parallelism | |
| function teststream() { | |
| wrn="0" | |
| if [[ -f "$wfile" ]]; then | |
| exts="1" | |
| else | |
| exts="0" | |
| fi | |
| ckf=$(grep "<item>" < $path/temp/1) | |
| if [[ ! -z "$ckf" ]]; then | |
| xmlproc | |
| fi | |
| glnk=$(grep -F "http" < "$path/temp/1" | sed '/EXTINF/d' | sed '/EXTM3U/d' | awk '!a[$0]++' | sed '/^$/d') | |
| echo "$glnk" | tr " " "\n" > "$path/temp/2" | |
| srvnmb=$(wc -l "$path/temp/2" | awk '{print$1}') | |
| rm -rf "$path/temp/stream" >/dev/null 2>&1 | |
| rm -rf "$path/temp/pid.tmp" >/dev/null 2>&1 | |
| # Multi-threaded checking using background processes | |
| for i in $(seq "$srvnmb"); do | |
| chkf=$(sed -n "${i}p" < "$path/temp/2") | |
| unique_id=$i # Unique identifier for each stream check | |
| check_stream "$chkf" "$i" "$srvnmb" "$wfile" "$unique_id" & | |
| done | |
| # Wait for all background processes to finish | |
| wait | |
| if [[ "$exts" == "0" ]]; then | |
| if [[ -f "$wfile" ]]; then | |
| echo "" | |
| echo -e "$green" "Job Finished" | |
| echo "" | |
| echo -e "$yellow" "You can find your new iptv list in :" | |
| echo -e "$orange" "$wfile" | |
| exit 1 | |
| fi | |
| else | |
| echo "" | |
| echo -e "$green" "Job Finished" | |
| echo "" | |
| echo -e "$yellow" "Your iptv list was updated in :" | |
| echo -e "$orange" "$wfile" | |
| exit 1 | |
| fi | |
| } | |
| # Case for remote m3u file | |
| function remotef() { | |
| wget "$file" -O "$path/temp/1" >/dev/null 2>&1 | |
| flsz=$(wc -c "$path/temp/1" | awk '{print$1}') | |
| if [[ "$flsz" -le "10" ]]; then | |
| echo -e "$yellow" "The remote link is down or the file size is too small to be an m3u iptv list file" | |
| echo "" | |
| exit 0 | |
| fi | |
| teststream | |
| } | |
| # Case for local m3u file | |
| function localf() { | |
| if [[ ! -f "$file" ]]; then | |
| echo -e "$yellow" "The file you specified does not exist" | |
| echo -e "$yellow" "in :$green $file " | |
| echo "" | |
| echo -e "$yellow" "Make sure you wrote the right path of it" | |
| exit 1 | |
| fi | |
| cp "$file" "$path/temp/1" >/dev/null 2>&1 | |
| flsz=$(wc -c "$path/temp/1" | awk '{print$1}') | |
| if [[ "$flsz" -le "10" ]]; then | |
| echo -e "$yellow" "The file you specified is too small to be an m3u iptv file" | |
| exit 0 | |
| fi | |
| teststream | |
| } | |
| # Main execution starts here | |
| file="$1" | |
| echo "$file" | grep "http" >/dev/null 2>&1 | |
| if [ "$?" -eq "0" ]; then | |
| remotef | |
| else | |
| localf | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment