Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add flac stream again #30

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The system design involves delivering the broadcast through two pathways. Liquid
## Scripts
- **icecast2.sh**: This script installs Icecast 2 and provides SSL support via Let's Encrypt/Certbot. Execute it using `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/oszuidwest/zwfm-liquidsoap/main/icecast2.sh)"`
- **install.sh**: Installs Liquidsoap 2.2.5 with fdkaac support and sets it up as an auto-start service. Execute it using `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/oszuidwest/zwfm-liquidsoap/main/install.sh)"`
- **monitor.sh**: Experimental log parser/dashboard for Liquidsoap status. Not installed by default. Work in progress.

## Configurations
- **radio.liq**: A production-ready Liquidsoap configuration that incorporates StereoTool as a MicroMPX encoder.
Expand Down
4 changes: 2 additions & 2 deletions icecast2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ EOF

# Configure environment
set_colors
are_we_root
check_user_privileges privileged
is_this_linux
is_this_os_64bit
set_timezone Europe/Amsterdam
Expand Down Expand Up @@ -61,7 +61,7 @@ cat <<EOF > "$ICECAST_XML"
<limits>
<clients>1000</clients>
<sources>10</sources>
<burst-size>65536</burst-size>
<burst-size>265536</burst-size>
</limits>

<authentication>
Expand Down
116 changes: 77 additions & 39 deletions install.sh
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
#!/usr/bin/env bash

# Set-up the functions library
# Load functions library
FUNCTIONS_LIB_PATH="/tmp/functions.sh"
FUNCTIONS_LIB_URL="https://raw.githubusercontent.com/oszuidwest/bash-functions/main/common-functions.sh"

# Set-up Liquidsoap
# Liquidsoap configuration
LIQUIDSOAP_VERSION="2.2.5"
LIQUIDSOAP_PACKAGE_BASE_URL="https://github.com/savonet/liquidsoap/releases/download/v$LIQUIDSOAP_VERSION"
LIQUIDSOAP_CONFIG_URL="https://raw.githubusercontent.com/oszuidwest/zwfm-liquidsoap/main/radio.liq"
LIQUIDSOAP_SERVICE_URL="https://raw.githubusercontent.com/oszuidwest/zwfm-liquidsoap/main/liquidsoap.service"
AUDIO_FALLBACK_URL="https://upload.wikimedia.org/wikipedia/commons/6/66/Aaron_Dunn_-_Sonata_No_1_-_Movement_2.ogg"

# Set-up StereoTool
STEREOTOOL_VERSION="1021"
# StereoTool configuration
STEREOTOOL_VERSION="1040"
STEREOTOOL_BASE_URL="https://download.thimeo.com"

# General options
# General settings
SUPPORTED_OS=("bookworm" "jammy")
TIMEZONE="Europe/Amsterdam"
DIRECTORIES=("/etc/liquidsoap" "/var/audio")

# Remove old functions library and download the latest version
# Download the latest version of the functions library
rm -f "$FUNCTIONS_LIB_PATH"
if ! curl -sLo "$FUNCTIONS_LIB_PATH" "$FUNCTIONS_LIB_URL"; then
if ! curl -sLo "$FUNCTIONS_LIB_PATH" "$FUNCTIONS_LIB_URL"; then
echo -e "*** Failed to download functions library. Please check your network connection! ***"
exit 1
fi

# Source the functions file
# Source the functions library
# shellcheck source=/tmp/functions.sh
source "$FUNCTIONS_LIB_PATH"

# Basic environment configuration
# Environment setup
set_colors
are_we_root
check_user_privileges privileged
is_this_linux
is_this_os_64bit
set_timezone "$TIMEZONE"
Expand All @@ -48,10 +48,8 @@ if [[ ! " ${SUPPORTED_OS[*]} " =~ ${os_version} ]]; then
exit 1
fi

# Start with a clean terminal
# Clear the terminal and display the banner
clear

