Add initial commit of new media management docker stack

Includes transmission, gluetun, sonarr, radarr stacks
Includes framework for adding plex, tautulli, prowlarr, overseerr, requestrr, and trash guides sync stacks
Includes port-watcher docker container that monitors gluetun port forwarding file and sets transmission peer_port automatically
This commit is contained in:
Chris King
2025-03-12 10:47:54 -07:00
parent 2abb9cb5d2
commit ff4bea25f6
9 changed files with 202 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
FROM python:3.11-alpine
WORKDIR /app
COPY port-watcher.py .
RUN pip install watchdog transmission-rpc
CMD ["python", "port-watcher.py"]

View File

@@ -0,0 +1,82 @@
#!/usr/bin/env python3
import os
import time
import logging
from transmission_rpc import Client
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
logger = logging.getLogger()
PORT_FILE = os.getenv('PORT_FILE', '/watch/forwarded_port')
TRANSMISSION_HOST = os.getenv('TRANSMISSION_HOST', 'gluetun')
TRANSMISSION_PORT = os.getenv('TRANSMISSION_PORT', 9091)
class PortFileHandler(FileSystemEventHandler):
def __init__(self):
self.last_port = None
self.transmission_client = Client(host=TRANSMISSION_HOST, port=TRANSMISSION_PORT)
self.check_port_file() # Initial check
def on_modified(self, event):
if not event.is_directory and event.src_path == PORT_FILE:
self.check_port_file()
def check_port_file(self):
try:
if not os.path.exists(PORT_FILE):
logger.info(f"Port file not found: {PORT_FILE}")
return
with open(PORT_FILE, 'r') as f:
port = f.read().strip()
if port != self.last_port and port.isdigit():
self.last_port = port
logger.info(f"Port forwarding changed to: {port}")
self.update_transmission(port)
except Exception as e:
logger.error(f"Error checking port file: {e}")
def update_transmission(self, port):
max_attempts = 5
attempt = 1
delay = 5 # seconds between retry attempts
while attempt <= max_attempts:
logger.info(f"Attempt {attempt}/{max_attempts}: Setting Transmission peer_port to {port}")
try:
self.transmission_client.set_session(peer_port=int(port))
logger.info(f"Successfully updated Transmission peer_port to {port}")
logger.info(f"Testing Transmission peer port...")
if self.transmission_client.port_test():
logger.info("Transmission peer port is open")
else:
logger.warning("Transmission peer port does not appear to be open")
return
except Exception as e:
logger.warning(f"Attempt {attempt}/{max_attempts} failed: {e}")
if attempt < max_attempts:
logger.info(f"Retrying in {delay} seconds...")
time.sleep(delay)
attempt += 1
logger.error(f"Failed to update Transmission peer_port after {max_attempts} attempts")
if __name__ == "__main__":
path = os.path.dirname(PORT_FILE)
logger.info(f"Starting port-watcher monitoring {PORT_FILE}")
event_handler = PortFileHandler()
observer = Observer()
observer.schedule(event_handler, path, recursive=False)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()