Changelog

This page keeps a detailed human friendly rendering of what’s new and changed in specific versions.

Unreleased

Added

Fixed

Changed

Miscellaneous

v1.3.0 - 2026-07-20

Added

  • Added various helper methods to Queue:

    • Queue.sort() to sort the queue by a given key function. Similar to Python’s built-in list.sort() method.

      • Example: queue.sort(key=lambda track: track.title) to sort by track title.

    • Queue.reverse() to reverse the order of the queue.

    • Queue.dedupe() to remove duplicate tracks from the queue.

    • Queue.__reversed__() to allow the built-in reversed() function on the queue.

  • Added History.enabled property for checking whether history recording is active.

  • Added Player.skip_to() to skip directly to a track at a specific queue index.

  • Added Queue.move() to move a track from one index to another, shifting other tracks accordingly.

  • Added Queue.remove_at() to remove and return a track by index without side effects on the current track.

  • Added a key parameter to Queue.remove() and Queue.remove_wait() for removing tracks by an arbitrary derived value instead of equality, without needing to hold the original Playable instance.

    • Example: queue.remove([track.identifier], key=lambda t: t.identifier) to remove a track by its identifier.

  • Added ShuffleMode and Queue.shuffle_mode for persistent shuffle support.

  • Added a key parameter to Queue.get() and Queue.get_wait() to avoid picking a track that collides with the current track on an arbitrary derived value, e.g. to avoid repeats.

    • Example: queue.get(key=lambda track: track.author) to avoid picking a track by the currently playing artist.

    • If every remaining candidate collides, the collision is allowed rather than raising.

  • Added a key parameter to Player.skip(), forwarded straight through to Queue.get(), so the same repeat-avoidance behaves consistently whether tracks are pulled from the queue directly or via the player.

    • Example: await player.skip(key=lambda track: track.author).

Fixed

  • Fixed Queue.get_wait() not registering the waiter before attempting to retrieve a track, causing a race condition where a concurrent put() could be missed and the waiter would hang indefinitely.

  • Fixed Queue.history returning a History instance when history is disabled; now correctly returns None.

  • Fixed Player.play() not pushing the previously playing track to history before starting a new track, matching the documented behavior.

  • Fixed Player.stop() with clear_queue=True not clearing AutoPlay-discovered tracks from the queue.

  • Fixed Player.stop() silently resetting Queue.mode to QueueMode.NORMAL when clear_queue=True; this is now documented behavior.

  • Fixed Queue.copy() creating a new History that shared a mutable reference to the original settings object, causing mutations to enabled or max_items to leak between copies.

  • Fixed Queue.remove() with a key parameter ignoring duplicate lookup values and crashing on unhashable types; both the remove_all=True and remove_all=False paths now consistently respect user-provided values.

  • Added missing exports for AutoPlaySeedMissing, FrameworkClientMismatch, and FrameworkImportError to the top-level __all__.

  • Fixed Player.on_track_end() dispatching TrackEndEvent with the wrong original track when skip() was triggered, because _original_track was overwritten by play() before the event was emitted.

  • Fixed Player.previous() pushing the previous track back into history after play() was called, creating a duplicate history entry.

  • Fixed Filters constructor not calling super().__init__(), leaving _client and _data uninitialised on direct construction.

Miscellaneous

  • Consolidated the separate pr-checks and pr-template workflows into a single pr-governance workflow.

  • Scoped all CI job permissions to read-only and disabled credential persistence on checkout for improved security.

  • Added a 15-minute timeout to every CI job.

  • Enabled pip caching across CI workflows.

  • Added concurrency control to the lint workflow to cancel redundant runs.

  • Added twine check and build provenance attestation to the release workflow.

  • Hardened the template-check validation and excluded draft PRs from template enforcement, triggering checks only on ready_for_review.

  • Added sticky h2/h3 headers, a hover-highlights toggle persisted in localStorage, and alphabetical “On this page” TOC sorting to the docs.

  • Enabled nitpicky Sphinx mode and sphinx-autodoc-typehints; replaced raw :class: references with proper cross-references throughout.

  • Exposed missing exception classes (SonoLinkException, NodeError, NetworkError) and Version/GitInfo models in the API docs.

v1.2.1 - 2026-07-04

Added

  • Added the missing NetworkError export to the public API.

Fixed

  • Fixed a typo in __repr_attrs__ of WebSocketClosedEvent.

  • Fixed an incorrect datetime timestamp in time caused by differing time units.

  • Fixed an issue where the node status would remain stuck on NodeStatus.CONNECTING after an attempt_connect failure.

  • Fixed Filters not populating data on the instance.

  • Fixed a race condition in the node reconnection flow that caused an intermittent “Timed out waiting for node READY payload” error after prolonged uptime.

v1.2.0 - 2026-06-23

Added

Fixed

  • Fixed an issue where the client would not attempt to reconnect to a node after a disconnection, even if auto_reconnect was enabled.

  • Fixed an issue with using the speed extra, or the curl-cffi package where it would raise a CurlError and the library would fail to handle it properly, causing the node to be left in a broken state.

  • Fixed an internal race condition where Node.connect() could be called on an already-connected node, causing a RuntimeError to be silently raised in the background after extended uptime.

v1.1.1 - 2026-05-15

Fixed

v1.1.0 - 2026-05-14

Added

Changed

Removed

  • Removed the fallback to discord.py as the default framework.

  • Removed the unused value argument from Player.pause(). Player.resume() is no longer an alias for unpausing — it must be called explicitly to resume playback.

Fixed

Miscellaneous

  • sonolink.gateway.Node has been split into multiple components internally for better separation of concerns and maintainability. This is not a breaking change as the public API remains the same, but it should improve code readability and future extensibility.

  • Formatted the project with Ruff for consistent code style and linting.

v1.0.1 - 2026-04-12

Fixed

  • Inconsistent environment variable usage across code and documentation

  • Fixed performance and memory issue in PlayerFactory caused by repeated metadata scans:

    • Reduced connection time (~11x faster)

    • Reduced memory peak (~12x lower)

    • Eliminated repeated expensive importlib.metadata.packages_distributions() calls

v1.0.0 - 2026-04-11

Initial release. For more information on what this added, consider referring to the API Reference or the examples.