Repository navigation
Conversation
Owner, 2026-11-04: full tracks get two built-in clients again, never in the
repository. build.rs reads PM_TIDAL_PKCE_CLIENT_ID / _SECRET (the browser
sign-in's) and PM_TIDAL_DEVICE_CLIENT_ID / _SECRET (the code sign-in's) and
writes each pair, only when both values are set, as masked bytes into
$OUT_DIR/tidal_clients.rs; src/client_mask.rs is the one helper build.rs and
project_apps share. Masking keeps the values out of the binary's plain strings;
it is not a security boundary.
- project_apps: tidal_pkce_client() and tidal_device_client().
- tidal_unofficial::client_of: the owner's client (Settings, then [tidal]
config, then PM_TIDAL_UNOFFICIAL_CLIENT_*), else the build's ("builtin"),
so sessions made with the old built-in device client renew again.
- release.yml: the four secrets only on the three steps that build (desktop,
Android, binaries) and on the image build as BuildKit secrets with
no-cache-filters: build; the desktop's npm ci moves to its own step so install
scripts never see them. Nothing at workflow level; action pins unchanged.
- Dockerfile: secret mounts read in the build stage's one RUN; no ARG or ENV,
nothing in the final image. build-armv7.sh forwards them by name.
Tests: masking with fake inputs present and absent (no plain value in the
generated file, read back exactly, blank pairs give none); the build inputs come
only from the build environment, scoped as above, and no built-in value is
plain in the source (replaces the test that no device client is fed in).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n, the answer logged On the owner's node TIDAL sent the device-code session AAC for HI_RES_LOSSLESS. python-tidal (tamland/python-tidal at cce10953) says only its PKCE client gets hi-res; this matches its login_pkce, pkce_get_auth_token and token_refresh. Sign in with TIDAL (browser sign-in), per person: - POST /v1/sources/tidal/unofficial/browser keeps a short-lived attempt (code verifier: 32 random bytes base64url; client_unique_key: 64 random bits hex; ten minutes) in the person's own state and answers the login.tidal.com authorize address: response_type, redirect_uri https://tidal.com/android/login/auth, client_id, lang, appMode=android, client_unique_key, S256 challenge, restrict_signup, in python-tidal's order. - POST .../browser/finish {text} takes the pasted landing address or the bare code. The host is checked first (https, tidal.com or a subdomain); a wrong host, http, no code, TIDAL's error, an unknown (409) or expired (410) attempt and a code TIDAL refuses each say so in plain words. The exchange sends code, client_id, redirect_uri, scope, code_verifier and client_unique_key (no secret, as python-tidal); the session is kept marked client = pkce, the way remembered. - Sessions say which client renews them (ClientKind, serde default: a session stored before is a device session, so nobody is signed out). A browser session renews with the PKCE id and secret, no scope; a device one as before. A python-tidal / tidal-dl-ng file with is_pkce imports as a browser session. Playback (open_blocking): one info line per opened track with what TIDAL answered (audioQuality, manifestMimeType, BTS / DASH codecs, bitDepth, sampleRate, the sign-in kind; never a URL or token), python-tidal's request headers, and AAC for HI_RES_LOSSLESS asked again as LOSSLESS before it plays. The health line of a sign-in that still gets AAC says so with what to do ("... Sign in with TIDAL again for lossless"; lossy: true) instead of "full tracks are playing". Hi-res DASH (FLAC in fragmented MP4) goes through the DASH reader into the decoder, which names the codec and depth from the stream (the signal path's source format). Stream and segment errors no longer carry URLs. The chooser (tidal::sign_in): Sign in with TIDAL first and Recommended (when the build carries its client), Sign in with a code second (a fallback TIDAL may send AAC only), a sign-in from another app only when one is found, then under Advanced (Way::advanced) the official app, Your own device client and Paste a token. A build without its clients lists both first ways as unavailable, saying why. Tests against mock TIDAL servers: authorize address and challenge, the exchange's parameters, renewal with the PKCE client, paste parsing (address, bare code, other host, look-alike hosts, http, no code, TIDAL's error), no and expired attempts, Recommended flag and order, per-person isolation, answer fixtures BTS FLAC / DASH FLAC hi-res / DASH AAC, the LOSSLESS retry, the health texts, an old stored device session that loads and renews with the device client, and no secret, token, verifier or CDN address in any log line (captured at trace level). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner's ask (2026-11-04). Gone from the web UI: the Sound quality dialog
(qualitySheet) and what only it used (focusQualityControl, conversionWhy, the
.qsheet and .flash styles); in the signal-path panel the footer with "Quality
choices…" (#qpquality) and "Now playing" (#qpnow), their handlers and the
footer's style. Nothing else opened the dialog: Now playing's quality label
(#npquality) now always opens Details (the signal path), as it did without a
format. The panel keeps "All DSP settings"; each source's quality setting stays
on its Sources page (GET/PUT /v1/sources/{source}/quality is unchanged).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e code sign-in second The web UI for the new chooser (owner, 2026-11-04), order and badge from the backend: - Sign in with TIDAL: one button opens TIDAL's sign-in in a new tab (opened at the click so no popup blocker stops it), then step 2 asks for the address of the tidal.com page you land on, with the problem in place when it isn't one; then done. Step cards as elsewhere. No client id or secret to enter. - The signin chooser (all sources) shows ways marked advanced under an "Advanced" disclosure, open when one of them is picked; TIDAL's official app, Your own device client (the client step card, Check, paste splitting) and Paste a token (which takes the file too) are there, without a badge. - A code sign-in sees one line, "Sign in with TIDAL again for lossless", with the button. A sign-in that gets AAC says so on its Health line (pill AAC, status "AAC only") instead of "Working: full tracks are playing". - tools/ui-stream-setup.js: the chooser's order, the badge, the closed Advanced, the new tab and the paste step (a wrong address, then signed in), the one "again" line, the AAC health line, then a build without its clients (both first ways unavailable, saying why) and your own device client through to the code; desktop and phone width. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…clients - guides/tidal-full-tracks.md: the ways in their new order, Sign in with TIDAL step by step (what the landing page looks like, what is read from the address, the errors), the code sign-in and when TIDAL sends it AAC, your own device client under Advanced and the client order, what each track logs, and that old sessions keep working. - STREAMING-PROVIDERS.md: the full-tracks row (both built-in clients from release secrets, the browser sign-in as python-tidal's login_pkce, the session's client, the LOSSLESS retry, the log line), the Advanced note. - deploy.md: what a release build carries and how a local image build passes the clients (BuildKit secrets, --no-cache-filter build). - api.md: the two browser sign-in endpoints and the status fields. - CHANGELOG under Unreleased. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to a client Review fixes for #255 (round 1): - The vault carries a full-tracks session under the app of the client that made it: a code sign-in under the device client's id, as before (device sessions synced already still match), a Sign in with TIDAL session under `pkce:` and the browser client's id. Bridges get an optional per-session app (`app_of_session`); the sync compares the vault copy against the node's app for that kind, records the app of the copy it synced, and checks "lost to a change of app" against the vault copy's kind. A node takes only a session it can renew, and a code sign-in made on a node without the browser client doesn't replace a lossless session elsewhere. Test with both kinds on three nodes (both clients, no browser client, another device client), and the sync decisions that follow. - Imports say they renew only when the node has the client of their kind: a device client for device sessions, this build's browser client for python-tidal's browser (PKCE) ones; an expired one without it is refused in plain words. Test. - The AAC health line suggests "Sign in with TIDAL again" only for a code sign-in on a build with the browser client; an imported or pasted one gets "Sign in with TIDAL for lossless", a build without the client says what lossless needs. Tests. - Stale wording: docs/api.md (quality, the ways that switch full tracks on), STREAMING-PROVIDERS.md (the ways), the import test's message; the CHANGELOG entry says the above. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ess field Review fixes for #255 (round 1): - The full-tracks status says "AAC only" only for a device session; a browser session whose last track came as AAC stays Working, and its Health line says that track may have no lossless version. - After Sign in with TIDAL is pressed and the chooser is drawn again, the address field has the focus, so whoever comes back from TIDAL's tab by keyboard or screen reader is on it. - tools/ui-stream-setup.js checks both, desktop and phone width. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TIDAL full tracks arrived as AAC (
AAC → 24/44.1 lossy) with the device-code sign-in. This adds TIDAL's browser sign-in (PKCE, python-tidal'slogin_pkce) as the Recommended way, with a built-in client, and removes the Sound quality dialog.What changes
PM_TIDAL_PKCE_CLIENT_*(new) andPM_TIDAL_DEVICE_CLIENT_*(restored after No built-in TIDAL device client: full tracks only with one the owner enters #216: REVISION 3 makes the device-code sign-in with the built-in client the fallback, and existing device sessions need it to renew). release.yml passes the secrets only to the build steps (desktopnpm cisplit out so install scripts never see them) and to the image as BuildKit secrets (no-cache-filters: build); the Dockerfile reads them in the build stage's one RUN, nothing in any layer or build arg. build.rs writes them masked into$OUT_DIR(src/client_mask.rs); no values in the repo. Dev builds without them: the browser way is unavailable, the code sign-in remains.POST /v1/sources/tidal/unofficial/browserstarts a per-person 10-minute attempt and returns the login.tidal.com authorize URL (S256, redirecthttps://tidal.com/android/login/auth);.../browser/finishtakes the landing address or the bare code, checks https + tidal.com host first, exchanges the code, stores the session markedclient: pkce. Refresh uses the PKCE client. Stored sessions without the marker are device sessions and keep working.Reference read: tamland/python-tidal
cce10953477362c4383731ad6a8f4ef6296a6168(tidalapi/session.py,media.py,request.py).Checks
-D warningspm-api; rustdoc-D warnings;cargo test -p pm-api426 passed / 0 failed / 4 ignored (new: authorize URL + challenge, code exchange, PKCE refresh, paste parsing, order/Recommended, per-person isolation, BTS FLAC / DASH FLAC / DASH AAC fixtures + LOSSLESS retry + health text, old session loads, masking with fake inputs, no secret in logs).Not yet measured
Whether the browser session really gets FLAC needs one real sign-in by the owner on the edge image; the result goes here after the NUC check.