# Banner
cat << "EOF"
______ _ ___ __ _ ______ __ __
|___ / (_) | \ \ / / | | | ____| \/ |
Expand All @@ -61,72 +59,112 @@ cat << "EOF"
/_____\__,_|_|\__,_| \/ \/ \___||___/\__| |_| |_| |_|
EOF

# Greeting
echo -e "${GREEN}⎎ Liquidsoap and StereoTool setup${NC}\n\n"
# Greeting and user input
echo -e "${GREEN}⎎ Liquidsoap and StereoTool setup${NC}\n"
ask_user "USE_ST" "n" "Do you want to use StereoTool for sound processing? (y/n)" "y/n"
ask_user "DO_UPDATES" "y" "Do you want to perform all OS updates? (y/n)" "y/n"

# OS-specific configurations for Debian Bookworm
# Configure repositories on Debian Bookworm
if [ "$os_version" == "bookworm" ]; then
install_packages silent software-properties-common
apt-add-repository -y non-free

# Identify deb822 format source files
deb822_files=()
readarray -d '' deb822_files < <(find /etc/apt/sources.list.d/ -type f -name "*.sources" -print0)

if [ "${#deb822_files[@]}" -gt 0 ]; then
echo -e "${BLUE}►► Adding 'contrib' and 'non-free' components to the sources list (deb822 format)...${NC}"
for source_file in "${deb822_files[@]}"; do
# Remove trailing null character from filename
source_file="${source_file%$'\0'}"

# Modify Debian repository sources to include 'contrib', 'non-free', and 'non-free-firmware'
if grep -qE '^Types:.*deb' "$source_file" && \
grep -qE "^Suites:.*$os_version" "$source_file" && \
grep -qE '^Components:.*main' "$source_file"; then
backup_file "$source_file"
sed -i '/^Components:/ {
/contrib/! s/$/ contrib/;
/non-free/! s/$/ non-free/;
/non-free-firmware/! s/$/ non-free-firmware/;
}' "$source_file"
fi
done
else
echo -e "${BLUE}►► Adding 'non-free' component using apt-add-repository...${NC}"
apt-add-repository -y contrib non-free non-free-firmware
fi
apt update
fi

# Update OS
# Perform OS updates if requested
if [ "$DO_UPDATES" == "y" ]; then
update_os silent
fi

# Liquidsoap installation
# Install Liquidsoap dependencies
install_packages silent fdkaac libfdkaac-ocaml libfdkaac-ocaml-dynlink

# Install Liquidsoap
echo -e "${BLUE}►► Installing Liquidsoap...${NC}"
package_url="${LIQUIDSOAP_PACKAGE_BASE_URL}/liquidsoap_${LIQUIDSOAP_VERSION}-${os_id}-${os_version}-1_${os_arch}.deb"
liquidsoap_package="/tmp/liquidsoap_${LIQUIDSOAP_VERSION}.deb"
curl -sLo "$liquidsoap_package" "$package_url"
curl -sLo "$liquidsoap_package" "$package_url"
apt -qq -y install "$liquidsoap_package" --fix-broken

# Directory setup
# Verify Liquidsoap installation
if ! command -v liquidsoap >/dev/null 2>&1; then
echo -e "${RED}*** Error: Liquidsoap installation failed. Exiting. ***${NC}"
exit 1
fi

# Create necessary directories
echo -e "${BLUE}►► Creating directories...${NC}"
for dir in "${DIRECTORIES[@]}"; do
mkdir -p "$dir" && chown liquidsoap:liquidsoap "$dir" && chmod g+s "$dir"
mkdir -p "$dir"
chown liquidsoap:liquidsoap "$dir"
chmod g+s "$dir"
done

# Download configuration and sample files
echo -e "${BLUE}►► Downloading files...${NC}"
curl -sLo /var/audio/fallback.ogg "$AUDIO_FALLBACK_URL"
curl -sLo /etc/liquidsoap/radio.liq "$LIQUIDSOAP_CONFIG_URL"
# Backup existing configuration and download new configuration files
backup_file "/etc/liquidsoap/radio.liq"
echo -e "${BLUE}►► Downloading configuration files...${NC}"
curl -sLo /var/audio/fallback.ogg "$AUDIO_FALLBACK_URL"
curl -sLo /etc/liquidsoap/radio.liq "$LIQUIDSOAP_CONFIG_URL"

