LastWave pairs a YouTube Music client with a cross-app scrobbler
Next-Gen YouTube Music Client with Algorithmic Smart Playlist Generator, Real-Time Synced Lyrics & Universal Last.fm Scrobbler for Android.
At a glance
- What is it?
- A Kotlin and Compose Android client for the YouTube Music catalogue that adds algorithmic taste mixes, LRCLIB karaoke lyrics, offline downloads and a Last.fm scrobbler which tracks playback from other apps too. It is distributed as an APK under GPL-3.0, and the repository carries several build byproducts you would rather not find in a tree.
- Who is it for?
- LastWave makes sense if you already pay for Last.fm and want your listening history to reflect what you play in Spotify or Apple Music too, since a scrobbler that watches the media session rather than only its own app is the feature that makes the rest interesting. Check three things first.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Kotlin, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 3, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A catalogue client with three additions layered on
LastWave is described as a native Android music client powered by the global YouTube Music catalogue. The base layer is familiar: stream tracks, albums, artists and public playlists, with background playback and no advertisements. The additions are what make it its own project.
The first is a smart playlist generator producing algorithmic taste mixes and mood radios from your listening history, seed artists, loved tracks and top genres, paired with a discovery feed offering a personalised recommendation radar, deep genre breakdowns, weekly listening recaps and one-tap Start Mix radios.
The second is real-time synchronised lyrics, described as millisecond-accurate animated karaoke lines powered by LRCLIB, with eight customisable fluid physics animations. The third is a Last.fm scrobbler described as universal because it tracks listening across YouTube Music, Spotify, Apple Music and local players, not only what LastWave itself plays. The project claims zero battery drain for that tracking.
Two smaller features round it out. An offline downloader writes files to a Music/LastWave directory with cover art tags and synchronised .lrc lyric files, and public playlists can be imported from Spotify and Apple Music into the library.
The build is 100% Kotlin on Jetpack Compose with Material 3 Expressive, Media3 ExoPlayer for audio with lockscreen controls and Android Auto, MVVM plus Clean Architecture, Room, DataStore, Hilt and Coroutines with Flow.
The scrobbler watches other apps, which is the actual trick
Most scrobblers record what their own player plays. LastWave's is built on the Last.fm API with native OS media session tracking, and the feature table is explicit that it follows listening activity across YouTube Music, Spotify, Apple Music and local players.
That distinction changes what the app is. With app-internal tracking, your Last.fm history only reflects the times you chose to listen inside LastWave. With media session tracking, the scrobbler is a background listener for the operating system, so a Spotify session shows up whether or not LastWave is in the foreground. For someone who splits listening between services, that is the difference between a history and a partial one.
The same mechanism carries a social feed. Because the data is already flowing through Last.fm, you can follow friends' listening activity, browse their recent scrobbles and explore their top tracks. Friend activity is a read of Last.fm data rather than anything LastWave holds itself, which is worth knowing when you think about what enabling the account exposes.
The detection is described as costing nothing in battery terms. No implementation detail is given in the documentation, so if that claim matters to you, the thing to check is whether the media session listener is registered continuously or only while a screen is open.
Taste mixes and the discovery radar need an account first
The setup instructions are four steps, and the third one unlocks most of the app. You download the APK, install it on Android 7.0 or newer, then connect a Last.fm account under Settings and Integrations, which is stated to unlock the scrobbler, the taste mixes and the personalised discovery radar.
So on first launch the useful surface is the streaming client, the lyrics, downloads and playlist import. Everything personalised waits for the account, and the account is a full Last.fm login rather than a read-only key. That is the right dependency given how the feature set is built, since the mixes derive from listening history and loved tracks and the radar derives from what you have played, all of which live in Last.fm.
One naming detail carries over from Last.fm itself: the mixes are described as taste mixes and mood radios rather than as playlists, and the feed offers instant Start Mix radios, so the vocabulary you see in the app is Last.fm's rather than YouTube Music's.
Android 7.0 as the floor is worth noting for a Compose application, since it sets the oldest device the current build will install on.
The documented APK name is pinned to one release
The install instructions name a specific artefact, LastWave-v4.2.2-release.apk, and tell you to install it on your device. That is accurate for the moment it was written and wrong the next time a release lands, because the version is in the filename.
The release cadence makes that a regular problem rather than a rare one. Three of the recent releases are 4.2.0 on 2026-09-23, 4.2.1 on 2026-09-26 and 4.2.2 on 2026-09-27, with the last push to main on 2026-10-02. Releases are titled with a leading Update v prefix while the tags themselves carry no prefix, so matching a filename against a tag takes a moment of thought. Take the artefact from the Releases tab, where the newest build is unambiguous, rather than trusting the name in the documentation.
The documentation also points at the Actions tab as a source of APKs, which is a faster route when you want the current main rather than the last tagged build, and a riskier one for the same reason.
Building from source is three commands, using the Gradle wrapper rather than a system Gradle:
git clone https://github.com/Clash-Projects/LastWave-native.git
cd LastWave-native
./gradlew assembleReleaseThe clone URL in that line uses a lowercase n in the clone name while the repository is published as LastWave-Native, which git resolves for you over HTTPS but is a small trap for anyone scripting it.
reference zip/ has a space in its name
The top level of the repository contains several things that belong in a build directory rather than in version control. Three run logs are committed as run_log.txt, run_log2.txt and run_log3.txt, alongside a build_log.txt. Two directories named .glance_core and .glance_temp are present, which look like scratch output from a preview or inspection tool rather than source. A Screenshot directory, lastwave_logo.png and lastwave_logo.svg are committed as well, which is ordinary for an app project.
The one that will cost you time is a directory literally named reference zip/, with a space between the two words. A path containing a space breaks unquoted shell invocations, and Gradle path handling has historically been inconsistent about spaces in module and directory names. If you hit an error that mentions a directory you did not recognise, that is the one. The name also suggests it holds a reference archive rather than build inputs, so it may be removable.
None of this is a blocker. It does mean the tree is not a clean checkout of source, which matters if you are diffing against upstream or if you are trying to work out what a given change touched.
The project is otherwise conventionally laid out, with app/, audio/, docs/ and tools/ directories, build.gradle.kts and settings.gradle.kts using the Kotlin DSL, gradle.properties, the wrapper plus gradlew.bat for Windows, and a full set of community files: SECURITY.md, CODE_OF_CONDUCT.md, CONTRIBUTING.md and CHANGELOG.md.
Signing credentials belong in local.properties
The .env.example file is a signing template, and it tells you to copy it to .env or to local.properties for local builds. It holds the release keystore path and two password fields plus a key alias, all filled with obvious placeholder values, and then a second block for GitHub Actions secrets where SIGNING_KEY is a base64-encoded keystore string alongside a key store password, an alias and a key password.
Both halves are reasonable as documentation. The mismatch is the destination. Release signing values belong in local.properties, which every Android project excludes from version control by convention, or in a secrets store. A .env file is neither by default, and several Android Gradle setups read local.properties specifically for signing. If you follow the instruction literally and put a real keystore password in .env, you have moved a credential out of the file designed to be ignored.
The CI block is worth reading for the other reason: it tells you the release pipeline takes the keystore as a base64 string in a repository secret named SIGNING_KEY, then reconstructs it. That is how unsigned local builds and signed release builds coexist in one project without the key ever entering the repository.
The placeholders themselves are correct practice, naming RELEASE_STORE_FILE, RELEASE_STORE_PASSWORD, RELEASE_KEY_ALIAS and RELEASE_KEY_PASSWORD rather than anything resembling a real secret.
The disclaimer carries the weight the feature list avoids
The feature list makes claims that need a legal frame, and the frame is in a separate section. The app is described as an educational and research project, open source and non-commercial, developed strictly for research and educational purposes to demonstrate modern Android application architecture with Jetpack Compose and AndroidX Media3.
The content policy is specific. LastWave is stated to be independent and not affiliated with, endorsed by or sponsored by Google LLC, YouTube, YouTube Music, Spotify, Apple Inc., Last.fm or any music service. It does not host, stream from private servers or distribute copyrighted media; all content and metadata are accessed directly from public endpoints in accordance with their respective terms, and trademarks belong to their owners.
That last clause is the load-bearing one. A client for a streamed catalogue with an ad-free claim and an offline downloader is doing something that sits close to the line between consuming a public endpoint and redistributing a service, and the project resolves it by stating that nothing is redistributed and that access is direct from public endpoints under each service's terms. Whether that holds depends on YouTube's terms, not on this repository, and the disclaimer is a statement of position rather than a grant of permission.
The GPL-3.0 licence covers the source. The project is built by Duxtami and Ajisth, distributes through Telegram and Discord channels rather than a store listing, and is listed under a Telegram channel as its homepage in the repository metadata while the actual site is lastwave.pages.dev.
Editorial conclusion
LastWave makes sense if you already pay for Last.fm and want your listening history to reflect what you play in Spotify or Apple Music too, since a scrobbler that watches the media session rather than only its own app is the feature that makes the rest interesting. Check three things first. Taste mixes, the discovery radar and the social feed all sit behind connecting a Last.fm account, so nothing personalised works on first launch. The APK filename in the documentation is pinned to one version while releases ship every few days, so take the artefact from the Releases tab rather than the filename. And if you build from source, expect the keystore variables to want local.properties rather than the .env the template suggests.
Frequently asked questions
What Android version does LastWave need?
Android 7.0 or newer. The project is built with 100% Kotlin and Jetpack Compose on Material 3 Expressive, and the audio path uses AndroidX Media3 ExoPlayer with lockscreen controls and Android Auto.
Does LastWave scrobble from Spotify and Apple Music?
Yes. It uses Last.fm API with native OS media session tracking and is described as tracking listening across YouTube Music, Spotify, Apple Music and local players, rather than only what LastWave itself plays.
Why are LastWave's smart playlists not available on first launch?
Taste mixes, mood radios and the personalised discovery radar unlock only after you connect a Last.fm account under Settings and Integrations. The scrobbler also needs that connection.
How do I get the latest LastWave APK?
Take it from the Releases tab or the Actions tab rather than relying on the filename in the documentation, which is pinned to one version such as LastWave-v4.2.2-release.apk. Releases 4.2.0, 4.2.1 and 4.2.2 all landed within four days in late September 2026.
Can I build LastWave from source?
Clone the repository, enter the directory and run ./gradlew assembleRelease. Release signing values are documented in .env.example, though release keystore credentials conventionally belong in local.properties rather than a .env file.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/clash-projects-lastwave-native)