diff --git a/media-dude/.env b/media-dude/.env new file mode 100644 index 0000000..e69de29 diff --git a/media-dude/docker-compose.yml b/media-dude/docker-compose.yml new file mode 100644 index 0000000..e69de29 diff --git a/media-dude/torrentarr/compose.torrentarr.yml b/media-dude/torrentarr/compose.torrentarr.yml new file mode 100644 index 0000000..4f4f4b0 --- /dev/null +++ b/media-dude/torrentarr/compose.torrentarr.yml @@ -0,0 +1,74 @@ +services: + transmission: + image: lscr.io/linuxserver/transmission:latest + environment: + DOCKER_MODS: linuxserver/mods:transmission-env-var-settings + PUID: 998 # media user + PGID: 998 # media group + UMASK: "002" + TZ: America/Los_Angeles + TRANSMISSION_DOWNLOAD_DIR: ${TORRENTARR_DOWNLOAD_DIR:?error}/complete + TRANSMISSION_INCOMPLETE_DIR: ${TORRENTARR_DOWNLOAD_DIR:?error}/incomplete + TRANSMISSION_SPEED_LIMIT_UP: "3750" + TRANSMISSION_SPEED_LIMIT_UP_ENABLED: "true" + TRANSMISSION_WATCH_DIR_ENABLED: "false" + TRANSMISSION_RPC_PORT: ${TORRENTARR_TRANSMISSION_RPC_PORT:?error} + TRANSMISSION_RPC_AUTHENTICATION_REQUIRED: "false" + volumes: + - ./transmission_config:/config + - ${TORRENTARR_DOWNLOAD_DIR:?error}:${TORRENTARR_DOWNLOAD_DIR:?error} + network_mode: "service:gluetun" + restart: unless-stopped + depends_on: + gluetun: + condition: service_healthy + + gluetun: + image: qmcgaw/gluetun + cap_add: + - NET_ADMIN + devices: + - /dev/net/tun:/dev/net/tun + volumes: + - gluetun_forwarding:/tmp/gluetun_forwarding + ports: + - ${TORRENTARR_TRANSMISSION_RPC_PORT:?error}:${TORRENTARR_TRANSMISSION_RPC_PORT:?error} + restart: unless-stopped + environment: + VPN_SERVICE_PROVIDER: protonvpn + VPN_TYPE: wireguard + VPN_PORT_FORWARDING: on + VPN_PORT_FORWARDING_STATUS_FILE: /tmp/gluetun_forwarding/forwarded_port + PORT_FORWARD_ONLY: "on" + SERVER_COUNTRIES: United States + SERVER_CITIES: Los Angeles + UPDATER_PERIOD: 24h + secrets: + - wireguard_private_key + port-watcher: + build: ../port-watcher + volumes: + - gluetun_forwarding:/watch + environment: + PORT_FILE: /watch/forwarded_port + TRANSMISSION_HOST: gluetun + TRANSMISSION_PORT: ${TORRENTARR_TRANSMISSION_RPC_PORT:?error} + restart: unless-stopped + healthcheck: + test: ["CMD", "test", "-f", "/watch/forwarded_port"] + interval: 10s + timeout: 60s + retries: 10 + start_period: 10s + depends_on: + transmission: + condition: service_started + gluetun: + condition: service_healthy + +volumes: + gluetun_forwarding: + +secrets: + wireguard_private_key: + file: ./secrets/wireguard_private_key \ No newline at end of file diff --git a/media-dude/torrentarr/movies/.env b/media-dude/torrentarr/movies/.env new file mode 100644 index 0000000..daa7cdc --- /dev/null +++ b/media-dude/torrentarr/movies/.env @@ -0,0 +1,4 @@ +COMPOSE_FILE=compose.yml:../compose.torrentarr.yml +TORRENTARR_DOWNLOAD_DIR=/media/movies/torrents +TORRENTARR_TRANSMISSION_RPC_PORT=10011 +COMPOSE_BAKE=true \ No newline at end of file diff --git a/media-dude/torrentarr/movies/compose.yml b/media-dude/torrentarr/movies/compose.yml new file mode 100644 index 0000000..8401c59 --- /dev/null +++ b/media-dude/torrentarr/movies/compose.yml @@ -0,0 +1,15 @@ +name: torrentarr-movies +services: + radarr: + image: ghcr.io/hotio/radarr + restart: unless-stopped + ports: + - "7878:7878" + environment: + PUID: 998 + PGID: 998 + UMASK: "002" + TZ: America/Los_Angeles + volumes: + - ./radarr_config:/config + - /media/movies/library:/media/movies/library \ No newline at end of file diff --git a/media-dude/torrentarr/port-watcher/Dockerfile b/media-dude/torrentarr/port-watcher/Dockerfile new file mode 100644 index 0000000..1727c44 --- /dev/null +++ b/media-dude/torrentarr/port-watcher/Dockerfile @@ -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"] \ No newline at end of file diff --git a/media-dude/torrentarr/port-watcher/port-watcher.py b/media-dude/torrentarr/port-watcher/port-watcher.py new file mode 100644 index 0000000..bfad882 --- /dev/null +++ b/media-dude/torrentarr/port-watcher/port-watcher.py @@ -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() \ No newline at end of file diff --git a/media-dude/torrentarr/tv/.env b/media-dude/torrentarr/tv/.env new file mode 100644 index 0000000..08af5d7 --- /dev/null +++ b/media-dude/torrentarr/tv/.env @@ -0,0 +1,4 @@ +COMPOSE_FILE=compose.yml:../compose.torrentarr.yml +TORRENTARR_DOWNLOAD_DIR=/media/tv/torrents +TORRENTARR_TRANSMISSION_RPC_PORT=10010 +COMPOSE_BAKE=true \ No newline at end of file diff --git a/media-dude/torrentarr/tv/compose.yml b/media-dude/torrentarr/tv/compose.yml new file mode 100644 index 0000000..3272ecb --- /dev/null +++ b/media-dude/torrentarr/tv/compose.yml @@ -0,0 +1,15 @@ +name: torrentarr-tv +services: + sonarr: + image: ghcr.io/hotio/sonarr + restart: unless-stopped + ports: + - "8989:8989" + environment: + PUID: 998 + PGID: 998 + UMASK: "002" + TZ: America/Los_Angeles + volumes: + - ./sonarr_config:/config + - /media/tv/library:/media/tv/library \ No newline at end of file