Skip to content

Instantly share code, notes, and snippets.

@ParkWardRR
Last active June 3, 2024 18:55
Show Gist options
  • Save ParkWardRR/9f0a5fd583e57f190ba8d538eefe02b1 to your computer and use it in GitHub Desktop.
Save ParkWardRR/9f0a5fd583e57f190ba8d538eefe02b1 to your computer and use it in GitHub Desktop.
#!/bin/bash
# =============================
# Script: YouTubeRelayService.sh
# Description: This script is designed to fetch and serve YouTube live streams,
# especially useful for bypassing YouTube geo-blocks by running on a lightweight VPS.
# It can be particularly effective for continuous streams such as 24-hour live streams.
# This script is intended to bootstrap an Ubuntu host.
# =============================
# Dependencies and Installation Steps:
# - Update and upgrade system packages
# - Install necessary packages: python3-pip, ffmpeg, curl, pipx
# - Install yt-dlp using pipx if not already installed
# - Set up a public_html directory
# - Validate FFmpeg functionality
# - Install and configure the Caddy web server to serve the stream
# =============================
# Server Configuration:
# CPU: 2B
# Memory: 4 GB
# =============================
# ============================
# User Configuration (Edit these variables as needed)
# WARNING: Do not use 0.0.0.0/0 for ALLOWED_IP for safety reasons
# ============================
YOUTUBE_URL="https://www.youtube.com/live/lAcLSbWhVEs?si=vz398W-IQ62FM_6B" # The URL of the YouTube live stream
ALLOWED_IP="111.11.11.187/32" # IP address range allowed to access the stream
SEGMENTS_DURATION=10 # Duration of each HLS segment in seconds
SEGMENTS_COUNT=3 # Number of HLS segments to keep
# =====================
# Script Execution Starts
# =====================
# Function to output error message but continue (no exit)
function error_report {
echo "[ERROR] $1" 1>&2
}
# Kill any existing ffmpeg processes to avoid conflicts
function kill_ffmpeg_processes {
echo "Killing any existing ffmpeg processes..."
pkill -f ffmpeg
}
# Trap function to kill ffmpeg processes on script exit
function on_exit {
echo "Cleaning up before exit..."
kill_ffmpeg_processes
echo "Exiting script."
exit 0
}
trap on_exit SIGINT SIGTERM
kill_ffmpeg_processes # Ensure any existing ffmpeg processes are killed at the beginning
# Function to start ffmpeg process in a loop with logging
function start_ffmpeg {
while true; do
echo "Fetching and converting live stream..."
FFMPEG_URL=$(yt-dlp -g "$YOUTUBE_URL" 2>/dev/null)
if [ -z "$FFMPEG_URL" ]; then
echo "[ERROR] Could not retrieve FFmpeg URL. Retrying in 10 seconds..."
sleep 10
continue
fi
ffmpeg -re -i "$FFMPEG_URL" -c copy -f hls -hls_time $SEGMENTS_DURATION -hls_list_size $SEGMENTS_COUNT -hls_flags delete_segments /home/$USER/public_html/stream.m3u8 &> /home/$USER/ffmpeg.log
if [ $? -ne 0 ]; then
error_report "FFmpeg encountered an error. Check /home/$USER/ffmpeg.log for details."
sleep 10
else
echo "[INFO] FFmpeg process ended. Restarting in 10 seconds..."
sleep 10
fi
done
}
# Update and upgrade the system packages
echo "Updating and upgrading the system..."
apt update -y && apt upgrade -y || error_report "Failed to update and upgrade the system."
# Install necessary packages including Python, ffmpeg, and curl if not already installed
echo "Checking and installing necessary packages..."
if ! dpkg -l | grep -qw python3-pip; then
apt install -y python3-pip || error_report "Failed to install python3-pip."
fi
if ! dpkg -l | grep -qw ffmpeg; then
apt install -y ffmpeg || error_report "Failed to install ffmpeg."
fi
if ! dpkg -l | grep -qw curl; then
apt install -y curl || error_report "Failed to install curl."
fi
# Install pipx if not already installed
if ! command -v pipx &> /dev/null; then
echo "pipx not found, installing..."
apt install -y pipx || error_report "Failed to install pipx."
pipx ensurepath
source ~/.bashrc
fi
# Install yt-dlp using pipx if not already installed
export PATH=$PATH:/root/.local/bin
if ! command -v yt-dlp &> /dev/null; then
echo "yt-dlp is not found in PATH, attempting reinstallation with pipx..."
# Remove any existing installation in pipx before reinstalling
pipx uninstall yt-dlp
pipx install yt-dlp
# Ensure the PATH is updated
export PATH=$PATH:/root/.local/bin
if ! command -v yt-dlp &> /dev/null; then
error_report "yt-dlp could not be installed or found in PATH."
fi
else
echo "yt-dlp is already installed."
fi
# Ensure yt-dlp is accessible from the current shell
export PATH=$PATH:~/.local/bin
# Create public_html directory if it doesn't exist
echo "Creating public_html directory..."
mkdir -p /home/$USER/public_html || error_report "Failed to create public_html directory."
chmod -R 755 /home/$USER/public_html # Ensure sufficient permissions
chown -R root:root /home/$USER/public_html
# Create a simple test HTML file to verify the directory
echo "<html><body><h1>Test Page</h1></body></html>" > /home/$USER/public_html/index.html
# Ensure FFmpeg is able to generate the .m3u8 file
echo "Testing FFmpeg output..."
start_ffmpeg &
sleep 20
if [ ! -f /home/$USER/public_html/stream.m3u8 ]; then
error_report "FFmpeg did not generate the m3u8 file. Check ffmpeg.log for errors."
else
echo "[INFO] FFmpeg successfully generated the m3u8 file."
pkill ffmpeg # Stop running ffmpeg as the first test passed
fi
# Install Caddy web server if not already installed
if ! command -v caddy &> /dev/null; then
echo "Installing Caddy web server..."
apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo apt-key add -
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee -a /etc/apt/sources.list.d/caddy-stable.list
apt update
apt install caddy || error_report "Failed to install Caddy."
else
echo "[INFO] Caddy is already installed."
fi
# Configure Caddy to serve the stream
echo "Configuring Caddy..."
cat > /etc/caddy/Caddyfile <<EOF
http://$(curl -s ifconfig.me) {
root * /home/$USER/public_html
file_server
encode gzip
@allowedIps not remote_ip $ALLOWED_IP
respond @allowedIps 403 {
close
body "Access denied"
}
}
EOF
# Restart Caddy to apply the new configuration
echo "Restarting Caddy to apply the configuration..."
systemctl restart caddy || error_report "Failed to restart Caddy."
# Check Caddy status silently
if systemctl is-active --quiet caddy; then
echo "[INFO] Caddy is running and serving the stream."
else
error_report "Caddy is not running. Please check Caddy logs for more details."
fi
# Verify that m3u8 file is accessible
ACCESS_URL="http://$(curl -s ifconfig.me)/stream.m3u8"
sleep 10
RESPONSE=$(curl -I "$ACCESS_URL" 2>/dev/null | head -n 1 | cut -d' ' -f2)
if [ "$RESPONSE" == "200" ]; then
echo "========================================"
echo "The stream is accessible at: $ACCESS_URL"
echo "========================================"
else
error_report "Caddy is not serving the m3u8 file correctly. HTTP Response Code: $RESPONSE"
echo "Check ffmpeg is running correctly by examining the log file: /home/$USER/ffmpeg.log"
echo "Check Caddy error logs with: journalctl -u caddy"
fi
echo "Checking if ffmpeg and caddy processes are running..."
# Check if ffmpeg process is running
if pgrep -x "ffmpeg" > /dev/null
then
echo "[INFO] FFmpeg is running."
else
error_report "FFmpeg is not running."
fi
# Check if caddy process is running
if pgrep -x "caddy" > /dev/null
then
echo "[INFO] Caddy is running."
else
error_report "Caddy is not running."
fi
echo "The script has completed. Please try accessing the stream at the following URL to confirm it is working:"
echo "========================================"
echo "The stream is accessible at: $ACCESS_URL"
echo "========================================"
# Kill any remaining ffmpeg processes at the end
kill_ffmpeg_processes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment