finds.dev← search

// the find

cwuom/NeriPlayer

★ 3,648 · Kotlin · GPL-3.0 · updated Oct 2026

A native Android audio player that combines multi-source streaming, local control, rich lyrics, and self-hosted sync. / ✨ 一个把多源在线播放、本地管理、歌词体验和自建同步做进原生 Android 的音频播放器 🎵

NeriPlayer is a native Android music player written in Kotlin on Jetpack Compose and Media3. It plays from Netease Cloud Music, Bilibili and YouTube Music alongside local files, and it is aimed at Android users who already have accounts on those platforms and want optional sync through their own GitHub repo or WebDAV server.

USB exclusive playback goes past the usual AudioTrack path. The native module drives UAC1.0 and UAC2.0 Type I PCM DACs through libusb, parses explicit feedback endpoints, and re-captures the feedback clock after long scheduling gaps. That is worth reading the native code for even if you never plug in a DAC. Download resume is split by transport: plain HTTP appends a Range header from the existing work file, chunked Range covers platforms that need explicit ranges, and HLS keeps a segment-index checkpoint. The queue survives restarts, and a manual cancel removes partial files, so pause and cancel mean different things. GitHub sync publishes through the Git Data API with a conditional ref update against the expected HEAD, so a concurrent writer fails loudly instead of being silently overwritten. Deletions are tombstones scoped to the member tokens actually observed, so an older delete cannot wipe a restored song on the next sync. The module boundaries are enforced by the build rather than left to a doc: 14 owned modules, a verifyModularization task, per-module CRAP thresholds, and a 2000-line limit on library source files.

The README admits that the USB path is verified by host model tests and four-ABI compilation, which is not the same as stability on a real phone and DAC. Anyone picking this for a bit-perfect setup should plan to test their own device. Three platform integrations rest on unofficial, reverse-engineered APIs, and YouTube playback depends on PoToken and EJS fallbacks that will break whenever the upstream player changes, so expect periodic regressions and treat the platform features as the first thing to check after an update. GitHub sync is not end-to-end encrypted: the remote holds ZSTD-compressed chunks that anyone with repo access can read, and the setup asks for a classic token with the full repo scope, which covers every private repository the account can reach, without suggesting a narrower fine-grained token. The main README and most in-repo design docs are in Chinese, and the feature list is long enough to read more like a changelog than a summary, which makes it harder for outside contributors to find their way in.

View on GitHub → Homepage ↗

// want more like this?

We dig through GitHub every week and send a few repos picked for what you actually care about — each with an honest take like this one.

Get finds in your inbox → Search again →