Skip to content

feat: per-platform providers, independent sessions, personalised discover - #7

Merged
Nxssie merged 6 commits into
mainfrom
feat/platform-providers
Sep 10, 2026
Merged

Nxssie merged 6 commits into
mainfrom
feat/platform-providers

Conversation

@Nxssie

@Nxssie Nxssie commented Sep 9, 2026

Copy link
Copy Markdown
Owner

Summary

Separates YouTube and SoundCloud into providers, gives the profile independent sessions for each, and fixes the SoundCloud login and Now Playing defects.

  • build: bundle a Google OAuth desktop client from WREN_GOOGLE_CLIENT_ID/SECRET (CI reads repo secrets), add jdk.jsobject/jdk.xml.dom to the jlinked runtime so the WebView works in packaged builds, AppImage script resolves JDK 21 via mise and survives a running instance.
  • auth: AuthStore with a local profile and per-provider session files; GoogleAuth and SoundCloudAuth; AuthEvents for reactive UI. Google login uses an ephemeral loopback port with a cancellable, single-flight listener and a robust browser opener. SoundCloud login is a native PKCE flow against secure.soundcloud.com with only the authorization page in the JavaFX WebView; the callback is intercepted and exchanged natively, refresh token stored. AuthDialog removed in favour of ProfileDialog.
  • now-playing: queue click keeps order (jumpTo), plain lyrics render static, auto-scroll yields to the user, seekable progress bar, artwork/timeouts, theme-aware hairlines.
  • provider: MusicProvider with YouTubeProvider and SoundCloudProvider; YT/SC switcher in the sidebar scopes Search, Discover and Library while the queue stays shared. SoundCloud calls carry the session token: Discover shows mixed-selections as collection cards plus the local weekly list, stations use the real endpoint, Library lists likes and playlists. YouTube gets per-track radio via the RDAMVM mix; its second tab is named "radios" since YouTube exposes no discovery feed.
  • ui: compositor scale detection for fractional scaling; sidebar profile row always opens the profile dialog.

Test plan

  • ./gradlew :desktop:test green (new tests for SoundCloud OAuth, collections, YT radio parser, AuthStore)
  • AppImage built and launched locally
  • SoundCloud sign-in with email/password completes and Discover shows "Made for you"
  • Google sign-in with the bundled client (no oauth.json)
  • Switch YT/SC and confirm each tab keeps its own state

Known limitation: "Continue with Google" inside the SoundCloud window stays blank — JavaFX WebKit cannot deliver Google's named-popup form submission. Email/password login works; a Chromium embed (KCEF) would be needed for social logins.

🤖 Generated with Claude Code

- generate BuildConfig from WREN_GOOGLE_CLIENT_ID/SECRET env vars so
  releases ship a desktop OAuth client; ~/.config/wren/oauth.json stays
  as an override. CI distro jobs read the values from repo secrets
- add jdk.jsobject and jdk.xml.dom to the jlinked runtime: javafx-web
  requires them and the packaged app crashed on WebView creation
- build-appimage.sh resolves a JDK 21 via mise, runs the Kotlin compiler
  in-process (daemon rejects 4-part JDK versions) and writes the image
  through a temp file so a running AppImage no longer blocks the build
- ignore squashfs-root/ and client_secret*.json
…ions

- replace AuthManager with AuthStore (profile + per-provider session
  files), GoogleAuth and SoundCloudAuth; AuthEvents lets Compose observe
  connect/disconnect without the auth layer depending on the UI
- Google: ephemeral loopback port, cancellable accept and single-flight
  listener fix "Address already in use" on retries; open the browser via
  Desktop, $BROWSER or xdg-open with a copy-link fallback in the dialog
- SoundCloud: native PKCE flow against secure.soundcloud.com using the
  scraped web client id; only the authorization page runs in the JavaFX
  WebView, the callback is intercepted and the code exchanged natively.
  Toolkit started once, popup handler and desktop UA for social logins,
  refresh token stored and refreshed near expiry
- ProfileDialog manages both sessions; AuthDialog removed
- main.kt: detect compositor scale (Hyprland, GDK_SCALE, Xft.dpi) so the
  UI renders at native resolution under fractional scaling
…irlines

- add FFmpegPlayer.jumpTo so clicking a queue row keeps the current
  order; loadQueue reshuffled and played a random track under shuffle
- plain lyrics carry no timestamps and render static; the fake 4s
  cadence highlighted and auto-scrolled lines that were never synced
- auto-scroll yields to the user for 6s after a manual scroll (lyrics
  and queue); constant lyric font size removes the jitter
- progress bar seeks on click/drag with a live scrub label
- explicit artwork accepted at any size, image fetch has timeouts,
  lyrics fetch keyed on the metadata it sends
- theme-aware Hairline tokens replace hard-coded black separators
- MusicProvider abstraction (search, artists, station, discover,
  library) with YouTubeProvider and SoundCloudProvider; a YT/SC switcher
  in the sidebar scopes Search, Discover and Library while the queue
  stays shared. Cross-platform search merging is gone
- SoundCloud: api-v2 calls carry the session token; Discover shows
  mixed-selections ("Made for you", curated, trending) as collection
  cards plus the local weekly list; stations use the real station
  endpoint; Library lists likes and own playlists, hydrating id stubs
  through /tracks?ids
- YouTube: per-track radio via the RDAMVM mix on the next endpoint;
  Discover offers one radio per recently played track
- PlaylistTrack and ListeningHistory carry their source; sidebar profile
  row always opens the profile dialog so either session can be added
- YouTube has no discovery feed reachable with the Data API scope; the
  tab is Wren's own construct (radios seeded by local plays), so the
  provider now owns the tab label and the empty-state hint and says so
@Nxssie
Nxssie merged commit 9ba65de into main Sep 10, 2026
5 checks passed
@Nxssie
Nxssie deleted the feat/platform-providers branch September 10, 2026 08:41
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