Commit Graph

2356 Commits

Author SHA1 Message Date
Kingkor Roy Tirtho
a7e47d0e00
Merge pull request #3165 from team-spotube/ios-crash-fix
Ios crash fix
2026-10-26 15:16:29 +06:00
Kingkor Roy Tirtho
bdf3655a23 fix(ios): make the login WebView identify as Mobile Safari
accounts.spotify.com rejected iOS logins ("Oops, something went wrong") because
the WebView sent WKWebView's default User-Agent, which lacks Safari's
"Version/x ... Safari/604.1" and reads as an embedded browser. The random
User-Agent header never reached any request: the screen replaces the content
before it loads.

Have WebKit build Safari's exact UA (with its frozen OS version) via a probe
WKWebView using Safari's applicationNameForUserAgent, prime it at startup and
apply it through webSettings.customUserAgentString so every request uses it.
2026-10-26 15:04:26 +06:00
Kingkor Roy Tirtho
cc21568457 fix(build): restore version catalog lost in dev merge
The merge of dev resolved the libs.versions.toml conflict by taking the wrong
catalog: it reverted the Kotlin 2.4.21 / Compose 1.12.2 / Zipline 1.28.0
upgrade and dropped dev's jmustache entries, so buildSrc failed with
"Unresolved reference 'jmustache'". Keep both sides: mokkery 3.5.1 plus jmustache.
2026-10-26 15:04:26 +06:00
Kingkor Roy Tirtho
7fa3b029f6 Merge branch 'dev' into ios-crash-fix
# Conflicts:
#	gradle/libs.versions.toml
2026-10-26 13:45:32 +06:00
Kingkor Roy Tirtho
cb8316d141 fix(ios): stream formats AVPlayer can play
AVPlayer can't open WebM/Ogg or DASH, so the default opus/webm stream failed
silently on iOS.

- Rank streams the platform's player can play above format/quality prefs
- Default iOS streaming to aac/mp4, migrate saved WebM/Ogg prefs on iOS and
  hide unplayable formats in the picker (desktop/Android keep opus/webm)
- Normalize codec/container names on iOS like androidJvm (mp4a -> aac, m4a -> mp4)
- Wait up to 30s for the audio plugin to load when resolving, so the queue
  restored at startup isn't failed permanently before plugins are ready
2026-10-26 13:40:00 +06:00
Kingkor Roy Tirtho
99ba08501b fix(server): don't crash when the proxy port is still in use
CIO reports a failed bind from its accept coroutine; unhandled, that
exception terminates the process on Kotlin/Native before the port fallback
can run, so relaunching iOS shortly after playback crashed (EADDRINUSE).
Contain it with a parent CoroutineExceptionHandler and enable reuseAddress
so the preferred port can be rebound while old connections are in TIME_WAIT.
2026-10-26 13:40:00 +06:00
Kingkor Roy Tirtho
0acc457890 feat(plugin): implement automatic plugin updates and enhance JSON parsing 2026-10-26 12:44:04 +06:00
Kingkor Roy Tirtho
7eb56c8593 fix(ios): run Zipline on an 8 MiB stack thread
newSingleThreadContext threads get only 512 KiB of stack on iOS, while
QuickJS may recurse ~6 MiB deep when compiling a plugin, so the app crashed
with SIGBUS at startup once a plugin was installed. Host the dispatcher on an
NSThread with an 8 MiB stack, matching JVM/Android.
2026-10-23 11:54:29 +06:00
Kingkor Roy Tirtho
ff7a1714ff refactor(network): central HttpClientFactory; drop Ktor CIO client
On iOS the CIO client engine competed with Darwin as the default engine and
has no TLS on Kotlin/Native, so HTTPS requests (e.g. plugin discovery) failed.

