Skip to content

Reliability: m3u8 manifest fetches and cover downloads use ad-hoc clients with no retries (main API client does retry) #4

Description

@JavaGT

Audit finding (read-only review of gamdl 3.8.5, commit 478c3f2). Cross-checked by two models; both judge it real.

Lens: reliability
Suggested grade: Worth exploring (luna: medium; grok: medium for m3u8 fetches, low for covers)

Evidence

  • The main AMP API client has a retry transport (gamdl/api/apple_music.py:192-198, RetryTransport(Retry(total=6, backoff_factor=1, status_forcelist=[429,500,502,503,504]))).
  • But AppleMusicBaseInterface.get_response (gamdl/interface/base.py:89-102) creates a fresh httpx.AsyncClient(timeout=60.0) per call with no retry transport, and it fetches the m3u8 master + variant playlists at interface/song.py:310, 416, 533 and interface/music_video.py:193, 358, 385.
  • Same pattern in get_cover_bytes (interface/base.py:204-217, fresh client, no retries). A transient 5xx or connection reset on a manifest or cover fetch raises, the whole track fails, and it is counted as an error — no retry even though the API client next to it retries 6 times.
  • Each call also opens a fresh TCP/TLS connection (no pooling), adding per-track latency.

Model verdicts

  • luna (gpt-5.6-luna): real, medium. "Use a shared appropriately configured client where lifecycle and headers permit it, or a shared retry policy/helper. Preserve the existing per-request timeouts."
  • grok (grok-4.6): real; medium for m3u8, low for covers. "A flaky m3u8 fetch failing the whole track is the real reliability gap... Do not fail the track if only the cover art request fails."

Fix direction: route manifest/cover fetches through a shared module-level AsyncClient carrying the same RetryTransport policy (GET-only methods are fine here). Optionally treat cover-fetch failure as non-fatal (download without embedded art + warning) rather than failing the track.

Adopt as upstream contribution candidate? (adopt / adapt / reject)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions