A clean, ad-free Android client that turns any YouTube channel's public RSS feed into a tappable, in-app video player. No Google account, no recommendations, no Shorts spam.
Built for people who follow a small set of channels and just want a chronological list of their latest uploads.
- Add channels by
@handle, channel URL, channel ID, or RSS feed URL - Chronological feed — newest videos first, no algorithm
- In-app playback via the YouTube IFrame Player API in a WebView — autoplay on tap, with proper landscape fullscreen on enlarge
- Channel detail view — drill into any channel for its uploads only
- Mark all watched — globally on Home or per-channel
- Hide Shorts — toggle in Settings to filter out Shorts everywhere (detected via HEAD probe at fetch time, not by
#shortsin titles) - Background sync — periodic refresh via WorkManager, optional new-video notifications
- Save for later with a bookmark on every video
- Search across titles and channel names
- Light / Dark / System theme
![]() Home feed |
![]() Channels |
![]() Channel detail |
![]() Player |
![]() Mark all watched |
![]() Settings |
![]() Hide Shorts on |
![]() Feed without Shorts |
- UI: Jetpack Compose with Material 3
- Architecture: MVVM, repository pattern, no DI framework
- Database: Room with Flow
- Networking: OkHttp + a small Atom/RSS pull-parser
- Background: WorkManager for periodic sync
- Image loading: Coil
- Persistence: DataStore (Preferences) for settings
- Player: YouTube IFrame Player API embedded in a WebView served via
WebViewAssetLoaderoverhttps://appassets.androidplatform.net/(so YouTube's anti-fraud accepts the origin)
YouTube's Atom feed doesn't expose duration or a "is short" flag, and #shorts in the title is unreliable. So at fetch time, each new videoId is probed:
HEAD https://www.youtube.com/shorts/<videoId>
→ 200 → it's a Short
→ 303 (redirect to /watch) → regular video
The probe runs concurrently for all entries on a feed, and the result is persisted on the row (VideoEntity.isShort). Filtering is then a single SQL parameter.
A subtle gotcha: an Android user-agent gets redirected to m.youtube.com for everything, which kills the signal. The probe sends a desktop UA.
Grab YouTubeFeed-vX.Y.Z.apk from Releases and adb install it, or sideload via your file manager. Min SDK 26.
JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home" \
./gradlew assembleReleaseMIT







