diff --git a/ROADMAP.md b/ROADMAP.md index 7704779..a659ab9 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -80,6 +80,17 @@ These are **not yet implemented**, but provide a development path for future rel - Medium term: Test and harden installer/uninstaller on mixed Windows environments (v3.0.0 complete, further refinements planned). - Long term: .m3u8 support, DB logs, recording functionality. +## 💻🥧 Installer Enhancement: Kiosk vs Headless Mode (Planned) +**Target Version:** v3.2.0 +**Status:** Planned +**Effort:** Medium + +- Add an interactive mode selector to the Raspberry Pi installer. +- Headless mode → install to `/home/iptv/iptv-server` with service user `iptv`. +- Kiosk mode → install to `/opt/RetroIPTVGuide` and auto-launch Chromium in fullscreen displaying RetroIPTVGuide. +- Support command-line flags: `--mode kiosk` or `--mode headless` for non-interactive installs. +- Ensure logs and services are properly separated between modes. + --- ## ✅ Completed @@ -96,7 +107,6 @@ These are **not yet implemented**, but provide a development path for future rel - [x] Basic Windows installer support (Git Bash + PowerShell bootstrap) (v2.3.0). - ## ✅ Completed (v3.0.0) - [x] Full Windows installer/uninstaller support with NSSM service, firewall rule, and Chocolatey integration (v3.0.0). - [x] Documentation updates (README.md, INSTALL.md) to reflect Windows support (v3.0.0). diff --git a/retroiptv_rpi.sh b/retroiptv_rpi.sh new file mode 100644 index 0000000..81a4fdd --- /dev/null +++ b/retroiptv_rpi.sh @@ -0,0 +1,299 @@ +#!/bin/bash +# RetroIPTVGuide Raspberry Pi Installer (Headless, Pi3/4/5) +# Installs to /home/iptv/iptv-server for consistency with Debian/Windows +# Logs to /var/log/retroiptvguide/install-YYYYMMDD-HHMMSS.log +# License: CC BY-NC-SA 4.0 + +# --- Banner --- +cat <<'EOF' +░█████████ ░██ ░██████░█████████ ░██████████░██ ░██ ░██████ ░██ ░██ +░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ +░██ ░██ ░███████ ░████████ ░██░████ ░███████ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░████████ ░███████ +░█████████ ░██ ░██ ░██ ░███ ░██ ░██ ░██ ░█████████ ░██ ░██ ░██ ░██ █████ ░██ ░██ ░██░██ ░██ ░██ ░██ +░██ ░██ ░█████████ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ██ ░██ ░██ ░██░██ ░██ ░█████████ +░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██░██ ░██ ░███ ░██ ░███ ░██░██ ░███ ░██ +░██ ░██ ░███████ ░████ ░██ ░███████ ░██████░██ ░██ ░███ ░█████░█ ░█████░██ ░██ ░█████░██ ░███████ + +EOF +echo "===========================================================================" +echo " RetroIPTVGuide | Raspberry Pi Edition (Headless)" +echo "===========================================================================" +echo "" + +set -e + +# --- Logging --- +LOG_DIR="/var/log/retroiptvguide" +TIMESTAMP=$(date +"%Y%m%d-%H%M%S") +LOG_FILE="$LOG_DIR/install-$TIMESTAMP.log" +sudo mkdir -p "$LOG_DIR" +sudo chmod 755 "$LOG_DIR" +exec > >(tee -a "$LOG_FILE") 2>&1 +echo "Log file: $LOG_FILE" +echo "" + +# --- Vars --- +APP_USER="iptv" +APP_DIR="/home/$APP_USER/iptv-server" +SERVICE_FILE="/etc/systemd/system/retroiptvguide.service" +CONFIG_FILE="/boot/config.txt" + +ACTION="$1" +AUTO_YES=false +AUTO_AGREE=false +for arg in "$@"; do + case "$arg" in + --yes|-y) AUTO_YES=true ;; + --agree|-a) AUTO_AGREE=true ;; + esac +done + +# --- Helper functions --- +set_gpu_mem() { + local val="$1" + if command -v raspi-config >/dev/null 2>&1; then + # Quietly apply GPU memory change and suppress unrelated warnings + sudo raspi-config nonint set_config_var gpu_mem "$val" "$CONFIG_FILE" 2>/dev/null || true + + # Verify it was written correctly + local current_val + current_val=$(grep -E "^gpu_mem=" "$CONFIG_FILE" 2>/dev/null | tail -n1 | cut -d'=' -f2) + if [ "$current_val" = "$val" ]; then + echo "✅ Verified: GPU memory successfully set to ${val}MB" | tee -a "$LOG_FILE" + else + echo "⚠️ Warning: Could not confirm gpu_mem=$val in $CONFIG_FILE" | tee -a "$LOG_FILE" + fi + else + # Manual fallback if raspi-config missing + sudo sed -i -E 's/^\s*gpu_mem\s*=.*/gpu_mem='"$val"'/g' "$CONFIG_FILE" 2>/dev/null || true + if ! grep -qE '^\s*gpu_mem\s*=' "$CONFIG_FILE" 2>/dev/null; then + echo "gpu_mem=$val" | sudo tee -a "$CONFIG_FILE" >/dev/null + fi + echo "✅ Fallback: gpu_mem set manually to ${val}MB" | tee -a "$LOG_FILE" + fi +} +ensure_owned_by_iptv() { sudo chown -R "$APP_USER:$APP_USER" "$APP_DIR"; } +pip_install_as_iptv() { sudo -u "$APP_USER" bash -lc "$1"; } + +#====================== INSTALL ======================# +install_app() { + echo "" + echo "============================================================" + echo " RetroIPTVGuide Raspberry Pi Headless Installer " + echo "============================================================" + echo "" + echo "This installer will perform the following actions:" + echo " - Detect Raspberry Pi model (3, 4, or newer)" + echo " - Check storage, RAM, and swap configuration" + echo " - Install dependencies (Python3, ffmpeg, etc.)" + echo " - Create system user 'iptv' (if not present)" + echo " - Clone RetroIPTVGuide into /home/iptv/iptv-server" + echo " - Configure Python virtual environment and systemd service" + echo " - Auto-configure GPU memory for headless operation" + echo " - Enable the retroiptvguide service on boot" + echo " - Optionally reboot when done" + echo "" + echo "By continuing, you agree that:" + echo " - This software should only be run on internal networks." + echo " - It must not be exposed to the public Internet." + echo " - You accept all risks; no warranty is provided." + echo "" + + if [ "$AUTO_AGREE" = true ]; then + echo "[Auto-agree] Terms accepted via --agree flag." + else + read -p "Do you agree to these terms? (yes/no): " agreement + [[ "$agreement" != "yes" ]] && echo "Installation aborted." && exit 1 + echo "Agreement accepted. Continuing..." + fi + echo "" + + # Detect Pi model + PI_MODEL=$(tr -d '\0' < /proc/device-tree/model 2>/dev/null || echo "Unknown Model") + case "$PI_MODEL" in + *"Raspberry Pi 5"*) PI_TYPE="pi5" ;; + *"Raspberry Pi 4"*) PI_TYPE="pi4" ;; + *"Raspberry Pi 3"*) PI_TYPE="pi3" ;; + *) PI_TYPE="unknown" ;; + esac + echo "Detected board: $PI_MODEL ($PI_TYPE)" + echo "" + + # Check SD card and swap + echo "Checking storage and memory..." + ROOT_DEV=$(df / | tail -1 | awk '{print $1}') + SD_SIZE=$(df -h / | awk 'NR==2 {print $2}') + MEM_TOTAL=$(awk '/MemTotal/ {print int($2/1024)}' /proc/meminfo) + SWAP_TOTAL=$(awk '/SwapTotal/ {print int($2/1024)}' /proc/meminfo) + echo "Root device: $ROOT_DEV" + echo "Storage size: $SD_SIZE" + echo "RAM: ${MEM_TOTAL}MB | Swap: ${SWAP_TOTAL}MB" + if [ "$MEM_TOTAL" -lt 1000 ] && [ "$SWAP_TOTAL" -lt 400 ]; then + echo "⚠️ Warning: <1GB RAM and <400MB swap — increase swap to 1GB for stability:" + echo " sudo dphys-swapfile swapoff && sudo sed -i 's/^CONF_SWAPSIZE=.*/CONF_SWAPSIZE=1024/' /etc/dphys-swapfile && sudo dphys-swapfile setup && sudo dphys-swapfile swapon" + fi + if df -BG / | awk 'NR==2 {exit ($2<8)}'; then + echo "⚠️ Warning: Root filesystem smaller than 8GB — limited space for logs/updates." + fi + echo "" + + # Create user if needed + if ! id "$APP_USER" &>/dev/null; then + echo "Creating user '$APP_USER'..." + sudo useradd -m -r -s /usr/sbin/nologin "$APP_USER" + fi + sudo mkdir -p "$APP_DIR" + ensure_owned_by_iptv + + # Update & deps + echo "Installing dependencies..." + sudo apt-get update -y + sudo apt-get dist-upgrade -y + sudo apt-get install -y git python3 python3-venv python3-pip ffmpeg mesa-utils v4l-utils raspi-config || true + + # Clone or update repo + if [ ! -d "$APP_DIR/.git" ]; then + sudo -u "$APP_USER" git clone https://github.com/thehack904/RetroIPTVGuide.git "$APP_DIR" + else + ( cd "$APP_DIR" && sudo -u "$APP_USER" git pull ) + fi + + # Python venv setup + if [ ! -d "$APP_DIR/venv" ]; then + sudo -u "$APP_USER" python3 -m venv "$APP_DIR/venv" + fi + pip_install_as_iptv "source '$APP_DIR/venv/bin/activate' && pip install --upgrade pip" + if [ -f "$APP_DIR/requirements.txt" ]; then + pip_install_as_iptv "source '$APP_DIR/venv/bin/activate' && pip install -r '$APP_DIR/requirements.txt'" + else + pip_install_as_iptv "source '$APP_DIR/venv/bin/activate' && pip install Flask" + fi + sudo -u "$APP_USER" mkdir -p "$APP_DIR/data" || true + + # GPU memory by model + echo "Configuring GPU memory..." + case "$PI_TYPE" in + pi4|pi5) set_gpu_mem 256 ;; + pi3|*) set_gpu_mem 128 ;; + esac + + # systemd service + echo "Creating systemd service..." + sudo tee "$SERVICE_FILE" >/dev/null </dev/null 2>&1; then + echo "✅ Web interface responding on port 5000 (after ${wait_time}s)." + echo "✅ Verified: HTTP response received." | tee -a "$LOG_FILE" + break + fi + sleep 2 + wait_time=$((wait_time+2)) + done + if [ $wait_time -ge $max_wait ]; then + echo "⚠️ Service active, but no HTTP response after ${max_wait}s. Check logs in $LOG_FILE." + echo "⚠️ Possible slow startup on first run (SQLite or dependencies still initializing)." | tee -a "$LOG_FILE" + fi + else + echo "❌ Service not active. Run: sudo systemctl status retroiptvguide" + fi + echo "" + + + # Optional reboot + if [ "$AUTO_YES" = false ]; then + read -t 10 -p "Reboot now to apply GPU memory? (Y/n, default Y in 10s): " R || R="Y" + R=${R:-Y} + if [[ "$R" =~ ^[Yy]$ ]]; then + echo "Rebooting..." + sleep 2 + sudo reboot + else + echo "Reboot skipped. Run 'sudo reboot' later if GPU memory changed." + fi + fi +} + +#====================== UNINSTALL ======================# +uninstall_app() { + echo "" + echo "============================================================" + echo " RetroIPTVGuide Uninstaller (Headless) " + echo "============================================================" + + if [ "$AUTO_YES" = false ]; then + read -p "Proceed with uninstallation? (yes/no): " c + [[ "$c" != "yes" ]] && echo "Aborted." && exit 1 + fi + + systemctl stop retroiptvguide 2>/dev/null || true + systemctl disable retroiptvguide 2>/dev/null || true + [ -f "$SERVICE_FILE" ] && sudo rm -f "$SERVICE_FILE" && sudo systemctl daemon-reload + + if [ -d "$APP_DIR" ]; then + if [ "$AUTO_YES" = true ]; then + sudo rm -rf "$APP_DIR" + echo "Removed $APP_DIR" + else + read -p "Delete $APP_DIR? (yes/no): " d + [[ "$d" == "yes" ]] && sudo rm -rf "$APP_DIR" && echo "Removed $APP_DIR" + fi + fi + + echo "" + echo "Uninstallation complete. End time: $(date)" + echo "Log file: $LOG_FILE" + echo "" +} + +#====================== MAIN ======================# +case "$ACTION" in + install) install_app ;; + uninstall) uninstall_app ;; + *) + echo "Usage: sudo $0 install|uninstall [--yes|-y] [--agree|-a]" + exit 1 + ;; +esac