From 008653a69c1735645ef58ca61b69aad36e669e0b Mon Sep 17 00:00:00 2001 From: Broque Thomas Date: Thu, 11 Sep 2025 13:53:36 -0700 Subject: [PATCH] Improve Docker compatibility for host service URLs Updated Soulseek client, web server, and docker-compose.yml to better handle service URLs when running inside Docker containers. Localhost URLs are now resolved to host.docker.internal, and Docker-specific volume mounts and extra_hosts are configured for improved interoperability between container and host services. --- core/soulseek_client.py | 9 ++++++++- docker-compose.yml | 10 ++++++++-- web_server.py | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/core/soulseek_client.py b/core/soulseek_client.py index 40b2e8ab..4ca8dd60 100644 --- a/core/soulseek_client.py +++ b/core/soulseek_client.py @@ -219,7 +219,14 @@ class SoulseekClient: logger.warning("Soulseek slskd URL not configured") return - self.base_url = config['slskd_url'].rstrip('/') + # Apply Docker URL resolution if running in container + slskd_url = config.get('slskd_url') + import os + if os.path.exists('/.dockerenv') and 'localhost' in slskd_url: + slskd_url = slskd_url.replace('localhost', 'host.docker.internal') + logger.info(f"Docker detected, using {slskd_url} for slskd connection") + + self.base_url = slskd_url.rstrip('/') self.api_key = config.get('api_key', '') self.download_path = Path(config.get('download_path', './downloads')) self.download_path.mkdir(parents=True, exist_ok=True) diff --git a/docker-compose.yml b/docker-compose.yml index 51bd20dd..3bae794b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,8 +13,11 @@ services: - ./config:/app/config - ./database:/app/database - ./logs:/app/logs - - ./downloads:/app/downloads - - ./Transfer:/app/Transfer + # Soulseek download and transfer directories (mapped to host E: drive paths) + - /mnt/e/Broque Projects/newMusic/downloads:/app/downloads + - /mnt/e/Broque Projects/newMusic/transfer:/app/transfer + # Stream folder for temporary playback files + - /mnt/e/Broque Projects/newMusic/stream:/app/stream # Optional: Mount your music library for Plex/Jellyfin access - /path/to/your/music:/music:ro environment: @@ -25,6 +28,9 @@ services: - SOULSYNC_CONFIG_PATH=/app/config/config.json # Set timezone - TZ=America/New_York + extra_hosts: + # Allow container to reach host services + - "host.docker.internal:host-gateway" restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8888/"] diff --git a/web_server.py b/web_server.py index 836f1e93..894de55a 100644 --- a/web_server.py +++ b/web_server.py @@ -1062,8 +1062,11 @@ def run_service_test(service, test_config): # 1. Save original config for the specific service original_config = config_manager.get(service, {}) - # 2. Temporarily set the new config for the test + # 2. Temporarily set the new config for the test (with Docker URL resolution) for key, value in test_config.items(): + # Apply Docker URL resolution for URL/URI fields + if isinstance(value, str) and ('url' in key.lower() or 'uri' in key.lower()): + value = docker_resolve_url(value) config_manager.set(f"{service}.{key}", value) # 3. Run the test with the temporary config @@ -1251,6 +1254,25 @@ def run_detection(server_type): print(f"Found {server_type} at localhost!") return localhost_result + # Priority 1.5: In Docker, try Docker host IP + import os + if os.path.exists('/.dockerenv'): + print(f"Docker detected, testing Docker host for {server_type}...") + try: + # Try host.docker.internal (Windows/Mac) + host_result = test_func("host.docker.internal") + if host_result: + print(f"Found {server_type} at Docker host!") + return host_result.replace("host.docker.internal", "localhost") # Convert back to localhost for config + + # Try Docker bridge gateway (Linux) + gateway_result = test_func("172.17.0.1") + if gateway_result: + print(f"Found {server_type} at Docker gateway!") + return gateway_result.replace("172.17.0.1", "localhost") # Convert back to localhost for config + except Exception as e: + print(f"Docker host detection failed: {e}") + # Priority 2: Test local IP print(f"Testing local IP {local_ip} for {server_type}...") local_result = test_func(local_ip) @@ -11238,6 +11260,17 @@ class WebMetadataUpdateWorker: print(f"Error uploading poster: {e}") return False +# --- Docker Helper Functions --- + +def docker_resolve_url(url): + """ + Resolve localhost URLs to Docker host when running in container + """ + import os + if os.path.exists('/.dockerenv') and 'localhost' in url: + return url.replace('localhost', 'host.docker.internal') + return url + # --- Main Execution --- def start_oauth_callback_servers():