NeriPlayer: a native Android player that treats your own GitHub repo as the cloud
A native Android audio player that combines multi-source streaming, local control, rich lyrics, and self-hosted sync. / ✨ 一个把多源在线播放、本地管理、歌词体验和自建同步做进原生 Android 的音频播放器 🎵
At a glance
- What is it?
- NeriPlayer combines NetEase Cloud Music, Bilibili and YouTube Music playback with local-first storage and optional GitHub or WebDAV sync. The design is honest about what it will not do, and that is the interesting part.
- Who is it for?
- Adopt NeriPlayer if you already hold accounts on the supported platforms and want playlists, history and play statistics stored on hardware you control rather than in a developer's backend. Skip it if you need a public catalogue, an iOS or desktop client, or a player that will write your listening history back to the streaming platform.
- 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 4 days 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 September 26, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What NeriPlayer actually solves for an Android user
Most Android music players pick one side. They either wrap a streaming service and treat local files as an afterthought, or they are local-only players that cannot search anything online. NeriPlayer sits between the two and makes a specific promise: the app is a client, not a service. The README states plainly that the project does not provide a public cloud library or media distribution, and that online audio depends on the user's own account authorisation on third-party platforms. Membership and restricted content still follow the original platform's rules.
The intended user is someone who already pays for or holds accounts on NetEase Cloud Music, Bilibili and YouTube Music, and who finds it irritating that playlists, play counts and history live in three separate vendor silos. NeriPlayer aggregates those sources inside one Jetpack Compose interface, keeps caches, downloads, playlists, history, statistics and settings on the device by default, and offers an optional sync path where the remote end is a GitHub repository you own or a WebDAV file you control. The README notes that a repository created from inside the app defaults to private.
That last point is the project's actual thesis. The maintainers say they deliberately keep sync decentralised, writing data to user-controlled GitHub or WebDAV remotes rather than uploading it to a central service run by the project. They also explain a related decision: although the app could report local playback history back to the streaming platforms, centralised platforms typically run risk-control and behaviour-sampling systems, and pushing listening history upstream risks abnormal-login flags, abnormal-playback flags or account freezes. NeriPlayer therefore does not upload local playback history or play statistics to those platforms. That is a design trade-off, not a missing feature, and it is worth understanding before you install.
How the playback, source-switching and sync layers fit together
The architecture is a single Activity plus Compose. MainActivity is the only external entry point, and the UI is organised by a Compose NavHost, a dynamic bottom bar, a Mini Player and a Now Playing overlay. The normal startup chain is Loading, then Disclaimer, then Onboarding, then Main. If the previous launch crashed or the system recorded an ANR, the app enters Safe Mode first. That recovery path is visible in the repository layout rather than hidden behind a crash reporter.
Playback is not a thin wrapper around three APIs. PlayerManager handles source resolution, queueing and failure recovery. When a NetEase track is unplayable, has no usable playback result, or returns only a preview fragment, the app first attempts a quality downgrade, then PlayerManagerNeteaseAutoSourceSwitch scores Bilibili candidates by title, artist and duration to find a fallback. On a playback error the current link is refreshed; after repeated failures the track is skipped or playback stops. YouTube compatibility has its own multi-level fallback: a logged-in session keeps valid identity cookies, anonymous visitor bootstrap and PoToken sessions are maintained separately, and cookie rotation, session parameters, player.js and challenge results are cached and reused. A stale player.js or a rejected playback candidate moves into an EJS or HLS fallback instead of retrying the same candidate.
Sync is metadata only. Playlists, favourites, recently played, per-song play counts, listening duration, daily buckets, playlist-open statistics and local playlist play statistics are written to the user's GitHub repository or WebDAV file. PlaybackStatsRepository identifies songs by a stable identity and participates in merge on sync. Writes are batched with a delay and flushed at key lifecycle points, and the number of daily statistic buckets is capped. When reading a remote snapshot the code tolerates old or missing fields and drops records whose song identity cannot be parsed. TrafficStatsRepository separates playback traffic, download traffic, Wi-Fi, mobile, roaming and cache hits. This is the part of the app that most clearly reflects the README's claim that statistics are not decoration.
Installing NeriPlayer and getting one song playing
There is no Play Store listing and no package-manager install documented. The README points readers at the releases page, and the repository root carries a Gradle wrapper and a settings.gradle.kts, so a source build is a Gradle wrapper invocation from the repository root. The README does not list a Gradle task for a debug build, so the exact task name is not something this article can quote; the release assets are the documented path to a runnable APK.
NeriPlayer
├── 多源在线播放:网易云 / Bilibili / YouTube Music
├── 本地优先数据:缓存、下载、歌单、历史、统计、设置
├── 可选自有同步:GitHub / WebDAV 元数据同步
├── 丰富播放体验:Media3、歌词、音效、流体背景、桌面小组件、启动器快捷方式、悬浮/状态栏歌词
└── 可恢复运行:安全模式、崩溃日志、ANR 记录、调试探针That block is the README's own summary of the feature surface, and it maps cleanly onto what you configure after install: multi-source online playback, local-first data, optional GitHub or WebDAV metadata sync, the playback experience layer, and the recovery layer.
On first launch the app walks through Loading, Disclaimer and Onboarding before reaching the main screen. Read the disclaimer. It states that the project is for study and research, that you should only access or save content you have the rights or platform permission to use, and that the project supplies no media content, keys, DRM or region-restriction workarounds, and no public media proxy or redistribution service. It also states that the project and maintainers accept no sponsorship, donations or commercial funding.
After onboarding, the practical first step is authorising a platform account, because the README describes the model as account-as-capability: search, playback, playlists and favourites are enabled through third-party platform authorisation. Once an account is connected, use search to find a track and start playback. The Mini Player supports horizontal swipes to move to the previous or next track without opening the full Now Playing screen, which is the fastest way to confirm that playback and queueing work.
If you want sync, the app can create a GitHub repository for you, and the README says repositories created in-app default to private. WebDAV is the other option. Both store metadata such as playlists, favourites, recently played and play statistics. Neither is a media store, so do not expect your audio files to land there. For the Listen Together feature the README points to its own deployment section for self-hosting the server side; that server is something you run, not something the project operates for you.
Where NeriPlayer is the wrong tool
The clearest boundary is the one the README draws itself: there is no public cloud library and no media distribution. If you want a player that works out of the box with a catalogue you did not have to authorise, this is not it. Every online capability is gated behind an account you already hold, and restricted or membership content still obeys the original platform's rules. A user with no NetEase, Bilibili or YouTube Music account gets a local player plus a lot of code that will never run.
The second boundary is platform scope. The repository is a native Android application with a single Activity and Compose UI, targeting Android 9 and above. There is no iOS client, no desktop client and no web client documented. Anyone who wants the same library on a laptop is looking at the wrong project.
The third boundary is upstream write-back. NeriPlayer will not push your listening history or play statistics to the streaming platforms, and the README gives the account-safety reasoning for that choice. If your workflow depends on scrobbling or on the platform's own recommendation engine learning from your plays, this omission is a real cost, not a philosophical nicety.
A fourth, quieter constraint sits in the feature list. Several capabilities are conditional: advanced blur is only available on Android 13 and above and only when the parent blur setting is on, with a 12 to 64 dp adjustment range; connected feedback is off by default, and with it off, detail pages such as playlists use a drawer-style expansion instead. USB exclusive playback targets UAC1.0 and compatible UAC2.0 Type I PCM devices, which means exotic USB DAC topologies are outside what the README claims to support. None of these are bugs, but they mean the app you get depends on your device.
How NeriPlayer differs from a self-hosted media server
The obvious comparison is a self-hosted media server such as Navidrome or Jellyfin paired with a Subsonic-compatible Android client. The difference in approach is where the library lives. A media server owns the files: you point it at a directory, it indexes your collection, and the client streams from your server. NeriPlayer does not index a server-side collection and does not serve media to other clients. It resolves playback from third-party platforms on the device, keeps local files and caches on the device, and uses your GitHub repository or WebDAV share only for metadata such as playlists, favourites, recently played and statistics.
That leads to different failure modes. A media server fails when the server is down, the disk is full or the index is stale. NeriPlayer fails when a platform changes its playback rules, which is why the README spends so much space on NetEase quality downgrade and Bilibili auto-source matching, and on YouTube cookie rotation, PoToken sessions, player.js caching and EJS or HLS fallback. The engineering effort is aimed at surviving someone else's API changes rather than at transcoding your FLAC collection.
The download model also differs. NeriPlayer does not use the system DownloadManager. It runs its own pipeline over a shared OkHttpClient with adjustable concurrency, work files and sidecar metadata, with separate resume strategies for direct HTTP transfers, transfers that require an explicit Range header, and HLS. Paused network policies can be resumed, unfinished queues are restored at startup, already-written cache hits settle immediately, and manual cancellation cleans up partial files. If a tag write fails after download, the audio that already landed is kept. That is a more explicit set of semantics than most players document, and it is the part of the project worth reading the source for.
Licence, maintenance and what an upgrade costs you
NeriPlayer is licensed GPL-3.0. For a self-hosted, self-synced Android app the practical implication is the usual one for copyleft: if you fork it and distribute a modified build, the source for that build has to travel with it under the same terms. The README's disclaimer adds a usage restriction on top of the licence, stating that the project is for study and research and must not be used for illegal purposes. That is a request from the maintainers, not a licence term, and it does not change your GPL rights. Nothing here is legal advice; read LICENSE and the disclaimer yourself if you plan to redistribute.
The repository is not archived, and the last push was on 2026-09-04. Releases are frequent and use commit-derived tags such as NeriPlayer-ac7bdea4.09031001, which suggests builds are cut from specific commits rather than from a curated version line. For a user, the upgrade cost is mostly about state. Settings are managed by AutoSettingsSchema and cover theme, dynamic colour, UI scaling, custom backgrounds, lyric typography, blur quality and per-song custom names, artists and covers. Sync snapshots are read with tolerance for old or missing fields, and records without a parseable song identity are filtered out. That is a compatibility posture aimed at letting an older remote snapshot survive a newer app version.
The maintenance risk is concentrated in the platform integrations. NetEase, Bilibili and YouTube Music playback compatibility is the part most exposed to upstream change, and the code carries dedicated fallback machinery for exactly that reason. If you depend on one of those sources, the release cadence on the releases page is the signal to watch, not the commit history.
Editorial conclusion
Adopt NeriPlayer if you already hold accounts on the supported platforms and want playlists, history and play statistics stored on hardware you control rather than in a developer's backend. Skip it if you need a public catalogue, an iOS or desktop client, or a player that will write your listening history back to the streaming platform. Before committing, check the release page for the current Android 9 (API 28) build, confirm the Listen Together server deployment notes if you intend to self-host, and read the disclaimer screen the first launch puts in front of you.
Frequently asked questions
Does NeriPlayer include its own music library or streaming catalogue?
No. The README states that the project does not provide a public cloud library or media distribution service, and that online audio depends on the user's own account authorisation on third-party platforms. Membership and restricted content still follow the original platform's rules.
Which Android versions does NeriPlayer support?
The README states that the app targets Android 9 (API 28) and above. Some features are conditional on newer versions: advanced blur is only available on Android 13 and above and only when the parent blur setting is enabled.
Where does NeriPlayer store my playlists and play history?
By default, caches, downloads, playlists, history, statistics and settings stay on the device. If you enable sync, playlists, favourites, recently played and play statistics go to a GitHub repository you own (in-app creation defaults to private) or to a WebDAV file you control.
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/cwuom-neriplayer)