﻿#!/bin/bash
COMPILETIME='Mon Mar 16 00:00:00 UTC 2026';
# Compilation Params
	COMPILED="YES";
	export LANG=en_US.UTF-8
# Setup URL Params - SOMNODE
	SETUPPATH="http://install.somnode.com/scripts";
	MIRROR="http://install.somnode.com/download";
	BETASETUPPATH="http://install.somnode.com/scripts_beta";
	BETAMIRROR="http://install.somnode.com/download";
	INSTALLDIR="/usr/local/somnode/";
    BasePath="/usr/local/somnode";
# Wowza Streaming Engine Params
	WowzaVersion="4.9.6+3";
	WowzaDownloadURLx64="${MIRROR}/WowzaStreamingEngine-4.9.6+3-linux-x64-installer.run";
	WowzaUpdateURL="${MIRROR}/WowzaStreamingEngine-Update-4.9.6+3.zip";
	WowzaUpgradeURL="${WowzaUpdateURL}";
	WowzaUpgradeFilename=$(printf -- "%s" "${WowzaUpgradeURL##*/}")
    WowzaUpgradeFilenameNoExtension=$(echo ${WowzaUpgradeFilename} | sed -e 's/\.zip//g')
    WowzaSkipJavaUpdate=0
    FlussonicVersion="25.05";
    NginxRtmpVersion="nginx-1.16.0-rtmp-1.2.9-20210705";
# Shoutcast Download
	SHOUTCAST_FILENAME="SHOUTCAST_FILES_20220407.zip";
	SHOUTCAST_DOWNLOAD="${MIRROR}/shoutcast/${SHOUTCAST_FILENAME}";
	GEOIP_FILENAME="GeoIP.zip";
# Somnode Params
	MCPInstallDir=/usr/local/somnode/htdocs;
	MCPInstallPort=2020;
	if [[ -f /usr/local/somnode/somnode.port ]]; then MCPInstallPort=`cat /usr/local/somnode/somnode.port`; fi
	if [[ ! -f /usr/local/somnode/somnode.port ]] && [[ -f /usr/local/somnode/htdocs/database.php ]]; then MCPInstallPort=2000; fi
	MCPInstallChownUser="somnode";
	MCPInstallChownGroup="somnode";
	PHPBINARY=/usr/local/somnode/php/bin/php;
	PHPCONF=/usr/local/somnode/php/php.ini;
	PHPEXTDIR=/usr/local/somnode/php/lib/php/extensions/;
# Development Environment Variables
	InstallSkipPanel="n";
	InstallSkipFFMPEG="n";
	InstallSkipIcecast="n";
# Number of make jobs
numberOfCores=`grep -c ^processor /proc/cpuinfo`;
makeJobCount=1;
if [ "${numberOfCores}" -ge 8 ]; then
	makeJobCount=6;
elif [ "${numberOfCores}" -ge 4 ]; then
makeJobCount=3
elif [ "${numberOfCores}" -gt 2 ]; then
makeJobCount=2
fi
systemTotalMemory=`grep MemTotal /proc/meminfo | awk '{print int(($2/1000/1000)+0.5)}'`
ulimit -n 1024000;
export DEBIAN_FRONTEND=noninteractive
function ver() { printf "%d%03d%03d%03d" $(echo "$1" | tr '.' ' '); }
function lowercase(){
echo "$1" | sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/"
}
# DETECT OPERATING SYSTEM
DISTRO="UNKNOWN";
DISTROBASE="UNKNOWN";
function DetectOS(){
  OS=`lowercase \`uname\``
  if [ "${OS}" = "linux" ]; then
    if [ -f /etc/redhat-release ] ; then
      DISTRO='Centos'
      Centos="Centos"
      DISTROBASE="Centos";
    elif [ `grep -c "debian" /etc/os-release` -gt 0 ] || [ -f /etc/debian_version ]; then
      if [[ `which lsb_release` == "" ]]; then apt -y install lsb-release; fi
      DISTRO=`lsb_release -is`
      DISTROBASE="Debian";
    fi
  fi
}
	DISTROVERSION="UNSUPPORTED";
	function DetectOSMajor(){
		DetectOS
		case $DISTRO in
			'Centos')
				DISTROVERSION=`cat /etc/redhat-release | grep -oE '[0-9]+\.[0-9]+' | cut -d"." -f1`;
        if [[ "${DISTROVERSION}" == "" ]]; then DISTROVERSION=`rpm --eval '%{centos_ver}'`; fi
			;;
			'Debian')
				DISTROVERSION=`lsb_release -sr`
			;;
			'Ubuntu')
				DISTROVERSION=`lsb_release -sr`
			;;
		esac
	}
	OSSupported="no";
	function IsOSSupported(){
		DetectOS
		DetectOSMajor
		case $DISTRO in
			'Centos')
				if [ "${DISTROVERSION}" == 7 ] || [ "${DISTROVERSION}" == 8 ]; then
					OSSupported="no";
				fi
				if [ "${DISTROVERSION}" == 9 ] || [ "${DISTROVERSION}" == 10 ]; then
					OSSupported="yes";
				fi
			;;
			'Debian')
				if [ "${DISTROVERSION}" == 11 ] || [ "${DISTROVERSION}" == 12 ] || [ "${DISTROVERSION}" == 13 ]; then
					OSSupported="yes";
				fi
			;;
			'Ubuntu')
				if [[ "${DISTROVERSION}" =~ 22.04 ]] || [[ "${DISTROVERSION}" =~ 24.04 ]]; then
					OSSupported="yes";
				fi
			;;
		esac
	}
	function ListSupportedOS(){
			echo " > CentOS Stream 9"
			echo " > CentOS Stream 10"
			echo " > AlmaLinux 9"
			echo " > AlmaLinux 10"
			echo " > Debian 11"
			echo " > Debian 12"
			echo " > Debian 13"
			echo " > Ubuntu 22.04 LTS"
			echo " > Ubuntu 24.04 LTS"
	}
	# HEADER
	function DisplayHeader(){
		clear;
		echo ""
		echo "-----------------------------------------------------------"
		echo ""
		echo " ${1}";
		echo ""
		echo "-----------------------------------------------------------"
		echo "";
	}
	function DisplayLine(){
		echo "-----------------------------------------------------------";
	}
	function DisplayBanner(){
		if [ "${isSilent}" != "1" ]; then
			clear;
		fi
		echo "      ____                   _   _           _      "
		echo "     / ___|  ___  _ __ ___  | \ | | ___   __| | ___ "
		echo "     \___ \ / _ \| '_ \` _ \ |  \| |/ _ \ / _\` |/ _ \\"
		echo "      ___) | (_) | | | | | || |\  | (_) | (_| |  __/"
		echo "     |____/ \___/|_| |_| |_||_| \_|\___/ \__,_|\___|"
		echo ""
		echo "      ___ _   _ ____ _____  _    _     _     "
		echo "     |_ _| \ | / ___|_   _|/ \  | |   | |    "
		echo "      | ||  \| \___ \ | | / _ \ | |   | |    "
		echo "      | || |\  |___) || |/ ___ \| |___| |___ "
		echo "     |___|_| \_|____/ |_/_/   \_\_____|_____|"
		echo ""
		echo ""
	}
	function SignalAbortInstall(){
		echo "SIGNAL: ABORT INSTALLATION";
		return 1;
	}
	function SignalCompletedInstall(){
		echo "SIGNAL: COMPLETED INSTALLATION";
	}