# StereoTool setup
# Install and configure StereoTool if selected
if [ "$USE_ST" == "y" ]; then
install_packages silent unzip
echo -e "${BLUE}►► Installing StereoTool...${NC}"
mkdir -p /opt/stereotool
curl -sLo /tmp/st.zip "${STEREOTOOL_BASE_URL}/Stereo_Tool_Generic_plugin_${STEREOTOOL_VERSION}.zip"
curl -sLo /tmp/st.zip "${STEREOTOOL_BASE_URL}/Stereo_Tool_Generic_plugin_${STEREOTOOL_VERSION}.zip"
unzip -o /tmp/st.zip -d /tmp/
extracted_dir=$(find /tmp/* -maxdepth 0 -type d -print0 | xargs -0 ls -td | head -n 1)

if [ "$os_arch" == "amd64" ]; then
cp "${extracted_dir}/lib/Linux/IntelAMD/64/libStereoToolX11_intel64.so" /opt/stereotool/st_plugin.so
curl -sLo /opt/stereotool/st_standalone "${STEREOTOOL_BASE_URL}/stereo_tool_cmd_64_${STEREOTOOL_VERSION}"
curl -sLo /opt/stereotool/st_standalone "${STEREOTOOL_BASE_URL}/stereo_tool_cmd_64_${STEREOTOOL_VERSION}"
elif [ "$os_arch" == "arm64" ]; then
cp "${extracted_dir}/lib/Linux/ARM/64/libStereoTool_arm64.so" /opt/stereotool/st_plugin.so
curl -sLo /opt/stereotool/st_standalone "${STEREOTOOL_BASE_URL}/stereo_tool_pi2_64_${STEREOTOOL_VERSION}"
curl -sLo /opt/stereotool/st_standalone "${STEREOTOOL_BASE_URL}/stereo_tool_pi2_64_${STEREOTOOL_VERSION}"
fi
chmod +x /opt/stereotool/st_standalone

# Generate and patch StereoTool config file
# Backup, generate and patch StereoTool settings file
backup_file "/etc/liquidsoap/st.ini"
/opt/stereotool/st_standalone -X /etc/liquidsoap/st.ini
sed -i 's/^\(Whitelist=\).*$/\1\/0/' /etc/liquidsoap/st.ini
sed -i 's/^\(Enable web interface=\).*$/\11/' /etc/liquidsoap/st.ini
else
# If StereoTool is not used, remove its configuration from the liquidsoap script
# Remove StereoTool configuration from Liquidsoap script if not used
sed -i '/# StereoTool implementation/,/output.dummy(radioproc)/d' /etc/liquidsoap/radio.liq
fi

# Liquidsoap service installation
echo -e "${BLUE}►► Setting up Liquidsoap service${NC}"
# Set up Liquidsoap as a system service
echo -e "${BLUE}►► Setting up Liquidsoap service...${NC}"
rm -f /etc/systemd/system/liquidsoap.service
curl -sLo /etc/systemd/system/liquidsoap.service "$LIQUIDSOAP_SERVICE_URL"
curl -sLo /etc/systemd/system/liquidsoap.service "$LIQUIDSOAP_SERVICE_URL"
systemctl daemon-reload
if ! systemctl is-enabled liquidsoap.service; then
systemctl enable liquidsoap.service
fi
systemctl enable liquidsoap.service

echo -e "${GREEN}Setup completed successfully!${NC}"
141 changes: 141 additions & 0 deletions monitor.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#!/bin/bash

# Monitor Script for /var/log/liquidsoap/radio.log
# Displays current on air source and status of studio_a and studio_b.
# Status includes whether connected with audio playing or silent.
# Refreshes every second without leaving residual characters on the screen.

# Path to the log file
LOG_FILE="/var/log/liquidsoap/radio.log"

# Check if the log file exists and is readable
if [[ ! -f "$LOG_FILE" ]]; then
echo "Error: Log file '$LOG_FILE' does not exist."
exit 1
fi

if [[ ! -r "$LOG_FILE" ]]; then
echo "Error: Log file '$LOG_FILE' is not readable."
exit 1
fi

# Function to extract the current on air source
get_current_on_air() {
# Extract the last radio_prod switch event
# Example lines:
# 2024/09/14 19:27:21 [radio_prod:3] Switch to noodband.
# 2024/09/14 19:27:46 [radio_prod:3] Switch to buffered_studio_a with transition.

# Declare the variable
local on_air
# Assign the value
on_air=$(grep 'radio_prod:3] Switch to' "$LOG_FILE" | tail -1 | \
awk -F 'Switch to ' '{print $2}' | \
sed -e 's/ with.*//' -e 's/\.$//')
echo "${on_air:-Unknown}"
}

