Skip to content

Fix playlist download issues and improve logging experience#944

Open
geekinsanemx wants to merge 1 commit intonathom:devfrom
geekinsanemx:dev
Open

Fix playlist download issues and improve logging experience#944
geekinsanemx wants to merge 1 commit intonathom:devfrom
geekinsanemx:dev

Conversation

@geekinsanemx
Copy link

@geekinsanemx geekinsanemx commented Mar 14, 2026

This PR addresses some IndexError bugs that were stopping playlist downloads and makes the download experience much cleaner by reducing log spam and providing more helpful error messages.

Bug Fixes

1. Handle empty tracks list from Deezer API

What was happening: Some tracks in playlists (especially geo-restricted ones) return album metadata with an empty tracks list, which caused an IndexError when trying to access the last track's disc number.

Why it happened: The code assumed there's always at least one track in the list. This can happen with albums that exist in Deezer's database but don't have accessible tracks in your region.

What changed: Now we check if the tracks list is empty before accessing it, and default to disctotal = 1 when needed.

Result: Playlist downloads keep going even when they encounter unavailable albums, instead of stopping completely.

2. Smart quality handling across all sources

What was happening: Using --quality 3 or --quality 4 on Deezer (which only supports up to quality 2) caused an IndexError.

Why it happened: Deezer's quality map only has 3 quality levels (0, 1, 2), so requesting index 3 was out of bounds.

What changed: Added automatic quality clamping in the base Client class. Each source now declares its maximum quality:

  • Deezer: max quality 2 (FLAC 16/44.1)
  • Tidal: max quality 3 (MQA/Hi-Res)
  • Qobuz: max quality 4 (Hi-Res 24/192)
  • SoundCloud: max quality 3

Result: You can now use --quality 3 or --quality 4 everywhere, and each source automatically uses its highest available quality. Shows a friendly one-time warning like: "Requested quality 3 exceeds Deezer maximum (quality 2). Using highest available quality (2) for all tracks."

3. Better version update detection

What was happening: Development versions showed "new version available" messages even when the PyPI version was older.

Why it happened: Version check used != instead of >, so any difference triggered the notification.

What changed: Now uses proper numeric comparison (e.g., 2.2.0 > 2.1.0).

Result: Update notifications only show when there's actually a newer version on PyPI.

User Experience Improvements

4. Cleaner logs - no more connection pool warnings

What was happening: Logs were flooded with "Connection pool is full" warnings during playlist downloads.

What changed: These urllib3 warnings are now suppressed since they're just performance warnings - downloads work perfectly fine.

Result: Much cleaner log output without harmless warnings.

5. Quality fallback messages are now quieter

What was happening: Console showed "Quality X not available, falling back..." for every single track.

What changed: These messages are now at DEBUG level, so they don't clutter the output.

Result: Cleaner console output. You can still enable debug logging if you want to see the quality fallback details.

6. Error messages now show actual song names

What was happening: Errors only showed track IDs like "Error for track 964342", so you had to look up which song that was.

What changed: Now extracts and shows the track title and artist from the API response.

Example:

  • Before: Error fetching download info for track 964342
  • After: Error fetching download info for "Bohemian Rhapsody" by Queen

Result: You instantly know which songs had issues without needing to look up IDs.

7. More helpful error messages

What was happening: Generic messages like "Missing download info. Skipping." didn't explain why tracks failed.

What changed: More descriptive messages like "Track not available for download (no file sizes returned by API). Likely removed, geo-restricted, or licensing issue."

Result: You understand why tracks fail instead of wondering if it's a bug.

Technical Details

New feature: Client.clamp_quality() base class method

  • Handles quality clamping consistently across all sources
  • Shows a friendly one-time warning per session if needed
  • All client implementations inherit this behavior

Files modified:

  • streamrip/client/client.py - Add clamp_quality() base method
  • streamrip/client/deezer.py - Use clamp_quality(), suppress connection warnings
  • streamrip/client/qobuz.py - Add super().init() call
  • streamrip/client/tidal.py - Add super().init() call
  • streamrip/client/soundcloud.py - Add super().init() call, set max_quality
  • streamrip/client/downloadable.py - Better error messages
  • streamrip/media/playlist.py - Extract track names for errors
  • streamrip/metadata/album.py - Handle empty tracks list safely
  • streamrip/rip/cli.py - Fix version comparison logic

Testing

Tested with:

  • ✅ Deezer playlists with geo-restricted tracks
  • ✅ Quality 3 and 4 requests on all sources
  • ✅ Empty tracks list responses
  • ✅ Version check with dev versions vs PyPI

This commit fixes two IndexError crashes that prevented playlist downloads
and significantly improves the user experience by reducing log spam while
providing more informative error messages.

## Critical Bug Fixes

### 1. Fix crash when Deezer API returns empty tracks list
**Issue:** When downloading playlists, some tracks return album metadata with
an empty tracks list (`{"tracks": []}`), causing IndexError at album.py:165
when trying to access `resp["tracks"][-1]["disk_number"]`.

**Error:** `IndexError: list index out of range`

**Root Cause:** Code assumed tracks list always contains at least one track.
This happens with geo-restricted or removed albums that exist in Deezer's
database but have no accessible tracks.

