From ac4ec88f424f7b0ed62b917aa2b9decc2f355dba Mon Sep 17 00:00:00 2001 From: Broque Thomas Date: Fri, 8 Aug 2025 18:23:53 -0700 Subject: [PATCH] fixed sync issue --- README.md | 2 +- .../music_database.cpython-312.pyc | Bin 71415 -> 71409 bytes .../__pycache__/sync_service.cpython-312.pyc | Bin 22254 -> 21823 bytes services/sync_service.py | 33 +++++++++++++----- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 07a228f6..924b5698 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ This application requires **slskd**, a web-based Soulseek client, to handle musi #### Installing slskd -**Option 1: Docker (MAYBE?)** +**Option 1: Docker (MAYBE? UNTESTED)** ```bash # Create directories for slskd mkdir -p ~/slskd/{config,downloads,incomplete} diff --git a/database/__pycache__/music_database.cpython-312.pyc b/database/__pycache__/music_database.cpython-312.pyc index 755b64179e98f20207fd109a462869991fde43b3..8e7825f08cdde280391ee0877f16e76ecc4825dc 100644 GIT binary patch delta 53 zcmeyqmgVDG7T(jmyj%=Gu)lv=M({@7i=Pj(#rwz8adF JpMDln1^^e;6g2<< delta 58 zcmeykmgW0e7T(jmyj%=Ga3pG4M&w4`i=P-pCOddbOrCe0ee%CgH~CT$OH$(#Q&Lh> O6dZ${H{bs(qznL|02iSE diff --git a/services/__pycache__/sync_service.cpython-312.pyc b/services/__pycache__/sync_service.cpython-312.pyc index 6d58a27f33513853b8b9ce362f4c7bd62a380941..eb8356858c999513a3fcc65a2d5e1a664217a54a 100644 GIT binary patch delta 4759 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 BRyhCw delta 4952 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 Y3*eQxbGr@$S+4|G?-H1@WoW(s04$?}(*OVf diff --git a/services/sync_service.py b/services/sync_service.py index 2c5e8193..f9412791 100644 --- a/services/sync_service.py +++ b/services/sync_service.py @@ -172,6 +172,18 @@ class PlaylistSyncService: plex_tracks = [r.plex_track for r in matched_tracks if r.plex_track] logger.info(f"Creating playlist with {len(plex_tracks)} matched tracks") + # Validate that all tracks have proper ratingKey attributes for playlist creation + valid_tracks = [] + for i, track in enumerate(plex_tracks): + if track and hasattr(track, 'ratingKey'): + valid_tracks.append(track) + logger.debug(f"✔️ Track {i+1} valid for playlist: '{track.title}' (ratingKey: {track.ratingKey})") + else: + logger.warning(f"❌ Track {i+1} invalid for playlist: {track} (type: {type(track)}, has ratingKey: {hasattr(track, 'ratingKey') if track else 'N/A'})") + + logger.info(f"Playlist validation: {len(valid_tracks)}/{len(plex_tracks)} tracks are valid Plex objects with ratingKeys") + plex_tracks = valid_tracks + sync_success = self.plex_client.update_playlist(playlist.name, plex_tracks) synced_tracks = len(plex_tracks) if sync_success else 0 @@ -232,16 +244,19 @@ class PlaylistSyncService: if db_track and confidence >= 0.7: logger.debug(f"✔️ Database match found for '{original_title}' by '{artist_name}': '{db_track.title}' with confidence {confidence:.2f}") - # Convert database track to format compatible with existing code - class MockPlexTrack: - def __init__(self, db_track): - self.id = str(db_track.id) - self.title = db_track.title - self.artist = db_track.artist_name - self.album = db_track.album_title - self.duration = db_track.duration + # Fetch the actual Plex track object using the database track ID + try: + actual_plex_track = self.plex_client.server.fetchItem(db_track.id) + if actual_plex_track and hasattr(actual_plex_track, 'ratingKey'): + logger.debug(f"✔️ Successfully fetched actual Plex track for '{db_track.title}' (ratingKey: {actual_plex_track.ratingKey})") + return actual_plex_track, confidence + else: + logger.warning(f"❌ Fetched Plex track for '{db_track.title}' lacks ratingKey attribute") - return MockPlexTrack(db_track), confidence + except Exception as fetch_error: + logger.error(f"❌ Failed to fetch actual Plex track for '{db_track.title}' (ID: {db_track.id}): {fetch_error}") + # Continue to try other artists rather than fail completely + continue except Exception as db_error: logger.error(f"Error checking track existence for '{original_title}' by '{artist_name}': {db_error}")