# Function to extract and map the latest status of a studio
get_studio_status() {
local studio="$1"
# Possible statuses: connected, disconnected, silence detected, audio resumed

# Declare the variable
local last_event
# Assign the value
last_event=$(grep "lang:3] ${studio}" "$LOG_FILE" | \
grep -E 'connected|disconnected|silence detected|audio resumed' | \
tail -1 | \
awk -F "lang:3] ${studio} " '{print $2}')

# Map the last event to the desired status
case "$last_event" in
"connected")
echo "Connected (audio playing)"
;;
"silence detected")
echo "Connected (silent)"
;;
"audio resumed")
echo "Connected (audio playing)"
;;
"disconnected")
echo "Disconnected"
;;
*)
echo "Unknown"
;;
esac
}

# Color codes for enhanced readability
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Clear the screen once at the start
clear

# Infinite loop to refresh every second
while true; do
# Fetch current on air source
CURRENT_ON_AIR=$(get_current_on_air)

# Fetch studio statuses
STUDIO_A_STATUS=$(get_studio_status "studio_a")
STUDIO_B_STATUS=$(get_studio_status "studio_b")

# Color-coding for studio_a
case "$STUDIO_A_STATUS" in
"Connected (audio playing)")
STUDIO_A_DISPLAY="${GREEN}$STUDIO_A_STATUS${NC}"
;;
"Connected (silent)")
STUDIO_A_DISPLAY="${YELLOW}$STUDIO_A_STATUS${NC}"
;;
"Disconnected")
STUDIO_A_DISPLAY="${RED}$STUDIO_A_STATUS${NC}"
;;
*)
STUDIO_A_DISPLAY="$STUDIO_A_STATUS"
;;
esac

# Color-coding for studio_b
case "$STUDIO_B_STATUS" in
"Connected (audio playing)")
STUDIO_B_DISPLAY="${GREEN}$STUDIO_B_STATUS${NC}"
;;
"Connected (silent)")
STUDIO_B_DISPLAY="${YELLOW}$STUDIO_B_STATUS${NC}"
;;
"Disconnected")
STUDIO_B_DISPLAY="${RED}$STUDIO_B_STATUS${NC}"
;;
*)
STUDIO_B_DISPLAY="$STUDIO_B_STATUS"
;;
esac

# Clear the screen before displaying new information
clear

# Display the information
echo "==================== Radio Station Status ===================="
echo "Timestamp: $(date '+%Y/%m/%d %H:%M:%S')"
echo ""
echo "Current On Air: $CURRENT_ON_AIR"
echo ""
echo "Studio Statuses:"
echo -e " studio_a: $STUDIO_A_DISPLAY"
echo -e " studio_b: $STUDIO_B_DISPLAY"
echo "==============================================================="

# Optional: Log the status to a file
# LOG_OUTPUT="/var/log/liquidsoap/status_monitor.log"
# echo "$(date '+%Y/%m/%d %H:%M:%S') - On Air: $CURRENT_ON_AIR | studio_a: $STUDIO_A_STATUS | studio_b: $STUDIO_B_STATUS" >> "$LOG_OUTPUT"

# Wait for 1 second before refreshing
sleep 1
done
Loading