diff --git a/CHANGELOG.md b/CHANGELOG.md index e31a247..1e392c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,34 @@ This project follows [Semantic Versioning](https://semver.org/). --- +## [3.0.0] - 2025-10-03 +### Added +- **Windows Support**: + - New `install_windows.ps1` and `install.bat` for automated setup. + - New `uninstall_windows.ps1` and `uninstall.bat` for clean removal. + - NSSM service created to run `venv\Scripts\python.exe app.py` automatically. + - Windows installer bootstraps Chocolatey, installs `python`, `git`, and `nssm`. + - Windows uninstaller removes the service, deletes firewall rule for port 5000, and lists remaining Chocolatey packages (with option to remove all). +- **Cross-platform Installer Enhancements**: + - `install.sh` improved to detect Linux, WSL, or Git Bash environments. + - Added pip upgrade check instead of always forcing upgrade. + - Unified handling of venv paths for Linux (`bin/`) and Windows (`Scripts/`). +- **bump_version.py**: + - Now also updates `install_windows.ps1`, `uninstall_windows.ps1`, and `uninstall.sh`. + - Automatically inserts `APP_VERSION`/`VERSION` if missing. + +### Changed +- **Documentation**: + - Updated `README.md` with Windows one-liner install. + - Updated `INSTALL.md` with new Windows instructions and update steps. +- **Uninstall Scripts**: + - Windows uninstall output cleaned to avoid duplicate Chocolatey lists. + - Linux/WSL uninstall script improved to fully remove `iptv-server` systemd service and venv. + +### Fixed +- Consistent logging of user agreement and installer actions. +- Ensured firewall rule removal on Windows during uninstall. + ## [2.3.2] - 2025-09-26 ### Added - Introduced unified **Themes submenu** (Light, Dark, AOL/CompuServe, TV Guide Magazine) across all admin and user pages. diff --git a/INSTALL.md b/INSTALL.md index f55b522..c0891a3 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,25 +1,27 @@ # Installation Guide ## Requirements -- Python 3.10+ -- Linux (Debian/Ubuntu with systemd) **or** Windows (Git Bash with Python 3.12+) +- Python 3.10+ (Linux) / Python 3.12+ (Windows) +- **Linux (Debian/Ubuntu with systemd)** or **Windows 10/11** - Administrative privileges: - **Linux/WSL:** run install/uninstall with `sudo` - - **Windows (Git Bash):** run from an Administrator shell + - **Windows:** run from an Administrator **PowerShell** session --- ## Installation -Clone the repository and run the installer (choose one, no need to do both below) +Clone the repository and run the installer. Choose the command based on your OS. -### Option 1: One-liner (quick setup) +### Linux / WSL + +#### Option 1: One-liner (quick setup) ```bash git clone https://github.com/thehack904/RetroIPTVGuide.git && cd RetroIPTVGuide && sudo chmod +x install.sh && sudo ./install.sh ``` or -### Option 2: Multi-line (step-by-step) +#### Option 2: Multi-line (step-by-step) ```bash git clone https://github.com/thehack904/RetroIPTVGuide.git cd RetroIPTVGuide @@ -27,18 +29,43 @@ sudo chmod +x install.sh sudo ./install.sh ``` -### What the installer does -- Detects environment (Linux, WSL, or Git Bash on Windows) -- Creates a system user `iptv` and sets up systemd service (Linux/WSL only) -- Installs into `/home/iptv/iptv-server` (Linux/WSL) or local project folder (Windows) -- Creates Python virtual environment + installs dependencies -- Logs the full install process to `install_YYYY-MM-DD_HH-MM-SS.log` +**What the installer does (Linux/WSL):** +- Detects Linux/WSL environment +- Ensures script is run with sudo +- Creates a system user `iptv` +- Installs into `/home/iptv/iptv-server` +- Ensures `python3-venv` is installed +- Creates Python virtual environment and installs dependencies +- Creates and enables the `iptv-server` systemd service +- Starts the service +- Logs the install to `install_YYYY-MM-DD_HH-MM-SS.log` + +--- + +### Windows 10/11 + +Run this one-liner from an **Administrator PowerShell** prompt: + +```powershell +Invoke-WebRequest https://github.com/thehack904/RetroIPTVGuide/archive/refs/heads/main.zip -OutFile RetroIPTVGuide.zip ; tar -xf RetroIPTVGuide.zip ; cd RetroIPTVGuide-windows ; .\install.bat +``` + +**What the installer does (Windows):** +- Bootstraps Chocolatey (if missing) +- Installs dependencies: `python`, `git`, `nssm` +- Registers Windows App Paths for `python` / `python3` +- Adds Python to Git Bash (`~/.bashrc`) +- Clones RetroIPTVGuide and runs `install.sh` under Git Bash to set up venv + requirements +- Creates an NSSM service to run `venv\Scripts\python.exe app.py` +- Opens Windows Firewall port 5000 +- Starts the RetroIPTVGuide service +- Logs the install to `install_YYYY-MM-DD_HH-MM-SS.log` --- ## Access -Once installed, access the guide in your browser: +Once installed, open your browser: ``` http://:5000 @@ -48,17 +75,17 @@ Default login: **admin / strongpassword123** --- -## Updating +## 🔄 Updating -### Linux/WSL +### Linux / WSL -#### Option 1: One-liner (quick update) +#### Quick update (one-liner) ```bash sudo -u iptv bash -H -c "cd /home/iptv/iptv-server && git fetch --all && git reset --hard origin/main" && sudo systemctl restart iptv-server.service ``` or -#### Option 2: Step-by-step +#### Step-by-step ```bash sudo -u iptv bash -H cd /home/iptv/iptv-server @@ -70,47 +97,59 @@ sudo systemctl restart iptv-server.service --- -### Windows (Git Bash) +### Windows 10/11 -Run these from the folder where you cloned the repo: +From an **Administrator PowerShell** prompt, go to your RetroIPTVGuide folder and run: -#### Option 1: One-liner -```bash -git fetch --all && git reset --hard origin/main && ./venv/Scripts/python app.py +```powershell +git fetch --all ; git reset --hard origin/main ; Restart-Service RetroIPTVGuide ``` - or -#### Option 2: Step-by-step -```bash +#### Step-by-step +```powershell git fetch --all git reset --hard origin/main -./venv/Scripts/python app.py +Restart-Service RetroIPTVGuide ``` +This will: +- Fetch the latest code from GitHub +- Reset your repo to the latest `windows` branch +- Restart the RetroIPTVGuide service (installed via NSSM) + --- ## Uninstallation -Run the included `uninstall.sh`: - +### Linux / WSL ```bash sudo chmod +x uninstall.sh sudo ./uninstall.sh ``` -### What the uninstaller does -- **Linux/WSL:** - - Stops and disables the systemd service - - Removes the systemd unit file - - Deletes the `iptv` system user and related logs - - Removes the Python virtual environment -- **Windows (Git Bash):** - - Stops any running `python app.py` process - - Removes the Python virtual environment - - Leaves the project folder in place - -âš ī¸ To completely remove the project, **manually delete the project folder** after running `uninstall.sh`. +**What the uninstaller does (Linux/WSL):** +- Stops and disables the systemd service +- Removes the systemd unit file +- Deletes the `iptv` system user and related logs +- Removes the Python virtual environment + +--- + +### Windows +From an Administrator PowerShell prompt: +```powershell +.\uninstall_windows.ps1 +``` + +**What the uninstaller does (Windows):** +- Stops and removes the NSSM service +- Removes the Python virtual environment +- Deletes the Windows Firewall rule (port 5000) +- Lists remaining Chocolatey packages +- Prompts whether to uninstall **all Chocolatey packages (including Chocolatey itself)** + +âš ī¸ To completely remove the project, manually delete the project folder after uninstalling. --- diff --git a/README.md b/README.md index 424e170..e11d6d2 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,18 @@ # RetroIPTVGuide -![Version](https://img.shields.io/badge/version-v2.3.2-blue) +![Version](https://img.shields.io/badge/version-v3.0.0-blue) RetroIPTVGuide is an IPTV Web Interface inspired by 90s/2000s cable TV guides. It is designed to work with [ErsatzTV](https://ersatztv.org/) [(GitRepo)](https://github.com/ErsatzTV/ErsatzTV/tree/main) but should support any `.m3u` and `.xml` IPTV source. -âš ī¸ **Note:** This is an initial BETA release. It is not recommended for direct Internet/public-facing deployments. +âš ī¸ **Note:** This is still a BETA release. It is not recommended for direct Internet/public-facing deployments. - [Installation / Uninstall Guide](INSTALL.md) - [Changelog](CHANGELOG.md) - [Roadmap](ROADMAP.md) - [License](LICENSE) -## ✨ Features (v2.3.2) +## ✨ Features (v3.0.0) - 🔑 **User Authentication** - Login/logout system with hashed passwords. - Admin and regular user accounts. @@ -41,15 +41,16 @@ It is designed to work with [ErsatzTV](https://ersatztv.org/) [(GitRepo)](https: - AOL/CompuServe - TV Guide Magazine - Theme persistence stored in browser localStorage, applied instantly across all pages. - - **New About Page under Settings menu (v2.3.1)** — shows version, Python, OS, uptime, paths. + - **About Page under Settings menu** — shows version, Python, OS, uptime, paths. - âš™ī¸ **System** - Automatic initialization of `users.db` and `tuners.db` on first run. - SQLite databases use WAL mode for better concurrency. - Preloads tuner/channel/guide data from DB on startup. - - **Cross-platform installer (Linux/Windows) (v2.3.0)**. - - **Uninstaller script (v2.3.0)**. - - **Automated version bump tool (`bump_version.py`) (v2.3.1)**. + - **Cross-platform installers (Linux/Windows)**. + - **Uninstaller scripts (Linux/Windows)**. + - **Automated version bump tool (`bump_version.py`)**. +--- ## 🌐 Browser Compatibility This project is designed to work with **all major browsers**. @@ -64,11 +65,16 @@ The web interface has been tested on: - **Ubuntu (desktop/server)** - **iOS (mobile/tablet)** - **Android (Samsung Mobile Phone)** +- **macOS** +- **Windows 10/11** - **MacOS** - **Windows** ## đŸ› ī¸ Installation Platform -The backend server should be installed on a **Debian/Ubuntu machine** for best compatibility. +- **Debian Based Linux (desktop/server)** +- **Windows 10/11** + +## đŸ“ē Screenshots ## đŸ“ē Guide Page ![Guide Screenshot](docs/screenshots/guide.png) diff --git a/ROADMAP.md b/ROADMAP.md index 2dd0f0a..fc8290f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -45,7 +45,10 @@ These are **not yet implemented**, but provide a development path for future rel ### 6. Cross-platform - [ ] Create installable container. - [ ] Create MacOS install/executable. -- [x] Create Microsoft Windows install/executable (basic support via Git Bash + PowerShell bootstrap) (v2.3.0) +- [x] Create Microsoft Windows install/executable (full support via PowerShell + NSSM service) (v3.0.0) +- [x] Add uninstall_windows.ps1 and uninstall.bat (v3.0.0) +- [x] Windows installer now bootstraps Chocolatey, installs Python, Git, NSSM, and configures service (v3.0.0) +- [x] Windows uninstaller cleans service, firewall rule, and optionally removes Chocolatey (v3.0.0) - [ ] Validate/test installer fully on Windows environments ### 7. New Features @@ -74,7 +77,7 @@ These are **not yet implemented**, but provide a development path for future rel ## 📅 Priority Suggestions - Short term: (none — unified UI headers already completed in v2.0.0). - Medium term: log filtering (still pending). -- Medium term: Validate installer/uninstaller on Windows (pending). +- 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. --- @@ -92,3 +95,8 @@ These are **not yet implemented**, but provide a development path for future rel - [x] Cross-platform `uninstall.sh` with sudo/admin checks and safe cleanup (v2.3.0). - [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/app.py b/app.py index 4671d57..b0cfbb3 100644 --- a/app.py +++ b/app.py @@ -1,4 +1,4 @@ -APP_VERSION = "v2.3.2" +APP_VERSION = "v3.0.0" APP_RELEASE_DATE = "2025-09-26" from flask import Flask, render_template, request, redirect, url_for, flash diff --git a/bump_version.py b/bump_version.py index 29a28be..d62f28b 100644 --- a/bump_version.py +++ b/bump_version.py @@ -15,9 +15,12 @@ APP_FILE = Path("app.py") CHANGELOG_FILE = Path("CHANGELOG.md") +INSTALL_WIN = Path("install_windows.ps1") +UNINSTALL_WIN = Path("uninstall_windows.ps1") +UNINSTALL_SH = Path("uninstall.sh") def update_app_py(new_version: str): - """Update APP_VERSION in app.py""" + """Update APP_VERSION in app.py, add if missing""" content = APP_FILE.read_text().splitlines() updated = [] found = False @@ -28,8 +31,8 @@ def update_app_py(new_version: str): else: updated.append(line) if not found: - print("âš ī¸ APP_VERSION not found in app.py") - sys.exit(1) + updated.insert(0, f'APP_VERSION = "v{new_version}"') + print("â„šī¸ APP_VERSION not found in app.py, added at top") APP_FILE.write_text("\n".join(updated) + "\n") print(f"✅ Updated app.py to v{new_version}") @@ -54,9 +57,7 @@ def update_changelog(new_version: str): inserted = False for i, line in enumerate(changelog): updated.append(line) - # Find the first --- *after* the Unreleased section if line.strip() == "---" and not inserted: - # Look back: did we already pass Unreleased? if any("## [Unreleased]" in l for l in changelog[:i]): updated.append("") # spacing updated.extend(new_block) @@ -69,11 +70,45 @@ def update_changelog(new_version: str): CHANGELOG_FILE.write_text("\n".join(updated) + "\n") print(f"✅ Inserted v{new_version} section into CHANGELOG.md") +def update_script_version(file: Path, new_version: str, is_bash: bool): + """Update or insert version string in shell or PowerShell scripts""" + if not file.exists(): + print(f"âš ī¸ {file} not found, skipping") + return + + content = file.read_text().splitlines() + updated = [] + found = False + + # Regex for version line + if is_bash: + pattern = re.compile(r'^\s*VERSION\s*=\s*".*"') + replacement = f'VERSION="{new_version}"' + else: # PowerShell + pattern = re.compile(r'^\s*\$?VERSION\s*=\s*".*"') + replacement = f'$VERSION = "{new_version}"' + + for line in content: + if pattern.match(line): + updated.append(replacement) + found = True + else: + updated.append(line) + + if not found: + # Insert at top + updated.insert(0, replacement) + print(f"â„šī¸ VERSION not found in {file}, added at top") + + file.write_text("\n".join(updated) + "\n") + print(f"✅ Updated {file} to v{new_version}") + def git_commit(new_version: str): """Commit changes with git""" try: subprocess.run( - ["git", "add", str(APP_FILE), str(CHANGELOG_FILE)], + ["git", "add", str(APP_FILE), str(CHANGELOG_FILE), + str(INSTALL_WIN), str(UNINSTALL_WIN), str(UNINSTALL_SH)], check=True ) subprocess.run( @@ -89,12 +124,17 @@ def main(): print("Usage: python bump_version.py [--commit]") sys.exit(1) - new_version = sys.argv[1].lstrip("v") # allow 'v2.4.0' or '2.4.0' + new_version = sys.argv[1].lstrip("v") do_commit = "--commit" in sys.argv update_app_py(new_version) update_changelog(new_version) + # Update other scripts + update_script_version(INSTALL_WIN, new_version, is_bash=False) + update_script_version(UNINSTALL_WIN, new_version, is_bash=False) + update_script_version(UNINSTALL_SH, new_version, is_bash=True) + if do_commit: git_commit(new_version) diff --git a/install.bat b/install.bat new file mode 100644 index 0000000..938f524 --- /dev/null +++ b/install.bat @@ -0,0 +1,2 @@ +@echo off +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0install_windows.ps1" diff --git a/install.sh b/install.sh index 127da24..8aeecbf 100644 --- a/install.sh +++ b/install.sh @@ -25,6 +25,66 @@ fi echo "Detected environment: $ENVIRONMENT" +windows_install() { +#!/usr/bin/env bash +# install.sh - Installer for RetroIPTVGuide +# Detects environment, creates venv, ensures pip is up-to-date only if needed. + +set -e + +echo "=== RetroIPTVGuide Installer ===" + +# Detect environment +if grep -qi "microsoft" /proc/version 2>/dev/null; then + ENVIRONMENT="WSL" +elif [ -n "$WINDIR" ] && [ -x "/bin/bash" ] && uname -s | grep -qi "mingw"; then + ENVIRONMENT="GITBASH" +else + ENVIRONMENT="LINUX" +fi + +echo "Environment detected: $ENVIRONMENT" + +# Ensure Python is available +if ! command -v python3 >/dev/null 2>&1 && ! command -v python >/dev/null 2>&1; then + echo "Python is not installed. Please install Python 3 and rerun." + exit 1 +fi + +# Pick python executable +if command -v python3 >/dev/null 2>&1; then + PY=python3 +else + PY=python +fi + +# Create virtual environment +if [ "$ENVIRONMENT" = "GITBASH" ]; then + $PY -m venv venv + PYTHON_BIN="$PWD/venv/Scripts/python.exe" +else + $PY -m venv venv + PYTHON_BIN="$PWD/venv/bin/python" +fi + +# Upgrade pip only if needed +CURRENT_PIP=$($PYTHON_BIN -m pip --version | awk '{print $2}') +LATEST_PIP=$(curl -s https://pypi.org/pypi/pip/json | grep -oP '"version":\s*"\K[0-9.]+' | head -1) + +if [ "$CURRENT_PIP" != "$LATEST_PIP" ] && [ -n "$LATEST_PIP" ]; then + echo "Upgrading pip from $CURRENT_PIP to $LATEST_PIP..." + $PYTHON_BIN -m pip install --upgrade pip +else + echo "pip is already up-to-date ($CURRENT_PIP)" +fi + +# Install requirements +$PYTHON_BIN -m pip install -r requirements.txt + +} + + +linux_install(){ # Ensure script is run with sudo on Linux/WSL if [[ "$ENVIRONMENT" == "LINUX" || "$ENVIRONMENT" == "WSL" ]]; then if [[ $EUID -ne 0 ]]; then @@ -124,10 +184,10 @@ else echo "Unsupported environment: $OSTYPE" exit 1 fi +} -echo "" -echo "=== Installation complete! ===" -echo "End time: $(date)" -echo "Access the server in your browser at: http://:5000" -echo "Default login: admin / strongpassword123" -echo "NOTE: This is a **BETA build**. Do not expose it directly to the public internet." +if [ "$ENVIRONMENT" = "GITBASH" ]; then + windows_install +else + linux_install +fi diff --git a/install_windows.ps1 b/install_windows.ps1 new file mode 100644 index 0000000..2bf2ccf --- /dev/null +++ b/install_windows.ps1 @@ -0,0 +1,320 @@ +$VERSION = "3.0.0" +<# +RetroIPTVGuide Windows Installer +Clean version with only prerequisite checks and service setup +#> + + +# === Start Transcript === +$logDir = "$PSScriptRoot\logs" +if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Force -Path $logDir | Out-Null } +$logFile = Join-Path $logDir ("install_{0:yyyyMMdd_HHmmss}.log" -f (Get-Date)) +Start-Transcript -Path $logFile -Append +Write-Host "=== RetroIPTVGuide Windows Installer ===" -ForegroundColor Cyan +Write-Host "Log file: $logFile" -ForegroundColor Gray + +# --- Ensure Admin Privileges --- +# Elevation check +$IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) +if (-not $IsAdmin) { + Write-Host "Re-launching with Administrator privileges..." -ForegroundColor Yellow + Stop-Transcript + Start-Process -FilePath "powershell.exe" -Verb RunAs -ArgumentList "-ExecutionPolicy Bypass -File `"$PSCommandPath`"" + exit +} + +Write-Host "" +Write-Host "============================================================" -ForegroundColor Yellow +Write-Host " RetroIPTVGuide Installer Agreement " -ForegroundColor Cyan +Write-Host "============================================================" -ForegroundColor Yellow +Write-Host "" +Write-Host "This installer will perform the following actions:" -ForegroundColor White +Write-Output " - Bootstraps / Installs Chocolatey" +Write-Output " - Installs dependencies: python, git, nssm" +Write-Output " - Registers Windows App Paths for python/python3" +Write-Output " - Adds Python to Git Bash (~/.bashrc)" +Write-Output " - Clones RetroIPTVGuide into the same folder as the installer" +Write-Output " - Runs install.sh via Git Bash" +Write-Output " - Creates an NSSM service to run venv\\Scripts\\python.exe app.py" +Write-Output " - Open Windows Firewall port 5000 for RetroIPTVGuide Service" +Write-Output " - Starts the RetroIPTVGuide service" +Write-Host "" +Write-Host "By continuing, you acknowledge and agree that:" -ForegroundColor White +Write-Output " - This software should ONLY be run on internal networks." +Write-Output " - It must NOT be exposed to the public Internet." +Write-Output " - You accept all risks; the author provides NO WARRANTY." +Write-Output " - The author is NOT responsible for any damage, data loss," +Write-Output " or security vulnerabilities created by this installation." +Write-Host "" +Write-Host "Do you agree to these terms? (yes/no)" -ForegroundColor Yellow + +$agreement = Read-Host "Type yes or no" +Write-Output "User response to agreement: $agreement" + +if ($agreement.ToLower() -ne "yes") { + Write-Host "Installation aborted by user." -ForegroundColor Red + Stop-Transcript + exit 1 +} + +# --- Chocolatey --- +Write-Host "Checking for Chocolatey..." -ForegroundColor Cyan +$choco = Get-Command choco -ErrorAction SilentlyContinue +if (-not $choco) { + Write-Host "Installing Chocolatey..." -ForegroundColor Yellow + Set-ExecutionPolicy Bypass -Scope Process -Force + [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 + Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") +} + +# --- Python --- +Write-Host "Checking for Python..." -ForegroundColor Cyan +if (choco list | Select-String -Pattern "^python3 ") { + Write-Host "Python3 is installed" +} else { + Write-Host "Python3 not found, installing..." + choco install python3 -y +} + +# --- Fix Python alias stubs from Microsoft Store --- +$aliases = @( + "$env:LOCALAPPDATA\Microsoft\WindowsApps\python.exe", + "$env:LOCALAPPDATA\Microsoft\WindowsApps\python3.exe", + "$env:LOCALAPPDATA\Microsoft\WindowsApps\python3.*.exe" +) + +foreach ($alias in $aliases) { + if (Test-Path $alias) { + try { + Remove-Item $alias -Force + Write-Host "Removed Microsoft Store alias: $alias" -ForegroundColor Yellow + } catch { + Write-Warning "Failed to remove alias ${alias}: $_" + } + } +} + +# --- Ensure Chocolatey shims directory comes first in PATH --- +$chocoBin = "C:\ProgramData\chocolatey\bin" +$currentPath = [System.Environment]::GetEnvironmentVariable("PATH", "Machine") + +if (-not ($currentPath -split ";" | ForEach-Object { $_.Trim() } | Where-Object { $_ -eq $chocoBin })) { + $newPath = "$chocoBin;$currentPath" + [System.Environment]::SetEnvironmentVariable("PATH", $newPath, "Machine") + Write-Host "Updated PATH to prioritize Chocolatey bin: $chocoBin" -ForegroundColor Green +} else { + Write-Host "Chocolatey bin already in PATH." -ForegroundColor Green +} + +# --- Add registry App Paths aliases for python/python3 --- +try { + $pythonExe = (Get-Command python.exe -ErrorAction SilentlyContinue).Source + if (-not $pythonExe) { + $pythonExe = "C:\Python313\python.exe" # fallback if not resolved via PATH + } + + if (Test-Path $pythonExe) { + New-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\python.exe" -Force | Out-Null + Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\python.exe" -Name "(Default)" -Value $pythonExe + + New-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\python3.exe" -Force | Out-Null + Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\python3.exe" -Name "(Default)" -Value $pythonExe + + Write-Host "Registered App Path aliases: python, python3 -> $pythonExe" -ForegroundColor Green + } else { + Write-Warning "Python executable not found for alias registration." + } +} catch { + Write-Warning "Failed to register python/python3 aliases in App Paths: $_" +} + + +# --- Ensure Chocolatey is installed --- +if (-not (Get-Command choco.exe -ErrorAction SilentlyContinue)) { + Write-Host "Installing Chocolatey..." -ForegroundColor Cyan + Set-ExecutionPolicy Bypass -Scope Process -Force + [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 + Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) +} else { + Write-Host "Chocolatey already installed." -ForegroundColor Green +} + +# --- Ensure dependencies --- +$packages = @("python3", "nssm", "git") + +foreach ($pkg in $packages) { + $installed = choco list --limit-output | Select-String -Pattern "^$pkg " + if (-not $installed) { + Write-Host "Installing $pkg..." -ForegroundColor Cyan + choco install $pkg -y | Out-Null + } else { + Write-Host "$pkg already installed." -ForegroundColor Green + } +} + +Write-Host "All dependencies installed." -ForegroundColor Green + +# --- Ensure Python aliases point to correct installed version --- +try { + $pythonExePath = (Get-Command python3.exe -ErrorAction SilentlyContinue).Source + if (-not $pythonExePath) { + $pythonExePath = (Get-Command python.exe -ErrorAction SilentlyContinue).Source + } + + if ($pythonExePath) { + Write-Host "Found Python executable at $pythonExePath" -ForegroundColor Cyan + + # Persist App Path so Windows resolves python/python3 correctly + $aliases = @("python.exe", "python3.exe") + foreach ($alias in $aliases) { + $regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\$alias" + if (-not (Test-Path $regPath)) { + New-Item -Path $regPath -Force | Out-Null + } + Set-ItemProperty -Path $regPath -Name "(Default)" -Value $pythonExePath + Set-ItemProperty -Path $regPath -Name "Path" -Value (Split-Path $pythonExePath) + } + + Write-Host "Registered App Path aliases: python, python3 -> $pythonExePath" -ForegroundColor Green + } else { + Write-Warning "Python executable not found in PATH. Aliases not created." + } +} catch { + Write-Warning "Failed to configure Python aliases: $_" +} + +# --- Ensure Python aliases point to correct installed version --- +try { + # Look up Python installation folder from Chocolatey + $pythonPkg = choco list | Select-String -Pattern "^python3 " + if ($pythonPkg) { + # Most choco python3 installs under C:\Python3xx + $pythonDir = Get-ChildItem "C:\Python*" -Directory | Sort-Object LastWriteTime -Descending | Select-Object -First 1 + $pythonExePath = Join-Path $pythonDir.FullName "python.exe" + + if (Test-Path $pythonExePath) { + Write-Host "Found Python executable at $pythonExePath" -ForegroundColor Cyan + + # Persist App Path so Windows resolves python/python3 correctly + $aliases = @("python.exe", "python3.exe") + foreach ($alias in $aliases) { + $regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\$alias" + if (-not (Test-Path $regPath)) { + New-Item -Path $regPath -Force | Out-Null + } + Set-ItemProperty -Path $regPath -Name "(Default)" -Value $pythonExePath + Set-ItemProperty -Path $regPath -Name "Path" -Value $pythonDir.FullName + } + + Write-Host "Registered App Path aliases: python, python3 -> $pythonExePath" -ForegroundColor Green + + # --- Add Python to Git Bash PATH via ~/.bashrc --- + $gitBashHome = Join-Path $env:USERPROFILE ".bashrc" + $bashrcLine = "export PATH=""/c/$($pythonDir.Name):/c/$($pythonDir.Name)/Scripts:`$PATH""" + + if (Test-Path $gitBashHome) { + if (-not (Select-String -Path $gitBashHome -Pattern $pythonDir.Name -Quiet)) { + Add-Content -Path $gitBashHome -Value $bashrcLine + Write-Host "Added Python to Git Bash PATH in .bashrc" -ForegroundColor Yellow + } + } else { + Set-Content -Path $gitBashHome -Value $bashrcLine + Write-Host "Created .bashrc and added Python PATH for Git Bash" -ForegroundColor Yellow + } + + } else { + Write-Warning "Python executable not found in expected location." + } + } else { + Write-Warning "Python not installed by Chocolatey, skipping alias setup." + } +} catch { + Write-Warning "Failed to configure Python aliases: $_" +} + + + + + +# --- Clone RetroIPTVGuide --- +$installDir = "$PSScriptRoot\RetroIPTVGuide" +if (Test-Path $installDir) { Remove-Item -Recurse -Force $installDir } +# Resolve Git path +$gitExe = (Get-Command git.exe -ErrorAction SilentlyContinue).Source +if (-not $gitExe) { $gitExe = "C:\Program Files\Git\bin\git.exe" } +if (-not (Test-Path $gitExe)) { $gitExe = "C:\Program Files (x86)\Git\bin\git.exe" } + +if (-not (Test-Path $gitExe)) { + Write-Error "Git executable not found even after installation. Please verify Git installation." + exit 1 +} + +# Clone the repository +#& $gitExe clone -b windows https://github.com/thehack904/RetroIPTVGuide.git $installDir + +# --- Run install.sh using Git Bash --- +try { + $gitBash = "C:\Program Files\Git\bin\bash.exe" + #$repoDir = Join-Path $PSScriptRoot "RetroIPTVGuide" + $repoDir = $PSScriptRoot + + if (Test-Path $gitBash -PathType Leaf) { + if (Test-Path (Join-Path $repoDir "install.sh")) { + Write-Host "Running install.sh with Git Bash..." -ForegroundColor Cyan + & "$gitBash" --login -i -c "cd '$repoDir' && chmod +x install.sh && ./install.sh" + } else { + Write-Warning "install.sh not found in $repoDir" + } + } else { + Write-Warning "Git Bash not found at $gitBash. Skipping install.sh" + } +} catch { + Write-Warning "Failed to run install.sh in Git Bash: $_" +} + +# --- PATCH: Open firewall port for RetroIPTVGuide --- +Write-Host "Opening Windows Firewall port 5000 for RetroIPTVGuide..." -ForegroundColor Yellow +netsh advfirewall firewall add rule name="RetroIPTVGuide" dir=in action=allow protocol=TCP localport=5000 | Out-Null + +# --- Configure NSSM service for RetroIPTVGuide --- +try { + $nssm = "C:\ProgramData\chocolatey\bin\nssm.exe" + #$repoDir = Join-Path $PSScriptRoot "RetroIPTVGuide" + $repoDir = $PSScriptRoot + $venvPython = Join-Path $repoDir "venv\Scripts\python.exe" + $appPy = Join-Path $repoDir "app.py" + + if ((Test-Path $nssm -PathType Leaf) -and (Test-Path $venvPython) -and (Test-Path $appPy)) { + Write-Host "Setting up NSSM service for RetroIPTVGuide..." -ForegroundColor Cyan + + # Install the service to directly run venv python + app.py + & $nssm install RetroIPTVGuide $venvPython $appPy + + # Set service parameters + & $nssm set RetroIPTVGuide Start SERVICE_AUTO_START + & $nssm set RetroIPTVGuide AppDirectory $repoDir + + Write-Host "NSSM service 'RetroIPTVGuide' installed successfully." -ForegroundColor Green + + # Start the service right away + Start-Service RetroIPTVGuide + Write-Host "Service 'RetroIPTVGuide' started." -ForegroundColor Green + } else { + Write-Warning "NSSM, venv python, or app.py not found. Could not create service." + } +} catch { + Write-Warning "Failed to configure NSSM service: $_" +} + +echo "" +Write-Host "Installation complete!" -ForegroundColor Cyan +echo "End time: $(date)" +echo "Access the server in your browser at: http://:5000" +echo "Default login: admin / strongpassword123" +echo "NOTE: This is a **BETA build**. Do not expose it directly to the public internet." +echo "" + +# === Done === +Stop-Transcript +pause diff --git a/uninstall.bat b/uninstall.bat new file mode 100644 index 0000000..9514868 --- /dev/null +++ b/uninstall.bat @@ -0,0 +1,2 @@ +@echo off +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0uninstall_windows.ps1" diff --git a/uninstall.sh b/uninstall.sh index 9c695c8..dfd6b21 100644 --- a/uninstall.sh +++ b/uninstall.sh @@ -1,7 +1,9 @@ +VERSION="3.0.0" #!/usr/bin/env bash # RetroIPTVGuide uninstall script # Run with sudo on Linux; run from Administrator shell on Windows + set -e SERVICE_NAME="iptv-server" diff --git a/uninstall_windows.ps1 b/uninstall_windows.ps1 new file mode 100644 index 0000000..ff49b83 --- /dev/null +++ b/uninstall_windows.ps1 @@ -0,0 +1,190 @@ +$VERSION = "3.0.0" +# RetroIPTVGuide Windows Uninstaller +# ================================== + + + +# Setup logging +$LogDir = "$PSScriptRoot\logs" +if (!(Test-Path $LogDir)) { New-Item -ItemType Directory -Force -Path $LogDir | Out-Null } +$Timestamp = Get-Date -Format "yyyyMMdd_HHmmss" +$LogFile = "$LogDir\uninstall_$Timestamp.log" + +Start-Transcript -Path $LogFile -Force +Write-Host "=== RetroIPTVGuide Windows Uninstaller ===" -ForegroundColor Cyan +Write-Host "Timestamp: $(Get-Date)" -ForegroundColor Cyan +Write-Host "Log file: $LogFile" -ForegroundColor Cyan + +# Elevation check +$IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) +if (-not $IsAdmin) { + Write-Host "Re-launching with Administrator privileges..." -ForegroundColor Yellow + Stop-Transcript + Start-Process -FilePath "powershell.exe" -Verb RunAs -ArgumentList "-ExecutionPolicy Bypass -File `"$PSCommandPath`"" + exit +} + +# Stop and remove RetroIPTVGuide service via NSSM +$serviceName = "RetroIPTVGuide" +try { + if (Get-Service -Name $serviceName -ErrorAction SilentlyContinue) { + Write-Host "Stopping service $serviceName..." -ForegroundColor Yellow + Stop-Service $serviceName -Force -ErrorAction SilentlyContinue + Write-Host "Removing service $serviceName..." -ForegroundColor Yellow + & nssm remove $serviceName confirm + } else { + Write-Host "Service $serviceName not found." -ForegroundColor DarkYellow + } +} catch { + Write-Warning "Error while removing $serviceName service: $_" +} + +# Remove firewall rule +try { + Write-Host "Removing Windows Firewall port rule for RetroIPTVGuide..." -ForegroundColor Yellow + netsh advfirewall firewall delete rule name="RetroIPTVGuide" +} catch { + Write-Warning "Could not remove firewall rule: $_" +} + +# Remove RetroIPTVGuide installation folder +#$installDir = "$PSScriptRoot" +#if (Test-Path $installDir) { +# Write-Host "Removing install directory $installDir..." -ForegroundColor Yellow +# try { +# Remove-Item -Recurse -Force $installDir +# Write-Host "Install directory removed." -ForegroundColor Green +# } catch { +# Write-Warning "Could not remove ${installDir}: $_" +# } +#} else { +# Write-Host "Install directory not found: $installDir" -ForegroundColor DarkYellow +#} + +## Optional cleanup of dependencies installed by Chocolatey +#function Uninstall-ChocoPackage($pkgName) { +# if (Get-Command choco.exe -ErrorAction SilentlyContinue) { +# $installed = choco list | Select-String -Pattern "^$pkgName" +# if ($installed) { +# Write-Host "Uninstalling $pkgName via Chocolatey..." -ForegroundColor Yellow +# choco uninstall $pkgName -y | Out-Null +# } else { +# Write-Host "$pkgName not found in Chocolatey, skipping." -ForegroundColor DarkYellow +# } +# } else { +# Write-Host "Chocolatey not found, cannot uninstall $pkgName." -ForegroundColor DarkYellow +# } +#} +# +#Uninstall-ChocoPackage "python" +#Uninstall-ChocoPackage "python3" +#Uninstall-ChocoPackage "nssm" +#Uninstall-ChocoPackage "git" +#Uninstall-ChocoPackage "git.install" + +# Improved Chocolatey uninstall function +function Uninstall-ChocoPackagePrefix($pkgPrefix) { + if (Get-Command choco.exe -ErrorAction SilentlyContinue) { + $installed = choco list | ForEach-Object { ($_ -split ' ')[0] } | Where-Object { $_ -like "$pkgPrefix*" } + if ($installed) { + foreach ($pkg in $installed) { + Write-Host "Uninstalling $pkg via Chocolatey..." -ForegroundColor Yellow + choco uninstall $pkg -y | Out-Null + } + } else { + Write-Host "No packages found with prefix '$pkgPrefix', skipping." -ForegroundColor DarkYellow + } + } else { + Write-Host "Chocolatey not found, cannot uninstall packages with prefix '$pkgPrefix'." -ForegroundColor DarkYellow + } +} + +# Remove all Python variants + NSSM + Git +Uninstall-ChocoPackagePrefix "python" +Uninstall-ChocoPackagePrefix "nssm" +Uninstall-ChocoPackagePrefix "git" + + +# --- Remove registry App Paths aliases for python/python3 --- +try { + if (Test-Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\python.exe") { + Remove-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\python.exe" -Recurse -Force + Write-Host "Removed App Path alias: python.exe" -ForegroundColor Yellow + } + if (Test-Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\python3.exe") { + Remove-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\python3.exe" -Recurse -Force + Write-Host "Removed App Path alias: python3.exe" -ForegroundColor Yellow + } +} catch { + Write-Warning "Failed to remove python/python3 App Path aliases: $_" +} + +# --- Optionally restore Microsoft Store stubs (App Execution Aliases) --- +$windowsApps = "$env:LOCALAPPDATA\Microsoft\WindowsApps" +$stubTargets = @( + "python.exe", + "python3.exe" +) + +foreach ($stub in $stubTargets) { + $stubPath = Join-Path $windowsApps $stub + if (-not (Test-Path $stubPath)) { + try { + # Recreate as a zero-byte placeholder to mimic default behavior + New-Item -Path $stubPath -ItemType File -Force | Out-Null + Write-Host "Restored Microsoft Store alias stub: $stubPath" -ForegroundColor Yellow + } catch { + Write-Warning "Failed to restore Store alias ${stub}: $_" + } + } +} + +Write-Host "" +Write-Host "Would you like to completely uninstall ALL remaining Chocolatey packages and Chocolatey itself?" -ForegroundColor Yellow +$fullUninstall = Read-Host "Type yes or no" +Write-Output "User response to full uninstall prompt: $fullUninstall" + +if ($fullUninstall.ToLower() -eq "yes") { + try { + Write-Host "" + Write-Host "Proceeding with full removal of all Chocolatey packages..." -ForegroundColor Red + + # Capture installed packages + $rawInstalled = & choco list 2>$null + if ($rawInstalled -is [string]) { $rawInstalled = $rawInstalled -split "`r?`n" } + + $installed = $rawInstalled | Where-Object { + ($_ -notmatch "^Chocolatey v") -and + ($_ -notmatch "Did you know Pro") -and + ($_ -notmatch "Features\? Learn more") -and + ($_ -notmatch "Package Synchronizer") -and + ($_ -notmatch "packages installed") -and + ($_ -ne "") + } + + # Extract package names (first token of each line) + $pkgNames = $installed | ForEach-Object { ($_ -split " ")[0] } + + if ($pkgNames) { + foreach ($pkg in $pkgNames) { + Write-Host "Uninstalling $pkg ..." -ForegroundColor Cyan + choco uninstall -y $pkg | Out-Null + } + } + + # Finally uninstall Chocolatey itself + Write-Host "Uninstalling Chocolatey..." -ForegroundColor Cyan + choco uninstall -y chocolatey | Out-Null + + Write-Host "Full Chocolatey removal complete." -ForegroundColor Green + Write-Output "Full Chocolatey removal complete." + } catch { + Write-Warning "Failed to completely remove all Chocolatey packages: $_" + } +} else { + Write-Host "Leaving remaining Chocolatey packages and Chocolatey itself installed." -ForegroundColor Cyan +} + +Stop-Transcript +Write-Host "=== Uninstallation complete ===" -ForegroundColor Cyan +pause