function LoadResource {
	echo "Loading resource ${SETUPPATH}/resources/${1} ..."
	if [[ "${2}" == "" ]]; then
	    wget -q ${SETUPPATH}/resources/${1};
	else
	    wget -q -O ${2} ${SETUPPATH}/resources/${1};
        if [[ ! -f ${2} ]]; then
            echo "Failed downloading resource ${2}";
        fi
	fi
}
function PluginConfig {
    cd ${BasePath}/htdocs/;
    LoadResource manage_plugin.php.txt
    mv manage_plugin.php.txt manage_plugin.php
    ${PHPBINARY} manage_plugin.php $1 $2;
    rm -f ${BasePath}/htdocs/manage_plugin.php;
}
function VersionSet {
	if [ ! -d ${BasePath}/versions/ ]; then
	    mkdir ${BasePath}/versions/;
	fi;
	echo $2 > ${BasePath}/versions/${1}
}
function VersionCheck {
	echo `cat ${BasePath}/versions/${1}`
}
function ReplaceString {
	sed -i "s/${2}/${3}/g" ${1}
}
function SetInstallDir {
	if [ ! -d /root/somnode_install ]; then
		mkdir /root/somnode_install;
	fi
	cd /root/somnode_install;
}
function CheckDebugMode {
	if [ ${isDebug} -eq 1 ]; then echo "(DEBUG) Press return to continue";read CONFIRM; fi
}
# ============================================================
# SSL / CERTBOT FUNCTIONS
# ============================================================
function AutoSSLAutoInstall {
    MCPSS "Installing AutoSSL";
    mkdir -p /root/somnode_install/autossl/;
    mkdir -p ${BasePath}/certbot/;
    LoadResource autossl/pre.sh /root/somnode_install/pre.sh;
    LoadResource autossl/post.sh /root/somnode_install/post.sh;
    chmod +x /root/somnode_install/autossl/*.sh;
    if ! test `which lsof`; then
      yum -y install lsof;
    fi
    echo "Running AutoSSL pre hooks";
    /root/somnode_install/pre.sh;
    if [[ -f ${BasePath}/hooks/autossl_pre.sh ]]; then
        ${BasePath}/hooks/autossl_pre.sh;
    fi
    nginxParentPid=`cat ${BasePath}/nginx/run/nginx.pid 2>/dev/null`;
    if [[ "${nginxParentPid}" -eq "" ]]; then
      CheckPorts="lsof -Pni :80 | grep 'LISTEN'";
    else
      nginxChildPids=`pgrep -P ${nginxParentPid} | tr '\n' '|' | sed 's/.$//'`
      CheckPorts="lsof -Pni :80 | grep 'LISTEN' | grep -Ev '${nginxParentPid}|${nginxChildPids}'";
    fi
    echo "Checking ports ... ";
    if [[ `eval ${CheckPorts} -c` -ne 0 ]]; then
        echo "Port 80 in use, unable to install AutoSSL";
        return
    fi
    echo "Running AutoSSL post hooks";
    /root/somnode_install/post.sh;
    if [[ -f ${BasePath}/hooks/autossl_post.sh ]]; then
        ${BasePath}/hooks/autossl_post.sh;
    fi
    echo "Running LetsEncryptInstall";
    LetsEncryptInstall
}
function GetDomain {
    if [ "${DOMAIN}" == "" ]; then
        INSTALLED=`${BasePath}/php/bin/php -r 'require("'${BasePath}'/htdocs/database.php"); echo isset($db_host)?"Y":"N";'`
        if [ "${INSTALLED}" == "Y" ]; then
            DOMAIN=`${BasePath}/php/bin/php -r 'require("'${BasePath}'/htdocs/database.php"); echo $setting["panel_url"];' | awk -F/ '{print $3}'  | awk -F: '{print $1}'`
        else
            DOMAIN=`cat ${BasePath}/somnode.domain`;
        fi
        DOMAIN=`echo ${DOMAIN} | awk '{print tolower($0)}'`
        echo "${DOMAIN}" > ${BasePath}/somnode.domain
    fi
}
function LetsEncryptInstall {
  DetectOS
  DetectOSMajor
    echo "Running AutoSSL pre hooks";
    if [[ -f ${BasePath}/hooks/autossl_pre.sh ]]; then
        ${BasePath}/hooks/autossl_pre.sh;
    fi
    GetDomain
    if [ "${DOMAIN}" == "" ]; then
        echo "Unable to determine domain name, exiting.";
        return;
    fi
    echo "Installing certbot ..";
    if [ ! -d ${BasePath}/certbot/ ]; then mkdir ${BasePath}/certbot; fi
    cd ${BasePath}/certbot/;
  if ! test `which snap`; then
    if [[ "${DISTRO}" == "Centos" ]]; then
      yum -y remove certbot;
      yum -y install snapd;
      systemctl enable --now snapd.socket
    else
      apt-get install snapd -V -y --force-yes;
      apt-get remove certbot -V -y --force-yes;
    fi
  fi
  systemctl restart snapd;
  ldconfig;
  if [[ "${DISTRO}" == "Debian" ]] && [[ ! `snap list core 2>/dev/null` ]]; then
    snap install core;
    snap refresh core;
  fi
  if [[ ! -L /snap ]] && [[ ! -d /snap ]]; then ln -s /var/lib/snapd/snap /snap; fi
  if ! test `which certbot`; then snap install --classic certbot; fi
  if [[ -L /snap/bin/certbot ]]; then
    if [[ ! -L /snap/bin/certbot ]]; then ln -s /snap/bin/certbot /usr/bin/certbot; fi
    if [[ -L ${BasePath}/certbot/certbot ]] || [[ -f ${BasePath}/certbot/certbot ]]; then rm -f certbot; fi
    ln -s /snap/bin/certbot ${BasePath}/certbot/certbot;
  elif [[ "${DISTRO}" == "Centos" ]]; then
    yum -y install certbot;
    if [[ -L ${BasePath}/certbot/certbot ]] || [[ -f ${BasePath}/certbot/certbot ]]; then rm -f certbot; fi
    ln -s /usr/bin/certbot ${BasePath}/certbot/certbot;
  fi
  sudo chmod 0755 ${BasePath}/certbot;
    sudo chown -R somnode:somnode ${BasePath}/certbot;
    if [ -d ${BasePath}/letsencrypt.disabled/ ]; then mv ${BasePath}/letsencrypt.disabled/ ${BasePath}/letsencrypt/; fi
    AutoSSLCreateHooks;
    if [[ -f /bin/firewall-cmd ]] && [[ `firewall-cmd --state 2>&1` == "running" ]]; then
        firewall-cmd --add-port=80/tcp --permanent
        firewall-cmd --reload
    fi
    ./certbot certonly \
    --register-unsafely-without-email -d ${DOMAIN} \
    --agree-tos --standalone \
    --preferred-challenges http-01 \
    --config-dir ${BasePath}/letsencrypt \
    --non-interactive \
    --keep-until-expiring \
    --agree-tos \
    --pre-hook=${BasePath}/certbot/pre.sh \
    --post-hook=${BasePath}/certbot/post.sh \
    --deploy-hook ${BasePath}/certbot/deploy_wrapper.sh;
    RETVAL=($?);
    if [[ ${RETVAL} -ne 0 ]] || [[ ! -f "${BasePath}/letsencrypt/live/${DOMAIN}/cert.pem" ]]; then
        echo "";
        echo "ERROR: AutoSSL Installation has failed";
        return 1;
    fi
    if [[ "${LetsEncryptUpdatePanelURL}" == "y" ]]; then
        cd ${BasePath}/htdocs/
        DBPREFIX=`${BasePath}/php/bin/php -r 'require "database.php"; echo $db_prefix;'`
        MYSQLCONNECTION="sudo -u somnode ${BasePath}/mysql/bin/mysql --protocol=SOCKET --socket=${BasePath}/mysql/data/mysql.sock --user=root somnode";
        echo "UPDATE ${DBPREFIX}settings SET value = REPLACE(value, 'http:','https:') WHERE setting = 'panel_url';" | ${MYSQLCONNECTION};
        cd /root/somnode_install;
    fi
  echo "Configuring Web Service";
    AutoSSLConfigWeb
    echo "Configuring Cron";
    AutoSSLInstallCronjob
    chown somnode:somnode -R ${BasePath}/letsencrypt
}
function AutoSSLCreateHooks {
    CBPATH=${BasePath}/certbot/;
    LoadResource autossl/pre.sh ${CBPATH}/pre.sh
    LoadResource autossl/post.sh ${CBPATH}/post.sh
    LoadResource autossl/deploy.sh ${CBPATH}/deploy.sh
    LoadResource autossl/deploy_wrapper.sh ${CBPATH}/deploy_wrapper.sh
    chmod +x ${CBPATH}/*.sh;
}
function AutoSSLConfigWeb {
    DOMAIN=`cat ${BasePath}/somnode.domain`;
    if [ -f ${BasePath}/letsencrypt/live/${DOMAIN}/fullchain.pem ]; then
        echo "Reapplying autossl configurations"
        rm -f ${BasePath}/nginx/fullchain.pem;
        rm -f ${BasePath}/nginx/server.pem;
        rm -f ${BasePath}/nginx/server.key;
        rm -f ${BasePath}/icecast2/icecast.cert;
        ln -s ${BasePath}/letsencrypt/live/${DOMAIN}/fullchain.pem ${BasePath}/nginx/fullchain.pem;
        ln -s ${BasePath}/letsencrypt/live/${DOMAIN}/cert.pem ${BasePath}/nginx/server.pem;
        ln -s ${BasePath}/letsencrypt/live/${DOMAIN}/privkey.pem ${BasePath}/nginx/server.key;
        if [[ ! -d ${BasePath}/content/certs/ ]]; then mkdir ${BasePath}/content/certs/; fi
        chown somnode:somnode ${BasePath}/content/certs/;
        if [[ -f ${BasePath}/content/certs/${DOMAIN}.crt ]]; then rm -f ${BasePath}/content/certs/${DOMAIN}.crt; fi
        if [[ -f ${BasePath}/content/certs/${DOMAIN}.key ]]; then rm -f ${BasePath}/content/certs/${DOMAIN}.key; fi
        ln -s ${BasePath}/letsencrypt/live/${DOMAIN}/fullchain.pem ${BasePath}/content/certs/${DOMAIN}.crt;
        ln -s ${BasePath}/letsencrypt/live/${DOMAIN}/privkey.pem ${BasePath}/content/certs/${DOMAIN}.key;
        cat ${BasePath}/nginx/server.key > ${BasePath}/icecast2/icecast.cert;
        cat ${BasePath}/nginx/fullchain.pem >> ${BasePath}/icecast2/icecast.cert;
        echo "" > ${BasePath}/nginx/conf.d/ssl.conf;
        echo "ssl on;" >> ${BasePath}/nginx/conf.d/ssl.conf
        echo "ssl_certificate ${BasePath}/nginx/fullchain.pem;" >> ${BasePath}/nginx/conf.d/ssl.conf;
        echo "ssl_certificate_key ${BasePath}/nginx/server.key;" >> ${BasePath}/nginx/conf.d/ssl.conf;
        echo "ssl_session_cache shared:le_nginx_SSL:1m;" >> ${BasePath}/nginx/conf.d/ssl.conf;
        echo "ssl_session_timeout 1440m;" >> ${BasePath}/nginx/conf.d/ssl.conf;
        echo "error_page 497 =307 https://${DOMAIN}:\$server_port\$request_uri;" >> ${BasePath}/nginx/conf.d/ssl.conf;
        if [[ ! -d ${BasePath}/proftpd/etc.d/ ]]; then mkdir -p ${BasePath}/proftpd/etc.d/; fi
    if [[ -f ${BasePath}/proftpd/etc.d/20_ssl.conf ]]; then rm -f ${BasePath}/proftpd/etc.d/20_ssl.conf; fi
    LoadResource proftpd.ssl.conf.txt
    mv proftpd.ssl.conf.txt ${BasePath}/proftpd/etc.d/20_ssl.conf;
    chmod 700 -R ${BasePath}/proftpd/etc.d/20_ssl.conf;
    else
        echo "AutoSSL not detected."
    fi
}
function AutoSSLInstallCronjob {
    CRON="0 0 * * * root DOMAIN=`cat ${BasePath}/somnode.domain` && ${BasePath}/certbot/certbot --standalone --config-dir ${BasePath}/letsencrypt renew --non-interactive --pre-hook=${BasePath}/certbot/pre.sh --post-hook=${BasePath}/certbot/post.sh --deploy-hook ${BasePath}/certbot/deploy_wrapper.sh >>/usr/local/somnode/log/autossl/autossl.log 2>&1;";
  if ! grep -R "${CRON}" /etc/crontab > /dev/null
  then
    sed -i '/\/usr\/local\/somnode\/certbot\/certbot/d' /etc/crontab;
    echo "${CRON}" >> /etc/crontab
  fi
}
function AutoSSLCheckCron {
  CRON="0 0 * * * root DOMAIN=`cat ${BasePath}/somnode.domain` && ${BasePath}/certbot/certbot --standalone --config-dir ${BasePath}/letsencrypt renew --non-interactive --pre-hook=${BasePath}/certbot/pre.sh --post-hook=${BasePath}/certbot/post.sh --deploy-hook ${BasePath}/certbot/deploy_wrapper.sh >>/usr/local/somnode/log/autossl/autossl.log 2>&1;";
    if ! grep -R "${CRON}" /etc/crontab > /dev/null
    then
        AutoSSLCreateHooks
        AutoSSLInstallCronjob
    fi
}
function AutoSSLHealthCheck {
  if [[ ! -d ${BasePath}/letsencrypt ]]; then
    return;
  fi
  if [[ ! -f ${BasePath}/certbot/certbot ]] && [[ -f ${BasePath}/certbot/certbot-auto ]]; then
      AutoSSLAutoInstall
    fi
  AutoSSLCheckCron
}
function LetsEncryptEnable {
    skipPortCheck=`echo "${params[@]}" | grep -c 'skip-port-check'`;
    DisplayHeader "Let's Encrypt SSL Certificate Installation";
    if [ ${skipPortCheck} -eq 0 ]; then
        if [[ ! -d ${BasePath}/certbot ]]; then mkdir ${BasePath}/certbot; fi
        LoadResource autossl/pre.sh /root/somnode_install/pre.sh;
        chmod +x /root/somnode_install/pre.sh;
        /root/somnode_install/pre.sh;
    nginxParentPid=`cat ${BasePath}/nginx/run/nginx.pid 2>/dev/null`;
    if [[ "${nginxParentPid}" -eq "" ]]; then
      CheckPorts="lsof -Pni :80 | grep 'LISTEN' | grep -Ev '${nginxParentPid}'";
    else
      nginxChildPids=`pgrep -P ${nginxParentPid} | tr '\n' '|' | sed 's/.$//'`
      CheckPorts="lsof -Pni :80 | grep 'LISTEN' | grep -Ev '${nginxParentPid}|${nginxChildPids}'";
    fi
    if [[ `eval ${CheckPorts} -c` -ne 0 ]]; then
          echo "Port 80 in use. Stop processes using port 80 first.";
          exit;
      fi
    fi
    DisplayHeader "Lets Encrypt Certificate Installation"
    GetDomain
    if [ "${DOMAIN}" == "" ]; then
        echo "Please enter the domain name to install on: [www.yourdomain.com]";
        read DOMAIN;
        while true
        do
            DOMAIN=`echo ${DOMAIN} | grep -P '(?=^.{5,254}$)(^(?:[a-zA-Z0-9_\-]{1,63}\.?)+\.(?:[a-z]{2,})$)'`;
            if [ ! "${DOMAIN}" == "" ]; then
                break;
            fi
            echo "";
            echo "Invalid domain, please enter a valid domain or sub-domain name:";
            read DOMAIN;
        done
        echo "${DOMAIN}" > ${BasePath}/somnode.domain
    fi
    LetsEncryptUpdatePanelURL="y";
    LetsEncryptInstall
    echo "Running AutoSSL post hooks";
    if [[ -f ${BasePath}/hooks/autossl_post.sh ]]; then
        ${BasePath}/hooks/autossl_post.sh;
    fi
    echo "Complete";
    ${BasePath}/service restart;
    echo "";
}
function LetsEncryptDisable {
    echo "Disabling Lets Encrypt ...";
    echo "" > ${BasePath}/nginx/conf.d/ssl.conf;
    rm -f ${BasePath}/proftpd/etc.d/20_ssl.conf;
    mv ${BasePath}/letsencrypt/ ${BasePath}/letsencrypt.disabled/;
    mv ${BasePath}/icecast2/icecast.cert ${BasePath}/icecast2/icecast.cert.backup;
    cd ${BasePath}/htdocs/
    DBPREFIX=`${BasePath}/php/bin/php -r 'require "database.php"; echo $db_prefix;'`
    MYSQLCONNECTION="sudo -u somnode ${BasePath}/mysql/bin/mysql --protocol=SOCKET --socket=${BasePath}/mysql/data/mysql.sock --user=root somnode";
    echo "UPDATE ${DBPREFIX}settings SET value = REPLACE(value, 'https:','http:') WHERE setting = 'panel_url';" | ${MYSQLCONNECTION};
    cd /root/somnode_install;
    ${BasePath}/service restart;
    echo "Complete.";
}
function RemoteScript {
    URL=$1;
    FILENAME=$(basename -- "${URL}");
    mkdir -p /root/somnode_install;
    if [ -f /root/somnode_install/${FILENAME} ]; then rm -f /root/somnode_install/${FILENAME}; fi
    wget ${URL} -O /root/somnode_install/${FILENAME};
    chmod +x /root/somnode_install/${FILENAME};
    echo "Running /root/somnode_install/${FILENAME};";
    /root/somnode_install/${FILENAME} ${2} ${3};
}
function TrimText() {
    echo $1 | awk '{ gsub(/^[ \t]+|[ \t]+$/, ""); print }'
}
# ============================================================
# PROGRESS / STATUS FUNCTIONS
# ============================================================
function ProgressBar() {
Title=$1
Percentage=`[ -n "${2}" ] && echo $2 || echo 0`
Divisible=4;
Progress=$((Percentage / Divisible))
echo -ne " ${Title}";
for x in {1..35} ; do
if [ "${x}" -gt "${#Title}" ]; then
        echo -ne " ";
    fi
done ;
echo -ne " [";
for x in {1..25} ; do
if [ "${x}" -le "${Progress}" ]; then
        echo -ne "#";
    else
        echo -ne " ";
    fi
done ;
echo -ne "] ${Percentage}%";
echo "";
}
function DetermineProgress(){
Progress='';unset Progress;array='';unset array;Logfile='';unset Logfile;
Logfile=$1
if [ ! -f "${Logfile}" ]; then echo "0"; return; fi
Progression=`awk '/MCPSP/ {a=$0} END{print a}' ${Logfile}`;
IFS=':' read -r -a array <<< "${Progression}";
Progress="${array[1]}";
if [ -z "${Progress}" ]; then echo "0"; return; fi
if [ "${Progress}" -gt "0" ]; then
echo ${Progress};
else
echo "0";
fi
}
function DetermineStatus(){
Logfile=$1
if [ ! -f "${Logfile}" ]; then echo "0"; return; fi
StatusMSG=`awk '/MCPSS/ {a=$0} END{print a}' ${Logfile}`;
IFS=':' read -r -a array <<< "${StatusMSG}";
StatusMSG="${array[1]}";
if [ -n "${StatusMSG}" ]; then
echo ${StatusMSG};
else
echo "";
fi
}
function DetermineSleep(){
Logfile=$1
SleepTime=$2
if [ ! -f "${Logfile}" ]; then echo "0"; return; fi
MCPSetSleep=`awk '/MCPSetSleep/ {a=$0} END{print a}' ${Logfile}`;
IFS=':' read -r -a array <<< "${MCPSetSleep}";
NewSleepTime="${array[1]}";
if [ -n "${NewSleepTime}" ]; then
echo ${NewSleepTime};
return;
fi
echo "${SleepTime}";
}
function GetStatus(){
if [ -f /root/somnode_install/status/${1} ]; then
echo `cat /root/somnode_install/status/${1} 2>/dev/null`;
else
echo 0;
fi
}
export StatusMessage='';
function RenderInstallStatusScreen(){
ShowRemaining=$1
if [ "${ShowRemaining}" == "" ]; then ShowRemaining=1; fi
StatusInstallPrerequisites=`GetStatus StatusInstallPrerequisites`;
StatusInstallFFMPEG=`GetStatus StatusInstallFFMPEG`;
StatusInstallWebService=`GetStatus StatusInstallWebService`;
StatusInstallIcecast=`GetStatus StatusInstallIcecast`;
StatusInstallLiquidSoap=`GetStatus StatusInstallLiquidSoap`;
StatusInstallPanel=`GetStatus StatusInstallPanel`;
StatusInstallNginxRtmp=`GetStatus StatusInstallNginxRtmp`;
clear;
DisplayHeader "SomNode Software Installation";
ProgressBar "Installing Prerequisites" "${StatusInstallPrerequisites}";
ProgressBar "Installing FFMPEG" ${StatusInstallFFMPEG};
ProgressBar "Installing Web Service" ${StatusInstallWebService};
ProgressBar "Installing Icecast" ${StatusInstallIcecast};
ProgressBar "Installing LiquidSoap" ${StatusInstallLiquidSoap};
ProgressBar "Installing Panel" ${StatusInstallPanel};
if [ "${InstallNginxRtmp}" == "y" ]; then
ProgressBar "Installing SomNode Video" ${StatusInstallNginxRtmp};
fi
echo "";
if [ -n "${StatusMessage}" ]; then
echo " Current Status: ${StatusMessage}";
fi
echo "";
echo " % Please Wait %";
}
function RenderUpdateStatusScreen(){
ShowRemaining=$1
if [ "${ShowRemaining}" == "" ]; then ShowRemaining=1; fi
StatusUpdatePrerequisites=`GetStatus StatusUpdatePrerequisites`;
StatusUpdateFFMPEG=`GetStatus StatusUpdateFFMPEG`;
StatusUpdateBackup=`GetStatus StatusUpdateBackup`;
StatusUpdateWeb=`GetStatus StatusUpdateWeb`;
StatusUpdateIcecast=`GetStatus StatusUpdateIcecast`;
StatusUpdateLiquidSoap=`GetStatus StatusUpdateLiquidSoap`;
StatusUpdatePanel=`GetStatus StatusUpdatePanel`;
StatusUpdateNginxRtmp=`GetStatus StatusUpdateNginxRtmp`;
clear;
DisplayHeader "SomNode Software Upgrade";
ProgressBar "Backup" "${StatusUpdateBackup}";
ProgressBar "Prerequisites" "${StatusUpdatePrerequisites}";
ProgressBar "FFMPEG" "${StatusUpdateFFMPEG}";
ProgressBar "Web Services" ${StatusUpdateWeb};
if [ -d ${BasePath}/nginx-rtmp/ ]; then
ProgressBar "SomNode Video" ${StatusUpdateNginxRtmp};
fi
ProgressBar "Icecast" ${StatusUpdateIcecast};
ProgressBar "LiquidSoap" ${StatusUpdateLiquidSoap};
ProgressBar "Panel" ${StatusUpdatePanel};
echo "";
if [ -n "${StatusMessage}" ]; then
echo " Current Status: ${StatusMessage}";
fi
echo "";
echo " % Please Wait %";
}
function UpdateInstallStatusScreen(){
InstallOrUpdate=$1
StatusVariable=$2
LogFile=$3
SleepTime=$4
if [ "${SleepTime}" == "" ]; then SleepTime=5; fi
StatusMessage="";
LogFileSize=0;
LastLogFileSize=0;
FileLastUpdated=0;
InstallStatusTimeout=450;
if [ -f /root/.somnodeslowinstall ]; then InstallStatusTimeout=1200; fi
mkdir -p /root/somnode_install/status/;
isSilent=`cat /root/somnode_install/isSilent 2>/dev/null`;
while true
do
Status=`DetermineProgress ${LogFile}`;
echo ${Status} > /root/somnode_install/status/${StatusVariable}
StatusMessage=`DetermineStatus ${LogFile}`
SleepTime=`DetermineSleep ${LogFile} ${SleepTime}`;
LogFileSize=`stat -c%s "$LogFile" 2>/dev/null || echo 0`
if [[ "${isSilent}" == "1" ]]; then
if [ -f "${LogFile}" ]; then
if [ "${LogFileSize}" -gt "${LastLogFileSize}" ]; then
tail -c +$((LastLogFileSize+1)) "${LogFile}"
fi
fi
else
if [ "${InstallOrUpdate}" == "Install" ]; then
RenderInstallStatusScreen
else
RenderUpdateStatusScreen
fi
fi
if grep -q 'MCPSP:100' "${LogFile}" 2>/dev/null; then
echo "100" > /root/somnode_install/status/${StatusVariable}
break;
fi
if grep -q 'SIGNAL: COMPLETED INSTALLATION' "${LogFile}" 2>/dev/null; then
echo "100" > /root/somnode_install/status/${StatusVariable}
break;
fi
if grep -q 'SIGNAL: ABORT INSTALLATION' "${LogFile}" 2>/dev/null; then
rm -f ${BasePath}/htdocs/.maintenance;
echo ""
echo "Installation Failed.";
echo "-------------------------------";
tail -15 ${LogFile};
echo "-------------------------------";
echo "";
echo "Please check log file for more information:";
echo ${LogFile};
exit;
fi
FileLastUpdated=$((FileLastUpdated+SleepTime));
if [ "${LogFileSize}" -gt "${LastLogFileSize}" ]; then
FileLastUpdated=0;
fi
LastLineProcessing="$(tail -n 1 -- "$LogFile" | grep -Eic '(installed|processing|gathering)')"
if [[ "${FileLastUpdated}" -gt "${InstallStatusTimeout}" ]] && [[ $LastLineProcessing -lt 0 ]]; then
rm -f ${BasePath}/htdocs/.maintenance;
echo ""
echo "Installation Failed.";
echo "-------------------------------";
tail -15 ${LogFile};
echo "-------------------------------";
echo "";
echo "Please check log file for more information:";
echo ${LogFile};
exit;
fi
LastLogFileSize=${LogFileSize}
sleep ${SleepTime};
done
return 0;
}
ShowMcpProgress="1";
function MCPSP(){
if [[ "${ShowMcpProgress}" == "0" ]]; then return; fi
echo "MCPSP:${1}";
}
function MCPSS(){
if [[ "${ShowMcpProgress}" == "0" ]]; then echo $1; return; fi
echo "MCPSS:${1}";
}
function MCPSetSleepTime(){
if [[ "${ShowMcpProgress}" == "0" ]]; then return; fi
echo "MCPSetSleep:${1}";
}
function GetEnvironmentSetup(){
DetectOS;
DetectOSMajor;
IsOSSupported;
KERNEL=`uname -r`
MACH=`uname -m`
ARCH=$(getconf LONG_BIT)
SomnodeRelease="stable"
isSilent=`cat /root/somnode_install/isSilent 2>/dev/null`;
if [ -f ${BasePath}/versions/release_branch ]; then
SomnodeRelease=`cat ${BasePath}/versions/release_branch &`;
fi
}
function version_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; }
function setReleaseBranch() {
    echo "Set release branch to ${1}";
SomnodeRelease=${1};
GetEnvironmentSetup
}
function Output(){
    text=$1
    color=$2
    if [[ "${color}" == "" ]]; then color="black"; return; fi
    ansiColor='\033[0m';
    case $color in
        'red') ansiColor='\033[0;31m';;
        'green') ansiColor='\033[0;32m';;
        'blue') ansiColor='\033[01;34m';;
        'black'|'default') ansiColor='\033[0m';;
    esac
    echo -e "${ansiColor}${text}\033[0m"
}
function DebianInstallPackages(){
  export DEBIAN_FRONTEND=noninteractive
  echo "Building apt install package list"
  for i in $1
    do
       if [ -z "$(apt-cache madison $i 2>/dev/null)" ]; then
         echo " > Package $i not available on repo."
       else
         echo " > Add package $i to the install list"
       packages="$packages $i"
       fi
   done
  echo "Installing $packages"
  if ! apt-get install --ignore-missing -V -y --force-yes $packages; then
    for i in $packages; do apt-get -o DPkg::Options::="--force-confdef" install --ignore-missing -V -y --force-yes $i; done
  fi
}
# ============================================================
# PREREQUISITES INSTALLATION
# ============================================================
function INSTALLPrerequisites(){
echo "% loading %";
DetectOS;
DetectOSMajor;
  rm -f /etc/sysctl.d/99-overcommit-memory.conf;
  sysctl -w vm.overcommit_memory=0
  check_and_create_swap
echo "YUM Update";
  MCPSS "Running 'yum update'";
  MCPSP 10
  yum -y update;
  RES=`echo $?`
  if [[ $RES -eq 1 ]]; then
    echo "yum update was not successful, remedy the issue and try again.";
    SignalAbortInstall
  fi
  MCPSP 20
  MCPSS "Installing prerequisites";
  yum -y --skip-broken install \
    sudo gcc gcc-c++ automake autoconf bzip2 cmake \
    freetype-devel git libtool make mercurial pkgconfig zlib-devel which \
    nscd;
  MCPSP 40
  MCPSetSleepTime 5
  yum -y --skip-broken install openssl-devel pcre-devel glibc.i686 mlocate expat-devel;
  yum -y --skip-broken install pcre2-devel libicu libicu-devel pkgconf-pkg-config;
  MCPSP 60
  if [[ "${DISTROVERSION}" == "8" ]] || [[ "${DISTROVERSION}" == "9" ]] || [[ "${DISTROVERSION}" == "10" ]]; then
    yum -y --skip-broken install dnf-plugins-core;
    if [[ "${DISTROVERSION}" == "8" ]]; then
      yum config-manager --set-enabled PowerTools
      yum config-manager --set-enabled powertools
    else
      yum config-manager --set-enabled crb;
      dnf -y install epel-release epel-next-release
    fi
    yum -y update;
    dnf -y install epel-release
    dnf -y upgrade
    dnf -y install --nogpgcheck https://dl.fedoraproject.org/pub/epel/epel-release-latest-$(rpm -E %rhel).noarch.rpm
    dnf -y install --nogpgcheck https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-$(rpm -E %rhel).noarch.rpm https://mirrors.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-$(rpm -E %rhel).noarch.rpm
    dnf -y update;
  fi
  if [[ "${DISTROVERSION}" == "9" ]] || [[ "${DISTROVERSION}" == "10" ]]; then
    dnf -y install perl-FindBin;
  fi
  MCPSP 80
  yum -y install lsof;
  yum install libstdc++.so.6 -y -d 0 -e 0
  if [ "${ARCH}" -eq "64" ]; then
    yum -y --skip-broken install zlib-devel.x86_64 ld-linux.so.2 lib32-glib -d 0 -e 0;
  fi
yum -y --skip-broken install \
  bzip2 unzip \
    logrotate \
    snapd;
  yum -y remove certbot;
systemctl restart snapd;
  snap install core;
  snap refresh core;
  if [[ ! -L /snap ]]; then ln -s /var/lib/snapd/snap /snap; fi
ldconfig;
snap install --classic certbot
ln -s /snap/bin/certbot /usr/bin/certbot
  echo "/usr/local/lib/" > /etc/ld.so.conf.d/somnode.conf
  echo "/usr/local/lib64/" >> /etc/ld.so.conf.d/somnode.conf
  echo "/usr/local/somnode/ffmpeg/lib/" >> /etc/ld.so.conf.d/somnode.conf
ldconfig;
sleep 1
echo "SIGNAL: COMPLETED INSTALLATION";
MCPSP 100
}
check_and_create_swap() {
  MIN_MEM_KB=$((2500 * 1024))
  MIN_SWAP_KB=$((1024 * 1024))
  total_mem=$(grep MemTotal /proc/meminfo | awk '{print $2}')
  swap_kb=$(grep SwapTotal /proc/meminfo | awk '{print $2}')
  swap_kb=${swap_kb:-0}
  swap_mb=$((swap_kb / 1024))
  if [ "$total_mem" -lt "$MIN_MEM_KB" ]; then
    echo "Detected physical memory is under 2.5GB."
    if [ "$swap_kb" -lt "$MIN_SWAP_KB" ]; then
      echo "Swap is less than 1GB. Creating 2GB swap..."
      swapoff -a 2>/dev/null || true
      [ -f /swapfile ] && rm -f /swapfile
      fallocate -l 2G /swapfile || dd if=/dev/zero of=/swapfile bs=1M count=2048
      chmod 600 /swapfile
      mkswap /swapfile
      swapon /swapfile
      if ! grep -q '^/swapfile' /etc/fstab; then
        echo '/swapfile none swap sw 0 0' >> /etc/fstab
      fi
      echo 'vm.swappiness=10' > /etc/sysctl.d/99-swap.conf
      sysctl -w vm.swappiness=10
      echo "Swap set to 2GB."
    fi
  fi
}
function InstallService(){
DISTROVERSION=`cat /etc/redhat-release | grep -oE '[0-9]+\.[0-9]+' | cut -d"." -f1`
cd /usr/local/somnode/;
    wget ${SETUPPATH}/${DISTRO}/conf/somnode.service -O /usr/lib/systemd/system/somnode.service;
    chmod +x /usr/lib/systemd/system/somnode.service;
chkconfig somnode on;
}
function UninstallService(){
systemctl disable somnode;
if [[ -f /usr/lib/systemd/system/somnode.service ]]; then 
  rm /usr/lib/systemd/system/somnode.service;
fi
}
# ============================================================
# SERVICE MANAGEMENT
# ============================================================
function StartSomnode(){
StartNginx
StartPHP
StartMysql
StartProftpd
StartRedis
StartQueue
if [[ -d /usr/local/somnode/nginx-rtmp ]]; then
    StartNginxRtmp
fi
sleep 3
echo "=================="
StatusSomnode
echo "=================="
echo "SomNode services started."
}
function StopSomnode(){
StopNginx
StopPHP
StopMysql
StopProftpd
StopRedis
StopQueue
if [[ -d /usr/local/somnode/nginx-rtmp ]]; then
    StopNginxRtmp
fi
echo "SomNode services stopped."
}
function StatusSomnode(){
StatusNginx
StatusPHP
StatusMysql
StatusProftpd
StatusRedis
StatusQueue
if [[ -d /usr/local/somnode/nginx-rtmp ]]; then
    StatusNginxRtmp
fi
}
function RestartSomnode(){
StopSomnode;
StartSomnode;
}
function StartNginx(){
echo "Starting Nginx..."
${BasePath}/nginx/sbin/nginx;
}
function StopNginx(){
PIDFILE=${BasePath}/nginx/run/nginx.pid;
PID=`cat ${PIDFILE}`
      if (kill -0 $PID 2>/dev/null) ; then
        echo "Shutting down Nginx"
        kill $PID
        wait_for_pid removed "$PID" "$PIDFILE"; return_value=$?
      else
        echo "Nginx server process #$PID is not running!"
        if [[ -f ${PIDFILE} ]]; then rm -f "$PIDFILE"; fi
      fi
}
function StatusNginx(){
PIDFILE=${BasePath}/nginx/run/nginx.pid;
if [ ! -f ${PIDFILE} ]; then
echo "Web server is not running"
return;
else
    PID=`cat ${PIDFILE}`
      if kill -0 $PID 2>/dev/null ; then
        echo "Web server is running ($PID)"
        return;
      else
        echo "Web server is not running"
        return;
      fi
fi
}
function StartNginxRtmp(){
echo "Starting SomNode Video..."
sudo -u somnode ${BasePath}/nginx-rtmp/sbin/nginx;
}
function StopNginxRtmp(){
PIDFILE=${BasePath}/nginx-rtmp/run/nginx.pid;
PID=`cat ${PIDFILE}`
      if (kill -0 $PID 2>/dev/null) ; then
        echo "Shutting down SomNode Video"
        kill $PID
        wait_for_pid removed "$PID" "$PIDFILE"; return_value=$?
      else
        echo "SomNode Video process #$PID is not running!"
        if [[ -f ${PIDFILE} ]]; then rm -f "$PIDFILE"; fi
      fi
}
function StatusNginxRtmp(){
PIDFILE=${BasePath}/nginx-rtmp/run/nginx.pid;
if [ ! -f ${PIDFILE} ]; then
echo "SomNode Video service is not running"
return 1;
else
    PID=`cat ${PIDFILE}`
      if kill -0 $PID 2>/dev/null ; then
        echo "SomNode Video service is running ($PID)"
        return 0;
      else
        echo "SomNode Video service is not running"
        return 1;
      fi
fi
}
function StartPHP(){
echo "Starting PHP-FPM..."
${BasePath}/php/sbin/php-fpm --fpm-config ${BasePath}/php/etc/php-fpm.conf
}
function StopPHP(){
echo "Stopping PHP-FPM...";
PIDFILE=${BasePath}/php/var/run/php-fpm.pid
PID=`cat ${PIDFILE}`
  if (kill -0 $PID 2>/dev/null) ; then
    echo "Shutting down PHP-FPM"
    kill -SIGTERM $PID
    wait_for_pid removed "$PID" "$PIDFILE"; return_value=$?
  else
    echo "PHP-FPM not running!"
    if [[ -f ${PIDFILE} ]]; then rm -f "$PIDFILE"; fi
  fi
}
function StatusPHP(){
PIDFILE=${BasePath}/php/var/run/php-fpm.pid
if [ ! -f ${PIDFILE} ]; then
echo "PHP is not running"
return;
else
    PID=`cat ${PIDFILE}`
      if kill -0 $PID 2>/dev/null ; then
        echo "PHP is running ($PID)"
      else
        echo "PHP is not running"
      fi
fi
}
function StartMysql(){
echo "Starting MySQL...";
PID=`pidof -c ${BasePath}/mysql/bin/mysqld`
if [ "${PID}" == "" ]; then
nohup ${BasePath}/mysql/bin/mysqld --defaults-file=${BasePath}/mysql/my.cnf --user=somnode --basedir=${BasePath}/mysql --datadir=${BasePath}/mysql/data --socket=${BasePath}/mysql/data/mysql.sock --log-error --skip-networking >/dev/null 2>&1 & echo $! >${BasePath}/mysql/mysql.pid
PID=`pidof -c ${BasePath}/mysql/bin/mysqld`
echo '-100' > "/proc/${PID}/oom_score_adj"
else
echo "Mysql is already running on ${PID}"
fi
}
function StopMysql(){
echo "Stopping MySQL...";
PIDFILE=${BasePath}/mysql/mysql.pid
PID=`pidof -c ${BasePath}/mysql/bin/mysqld`
      if (kill -0 $PID 2>/dev/null) ; then
        echo "Shutting down MySQL"
        kill -SIGTERM $PID
        wait_for_pid removed "$PID" "$PIDFILE"; return_value=$?
      else
        echo "MySQL not running!"
        if [[ -f ${PIDFILE} ]]; then rm -f "$PIDFILE"; fi
      fi
}
function StatusMysql(){
PIDFILE=${BasePath}/mysql/mysql.pid
if [ ! -f ${PIDFILE} ]; then
echo "MySQL database is not running"
else
    PID=`cat ${PIDFILE}`
      if kill -0 $PID 2>/dev/null ; then
        echo "MySQL database is running ($PID)"
      else
        echo "MySQL database is not running"
      fi
fi
}
function StartProftpd(){
echo "Starting ProFTPd..."
nohup ${BasePath}/proftpd/sbin/proftpd -c ${BasePath}/proftpd/etc/proftpd.conf >/dev/null 2>&1 & echo $! >${BasePath}/proftpd/proftpd.pid
}
function StopProftpd(){
echo "Stopping ProFTPd...";
PIDFILE=${BasePath}/proftpd/proftpd.pid
PID=`pidof -c ${BasePath}/proftpd/sbin/proftpd`
      if (kill -0 $PID 2>/dev/null) ; then
        echo "Shutting down ProFTPd"
        kill $PID
        wait_for_pid removed "$PID" "$PIDFILE"; return_value=$?
      else
        echo "ProFTPd not running!"
        if [[ -f ${PIDFILE} ]]; then rm -f "$PIDFILE"; fi
      fi
}
function StatusProftpd(){
PIDFILE=${BasePath}/proftpd/proftpd.pid
PID=`pidof -c ${BasePath}/proftpd/sbin/proftpd`
if [ ! -f ${PIDFILE} ]; then
echo "FTP service ProFTPd is not running"
else
      if kill -0 $PID 2>/dev/null ; then
        echo "FTP service ProFTPd is running ($PID)"
      else
        echo "FTP service ProFTPd is not running"
      fi
fi
}
function StartRedis(){
echo "Starting Redis..."
nohup ${BasePath}/redis/bin/redis-server ${BasePath}/redis/redis.conf >/dev/null 2>&1 & echo $! >${BasePath}/redis/redis.pid
}
function StopRedis(){
echo "Stopping Redis...";
PIDFILE=${BasePath}/redis/redis.pid
PID=`pidof -c ${BasePath}/redis/bin/redis-server`
      if (kill -0 $PID 2>/dev/null) ; then
        echo "Shutting down Redis"
        kill $PID
        wait_for_pid removed "$PID" "$PIDFILE"; return_value=$?
      else
        echo "Redis not running!"
        if [[ -f ${PIDFILE} ]]; then rm -f "$PIDFILE"; fi
      fi
}
function StatusRedis(){
PIDFILE=${BasePath}/redis/redis.pid
PID=`pidof -c ${BasePath}/redis/bin/redis-server`
if [ ! -f ${PIDFILE} ]; then
echo "Redis service is not running"
else
      if kill -0 $PID 2>/dev/null ; then
        echo "Redis service is running ($PID)"
      else
        echo "Redis service is not running"
      fi
fi
}
function StartQueue(){
    if [[ -f ${BasePath}/php/queuemanager.pid ]]; then
        PID=`cat ${BasePath}/php/queuemanager.pid`
        if kill -0 $PID 2>/dev/null ; then
            echo "Queue Manager is already running";
            StopQueue
        fi
    fi
echo "Starting Queue Manager..."
sudo -u somnode nohup ${BasePath}/php/bin/php ${BasePath}/htdocs/system/init_resque.php >${BasePath}/log/somnode/queue.log 2>&1 &
}
function StopQueue(){
echo "Stopping Queue Manager...";
PIDFILE=${BasePath}/php/queuemanager.pid
PID=`cat ${PIDFILE}`
      if (kill -0 $PID 2>/dev/null) ; then
        echo "Shutting down Queue Manager"
        if [[ "${PID}" != "" ]];then
            kill $PID
            wait_for_pid removed "$PID" "$PIDFILE" 10; return_value=$?
        fi
        PIDS=`ps aux | grep 'resque-1.2' | grep -v grep | awk '{print $2}'`
        if [[ "${PIDS}" != "" ]];then
            kill -9 ${PIDS};
        fi
      else
        echo "Queue Manager not running!"
        if [[ -f ${PIDFILE} ]]; then rm -f "$PIDFILE"; fi
      fi
}
function StatusQueue(){
PIDFILE=${BasePath}/php/queuemanager.pid
PID=`cat ${PIDFILE}`
if [ ! -f ${PIDFILE} ]; then
echo "Queue Manager is not running"
else
      if kill -0 $PID 2>/dev/null ; then
        echo "Queue Manager is running ($PID)"
      else
        echo "Queue Manager is not running"
      fi
fi
}
wait_for_pid () {
  verb="$1"
  pid="$2"
  pid_file_path="$3"
  timeout="$4"
  if [[ "${timeout}" == "" ]]; then timeout=120; fi
  i=0
  avoid_race_condition="by checking again"
  while test $i -ne ${timeout} ; do
    case "$verb" in
      'created')
        test -s "$pid_file_path" && i='' && break
        ;;
      'removed')
        test ! -s "$pid_file_path" && i='' && break
        ;;
    esac
    if test -n "$pid"; then
      if kill -0 "$pid" 2>/dev/null; then
        :
      else
        if test -n "$avoid_race_condition"; then
          avoid_race_condition=""
          continue
        fi
    if [[ -f ${pid_file_path} ]]; then rm -f ${pid_file_path}; fi
        return 1
      fi
    fi
    i=`expr $i + 1`
    sleep 1
  done
  if test -z "$i" ; then
    return 0
  else
    return 1
  fi
}
# ============================================================
# SOFTWARE VERSION DECLARATIONS
# ============================================================
nginx_version="nginx-1.22.1";
nginx_status_version="nginx-1.22.1-lua";
php_version="php-8.3.20";
php_customini="installed-20250415";
mysql_version="mysql-8.0.31-linux-glibc2.12-x86_64";
proftpd_version="proftpd-1.3.9";
proftpd_status_version="proftpd-1.3.9";
ioncube_version="14.4.0";
ioncube_php_version="8.3";
redis_version="7.0.5";
DetectOS
DetectOSMajor
if [[ "${DISTROVERSION}" == "7" ]]; then
    redis_version="5.0.5";
fi
openssl_version="openssl-1.1.1w";
# LiquidSoap
liquidsoap_version="liquidsoap-2.4.0-ocaml-4142";
liquidsoap_base_version="2.4.0";
ocaml_version="4.14.2"
# ============================================================
# WEB SERVICE INSTALLATION
# ============================================================
function INSTALLWebServiceUsers(){
groupadd somnode;
useradd -M somnode -g somnode;
}
function InstallStaticNginx(){
NGINXOK=1
    echo "Installing compiled NGINX";
    if [ -f nginx.tar.gz ]; then rm nginx.tar.gz; fi
    wget ${MIRROR}/centos/centos${DISTROVERSION}_${nginx_version}.tar.gz -O nginx.tar.gz || ( rm -f nginx.tar.gz && false );
    NGINXOK=($?);
    if [[ ${NGINXOK} -eq 0 ]]; then
        tar xf nginx.tar.gz -C ${BasePath};
        ${BasePath}/nginx/sbin/nginx -v 2>/dev/null
        NGINXOK=($?);
    fi
}
function INSTALLWebServiceNginx(){
DOMAIN=`cat ${BasePath}/somnode.domain`;
echo "WEBSERVICE Installation...";
if [ -f ${BasePath}/apache2/bin/apachectl ]; then ${BasePath}/apache2/bin/apachectl stop; fi
InstallStaticNginx
if [ ${NGINXOK} -ne 0 ]; then
    if ! pkg-config --exists libmaxminddb; then
      wget ${MIRROR}/common/libmaxminddb-1.7.1.tar.gz;
      tar xf libmaxminddb-1.7.1.tar.gz;
      cd libmaxminddb-1.7.1;
      ./configure; make; make install; ldconfig;
      cd ../;
    fi
wget ${MIRROR}/common/${nginx_version}.tar.gz;
tar xvfz ${nginx_version}.tar.gz;
cd ${nginx_version}/;
    wget ${MIRROR}/common/nginx-vod-module-1.33.tar.gz
    tar xf nginx-vod-module-1.33.tar.gz
    wget ${MIRROR}/common/ngx_http_geoip2_module-3.4.tar.gz
    tar xf ngx_http_geoip2_module-3.4.tar.gz
wget ${MIRROR}/common/luajit2-2.1-20250117.tar.gz
    tar xzf luajit2-2.1-20250117.tar.gz
    cd luajit2-2.1-20250117
    make -j${makeJobCount}
    make install PREFIX=${BasePath}/nginx/luajit
    cd ../
    wget ${MIRROR}/common/lua-nginx-module-0.10.28.tar.gz
    tar xzf lua-nginx-module-0.10.28.tar.gz;
    wget ${MIRROR}/common/ngx_devel_kit-0.3.4.tar.gz;
    tar xzf ngx_devel_kit-0.3.4.tar.gz;
    wget ${MIRROR}/common/stream-lua-nginx-module-0.0.16.tar.gz;
    tar xzf stream-lua-nginx-module-0.0.16.tar.gz;
    if pkg-config --exists libpcre2-8; then
      PCRE_FLAG=""
      LD_OPT_RGX=""
    elif pkg-config --exists libpcre; then
      PCRE_FLAG="--with-pcre"
      LD_OPT_RGX="-lpcre"
    else
      echo "No PCRE/PCRE2 dev libs found.";
      SignalAbortInstall
      return 1
    fi
    ldconfig;
    export LUAJIT_LIB=${BasePath}/nginx/luajit/lib
    export LUAJIT_INC=${BasePath}/nginx/luajit/include/luajit-2.1
    export EXTRA_CFLAGS="-Wno-error=cast-function-type"
./configure --prefix=${BasePath}/nginx \
--user=somnode \
--group=somnode \
${PCRE_FLAG} \
--with-pcre \
--with-http_ssl_module \
--with-threads \
--with-http_realip_module \
--with-file-aio \
--with-http_v2_module \
--with-http_auth_request_module \
--with-pcre-jit \
  --with-http_stub_status_module \
  --with-stream \
    --with-stream_ssl_module \
  --with-cc-opt="${EXTRA_CFLAGS}" \
    --with-ld-opt="-Wl,-rpath,${BasePath}/nginx/luajit/lib ${LD_OPT_RGX}" \
--error-log-path=log/nginx/error.log \
--http-log-path=log/nginx/access.log \
--pid-path=run/nginx.pid \
--lock-path=run/nginx.lock \
    --add-module=./nginx-vod-module-1.33 \
    --add-module=./ngx_http_geoip2_module-3.4 \
    --add-module=./ngx_devel_kit-0.3.4 \
    --add-module=./lua-nginx-module-0.10.28 \
    --add-module=./stream-lua-nginx-module-0.0.16 || SignalAbortInstall || return 1
make --jobs=${makeJobCount} || SignalAbortInstall || return 1
make install || SignalAbortInstall || return 1
    wget ${MIRROR}/common/lua-resty-core-0.1.31.tar.gz;
    tar xzf lua-resty-core-0.1.31.tar.gz;
    cd lua-resty-core-0.1.31/;
    make install PREFIX=${BasePath}/nginx
    cd ../;
    wget ${MIRROR}/common/lua-resty-lrucache-0.15.tar.gz
    tar xzf lua-resty-lrucache-0.15.tar.gz
    cd lua-resty-lrucache-0.15/;
    make install PREFIX=${BasePath}/nginx
    cd ../;
    wget ${MIRROR}/common/lua-resty-mysql-0.28.tar.gz;
    tar xzf lua-resty-mysql-0.28.tar.gz;
    cd lua-resty-mysql-0.28/;
    make install PREFIX=${BasePath}/nginx
    cd ../;
    wget ${MIRROR}/common/lua-resty-string-0.16.tar.gz;
    tar xzf lua-resty-string-0.16.tar.gz
    cd lua-resty-string-0.16/
    make install PREFIX=${BasePath}/nginx
fi
CONFIGUREWebServiceConf;
chown somnode:somnode -R ${BasePath}/htdocs/;
VersionSet nginx ${nginx_version}
VersionSet nginx_status ${nginx_status_version}
}
function RefreshNginxConf(){
mkdir -p ${BasePath}/log/nginx;
chown somnode:somnode ${BasePath}/log/nginx;
mkdir -p ${BasePath}/nginx/vod;
chown somnode:somnode ${BasePath}/nginx/vod;
if [[ -f ${BasePath}/nginx/conf/nginx.conf ]]; then rm -f ${BasePath}/nginx/conf/nginx.conf; fi
wget -O ${BasePath}/nginx/conf/nginx.conf ${SETUPPATH}/Centos/conf/somnode_nginx.conf;
if [[ -f ${BasePath}/nginx/conf/security.conf ]]; then rm -f ${BasePath}/nginx/conf/security.conf; fi
wget -O ${BasePath}/nginx/conf/security.conf ${SETUPPATH}/resources/nginx_security.conf;
if [[ -f ${BasePath}/nginx/conf/proxy_cache_settings ]]; then rm -f ${BasePath}/nginx/conf/proxy_cache_settings; fi
wget -O ${BasePath}/nginx/conf/proxy_cache_settings ${SETUPPATH}/resources/proxy_cache_settings;
if [[ -f ${BasePath}/nginx/conf/locations.conf ]]; then rm -f ${BasePath}/nginx/conf/locations.conf; fi
wget -O ${BasePath}/nginx/conf/locations.conf ${SETUPPATH}/resources/nginx_locations.conf;
if [[ "${InstallNginxRtmp}" == "y" ]] || [[ -d ${BasePath}/nginx-rtmp/ ]]; then
    wget -O ${BasePath}/nginx/conf/somnode_video_locations.conf ${SETUPPATH}/resources/somnode_video_locations.conf;
fi
echo "" > ${BasePath}/nginx/html/index.html;
}
function RefreshPHPConf(){
mkdir -p ${BasePath}/log/php;
chown somnode:somnode ${BasePath}/log/php;
PHPFPMCONF='${BasePath}/php/etc/php-fpm.conf'
PHPWWWCONF='${BasePath}/php/etc/php-fpm.d/www.conf';
PHPDIR='${BasePath}/php';
  if [[ -f ${PHPWWWCONF} ]]; then rm -f ${PHPFPMCONF}; fi
LoadResource php-fpm.conf
mv php-fpm.conf ${PHPFPMCONF};
    if [[ -f ${PHPWWWCONF} ]]; then rm -f ${PHPWWWCONF}; fi
    if [ "${systemTotalMemory}" -ge 4 ]; then
        LoadResource php-fpm-www.conf
        mv php-fpm-www.conf ${PHPWWWCONF};
else
    LoadResource php-fpm-www-low-resource.conf
    mv php-fpm-www-low-resource.conf ${PHPWWWCONF};
fi
}
function CONFIGUREWebServiceConf(){
DOMAIN=`cat ${BasePath}/somnode.domain`;
echo "Configure nginx.conf";
sleep 5;
RefreshNginxConf
if [ ! -f ${BasePath}/nginx/custom.conf ]; then touch ${BasePath}/nginx/custom.conf; fi
if [ ! -d ${BasePath}/nginx/conf.d ]; then mkdir -p ${BasePath}/nginx/conf.d; fi
AutoSSLConfigWeb
chown somnode:somnode -R ${BasePath}/nginx/;
}
function INSTALLWebService(){
SetInstallDir
rm -f /root/somnode_install/webservices/;
mkdir /root/somnode_install/webservices/;
cd /root/somnode_install/webservices/;
INSTALLWebServiceUsers;
MCPSP 10
MCPSS "Installing Nginx";
INSTALLWebServiceNginx;
MCPSP 30
MCPSS "Installing PHP";
INSTALLWebServicePHP;
MCPSP 60
MCPSS "Installing MySQL";
INSTALLMySQL;
MCPSP 70
MCPSS "Installing ProFTPD";
INSTALLProFTP;
MCPSP 80
INSTALLRedis
MCPSP 90
MCPSS "Configuring Firewall";
INSTALLFirewall;
 MCPSP 100
 SignalCompletedInstall
}
function INSTALLFirewall(){
SetInstallDir
DetectOSMajor
if [[ "${DISTROVERSION}" == "7" ]] || [[ "${DISTROVERSION}" == "8" ]] || [[ "${DISTROVERSION}" == "9" ]] || [[ "${DISTROVERSION}" == "10" ]]; then
    /usr/bin/firewall-cmd --zone=public --permanent --add-port=80/tcp
    /usr/bin/firewall-cmd --zone=public --permanent --add-port=443/tcp
    /usr/bin/firewall-cmd --zone=public --permanent --add-port=${MCPInstallPort}/tcp
    /usr/bin/firewall-cmd --zone=public --permanent --add-port=2121/tcp
    /usr/bin/firewall-cmd --zone=public --permanent --add-port=50000-51000/tcp
    /usr/bin/firewall-cmd --reload
fi
}
function SomnodeConfigFirewall(){
    echo "Configuring firewall";
    if [[ -x /usr/sbin/ufw ]]; then
      /usr/sbin/ufw allow 8000:9000/tcp
      /usr/sbin/ufw allow 18000:19000/tcp
      /usr/sbin/ufw allow 6800:7000/tcp
    fi
    if [[ -f /bin/firewall-cmd ]] && [[ `firewall-cmd --state 2>&1` == "running" ]]; then
          /usr/bin/firewall-cmd --zone=public --permanent --add-port=8000-9000/tcp
          /usr/bin/firewall-cmd --zone=public --permanent --add-port=18000-19000/tcp
          /usr/bin/firewall-cmd --zone=public --permanent --add-port=6800-7000/tcp
      /usr/bin/firewall-cmd --reload
    fi
}
SomnodeSystemSecLimits(){
  if [[ ! -f /etc/security/limits.d/somnode.conf ]]; then
    echo "somnode soft nofile 102400" > /etc/security/limits.d/somnode.conf;
  fi
}
SomnodeLogRotateConfig(){
    echo "Installing logrotate config..."
    mkdir -p ${BasePath}/log/nginx;
    mkdir -p ${BasePath}/log/nginx-rtmp;
    mkdir -p ${BasePath}/log/php;
    mkdir -p ${BasePath}/log/mysql;
    mkdir -p ${BasePath}/log/proftpd;
    mkdir -p ${BasePath}/log/autossl;
    mkdir -p ${BasePath}/log/somnode;
    chown somnode:somnode -R ${BasePath}/log/;
    LoadResource logrotate.conf /etc/logrotate.d/somnode;
}
# ============================================================
# PHP INSTALLATION
# ============================================================
function INSTALLWebServicePHP(){
DOMAIN=`cat ${BasePath}/somnode.domain`;
echo "Installing PHP...";
PHPOK=1
    if [ -f php.tar.gz ]; then rm php.tar.gz; fi
    wget ${MIRROR}/centos/centos${DISTROVERSION}_${php_version}.tar.gz -O php.tar.gz || ( rm -f php.tar.gz && false );
    PHPOK=($?);
    if [[ ${PHPOK} -eq 0 ]]; then
        tar xf php.tar.gz -C ${BasePath};
        ${BasePath}/php/bin/php -v 2>/dev/null
        PHPOK=($?);
    fi
if [ ${PHPOK} -ne 0 ]; then
wget ${MIRROR}/common/${php_version}.tar.gz;
tar xvfz ${php_version}.tar.gz;
cd ${php_version}/;
    if [[ "${DISTROVERSION}" == "9" ]] || [[ "${DISTROVERSION}" == "10" ]]; then
       if [[ ! -d ${BasePath}/openssl11/ ]]; then
         wget ${MIRROR}/common/${openssl_version}.tar.gz;
         tar xf ${openssl_version}.tar.gz;
         cd ${openssl_version};
         ./config --prefix=${BasePath}/openssl11 --openssldir=${BasePath}/openssl11 shared zlib;
         make -j${makeJobCount}; make install;
         cd ..;
       fi
       OPENSSL_FLAGS="--with-openssl=${BasePath}/openssl11"
    else
       OPENSSL_FLAGS="--with-openssl"
    fi
./configure --prefix=${BasePath}/php \
--with-mysqli \
--with-pdo-mysql \
--with-curl \
--with-gd \
--with-zlib \
--with-gettext \
--enable-bcmath \
--enable-mbstring \
--enable-zip \
--enable-fpm \
--enable-soap \
--enable-opcache \
--enable-intl \
--with-fpm-user=somnode \
--with-fpm-group=somnode \
${OPENSSL_FLAGS} || SignalAbortInstall || return 1
make --jobs=${makeJobCount} || SignalAbortInstall || return 1
make install || SignalAbortInstall || return 1
        mkdir -p ${BasePath}/php/php.d/;
        # Ioncube
        wget ${MIRROR}/common/ioncube_loaders_lin_x86-64.tar.gz;
        tar xf ioncube_loaders_lin_x86-64.tar.gz;
        cp ioncube/ioncube_loader_lin_${ioncube_php_version}.so ${BasePath}/php/lib/php/extensions/no-debug-non-zts-20230831/;
        echo "zend_extension=ioncube_loader_lin_${ioncube_php_version}.so" > ${BasePath}/php/php.d/00-ioncube.ini
        # Redis
        wget ${MIRROR}/common/phpredis-6.2.0.zip;
        unzip phpredis-6.2.0.zip;
        cd phpredis-6.2.0/;
        ${BasePath}/php/bin/phpize;
        ./configure --with-php-config=${BasePath}/php/bin/php-config;
        make -j${makeJobCount}; make install;
        echo "extension=redis.so" > ${BasePath}/php/php.d/20-redis.ini
        cd ..;
fi
RefreshPHPConf;
VersionSet php ${php_version}
}
# ============================================================
# MYSQL INSTALLATION
# ============================================================
function INSTALLMySQL(){
echo "Installing MySQL...";
cd /root/somnode_install/;
if [ -f mysql.tar.xz ]; then rm mysql.tar.xz; fi
wget ${MIRROR}/common/${mysql_version}.tar.xz -O mysql.tar.xz;
tar -xJf mysql.tar.xz;
mv ${mysql_version} ${BasePath}/mysql;
mkdir -p ${BasePath}/mysql/data;
mkdir -p ${BasePath}/log/mysql;
chown somnode:somnode -R ${BasePath}/mysql/;
chown somnode:somnode -R ${BasePath}/log/mysql;
    LoadResource mysql.cnf
    if [ "${systemTotalMemory}" -ge 16 ]; then
        LoadResource mysql-huge.cnf
        mv mysql-huge.cnf ${BasePath}/mysql/my.cnf;
    elif [ "${systemTotalMemory}" -ge 8 ]; then
        LoadResource mysql-large.cnf
        mv mysql-large.cnf ${BasePath}/mysql/my.cnf;
    elif [ "${systemTotalMemory}" -ge 4 ]; then
        LoadResource mysql-medium.cnf
        mv mysql-medium.cnf ${BasePath}/mysql/my.cnf;
    else
        mv mysql.cnf ${BasePath}/mysql/my.cnf;
    fi
${BasePath}/mysql/bin/mysqld --defaults-file=${BasePath}/mysql/my.cnf --initialize-insecure --user=somnode --basedir=${BasePath}/mysql --datadir=${BasePath}/mysql/data;
StartMysql;
sleep 10;
${BasePath}/mysql/bin/mysql --protocol=SOCKET --socket=${BasePath}/mysql/data/mysql.sock --user=root -e "CREATE DATABASE IF NOT EXISTS live_streaming;"
VersionSet mysql ${mysql_version}
}
# ============================================================
# PROFTPD INSTALLATION
# ============================================================
function INSTALLProFTP(){
echo "Installing ProFTPD...";
PROFTPDOK=1
    if [ -f proftpd.tar.gz ]; then rm proftpd.tar.gz; fi
    wget ${MIRROR}/centos/centos${DISTROVERSION}_${proftpd_version}.tar.gz -O proftpd.tar.gz || ( rm -f proftpd.tar.gz && false );
    PROFTPDOK=($?);
    if [[ ${PROFTPDOK} -eq 0 ]]; then
        tar xf proftpd.tar.gz -C ${BasePath};
        ${BasePath}/proftpd/sbin/proftpd -v 2>/dev/null
        PROFTPDOK=($?);
    fi
if [ ${PROFTPDOK} -ne 0 ]; then
wget ${MIRROR}/common/${proftpd_version}.tar.gz;
tar xvfz ${proftpd_version}.tar.gz;
cd ${proftpd_version}/;
        wget ${MIRROR}/common/proftpd-mod_vroot-0.9.12.tar.gz
        tar xf proftpd-mod_vroot-0.9.12.tar.gz
./configure --prefix=${BasePath}/proftpd \
--with-modules=mod_vroot:mod_quotatab:mod_tls:mod_exec \
--sysconfdir=${BasePath}/proftpd/etc || SignalAbortInstall || return 1
make --jobs=${makeJobCount} || SignalAbortInstall || return 1
make install || SignalAbortInstall || return 1
fi
if [[ ! -d ${BasePath}/proftpd/etc/ ]]; then mkdir -p ${BasePath}/proftpd/etc/; fi
wget -O ${BasePath}/proftpd/etc/proftpd.conf ${SETUPPATH}/Centos/conf/proftpd.conf.txt;
VersionSet proftpd ${proftpd_version}
}
# ============================================================
# REDIS INSTALLATION
# ============================================================
function INSTALLRedis(){
echo "Installing Redis...";
    wget ${MIRROR}/common/redis-${redis_version}.tar.gz;
    tar xzf redis-${redis_version}.tar.gz;
    cd redis-${redis_version};
    make -j${makeJobCount};
    mkdir -p ${BasePath}/redis/bin;
    cp src/redis-server ${BasePath}/redis/bin/;
    cp src/redis-cli ${BasePath}/redis/bin/;
    echo "port 6378" > ${BasePath}/redis/redis.conf
    echo "bind 127.0.0.1" >> ${BasePath}/redis/redis.conf
    echo "maxmemory 256mb" >> ${BasePath}/redis/redis.conf
    echo "maxmemory-policy allkeys-lru" >> ${BasePath}/redis/redis.conf
    VersionSet redis ${redis_version}
}
# ============================================================
# STREAMING SERVICE INSTALLATION
# ============================================================
function INSTALLLiquidSoap(){
    echo "Installing LiquidSoap ${liquidsoap_version}...";
    # Rebrand LiquidSoap install to Somnode
    RemoteScript ${SETUPPATH}/${DISTRO}/liquidsoap_install install;
    VersionSet liquidsoap ${liquidsoap_version}
}
function INSTALLIcecast(){
    echo "Installing Icecast...";
    RemoteScript ${SETUPPATH}/icecast install;
}
function INSTALLFFMPEG(){
    echo "Installing FFmpeg...";
    RemoteScript ${SETUPPATH}/ffmpeg install;
}
function INSTALLNginxRtmp(){
    echo "Installing SomNode Video Engine...";
    RemoteScript ${SETUPPATH}/nginxrtmp install;
}
# ============================================================
# PANEL INSTALLATION (REBRANDED)
# ============================================================
# ============================================================
# NODE.JS AND GO INSTALLATION
# ============================================================
node_version="v20.11.1";
go_version="1.22.1";

function INSTALLNode(){
    echo "Installing Node.js \...";
    cd /root/somnode_install/;
    wget https://nodejs.org/dist/\/node-\-linux-x64.tar.xz;
    tar -xJf node-\-linux-x64.tar.xz;
    mv node-\-linux-x64 \/node;
    ln -sf \/node/bin/node /usr/bin/node;
    ln -sf \/node/bin/npm /usr/bin/npm;
    ln -sf \/node/bin/npx /usr/bin/npx;
    # Install PM2 for process management
    \/node/bin/npm install pm2 -g;
    ln -sf \/node/bin/pm2 /usr/bin/pm2;
}

function INSTALLGo(){
    echo "Installing Go \...";
    cd /root/somnode_install/;
    wget https://go.dev/dl/go\.linux-amd64.tar.gz;
    tar -C \ -xzf go\.linux-amd64.tar.gz;
    mv \/go \/go_lang;
    ln -sf \/go_lang/bin/go /usr/bin/go;
}

function INSTALLPanel(){
    SetInstallDir
    echo "Deploying SomNode Next.js Panel & Go API...";
    MCPSP 10
    MCPSS "Downloading Components";
    mkdir -p \/panel;
    mkdir -p \/api_src;
    wget -O panel.zip \/somnode/panel.zip;
    wget -O api.zip \/somnode/api.zip;
    
    MCPSP 30
    MCPSS "Extracting Panel";
    unzip -q -o panel.zip -d \/panel/;
    unzip -q -o api.zip -d \/api_src/;
    
    MCPSP 50
    MCPSS "Building API";
    cd \/api_src;
    if [ -f .env.example ]; then cp .env.example .env; fi
    # Update API .env
    sed -i "s/DB_NAME=.*/DB_NAME=live_streaming/" .env
    go build -o \/api_src/somnode-api main.go;
    
    MCPSP 70
    MCPSS "Building Panel";
    cd \/panel;
    if [ -f .env.example ]; then cp .env.example .env; fi
    npm install;
    npm run build;
    
    MCPSP 90
    MCPSS "Configuring Services";
    chown -R somnode:somnode \/panel;
    chown -R somnode:somnode \/api_src;
    
    # Simple PM2 setup
    sudo -u somnode pm2 start "npm start" --name "somnode-panel" --cwd \/panel;
    sudo -u somnode pm2 start "./somnode-api" --name "somnode-api" --cwd \/api_src;
    sudo -u somnode pm2 save;
    
    MCPSP 100
    SignalCompletedInstall
}
# ============================================================
# MAIN INSTALLATION ORCHESTRATION
# ============================================================
function SomnodeInstallation(){
    DisplayHeader "SomNode Software Installation"
    echo "This script will install the SomNode software on your server.";
    echo "";
    GetDomain
    echo "Domain Name: \";
    echo "Install Path: \";
    echo "";
    if [ "\" != "1" ]; then
        echo "Press return to continue or CTRL + C to exit";
        read NULLVAR;
    fi
    # Start Log
    INSTALL_LOG="/root/somnode_install/INSTALL.log";
    rm -f \;
    touch \;
    # 1. Prerequisites
    ( INSTALLPrerequisites >> \ 2>&1 ) &
    UpdateInstallStatusScreen Install StatusInstallPrerequisites \
    # 2. Node & Go
    ( INSTALLNode >> ${INSTALL_LOG} 2>&1 ) &
    UpdateInstallStatusScreen Install StatusInstallNode ${INSTALL_LOG}
    ( INSTALLGo >> ${INSTALL_LOG} 2>&1 ) &
    UpdateInstallStatusScreen Install StatusInstallGo ${INSTALL_LOG}
    # 3. Web Service
    ( INSTALLWebService >> \ 2>&1 ) &
    UpdateInstallStatusScreen Install StatusInstallWebService \
    # 4. FFmpeg
    if [ "\" != "y" ]; then
        ( INSTALLFFMPEG >> \ 2>&1 ) &
        UpdateInstallStatusScreen Install StatusInstallFFMPEG \
    fi
    # 5. Icecast
    if [ "\" != "y" ]; then
        ( INSTALLIcecast >> \ 2>&1 ) &
        UpdateInstallStatusScreen Install StatusInstallIcecast \
    fi
    # 6. LiquidSoap
    ( INSTALLLiquidSoap >> \ 2>&1 ) &
    UpdateInstallStatusScreen Install StatusInstallLiquidSoap \
    # 7. Panel
    if [ "\" != "y" ]; then
        ( INSTALLPanel >> \ 2>&1 ) &
        UpdateInstallStatusScreen Install StatusInstallPanel \
    fi
    # 8. Finalize
    SomnodeSystemSecLimits
    SomnodeLogRotateConfig
    InstallService
    StartSomnode
    echo "";
    echo "SomNode Installation Completed!";
    echo "URL: http://\/";
    echo "";
}
# ============================================================
# MAIN ENTRY POINT
# ============================================================
function DisplayMainMenu {
echo "";
DisplayBanner;
echo "Please select an option then press return: ";
echo "";
if [ -d ${BasePath} ]; then
echo "[1] SomNode Reinstallation";
else
echo "[1] SomNode Installation";
fi
echo "[2] Exit Setup";
echo "";
read MainMenuOption;
case ${MainMenuOption} in
1)
SomnodeInstallation;
  ;;
2)
echo "Exit Setup";
exit;
  ;;
*)
  DisplayMainMenu
  ;;
esac
}
# Load input params
params=("$@")
isSilent=`echo "${params[@]}" | grep -c 'silent\|--silent'`;
isDebug=`echo "${params[@]}" | grep -c 'debug\|--debug'`;
DOMAIN=`echo "${params[@]}" | grep -oP '(?<=--domain=)[^ ]+'`;
# Check OS
IsOSSupported
if [ "${OSSupported}" == "no" ]; then
    echo "ERROR: Your operating system is not supported.";
    ListSupportedOS
    exit 1;
fi
# Start Menu or Auto Install
if [[ "${isSilent}" == "1" ]] || [[ `echo "${params[@]}" | grep -c "install"` -gt 0 ]]; then
    SomnodeInstallation;
else
    DisplayMainMenu
fi



