From 281f03835dc4fd04b3b9788bf6b28a034994804e Mon Sep 17 00:00:00 2001 From: Admin9705 <9705@duck.com> Date: Mon, 7 Apr 2025 13:42:24 -0400 Subject: [PATCH 01/12] update --- Dockerfile | 23 ++- main.py | 24 +++- requirements.txt | 3 +- setup.py | 27 ++++ templates/index.html | 134 ++++++++++++++++++ .../.github}/workflows/docker-image.yml | 0 utils/logger.py | 14 +- webserver.py | 0 8 files changed, 218 insertions(+), 7 deletions(-) create mode 100644 setup.py create mode 100644 templates/index.html rename {.github => utils/.github}/workflows/docker-image.yml (100%) create mode 100644 webserver.py diff --git a/Dockerfile b/Dockerfile index c2e402ab..01493e1c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,27 @@ FROM python:3.9-slim WORKDIR /app + # Install dependencies COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt + +# Install Flask for the web interface +RUN pip install --no-cache-dir flask + # Copy application files COPY main.py config.py api.py state.py ./ COPY missing.py upgrade.py ./ +COPY web_server.py ./ COPY utils/ ./utils/ -# Create state directory + +# Create templates directory and copy index.html +RUN mkdir -p templates +COPY templates/ ./templates/ + +# Create required directories RUN mkdir -p /tmp/huntarr-state +RUN mkdir -p /tmp/huntarr-logs + # Default environment variables ENV API_KEY="your-api-key" \ API_URL="http://your-sonarr-address:8989" \ @@ -20,5 +33,9 @@ ENV API_KEY="your-api-key" \ RANDOM_SELECTION="true" \ MONITORED_ONLY="true" \ DEBUG_MODE="false" -# Run the application -CMD ["python", "main.py"] \ No newline at end of file + +# Expose web interface port +EXPOSE 8988 + +# Run the application with web interface +CMD ["sh", "-c", "python web_server.py & python main.py"] \ No newline at end of file diff --git a/main.py b/main.py index 636f59f0..15bd95a0 100644 --- a/main.py +++ b/main.py @@ -6,6 +6,7 @@ import time import sys +import os from utils.logger import logger from config import HUNT_MODE, SLEEP_DURATION, MINIMUM_DOWNLOAD_QUEUE_SIZE, log_configuration from missing import process_missing_episodes @@ -15,6 +16,12 @@ def main_loop() -> None: """Main processing loop for Huntarr-Sonarr""" + + # Log welcome message for web interface + logger.info("=== Huntarr [Sonarr Edition] Starting ===") + logger.info("Web interface available at http://YOUR_SERVER_IP:8988") + logger.info("GitHub: https://github.com/plexguide/huntarr-sonarr") + while True: # Check if state files need to be reset check_state_reset() @@ -38,7 +45,7 @@ def main_loop() -> None: processing_done = True else: - logger.info(f"Download queue size ({download_queue_size}) is above the minimum threshold ({MINIMUM_DOWNLOAD_QUEUE_SIZE}). Skipped processing.") + logger.info(f"Download queue size ({download_queue_size}) is above the minimum threshold ({MINIMUM_DOWNLOAD_QUEUE_SIZE}). Skipped processing.") # Calculate time until the next reset calculate_reset_time() @@ -46,7 +53,20 @@ def main_loop() -> None: # Sleep at the end of the cycle only logger.info(f"Cycle complete. Sleeping {SLEEP_DURATION}s before next cycle...") logger.info("⭐ Tool Great? Donate @ https://donate.plex.one for Daughter's College Fund!") - time.sleep(SLEEP_DURATION) + logger.info("Web interface available at http://YOUR_SERVER_IP:8988") + + # Sleep with progress updates for the web interface + sleep_start = time.time() + sleep_end = sleep_start + SLEEP_DURATION + + while time.time() < sleep_end: + # Sleep in smaller chunks for more responsive shutdown + time.sleep(min(10, sleep_end - time.time())) + + # Every minute, log the remaining sleep time for web interface visibility + if int((time.time() - sleep_start) % 60) == 0 and time.time() < sleep_end - 10: + remaining = int(sleep_end - time.time()) + logger.debug(f"Sleeping... {remaining}s remaining until next cycle") if __name__ == "__main__": # Log configuration settings diff --git a/requirements.txt b/requirements.txt index eed69883..730695f6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -requests>=2.25.0 \ No newline at end of file +requests>=2.25.0 +flask>=2.0.0 \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..7cb23d34 --- /dev/null +++ b/setup.py @@ -0,0 +1,27 @@ +#!/bin/bash +# Setup script for Huntarr-Sonarr Web Interface + +# Create directories +mkdir -p templates +mkdir -p utils + +# Ensure file destinations exist +touch requirements.txt +touch main.py +touch config.py +touch api.py +touch missing.py +touch upgrade.py +touch state.py +touch web_server.py +touch utils/logger.py +touch utils/__init__.py +touch templates/index.html + +echo "Directory structure created successfully!" +echo "Please copy the files from the artifacts into the appropriate locations." +echo "Then build the Docker image with: docker build -t huntarr/4sonarr:latest ." + +# Reminder about port exposure +echo "Remember to expose port 8988 when running the Docker container:" +echo "docker run -d --name huntarr-sonarr -p 8988:8988 ... huntarr/4sonarr:latest" \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 00000000..122df930 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,134 @@ + + + + + + Huntarr-Sonarr Log Viewer + + + +
+