Remove ktor-client-cio and build every client through a Koin-provided
HttpClientFactory that owns one client on the platform default engine
(Darwin on iOS, OkHttp on Android/desktop). Consumers use the shared
default/json clients or derive their own via create { }, sharing the engine.
2026-10-23 11:54:29 +06:00
Kingkor Roy Tirtho
09df4b494c build: upgrade to Kotlin 2.4.21 and Compose Multiplatform 1.12.2
Several dependencies (coil 3.5.0, millennium, mqtt/ditchoom, composeunstyled,
markdown-renderer, composewebview, kmp-zip, filekit) now ship klibs built with
Kotlin 2.4, which Kotlin/Native 2.3 refuses to read, breaking the iOS build.

- Bump zipline (1.28.0), mokkery (3.5.1) and ksp (2.3.12) for the new compiler
- Type TOP_LEVEL_ROUTES as Set<NavKey> (Kotlin 2.4 inferred Set<Any>)
- Import ComposeApp in iOSApp.swift, which uses ExternalUriHandler
2026-10-23 11:54:29 +06:00
Kingkor Roy Tirtho
2edbfefe93 fix(gradle): restore VFS watch setting and clean up properties 2026-10-23 10:12:10 +06:00
Kingkor Roy Tirtho
8ab9463c9a feat(packaging): Flathub, AUR, WinGet and Chocolatey publishing
- Flatpak manifest (GNOME 51, libvlc built from source) installing from a new
  portable spotube-linux-<version>-<arch>.tar.xz, shared with the AUR package
- Release workflow builds and attaches the Linux tarballs for x86_64 and aarch64
- Package files are JMustache templates rendered by :composeApp:renderPackaging<Target>
  with the version, release asset checksums and git-cliff release notes; the
  metainfo release history is generated
- Publish workflow (workflow_dispatch, release tag input) renders once and pushes to
  Flathub, the AUR, WinGet (PR from team-spotube/winget-pkgs) and Chocolatey
- Chocolatey and WinGet updated for the NSIS installer
2026-10-23 10:08:29 +06:00
Kingkor Roy Tirtho
79d47c1d87 feat: enhance loading states for various UI components and update dependencies 2026-10-20 20:32:47 +06:00
Kingkor Roy Tirtho
08892c2aa0 fix(downloads): respect download format/quality and never save manifests or video
- Downloads resolve streams with the user's download format/quality via a
  new StreamRequest instead of the streaming settings, and bypass the
  playback stream-URL cache in both directions
- Downloads only consider progressive streams; DASH/HLS manifests were
  previously saved as-is instead of audio
- NewPipe: map AAC "mp4a.40.x"/"m4a" to the advertised "aac"/"mp4" so real
  AAC streams can match (previously the hard-coded aac/mp4 manifests always
  won), report each stream's real delivery method, skip streams without a
  format or non-URL content
