Commit graph

32 commits

Author SHA1 Message Date
Broque Thomas
d9217237d2 Clean up 286 ruff lint errors to unblock CI and fix 10 latent bugs
PR #340 added ruff to the build-and-test.yml CI gate, which surfaced
286 pre-existing lint errors. Left unfixed, every feature branch push
fails CI. This commit resolves all of them so CI goes green and
contributors can actually land work.

Auto-fixes (248 of 286): removed unused f-string prefixes (F541),
renamed unused loop control variables with underscore prefix (B007),
removed duplicate imports (F811).

Manually fixed 10 latent bugs ruff caught (all wrapped in try/except
today, silently failing):

- music_database.py: _add_discovery_tables() called undefined
  conn.commit() — would have crashed the iTunes-support migration
  for existing databases. Now uses cursor.connection.commit().
- web_server.py settings GET: referenced undefined download_orchestrator
  when it should be soulseek_client. Feature (_source_status on the
  settings payload) was silently missing for UI auto-disable logic.
- web_server.py _process_wishlist_automatically: active_server
  undefined in track-ownership check. Auto-wishlist was falling
  through to the error handler and re-downloading owned tracks.
- web_server.py start_wishlist_missing_downloads: same active_server
  bug in the manual wishlist path.
- web_server.py _process_failed_tracks_to_wishlist_exact: emitted
  wishlist_item_added automation event with undefined artist_name
  and track. Automation event silently never fired correctly.
- web_server.py discovery metadata enrichment: referenced cache
  without calling get_metadata_cache() first. Track enrichment from
  cached API responses was silently skipped.
- web_server.py Beatport discovery worker: wing-it fallback branch
  used undefined successful_discoveries variable. Wing-it counter
  never incremented correctly. Now uses state['spotify_matches']
  consistently with the rest of the function.
- web_server.py _run_full_missing_tracks_process: stale import json
  mid-function shadowed the module-level import, making an earlier
  json.dumps() call reference an unbound local (F823).
- web_server.py discovery loop: platform loop variable shadowed
  the module-level platform import (F402).
- core/watchlist_scanner.py: 7 lambda captures of loop variables
  (B023 classic Python closure-in-loop bug) now bind at creation.

No existing tests had to change. Full suite stays at 263 passed.
2026-04-21 13:30:52 -07:00
Antti Kettunen
71e114b6fe
Tighten legacy logging output
- collapse old multi-line debug bursts into single structured rows
- remove leftover DEBUG-style prefixes from message text
- keep the app log readable without losing useful trace detail
2026-04-21 18:00:31 +03:00
Broque Thomas
71a56bf9b7 Fix playlist cover art not syncing to Plex/Jellyfin from Deezer and other sources
- Pass playlist image_url to _run_sync_task from all source-specific sync
  start handlers (Deezer, Tidal, Spotify public, YouTube, automation mirror)
  — previously only the /api/sync/start endpoint passed it
- Fix plex_client.set_playlist_image: use uploadPoster(url=) instead of
  uploadPoster(data=) which is not a valid PlexAPI argument
- deezer_client: use picture_xl > picture_big > picture_medium fallback
  for better cover art resolution
- tidal_client: extract image_url in get_playlist() from JSON:API
  relationships (was only extracted in metadata-only listing)
- parse_youtube_playlist: capture playlist thumbnail from yt-dlp result
- Add visible logging for image upload attempts and outcomes
2026-04-15 10:25:38 -07:00
Broque Thomas
1c1be6190a Fix Plex playlists crash on Tag objects and add Unknown Artist guard
Plex API can return Tag objects mixed with playlists — these lack the
playlistType attribute, causing AttributeError. Use getattr with safe
default instead of direct attribute access.

Add 3-tier Unknown Artist guard in post-processing: checks track_info
artists, original search result, then re-fetches from metadata API
before building folder paths or embedding tags. Prevents files from
landing in Unknown Artist folders when the download context has
incomplete artist data.
2026-04-12 10:43:51 -07:00
Broque Thomas
71e4df65e3 Remove emojis from all Python log and print statements
Stripped 4,200+ emoji characters from print(), logger calls across
39 Python files. Logs are now clean text — easier to grep, more
professional, no encoding issues on terminals without Unicode support.

Seasonal config icons preserved for UI display.
2026-04-11 21:11:02 -07:00
Broque Thomas
963a003ca0 Set playlist poster image on Plex/Jellyfin/Emby after sync
After a successful playlist sync, if the source playlist has cover
art (Spotify, Tidal, Deezer, etc.), the image is downloaded and
uploaded as the playlist poster on the media server. Plex uses
uploadPoster(), Jellyfin/Emby uses POST /Items/{id}/Images/Primary.
Navidrome skipped (no playlist image API). Failure is silent — sync
result unchanged. Automation-triggered syncs and playlists without
images are unaffected.
2026-04-09 10:08:18 -07:00
Broque Thomas
cfb0e85564 Add Listening Stats page with media server play data integration
Full stats dashboard that polls Plex/Jellyfin/Navidrome for play
history and presents it with Chart.js visualizations:

