From 7a5bba2ef3bb6d50433169c20630562e562305bc Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Wed, 4 Feb 2026 11:13:08 -0700 Subject: [PATCH] feat: Continuously poll playlists and execute command on song count change Co-authored-by: aider (gemini/gemini-2.5-pro) --- main.py | 79 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/main.py b/main.py index e0380e8..61d8b87 100644 --- a/main.py +++ b/main.py @@ -2,6 +2,8 @@ import os, logging import hashlib import random import string +import subprocess +import time import requests DEBUG = os.environ.get('DEBUG') @@ -40,36 +42,67 @@ def main(): 'f': 'json' } - api_url = f"{navidrome_url.rstrip('/')}/rest/getPlaylists.view" + playlist_song_counts = {} - try: - response = requests.get(api_url, params=params) - response.raise_for_status() # Raise an exception for bad status codes - except requests.exceptions.RequestException as e: - logging.error(f"Error connecting to Navidrome: {e}") - return + while True: + api_url = f"{navidrome_url.rstrip('/')}/rest/getPlaylists.view" - data = response.json() + try: + response = requests.get(api_url, params=params) + response.raise_for_status() # Raise an exception for bad status codes + except requests.exceptions.RequestException as e: + logging.error(f"Error connecting to Navidrome: {e}") + time.sleep(5) + continue - subsonic_response = data.get('subsonic-response') - if not subsonic_response: - logging.error("Invalid response format from server.") - return + data = response.json() - if subsonic_response.get('status') == 'failed': - error = subsonic_response.get('error', {}) - logging.error(f"API Error: {error.get('message')} (code: {error.get('code')})") - return + subsonic_response = data.get('subsonic-response') + if not subsonic_response: + logging.error("Invalid response format from server.") + time.sleep(5) + continue - playlists = subsonic_response.get('playlists', {}).get('playlist', []) + if subsonic_response.get('status') == 'failed': + error = subsonic_response.get('error', {}) + logging.error(f"API Error: {error.get('message')} (code: {error.get('code')})") + time.sleep(5) + continue - if not playlists: - logging.info("No playlists found for user '%s'.", username) - return + playlists = subsonic_response.get('playlists', {}).get('playlist', []) + + current_playlists = {p.get('id'): p for p in playlists} - print(f"Playlists for {username}:") - for playlist in playlists: - print(f" - [{playlist.get('id')}] {playlist.get('name')} ({playlist.get('songCount')} songs)") + # On the first successful poll, print the list of playlists and populate the counts + if not playlist_song_counts and playlists: + logging.info("Initial scan. Monitoring playlists for changes.") + print(f"Playlists for {username}:") + for playlist_id, playlist_data in current_playlists.items(): + print(f" - [{playlist_id}] {playlist_data.get('name')} ({playlist_data.get('songCount')} songs)") + + # Check for song count changes in playlists we are already tracking + for playlist_id, playlist_data in current_playlists.items(): + current_song_count = playlist_data.get('songCount') + if playlist_id in playlist_song_counts and playlist_song_counts[playlist_id] != current_song_count: + logging.info(f"Song count changed for '{playlist_data.get('name')}' ({playlist_id}): {playlist_song_counts[playlist_id]} -> {current_song_count}. Running command.") + + cmd = ['docker', 'exec', 'navidrome-navidrome-1', '/app/navidrome', 'pls', '-l', 'error', '-np', playlist_id] + try: + result = subprocess.run(cmd, capture_output=True, text=True, check=False) + print(f"\n--- Output for playlist '{playlist_data.get('name')}' ---") + if result.stdout.strip(): + print(result.stdout.strip()) + if result.stderr.strip(): + print("STDERR:") + print(result.stderr.strip()) + print("--- End output ---\n") + except FileNotFoundError: + logging.error("Command 'docker' not found. Please ensure it is installed and in your PATH.") + + # Update the state for the next iteration. This handles new, deleted, and updated playlists. + playlist_song_counts = {pid: pdata.get('songCount') for pid, pdata in current_playlists.items()} + + time.sleep(5) if __name__ == "__main__":