- Fail the download on non-2xx responses, on a range request answered with
  a full 200, and on video/* content, with localized reasons, instead of
  writing the response body to disk
- Save AAC as .m4a
- Tests for request overrides, manifest exclusion and cache isolation
2026-10-20 16:03:48 +06:00
Kingkor Roy Tirtho
8bbefdfb7d fix(android): app stuck on splash screen from main-thread string loading
PlaybackService.onCreate runs on the main thread and called
runBlocking { getString(...) } for its notification strings. Compose
resources share one in-flight load per strings file (AsyncCache creates the
Deferred in the caller's scope); when App()'s stringResource started that
load on the main dispatcher first, blocking main to await it deadlocked and
the first frame never rendered. Timing-dependent, so mostly seen under the
debugger.

Create the notification channel immediately under the app name and update
its localized name/description from serviceScope. The short-lived
placeholder notification no longer carries localized text.
2026-10-20 16:03:48 +06:00
Kingkor Roy Tirtho
d4961bb5ed feat: download diagnostics, live connect status, remote settings on devices screen
Downloads
- Show the real download folder: "Current folder: <path> (default)" in
  settings instead of the misleading "default music folder", and a
  "Saved to <path>" line on the Downloads screen
- Register finished downloads with Android's MediaStore (MediaScanner) so
  music players and the Files app see them immediately
- Add tagged logs across the download path to diagnose format/quality
  selection: raw NewPipe streams ([Streams]), every selection candidate
  with its rank key and fallback warnings ([Resolve]), and per-download
  enqueue prefs, resolved stream, HEAD/GET status + content type, segment
  responses and written vs expected bytes ([Download])

Connect status
- Mobile Home keeps its Devices / Group Jam / Support icons (Jam now uses
  the sound icon) and shows a slim banner only while remote-controlling a
  device or in a Jam ("Playing on krtx", "Hosting · 3 listeners")
- Sidebar Devices / Group Jam rows get a live dot and status line
- New ConnectStatusViewModel feeds both

Remote control settings
- Extract "Allow remote control" and "Device name" into shared
  remoteControlSettingCards, used by Playback settings and a new
  "This device" section on the Devices screen
2026-10-20 15:54:23 +06:00
Kingkor Roy Tirtho
b38a4f6963 feat(remote): redesign remote control and devices screens, fix connection issues
- Remove the unused "Enable Connect" setting and its strings
- Redesign RemoteControlScreen to match the expanded player: artwork sized
  to fit, side-by-side queue panel on wide screens, proper connecting /
  disconnected / error states, "Playing on <device>" subtitle
- Seek and volume sliders keep local drag state and only commit on release
  (volume throttled while dragging) instead of sending a command per frame
- Redesign DevicesScreen with the settings card components, a connected
  device card, error banner and empty state; ViewModels expose one UiState
- Fix tapping an already-connected device doing nothing; reopen its remote
  screen instead, and switch devices by disconnecting first
- Fix the controller getting stuck in Connecting after the host denies a
  request: Ktor never delivers Close frames to `incoming`, so detect the
  close reason after the receive loop ends
- Fix a UI freeze when leaving the devices screen on desktop: run discovery
  (and JmDNS's blocking close/resolve) on Dispatchers.IO
- Advertise the LAN address of the default-route interface on desktop;
  dns-sd-kt otherwise picks any site-local address, e.g. a Docker bridge
2026-10-20 15:11:10 +06:00
Kingkor Roy Tirtho
facc8ed0b9 fix(android): update playback state management to ensure guests follow host's play state 2026-10-20 14:28:18 +06:00
Kingkor Roy Tirtho
0b21eff4c7 fix(android): simplify service start logic for PlaybackService to avoid crashes on background playback 2026-10-20 13:44:30 +06:00
Kingkor Roy Tirtho
9d5854023b fix(android): update sharing functionality to use chooser intent with new task flag 2026-10-20 13:19:04 +06:00
Kingkor Roy Tirtho
38e9bbc1d8 fix(android): create intermediate directories for Rust targets to prevent runtime errors 2026-10-20 13:00:29 +06:00
Kingkor Roy Tirtho
64fb23e62b
Merge pull request #3152 from team-spotube/macos-dmg-fixes
fix(macos): add GraalVM runtime dependency and initialize GraalVm in …
2026-10-19 19:19:00 +06:00
Kingkor Roy Tirtho
64a78727ce
Update gradle/libs.versions.toml 2026-10-19 19:18:25 +06:00
Kingkor Roy Tirtho
046f724c9b
Merge branch 'dev' into macos-dmg-fixes 2026-10-19 19:15:56 +06:00
Kingkor Roy Tirtho
e92e62613e chore: implement Linux AppImage bundling for GTK and WebKitGTK, update dependencies and documentation 2026-10-19 19:15:13 +06:00
Kingkor Roy Tirtho
7ee3c70c96 fix(macos): add GraalVM runtime dependency and initialize GraalVm in main function 2026-10-19 18:50:27 +06:00
Kingkor Roy Tirtho
069b586d44 chore: update release workflow and documentation for dependency management 2026-10-19 11:50:53 +06:00
Kingkor Roy Tirtho
ced26462a9 chore: update GitHub Actions workflow for release process and improve permissions 2026-10-19 11:16:29 +06:00
Kingkor Roy Tirtho
d4d8ebd853 chore: configure UniFFI to generate bindings from host library on Linux arm64 2026-10-19 10:34:46 +06:00
Kingkor Roy Tirtho
2f7eb742cf chore: disable Android Rust build tasks on Linux arm64 hosts 2026-10-18 23:49:34 +06:00
Kingkor Roy Tirtho
b333c299d1 chore: update Android SDK setup to include NDK for composeApp configuration 2026-10-18 22:58:57 +06:00
Kingkor Roy Tirtho
613159e26e chore: add --stacktrace option to gradlew command for better debugging 2026-10-18 20:47:51 +06:00
Kingkor Roy Tirtho
33a8fdb8c2 cd: add GitHub token for API calls and set up Android SDK in workflow 2026-10-18 20:33:51 +06:00
Kingkor Roy Tirtho
03aaffeca8 chore: update spotube gradle plugin version 2026-10-18 20:07:20 +06:00
Kingkor Roy Tirtho
1233967982 chore: update contact information and library version in project files 2026-10-18 19:23:18 +06:00
Kingkor Roy Tirtho
17f2068950 feat(navigation): implement fade-through and stack transition animations for navigation 2026-10-18 18:31:51 +06:00
Kingkor Roy Tirtho
75ced1285e feat(local-tracks): implement LocalFolder screen and view model for folder navigation 2026-10-18 18:04:53 +06:00
Kingkor Roy Tirtho
c767b8dcd6 chore: update GitHub Actions to use latest versions of checkout, setup-java, setup-gradle, and upload-artifact 2026-10-17 19:21:42 +06:00
Kingkor Roy Tirtho
aa83708499 feat(graalvm): enable GraalVM native image support and update packaging configurations 2026-10-17 17:01:40 +06:00
Kingkor Roy Tirtho
62c1fe7902 feat: enhance Android build configuration with stable/nightly flavors and update launcher icons 2026-10-16 21:34:44 +06:00
Kingkor Roy Tirtho
9fba2aa33d feat(window): implement window state persistence and restoration 2026-10-16 20:49:16 +06:00
Kingkor Roy Tirtho
9db35e092b feat(server): implement port fallback mechanism for playback proxy server 2026-10-16 20:06:12 +06:00
Kingkor Roy Tirtho
2474c26a83 refactor: move package name from dev.krtirtho to org.spotube 2026-10-16 15:37:15 +06:00
Kingkor Roy Tirtho
7743d6d4c3 feat(lyrics): implement SyncedLyricsList component and enhance LyricsViewModel for better state management 2026-10-16 15:12:10 +06:00
Kingkor Roy Tirtho
77a9cef3a1 fix(stream-proxy): improve logging for cache timeout and handle disconnection scenarios 2026-10-16 14:44:39 +06:00
Kingkor Roy Tirtho
c9d16a25c6 fix(audio-player): android shuffle wasnt working 2026-10-16 14:36:27 +06:00
Kingkor Roy Tirtho
da394d40ea fix(audio-api): enhance fallback mechanism for text search results in YouTube 2026-10-16 14:29:43 +06:00
Kingkor Roy Tirtho
09d77211b9 fix(newpipe): fall back through multiple searches when ISRC search misses
NewPipe durations are seconds, not ms, so duration scoring never matched.
Fix the uploader match direction, normalize titles, and walk a ladder of
searches (ISRC, songs, videos, title only) until a confident match is found.
Return nothing rather than unrelated results. Add detailed ISRC/NewPipe logs.
2026-10-16 14:26:39 +06:00
Kingkor Roy Tirtho
61dd89f3ed fix(stream-proxy): stream upstream audio instead of buffering the whole track
Ktor's request() buffers the full body before returning, so ExoPlayer timed
out waiting for headers. Use prepareRequest().execute{} and tee the body to
the cache file, committing only complete 200 responses. Treat player
disconnects (broken pipe) as debug-level noise rather than upstream errors.
2026-10-16 14:26:39 +06:00
Kingkor Roy Tirtho
ba62ff03c3 feat(user-agents): implement dynamic user agent fetching and caching mechanism 2026-10-16 13:47:08 +06:00