#!/usr/bin/env bash # install_for_python - Radio automation installer for Linux Mint 22.3 # # Installs the liquidsoap-based radio automation stack: # - Creates the 'liquidsoap' system user # - Prompts for storage path, Icecast credentials, gpodder.net credentials # - Generates config.json from the answers # - Sets up directory structure under / # - Ensures SQLite databases exist with correct schema # - Installs JRuby gems (sequel, jdbc-sqlite3, nokogiri, json) one at a time # - Writes the self-locating run_radio.sh launcher # - Installs crontab entries (as liquidsoap) for periodic fetch + update # - Optionally enables the systemd service # # Usage: sudo ./install_for_python set -euo pipefail # --------------------------------------------------------------------------- # Derive service name from containing directory name # --------------------------------------------------------------------------- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SERVICE_NAME="$(basename "$SCRIPT_DIR")" SYSTEMD_UNIT="/etc/systemd/system/${SERVICE_NAME}.service" echo "=== ${SERVICE_NAME} Installer ===" echo # --------------------------------------------------------------------------- # Root check # --------------------------------------------------------------------------- if [[ $EUID -ne 0 ]]; then echo "ERROR: Please run as root (sudo)." >&2 exit 1 fi # --------------------------------------------------------------------------- # Create liquidsoap system user if missing # --------------------------------------------------------------------------- if ! id -u liquidsoap >/dev/null 2>&1; then echo "Creating system user 'liquidsoap'..." useradd --system --create-home --shell /usr/sbin/nologin liquidsoap echo "Done." else echo "User 'liquidsoap' already exists." fi # --------------------------------------------------------------------------- # Prompt for configuration values # --------------------------------------------------------------------------- echo read -rp "Station data directory [/mnt/storage/radio]: " STORAGE STORAGE="${STORAGE:-/mnt/storage/radio}" read -rp "Icecast host [192.168.0.200]: " ICECAST_HOST ICECAST_HOST="${ICECAST_HOST:-192.168.0.200}" read -rp "Icecast source port [7777]: " ICECAST_PORT ICECAST_PORT="${ICECAST_PORT:-7777}" read -rp "Icecast mount point [/data]: " ICECAST_MOUNT ICECAST_MOUNT="${ICECAST_MOUNT:-/data}" read -rp "Icecast source username [source]: " SOURCE_USER SOURCE_USER="${SOURCE_USER:-source}" read -rsp "Icecast source password: " SOURCE_PASS echo GPODDER_ENABLE="" until [[ "$GPODDER_ENABLE" =~ ^[YyNn]$ ]]; do read -rp "Enable gPodder.net sync? [y/N]: " GPODDER_ENABLE done GPODDER_ENABLED=false [[ "$GPODDER_ENABLE" =~ ^[Yy]$ ]] && GPODDER_ENABLED=true GPODDER_HOST="gpodder.net" GPODDER_USER="" GPODDER_PASS="" if [[ "$GPODDER_ENABLED" == true ]]; then read -rp "gPodder.net host [gpodder.net]: " GPODDER_HOST_IN GPODDER_HOST="${GPODDER_HOST_IN:-gpodder.net}" read -rp "gPodder.net username: " GPODDER_USER read -rsp "gPodder.net password: " GPODDER_PASS echo fi # --------------------------------------------------------------------------- # Create directory structure # --------------------------------------------------------------------------- echo echo "Creating directory structure under ${STORAGE} ..." mkdir -p "${STORAGE}"/{state,podcasts,music,jingles,announcements,playlists,logs} chown -R liquidsoap:liquidsoap "${STORAGE}" chmod -R u+rwX,g+rwX,o+rX "${STORAGE}" echo "Done." # --------------------------------------------------------------------------- # Generate config.json # --------------------------------------------------------------------------- CONFIG_FILE="${SCRIPT_DIR}/config.json" cat > "$CONFIG_FILE" < gem install ${gem_name} ${extra_args[*]}" sudo -u liquidsoap bash -c " export GEM_HOME=${GEMS_HOME} export GEM_PATH=${GEMS_HOME}:/opt/jruby/lib/ruby/gems/shared ${GEM_BIN} install ${gem_name} ${extra_args[*]} --no-document " || echo " WARNING: failed to install ${gem_name}" } # Core persistence install_gem "sequel" install_gem "jdbc-sqlite3" # XML parsing. Pure-Java build under JRuby (--platform java) bundles # Xerces/NekoHTML/Xalan as JARs; no libxml2-dev or compiler required. install_gem "nokogiri" "--platform" "java" # Convenience JSON (usually stdlib, but ensure availability) install_gem "json" echo "JRUBY DEPENDENCIES COMPLETE" else echo echo "WARNING: ${JRUBY_BIN} not found; skipping JRuby gem installation." echo " Install JRuby manually, then re-run this installer or run:" echo " sudo -u liquidsoap ${GEM_BIN} install sequel jdbc-sqlite3 json" echo " sudo -u liquidsoap ${GEM_BIN} install nokogiri --platform java" fi # --------------------------------------------------------------------------- # Self-locating launcher (sets GEM_HOME/GEM_PATH before JRuby boots) # --------------------------------------------------------------------------- LAUNCHER="${SCRIPT_DIR}/run_radio.sh" cat > "$LAUNCHER" <<'LAUNCH_EOF' #!/usr/bin/env bash # run_radio.sh - self-locating JRuby launcher for the radio automation scripts. # Exports GEM_HOME/GEM_PATH BEFORE jruby boots, because mutating them inside a # running JRuby process does not reliably affect gem resolution (JRuby #5269). # # Usage: ./run_radio.sh [args...] set -euo pipefail SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" GEMS_HOME="${SELF_DIR}/.gems" JRUBY_HOME="/opt/jruby" export GEM_HOME="${GEMS_HOME}" export GEM_PATH="${GEMS_HOME}:${JRUBY_HOME}/lib/ruby/gems/shared" exec "${JRUBY_HOME}/bin/jruby" "${SELF_DIR}/$@" LAUNCH_EOF chmod +x "$LAUNCHER" chown liquidsoap:liquidsoap "$LAUNCHER" echo "Wrote ${LAUNCHER}" # Make the Ruby scripts executable for rb in "${SCRIPT_DIR}"/*.rb; do [[ -f "$rb" ]] && chmod +x "$rb" && chown liquidsoap:liquidsoap "$rb" done # --------------------------------------------------------------------------- # Crontab entries (installed into liquidsoap's crontab, not root's) # --------------------------------------------------------------------------- CRON_FETCH="*/30 * * * * cd ${SCRIPT_DIR} && ./run_radio.sh fetch_podcasts.rb >> ${STORAGE}/logs/cron_fetch.log 2>&1" CRON_UPDATE="15 * * * * cd ${SCRIPT_DIR} && ./run_radio.sh update_playlists.rb >> ${STORAGE}/logs/cron_update.log 2>&1" echo echo "Installing crontab entries for user 'liquidsoap'..." ( crontab -l -u liquidsoap 2>/dev/null || true ) | grep -vF "run_radio.sh" | \ { cat; echo "$CRON_FETCH"; echo "$CRON_UPDATE"; } | crontab -u liquidsoap - echo "Crontab updated." # --------------------------------------------------------------------------- # Optional systemd service # --------------------------------------------------------------------------- ENABLE_SERVICE="" until [[ "$ENABLE_SERVICE" =~ ^[YyNn]$ ]]; do read -rp "Enable ${SERVICE_NAME} systemd service now? [y/N]: " ENABLE_SERVICE done if [[ "$ENABLE_SERVICE" =~ ^[Yy]$ ]]; then echo echo "Writing ${SYSTEMD_UNIT} ..." cat > "$SYSTEMD_UNIT" <" echo " sudo -u liquidsoap ./run_radio.sh update_playlists.rb" echo "=============================================="