Works · 02
BPlayer · BTelly
A third-party Bilibili client for Android TV and car head units — unofficial and ad-free, with a dual playback core, danmaku comments and the airborne assistant, built on Kotlin + Koin.
View repository › Codeberg ›Why I built it
The Bilibili experience on TV and in the car has long been a low point: the official clients treat remote-control and in-car interaction as an afterthought, while the ads and the feed noise stay exactly the same. I just wanted to sit on the living-room sofa, or spend that commuting hour, quietly watching the people I follow post something new. The point of a third-party client was never cracking anything — it was handing a screen that belongs to the viewer back to the viewer.
Where the difficulty lives
- Endpoint archaeology: a third-party client lives in a world where the API changes without notice. When the follow-list endpoint died, even the public API-collection repositories had been wiped clean — the correct endpoint ended up being dug out of another open-source client’s source, then corrected field by field against real responses: what the cover field is actually called, who hands down the pagination terminator, where the live count comes from. All of it verified against real traffic, none of it guessed.
- Two form factors, one codebase: the same ten-foot interface means different things. TV wants focus flow driven by remote directional keys; a car head unit wants zero-thought operation while driving. Two interaction philosophies have to coexist in one repository.
- Watermark and attribution: attribution cannot live only in the README. Build time bakes the author identity and repository origin into the artifact — visible in-app, self-verifying. That is the bare minimum honesty a third-party project owes its users.
Where it stands
- Dual playback cores, danmaku comments, airborne assistant — no ads, no feed injection
- The “My Follows” live page groups by “Live now / Not live”, showing everything currently streaming with paginated loading, and dimming the offline ones with a direct jump to their space
- In-app updates over dual channels (GitHub primary + Codeberg mirror), with automatic fallback when the primary fails
- Mac build machine produces signed artifacts; GitHub Actions output matches the local certificate exactly
What I learned
Maintaining a project that lives on top of someone else’s API, the skill that matters is not shipping features — it is how fast you can stand back up when the API turns on you. Isolate the network layer into its own module, document the endpoint archaeology, bake attribution into the artifact instead of the docs: all of it looks like overhead on a good day, and all of it is a lifesaver on the day the API changes its face. Two banned accounts also taught me one thing: a mirror channel is not a backup ritual — it is the road you will actually end up taking.