**Fix:** Check if tracks list is empty before accessing the last element.
Default to `disctotal = 1` when list is empty (streamrip/metadata/album.py).

**Impact:** Playlist downloads now continue instead of crashing when
encountering unavailable albums.

### 2. Fix crash when requested quality exceeds source maximum
**Issue:** Requesting quality 3 or 4 on Deezer (which only supports 0-2)
caused IndexError at deezer.py:166 when accessing `size_map[quality]`.

**Error:** `IndexError: list index out of range`

**Root Cause:** User requests `--quality 3` (Hi-Res), but Deezer's quality_map
only has 3 elements (indices 0, 1, 2). Code tried to access index 3 which
doesn't exist.

**Fix:** Implemented smart quality clamping in base Client class. Each source
declares its max_quality (Deezer=2, Tidal=3, Qobuz=4, SoundCloud=3), and
requests are automatically clamped to the maximum supported quality.

**New Behavior:**
- Warns ONCE per session: "Requested quality 3 exceeds Deezer maximum (quality 2).
  Using highest available quality (2) for all tracks."
- Automatically uses highest available quality for all subsequent tracks
- No more repeated warnings or crashes

**Impact:** Users can use `--quality 3` or `--quality 4` globally, and each
source will automatically use its maximum quality without crashes.

### 3. Fix version check showing false update notifications
**Issue:** Running development version (2.2.0) showed "new version 2.1.0
available" because code only checked if versions were different, not if
PyPI version was actually newer.

**Root Cause:** Version comparison used `!=` instead of `>`, so any difference
triggered the update message.

**Fix:** Changed to numeric version comparison using tuple comparison
(e.g., (2,2,0) > (2,1,0)).

**New Behavior:**
- Shows update message ONLY when PyPI version is numerically greater than
  running version
- Running 2.2.0 with PyPI at 2.1.0 = No message
- Running 2.1.0 with PyPI at 2.2.0 = Shows message

## User Experience Improvements

### 4. Eliminate connection pool warning spam
**Issue:** Logs flooded with "Connection pool is full, discarding connection"
warnings every few seconds during playlist downloads.

**Root Cause:** urllib3 (used by deezer-py) has default pool size of 10.
Concurrent metadata fetches for 20+ tracks exhaust the pool.

**Fix:** Suppress urllib3.connectionpool logger warnings. These are performance
warnings, not failures - downloads work perfectly, just with new connections
instead of reused ones.

**Impact:** Clean logs without harmless warnings. Downloads unaffected.

### 5. Reduce quality fallback logging to DEBUG level
**Issue:** Logs spammed with "The requested quality 2 is not available.
Falling back to quality 1" for every track that lacks the requested quality.

**Fix:** Consolidated to single DEBUG-level message per track. Only logs when
fallback actually occurs, not for every quality level checked.

**Impact:** Significantly cleaner output. Enable debug logging if you want
to see which tracks fell back to lower quality.

### 6. Show track names in error messages
**Issue:** Error messages only showed track IDs, requiring users to manually
look up which songs failed: "Error fetching download info for track 964342"

**Fix:** Extract and display track title and artist from API response before
errors occur. Handle different API response formats (dict vs list for artist).

**New Error Format:**
- Before: `Error fetching download info for track 964342: Track not available...`
- After: `Error fetching download info for "Bohemian Rhapsody" by Queen: Track not available...`

**Impact:** Users instantly know which songs failed without looking up IDs.

### 7. Improve error messages for unavailable tracks
**Issue:** Generic "Missing download info. Skipping." didn't explain why.

**Fix:** More descriptive message: "Track not available for download (no file
sizes returned by API). Likely removed, geo-restricted, or licensing issue."

**Impact:** Users understand why tracks fail instead of wondering if it's a bug.

## Implementation Details

**New Base Class Method:** `Client.clamp_quality(requested_quality)`
- Implemented in base Client class (streamrip/client/client.py)
- Each source declares max_quality as class attribute
- Warns once per session if clamping occurs
- All clients (Deezer, Tidal, Qobuz, SoundCloud) now inherit this behavior

**Modified Files:**
- streamrip/client/client.py: Add clamp_quality() base method
- streamrip/client/deezer.py: Use clamp_quality(), suppress warnings
- streamrip/client/qobuz.py: Add super().__init__() call
- streamrip/client/tidal.py: Add super().__init__() call
- streamrip/client/soundcloud.py: Add super().__init__() call, set max_quality
- streamrip/client/downloadable.py: Improve error message for missing download info
- streamrip/media/playlist.py: Extract track names for error messages
- streamrip/metadata/album.py: Handle empty tracks list safely
- streamrip/rip/cli.py: Fix version comparison logic

## Testing

Tested with:
- Deezer playlists containing geo-restricted tracks
- Quality 3 and 4 requests on all sources
- Empty tracks list responses
- Version check with dev version vs PyPI version

All previously crashing scenarios now work correctly with informative messages.
@geekinsanemx geekinsanemx changed the title Fix multiple bugs and improve user experience Fix playlist download issues and improve logging experience Mar 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant