from datetime import datetime from ifireflylib import IFireflyClient as FireflyDatabase class FireflyDB: def __init__(self): # Initialize with default values self.use_db = False self.db = None self.artists = set() self.albums = set() self.genres = set() self.years = set() def connect_to( self, use_db=False, db_host="localhost", db_port=6379, db_password=None ): # Set the use_db flag self.use_db = use_db # Metadata organization self.artists = set() self.albums = set() self.genres = set() self.years = set() if use_db: try: print(f"Connecting to FireflyDB at {db_host}:{db_port}") self.db = FireflyDatabase( host=db_host, port=db_port, password=db_password ) # Test connection if not self.db.ping(): print( "Warning: Could not connect to FireflyDB. Continuing without database." ) self.use_db = False self.db = None else: print("Successfully connected to FireflyDB") # Store connection timestamp timestamp = str(datetime.now()) print(f"Setting last_connection timestamp: {timestamp}") self.db.string_ops.string_set("last_connection", timestamp) print("Connection timestamp stored successfully") except Exception as e: print(f"Error connecting to FireflyDB: {e}") import traceback traceback.print_exc() self.use_db = False self.db = None def close(self): """Close database connection when done""" if self.db: self.db.close() self.db = None def has_metadata_in_db(self, file_path): """Check if metadata for a file already exists in the database""" if not self.use_db or not self.db: return False try: key = f"audio:{file_path}" # Use hash_exists to check if the key exists in the database exists = self.db.hash_ops.hash_exists(key, "title") return exists except Exception as e: print(f"Error checking metadata in database: {e}") return False def store_metadata(self, metadata): """Store audio file metadata in the database""" if not self.use_db or not self.db: print("Database usage is disabled, not storing metadata") return False try: # Use the file path as a unique key file_path = metadata["file_path"] key = f"audio:{file_path}" # Log the storage attempt print(f"Storing metadata for {file_path} in FireflyDB") print(f"Metadata fields: {list(metadata.keys())}") # Store as a hash with all metadata fields success = True for field, value in metadata.items(): if field != "file_path": # Skip using file_path as a field print(f" Setting field {field}={value}") # Use the direct hash_set method instead of hash_ops result = self.db.hash_ops.hash_set(key, field, value) if not result: print( f" Failed to store field {field} for {file_path}" ) success = False else: print(f" Successfully stored field {field}") # Add to index lists for quick lookup if "artist" in metadata and metadata["artist"]: artist_key = f"index:artist:{metadata['artist']}" print(f" Adding to artist index: {artist_key}") self.db.list_ops.list_right_push(artist_key, file_path) if "album" in metadata and metadata["album"]: album_key = f"index:album:{metadata['album']}" print(f" Adding to album index: {album_key}") self.db.list_ops.list_right_push(album_key, file_path) if "genre" in metadata and metadata["genre"]: genre_key = f"index:genre:{metadata['genre']}" print(f" Adding to genre index: {genre_key}") self.db.list_ops.list_right_push(genre_key, file_path) # Add to a master list of all audio files for easy retrieval print(" Adding to master audio files list") self.db.list_ops.list_right_push("all_audio_files", file_path) # Store timestamp of when metadata was added self.db.hash_ops.hash_set(key, "timestamp", str(datetime.now())) # Verify storage by retrieving one field if "title" in metadata: retrieved_title = self.db.hash_ops.hash_get(key, "title") print(f" Verification - Retrieved title: {retrieved_title}") if retrieved_title != metadata["title"]: print( f" Verification failed: expected '{metadata['title']}', got '{retrieved_title}'" ) success = False print( f"Metadata storage {'successful' if success else 'partially failed'} for {file_path}" ) return success except Exception as e: print(f"Error storing metadata in database: {e}") import traceback traceback.print_exc() return False def get_metadata_from_db(self, file_path): """Retrieve metadata for a file from the database""" if not self.use_db or not self.db: return None try: key = f"audio:{file_path}" metadata = self.db.hash_ops.hash_get_all(key) if metadata: # Add the file path to the metadata metadata["file_path"] = file_path return metadata return None except Exception as e: print(f"Error retrieving metadata from database: {e}") return None def search_by_artist(self, artist): """Search for files by artist""" if not self.use_db or not self.db: return [] try: key = f"index:artist:{artist}" return self.db.list_range(key, 0, -1) except Exception as e: print(f"Error searching by artist: {e}") return [] # Similar methods for album and genre searches def process_metadata(self, metadata): """Process extracted metadata""" if "artist" in metadata and metadata["artist"]: self.artists.add(metadata["artist"]) if "album" in metadata and metadata["album"]: self.albums.add(metadata["album"]) if "genre" in metadata and metadata["genre"]: self.genres.add(metadata["genre"]) if "year" in metadata and metadata["year"]: self.years.add(metadata["year"]) # Store in database if enabled if self.use_db and self.db: db_success = self.store_metadata(metadata) if db_success: print( f"Successfully stored metadata for {metadata.get('file_path', 'unknown file')} in database" ) else: print( f"Failed to store metadata for {metadata.get('file_path', 'unknown file')} in database" ) def verify_database_connection(self): """Verify that the database connection is working properly""" if not self.use_db or not self.db: print("Database usage is disabled") return False try: # Test ping ping_result = self.db.ping() if not ping_result: print("Database ping failed") return False # Test basic operations test_key = "test:connection" test_value = "connection_test" # Test string operations string_set_result = self.db.string_set(test_key, test_value) if not string_set_result: print("Failed to set test string in database") return False string_get_result = self.db.string_get(test_key) if string_get_result != test_value: print( f"String get test failed. Expected '{test_value}', got '{string_get_result}'" ) return False # Clean up self.db.delete(test_key) print("Database connection verified successfully") return True except Exception as e: print(f"Database verification failed with error: {e}") return False