Backend:
- ListeningStatsWorker polls active server every 30 min
- listening_history DB table with dedup, play_count/last_played on tracks
- get_play_history() and get_track_play_counts() for all 3 servers
- Pre-computed cache for all time ranges (7d/30d/12m/all) rebuilt each sync
- Single cached endpoint serves all stats data instantly
- Stats query methods: top artists/albums/tracks, timeline, genres, health

Frontend:
- New Stats nav page with glassmorphic container matching dashboard style
- Overview cards (plays, time, artists, albums, tracks) with accent hover
- Listening timeline bar chart (Chart.js)
- Genre breakdown doughnut chart with legend
- Top artists visual bubbles with profile pictures + ranked list
- Top albums and tracks ranked lists with album art
- Library health: format breakdown bar, unplayed count, enrichment coverage
- Recently played timeline with relative timestamps
- Time range pills with instant switching via cache
- Sync Now button with spinner, last synced timestamp
- Clickable artist names navigate to library artist detail
- Last.fm global listeners shown alongside personal play counts
- SoulID badges on matched artists
- Empty state when no data synced yet
- Mobile responsive layout

DB migrations: listening_history table, play_count/last_played columns,
all with idempotent CREATE IF NOT EXISTS / PRAGMA checks.
2026-03-22 13:18:14 -07:00
Broque Thomas
7b854baba8 Detect and remove deleted content during incremental database updates
Incremental database updates now detect when artists or albums have been removed from your media server (Plex, Jellyfin, or Navidrome) and automatically clean them up from SoulSync's database. Previously, deleted content would persist as ghost entries until you ran a full refresh. Removal counts are reported in the scan results. Includes safety checks to prevent accidental mass deletion if the server is unreachable or returns incomplete data.
2026-03-03 13:13:38 -08:00
Broque Thomas
a8766828d9 Add content type filters for watchlist artists
Introduces new filters for live versions, remixes, acoustic versions, and compilation albums to the watchlist artist configuration. Updates the database schema, backend API, and web UI to support these options, allowing users to customize which content types are included for each artist in their watchlist.
2026-01-11 01:33:39 -08:00
Broque Thomas
576f151c5c preferred quality updates. 2025-11-09 14:16:38 -08:00
Broque Thomas
8c7cb6d448 manual library selection for plex servers 2025-10-15 15:04:05 -07:00
Broque Thomas
a73d89bc9e Update plex_client.py 2025-09-22 15:15:34 -07:00
Broque Thomas
e06f0ea372 auto scan after download completion and follow with auto incremental update for active server 2025-09-22 15:01:28 -07:00
Broque Thomas
d51171c180 Update plex_client.py 2025-09-12 12:47:00 -07:00
Broque Thomas
845f8e995f playlist backup functionality 2025-08-10 12:42:31 -07:00
Broque Thomas
aee5995c1a auto incremental update 2025-08-09 01:37:25 -07:00
Broque Thomas
73679f5709 bug fixes 2025-08-07 14:53:16 -07:00
Broque Thomas
6bc87cc0f5 improved metadata speed 2025-07-29 14:10:06 -07:00
Broque Thomas
b5859a5ed5 Update plex_client.py 2025-07-29 11:07:16 -07:00
Broque Thomas
2b97e685dc fixed false positive issue from fallback query
removing artist from the search introduced false positives when searching plex.
2025-07-29 10:35:57 -07:00
Broque Thomas
8a2f5eb503 good 2025-07-28 20:41:06 -07:00
Broque Thomas
fc87fe1740 good 2025-07-28 18:59:19 -07:00
Broque Thomas
5265391ae4 good 2025-07-28 16:06:57 -07:00
Broque Thomas
852e755b95 progress 2025-07-25 18:04:23 -07:00
Broque Thomas
ff33f9b3ef better 2025-07-25 00:48:23 -07:00
Broque Thomas
1af9e7d3d3 good 2025-07-24 18:17:50 -07:00
Broque Thomas
8e0e77f4d2 good 2025-07-24 18:09:31 -07:00
Broque Thomas
6358de554f good 2025-07-24 17:45:42 -07:00
Broque Thomas
3f04d7f984 better 2025-07-24 16:10:07 -07:00
Broque Thomas
39ca1e369a good 2025-07-24 14:53:05 -07:00
Broque Thomas
9197081092 better 2025-07-20 10:05:54 -07:00
Broque Thomas
7d43bda3e5 Initial commit 2025-07-09 12:07:41 -07:00