Huntarr-Sonarr Log Viewer

+

View the real-time logs from Huntarr-Sonarr

+
+ +
Connected: Yes | Auto-refresh: Every 1 second
+
+ + + + + + \ No newline at end of file diff --git a/.github/workflows/docker-image.yml b/utils/.github/workflows/docker-image.yml similarity index 100% rename from .github/workflows/docker-image.yml rename to utils/.github/workflows/docker-image.yml diff --git a/utils/logger.py b/utils/logger.py index 05128a62..7a1150c5 100644 --- a/utils/logger.py +++ b/utils/logger.py @@ -6,8 +6,14 @@ import logging import sys import os +import pathlib from config import DEBUG_MODE +# Create log directory +LOG_DIR = pathlib.Path("/tmp/huntarr-logs") +LOG_DIR.mkdir(parents=True, exist_ok=True) +LOG_FILE = LOG_DIR / "huntarr.log" + def setup_logger(): """Configure and return the application logger""" logger = logging.getLogger("huntarr-sonarr") @@ -19,15 +25,21 @@ def setup_logger(): console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(logging.DEBUG if DEBUG_MODE else logging.INFO) + # Create file handler for the web interface + file_handler = logging.FileHandler(LOG_FILE) + file_handler.setLevel(logging.DEBUG if DEBUG_MODE else logging.INFO) + # Set format formatter = logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S", ) console_handler.setFormatter(formatter) + file_handler.setFormatter(formatter) - # Add handler to logger + # Add handlers to logger logger.addHandler(console_handler) + logger.addHandler(file_handler) return logger diff --git a/webserver.py b/webserver.py new file mode 100644 index 00000000..e69de29b From 5fb7b67d62864ed4873673a5e4dfc3fb6ec4302b Mon Sep 17 00:00:00 2001 From: Admin9705 <9705@duck.com> Date: Mon, 7 Apr 2025 13:43:09 -0400 Subject: [PATCH 02/12] update --- setup.py | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 setup.py diff --git a/setup.py b/setup.py deleted file mode 100644 index 7cb23d34..00000000 --- a/setup.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# Setup script for Huntarr-Sonarr Web Interface - -# Create directories -mkdir -p templates -mkdir -p utils - -# Ensure file destinations exist -touch requirements.txt -touch main.py -touch config.py -touch api.py -touch missing.py -touch upgrade.py -touch state.py -touch web_server.py -touch utils/logger.py -touch utils/__init__.py -touch templates/index.html - -echo "Directory structure created successfully!" -echo "Please copy the files from the artifacts into the appropriate locations." -echo "Then build the Docker image with: docker build -t huntarr/4sonarr:latest ." - -# Reminder about port exposure -echo "Remember to expose port 8988 when running the Docker container:" -echo "docker run -d --name huntarr-sonarr -p 8988:8988 ... huntarr/4sonarr:latest" \ No newline at end of file From 52842cefdb6b9100965f1de7e82d413454699d26 Mon Sep 17 00:00:00 2001 From: Admin9705 <9705@duck.com> Date: Mon, 7 Apr 2025 13:46:03 -0400 Subject: [PATCH 03/12] update --- .github/workflows/docker-image.yml | 93 ++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 .github/workflows/docker-image.yml diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 00000000..ea7c086d --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,93 @@ +name: Docker Build and Push +on: + push: + branches: + - main + - dev + tags: + - "*" # This will trigger on any tag push + pull_request: + branches: + - main +jobs: + build-and-push: + runs-on: ubuntu-latest + steps: + # 1) Check out your repository code with full depth + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + # 2) List files to verify huntarr.py is present + - name: List files in directory + run: ls -la + + # 3) Set up QEMU for multi-architecture builds + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + with: + platforms: arm64,amd64 + + # 4) Set up Docker Buildx + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + # 5) Log in to Docker Hub + - name: Log in to Docker Hub + if: github.event_name != 'pull_request' + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + + # 6) Extract version from tag if it's a tag push + - name: Extract version from tag + if: startsWith(github.ref, 'refs/tags/') + id: get_version + run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + + # 7a) Build & Push if on 'main' branch + - name: Build and Push (main) + if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + uses: docker/build-push-action@v3 + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + tags: | + huntarr/4sonarr:latest + huntarr/4sonarr:${{ github.sha }} + + # 7b) Build & Push if on 'dev' branch + - name: Build and Push (dev) + if: github.ref == 'refs/heads/dev' && github.event_name != 'pull_request' + uses: docker/build-push-action@v3 + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + tags: | + huntarr/4sonarr:dev + huntarr/4sonarr:${{ github.sha }} + + # 7c) Build & Push if it's a tag/release + - name: Build and Push (release) + if: startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request' + uses: docker/build-push-action@v3 + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + tags: | + huntarr/4sonarr:${{ steps.get_version.outputs.VERSION }} + huntarr/4sonarr:latest + + # 7d) Just build on pull requests + - name: Build (PR) + if: github.event_name == 'pull_request' + uses: docker/build-push-action@v3 + with: + context: . + push: false + platforms: linux/amd64,linux/arm64 \ No newline at end of file From be90b6b717371e389507c18d382d5f683bba67d5 Mon Sep 17 00:00:00 2001 From: Admin9705 <9705@duck.com> Date: Mon, 7 Apr 2025 13:51:36 -0400 Subject: [PATCH 04/12] update --- web_server.py | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++ webserver.py | 0 2 files changed, 64 insertions(+) create mode 100644 web_server.py delete mode 100644 webserver.py diff --git a/web_server.py b/web_server.py new file mode 100644 index 00000000..1c032115 --- /dev/null +++ b/web_server.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +""" +Web server for Huntarr-Sonarr +Provides a web interface to view logs in real-time +""" + +import os +import time +import datetime +import pathlib +from flask import Flask, render_template, Response, stream_with_context +import logging + +# Disable Flask default logging +log = logging.getLogger('werkzeug') +log.setLevel(logging.ERROR) + +# Create Flask app +app = Flask(__name__) + +# Log file location +LOG_FILE = "/tmp/huntarr-logs/huntarr.log" +LOG_DIR = pathlib.Path("/tmp/huntarr-logs") +LOG_DIR.mkdir(parents=True, exist_ok=True) + +@app.route('/') +def index(): + """Render the main page""" + return render_template('index.html') + +@app.route('/logs') +def stream_logs(): + """Stream logs to the client""" + def generate(): + # First get all existing logs + if os.path.exists(LOG_FILE): + with open(LOG_FILE, 'r') as f: + # Read the last 100 lines of the log file + lines = f.readlines()[-100:] + for line in lines: + yield f"data: {line}\n\n" + + # Then stream new logs as they appear + with open(LOG_FILE, 'r') as f: + # Move to the end of the file + f.seek(0, 2) + while True: + line = f.readline() + if line: + yield f"data: {line}\n\n" + else: + time.sleep(0.1) + + return Response(stream_with_context(generate()), + mimetype='text/event-stream') + +if __name__ == "__main__": + # Create a basic log entry at startup + timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + with open(LOG_FILE, 'a') as f: + f.write(f"{timestamp} - huntarr-web - INFO - Web server starting on port 8988\n") + + # Run the Flask app + app.run(host='0.0.0.0', port=8988, debug=False, threaded=True) \ No newline at end of file diff --git a/webserver.py b/webserver.py deleted file mode 100644 index e69de29b..00000000 From 4f366ea29bf1d4716917421ecf736b73f06785be Mon Sep 17 00:00:00 2001 From: Admin9705 <9705@duck.com> Date: Mon, 7 Apr 2025 14:18:47 -0400 Subject: [PATCH 05/12] update --- templates/index.html | 168 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 151 insertions(+), 17 deletions(-) diff --git a/templates/index.html b/templates/index.html index 122df930..ed81d699 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,73 +1,194 @@ - + Huntarr-Sonarr Log Viewer

Huntarr-Sonarr Log Viewer

-

View the real-time logs from Huntarr-Sonarr

+

View the real-time logs from Huntarr-Sonarr - Visit the Huntarr [Sonarr Edition] GITHUB Page and click the ⭐ in the Upper Right!

-
Connected: Yes | Auto-refresh: Every 1 second
+
+ 💰 Tool Great? Donate @ https://donate.plex.one for my Daughter's College Fund! +
+ +
+
Connected: Yes | Auto-refresh: Every 1 second
+
+ + Night Mode +
+
+