Repository navigation
Conversation
b278e6a to
e40cdda
Compare
|
A note on why I think this matters beyond Recently played: TIDAL's own SDK puts the play log in its NECESSARY consent category (streaming metrics are PERFORMANCE), and every official player sends it for every play. Without it, plays from tidalapi-based players may not count the way TIDAL's own players' plays do, possibly including what artists get paid for them. I can't confirm how TIDAL uses it, but it seems worth getting right. Two things you may want to weigh: the session's OAuth client is TIDAL's Android app, while the events describe the real client (OS, app version), so they don't fully match. And since |
|
Thanks for the PR and you make a good point regarding the misuse risk. I'm holding this PR out of v0.9.0 for now, mainly because report_playback accepts any timestamps and track IDs, which makes faking plays too easy. Some suggestions for improvements:
Potential bugs:
By the way, main has changed a bit since you opened this PR. Soon it will require Python 3.11+ and runs ruff's UP rules in
|
The library measures each play and refuses implausible ones. Replies are handled as in TIDAL's SDKs: a play is done only when the reply lists it as sent or as a sender fault, anything else leaves it unsent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
e40cdda to
ffe1452
Compare
|
Thanks for the review! I've reworked it along those lines and rebased it on main (Python 3.11+, Measuring. Checks. Your bug questions.
Two things I'd like your call on.
The tests here are offline, but I also ran this code against TIDAL: a test build of High Tide reported real listening through the tracker. TIDAL confirmed every play by id, including ones with a pause and seeks, and the tracker's position stayed within about 0.1 seconds of the player's. |
Fixes #401.
Tracks played through tidalapi never show up in Recently played, and don't count in the listening history TIDAL uses for recommendations. Fetching and playing a stream isn't enough: the official players report every play as a
playback_sessionevent to TIDAL's event producer (https://ec.tidal.com/api/event-batch). The attempt in #401 sent the web player's events totidal.com/api/event-batch, which TIDAL accepts but doesn't show anywhere.This adds
Session.start_playback(),Session.report_playback()and atidalapi.playlogmodule. The library measures each play and builds the same events as TIDAL's own players. The layout comes from TIDAL's open source SDK, tidal-sdk-android: theeventproducermodule (an SQSSendMessageBatchform with aHeadersattribute) and theplayer/eventsmodels (PlaybackSession,AudioPlaybackSession,User,Client). The user and client fields come from the access token's claims, as the SDK does.Apart from the client id of the OAuth client the session logged in with, the events describe the real client: the operating system and version from
platform, and an application version the caller passes in (defaults to the tidalapi version). They don't add device details. Events in this format showed up in Recently played within 20 seconds in my tests.ITEMwith the track's own id for a track played on its own. Recently played lists the source.local_copy=True), for applications with an offline cache.report_playbackrefuses plays that can't have happened: ending before they start, in the future or over 14 days ago, with a position past the end of the track, with more listening than time passed, overlapping another play of the session, or already reported.to_dict()and try again later withfrom_dict(). Retries reuse the same ids. It uses the session's token refresh and backoff.The tests in
tests/test_playlog.pyrun offline and are added to the test workflow. There are also docs inapi.rstand an entry inHISTORY.rst.High Tide, which uses tidalapi, already reports plays with these events in a local build, and a test build reported real listening through this tracker: TIDAL confirmed every play by id.
🤖 Generated with Claude Code