122 lines
4.3 KiB
Python
122 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
import os
|
|
import time
|
|
import requests
|
|
import tempfile
|
|
from pathlib import Path
|
|
from watchdog.observers import Observer
|
|
from watchdog.events import FileSystemEventHandler
|
|
|
|
class PortFileHandler(FileSystemEventHandler):
|
|
def __init__(self, port_syncer):
|
|
self.port_syncer = port_syncer
|
|
|
|
def on_modified(self, event):
|
|
if not event.is_directory and event.src_path == self.port_syncer.port_file:
|
|
self.port_syncer.update_port()
|
|
|
|
class QBitTorrentPortSyncer:
|
|
def __init__(self):
|
|
self.cookies_file = "/tmp/cookies.txt"
|
|
self.port_file = os.getenv('PORT_FORWARDED', '/tmp/port_forwarded')
|
|
self.qbittorrent_user = os.getenv('QBITTORRENT_USER')
|
|
self.qbittorrent_pass = os.getenv('QBITTORRENT_PASS')
|
|
self.qbittorrent_server = os.getenv('QBITTORRENT_SERVER')
|
|
self.qbittorrent_port = os.getenv('QBITTORRENT_PORT')
|
|
self.http_s = os.getenv('HTTP_S', 'http')
|
|
|
|
# Validate required environment variables
|
|
required_vars = [
|
|
'PORT_FORWARDED', 'QBITTORRENT_USER', 'QBITTORRENT_PASS',
|
|
'QBITTORRENT_SERVER', 'QBITTORRENT_PORT'
|
|
]
|
|
|
|
missing_vars = [var for var in required_vars if not os.getenv(var)]
|
|
if missing_vars:
|
|
raise ValueError(f"Missing required environment variables: {', '.join(missing_vars)}")
|
|
|
|
def update_port(self):
|
|
"""Update qBittorrent port from the port file"""
|
|
try:
|
|
# Read the port from the file
|
|
with open(self.port_file, 'r') as f:
|
|
port = f.read().strip()
|
|
|
|
if not port:
|
|
print(f"Warning: Port file {self.port_file} is empty")
|
|
return
|
|
|
|
# Remove old cookies file
|
|
if os.path.exists(self.cookies_file):
|
|
os.remove(self.cookies_file)
|
|
|
|
# Login to qBittorrent
|
|
login_url = f"{self.http_s}://{self.qbittorrent_server}:{self.qbittorrent_port}/api/v2/auth/login"
|
|
login_data = {
|
|
'username': self.qbittorrent_user,
|
|
'password': self.qbittorrent_pass
|
|
}
|
|
|
|
session = requests.Session()
|
|
login_response = session.post(login_url, data=login_data)
|
|
|
|
if login_response.status_code != 200:
|
|
print(f"Failed to login to qBittorrent: HTTP {login_response.status_code}")
|
|
return
|
|
|
|
# Update port preferences
|
|
prefs_url = f"{self.http_s}://{self.qbittorrent_server}:{self.qbittorrent_port}/api/v2/app/setPreferences"
|
|
prefs_data = {
|
|
'json': f'{{"listen_port": "{port}"}}'
|
|
}
|
|
|
|
prefs_response = session.post(prefs_url, data=prefs_data)
|
|
|
|
if prefs_response.status_code == 200:
|
|
print(f"Successfully updated qbittorrent to port {port}")
|
|
else:
|
|
print(f"Failed to update port: HTTP {prefs_response.status_code}")
|
|
|
|
except FileNotFoundError:
|
|
print(f"Couldn't find file {self.port_file}")
|
|
except Exception as e:
|
|
print(f"Error updating port: {e}")
|
|
|
|
def run(self):
|
|
"""Main loop to monitor port file changes"""
|
|
observer = Observer()
|
|
event_handler = PortFileHandler(self)
|
|
|
|
while True:
|
|
if os.path.exists(self.port_file):
|
|
print(f"Found port file {self.port_file}, starting monitoring...")
|
|
|
|
# Push port on startup - wait a moment for file to be fully written
|
|
time.sleep(2)
|
|
print("Pushing port on startup...")
|
|
self.update_port()
|
|
|
|
# Start file monitoring
|
|
observer.schedule(event_handler, os.path.dirname(self.port_file), recursive=False)
|
|
observer.start()
|
|
|
|
try:
|
|
while True:
|
|
time.sleep(1)
|
|
except KeyboardInterrupt:
|
|
observer.stop()
|
|
break
|
|
else:
|
|
print(f"Couldn't find file {self.port_file}")
|
|
print("Trying again in 10 seconds")
|
|
time.sleep(10)
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
syncer = QBitTorrentPortSyncer()
|
|
syncer.run()
|
|
except KeyboardInterrupt:
|
|
print("\nShutting down...")
|
|
except Exception as e:
|
|
print(f"Error: {e}")
|
|
exit(1) |