#!/usr/bin/env python3 """ Import Shortwave radio stations into Navidrome via Subsonic API """ import sqlite3 import json import requests import hashlib import random import string from urllib.parse import urljoin # ============= CONFIGURATION ============= # Edit these values for your setup NAVIDROME_URL = "http://192.168.1.105:4533" # Your Navidrome URL USERNAME = "tommal" # Your Navidrome username PASSWORD = "tommal" # Your Navidrome password SHORTWAVE_DB = "/home/tommal/snap/shortwave/114/.local/share/Shortwave/Shortwave.db" # ========================================= def generate_token(password, salt): """Generate authentication token for Subsonic API""" token_str = password + salt return hashlib.md5(token_str.encode()).hexdigest() def create_radio_station(base_url, username, token, salt, name, stream_url, homepage_url=""): """Create internet radio station in Navidrome""" url = urljoin(base_url, "/rest/createInternetRadioStation") params = { 'u': username, 't': token, 's': salt, 'v': '1.16.1', 'c': 'ShortwaveImport', 'f': 'json', 'name': name, 'streamUrl': stream_url, 'homepageUrl': homepage_url } try: response = requests.get(url, params=params, timeout=10) response.raise_for_status() result = response.json() if result.get('subsonic-response', {}).get('status') == 'ok': return True, "Success" else: error = result.get('subsonic-response', {}).get('error', {}) return False, f"Error: {error.get('message', 'Unknown error')}" except Exception as e: return False, str(e) def main(): # Generate salt and token salt = ''.join(random.choices(string.ascii_letters + string.digits, k=16)) token = generate_token(PASSWORD, salt) print(f"Connecting to Shortwave database: {SHORTWAVE_DB}") # Connect to Shortwave database conn = sqlite3.connect(SHORTWAVE_DB) cursor = conn.cursor() # Get all stations from library cursor.execute("SELECT uuid, data FROM library") stations = cursor.fetchall() print(f"\nFound {len(stations)} stations in Shortwave library") print(f"Importing to Navidrome at {NAVIDROME_URL}...\n") success_count = 0 failed_count = 0 for uuid, data_json in stations: try: # Parse JSON data data = json.loads(data_json) name = data.get('name', '').strip() # Prefer url_resolved over url stream_url = data.get('url_resolved') or data.get('url', '') homepage = data.get('homepage', '') if not name or not stream_url: print(f"⚠️ Skipping station with missing data (UUID: {uuid})") failed_count += 1 continue print(f"Importing: {name}") print(f" URL: {stream_url}") success, message = create_radio_station( NAVIDROME_URL, USERNAME, token, salt, name, stream_url, homepage ) if success: print(f" ✓ Success\n") success_count += 1 else: print(f" ✗ Failed: {message}\n") failed_count += 1 except json.JSONDecodeError: print(f"⚠️ Skipping station with invalid JSON (UUID: {uuid})") failed_count += 1 except Exception as e: print(f"⚠️ Error processing station {uuid}: {e}") failed_count += 1 conn.close() # Summary print("=" * 50) print(f"Import complete!") print(f" ✓ Successfully imported: {success_count}") print(f" ✗ Failed: {failed_count}") print(f" Total: {len(stations)}") print("=" * 50) if __name__ == "__main__": main()