A Self-Hosted YouTube Media Center -- iOS & Web App
NullFeed is a self-hosted YouTube media center that delivers a streaming-service-quality browsing and playback experience for your personal YouTube library. The Flutter app targets iOS, and also runs in the browser — the NullFeed backend (Docker, on Unraid or any Docker host) bakes in the web build and serves it at /, so there's no separate web app to deploy. On a desktop browser it uses a side navigation rail; offline-save is iOS-only (the browser has no on-device storage).
Think Netflix, but for your YouTube subscriptions -- channel-centric navigation, resume-aware playback, multi-user profiles, and AI-powered discovery.
- Instant Playback with Progressive Quality -- Tap any episode and it starts immediately, even one that isn't cached on the server yet. Playback begins on a fast progressive stream, then seamlessly upgrades to the full-quality version once it's ready -- no buffering, no interruption.
- Channel-Centric Navigation -- Browse your subscriptions like shows in a streaming app, with channel art, banners, and episode lists.
- Resume-Aware Home Screen -- Continue Watching, New Episodes, and Recently Added rows keep you up to date.
- Native Video Playback -- AVPlayer-backed playback with seeking and Picture-in-Picture.
- Multi-User Profiles -- Netflix-style profile picker with independent subscriptions, watch history, and recommendations per user.
- AI-Powered Discover Tab -- Claude-powered channel and video suggestions based on your subscription graph.
- Invisible Caching -- There's no download queue to manage. Following a channel quietly caches its episodes in the background so they open instantly; your library is simply the channels you follow plus watch-later.
- Sponsor-Skip -- Automatically detects and skips sponsor/ad reads during playback (SponsorBlock + AI), with a brief "Skipped sponsor" note.
- Save Offline -- Keep any video on your device for offline playback with one tap; saved videos live in the Offline tab.
- Adaptive Layout -- Single codebase optimized for iPhone and iPad.
- Offline Metadata Caching -- Hive-based local storage for user sessions and cached metadata.
- Dark Theme -- Media-center-class dark UI with true black backgrounds and deep purple accents.
Coming soon.
- Flutter SDK 3.41+ (stable channel)
- Xcode 26 with iOS SDK
- CocoaPods (installed via
gem install cocoapodsor bundled with Xcode) - A running NullFeed backend instance
- iOS 17+ device or simulator
-
Clone the repository:
git clone https://github.com/windoze95/nullfeed-flutter.git cd nullfeed-flutter -
Install dependencies:
flutter pub get
-
Run code generation (Freezed models, Riverpod, JSON serialization):
dart run build_runner build --delete-conflicting-outputs
-
Install iOS pods:
cd ios && pod install && cd ..
-
Run on iOS Simulator:
flutter run
NullFeed follows a clean, provider-based architecture with clear separation of concerns.
All application state is managed through Riverpod providers with code generation (riverpod_generator). Providers are organized by domain:
| Provider | Responsibility |
|---|---|
authStateProvider |
User session and profile management |
channelsProvider |
Channel list with subscribe/unsubscribe |
homeFeedProvider |
Aggregated home feed data |
discoverProvider |
AI recommendation state |
offlineVideosProvider |
On-device saved (offline) videos |
videoProvider |
Video metadata and playback state |
settingsProvider |
Server URL and quality preferences |
webSocketConnectionProvider |
WebSocket lifecycle tied to auth state |
Declarative routing via go_router with support for deep linking and tab-based navigation across five main sections:
- Home -- Resume-aware feed with Continue Watching, New Episodes, Recently Added rows
- Library -- All subscribed channels in a grid layout
- Discover -- AI-powered channel recommendations
- Offline -- Videos saved on this device for offline playback
- Settings -- Server connection, quality preferences, profile management
All backend communication uses Dio with interceptors for request logging, retry logic, and user session headers. WebSocket connections are managed separately via web_socket_channel for real-time events: cache/download completion, new-episode alerts, sponsor-segment readiness, and recommendation refresh signals.
Immutable data models generated by Freezed with JSON serialization via json_serializable. Models map directly to the backend API contract.
Hive provides lightweight local persistence for user sessions, server connection details, and cached metadata for offline resilience.
The adaptive_layout.dart widget handles layout differences between iPhone and iPad form factors.
flutter build ios --releaseOpen ios/Runner.xcworkspace in Xcode to archive and distribute via TestFlight or the App Store.
flutter build web --releaseYou don't deploy the web build separately — the NullFeed backend image builds it and serves it at /. This flutter build web is the same step the backend's web Docker stage runs, and it's covered by the Build Web CI check.
After modifying any Freezed model, Riverpod provider, or JSON-annotated class:
dart run build_runner build --delete-conflicting-outputsFor continuous rebuilds during development:
dart run build_runner watch --delete-conflicting-outputsOn first launch, the app prompts you to enter your NullFeed server address:
- Server URL:
http://<server-ip>:8484(or your custom port)
This is stored locally via Hive and can be changed at any time in Settings. The settings screen includes a connection test to verify the backend is reachable.
After connecting, select or create a user profile to begin using the app.
| Repository | Description |
|---|---|
| nullfeed-backend | Python/FastAPI backend -- Docker-based server with yt-dlp, Celery, Redis, and SQLite |
| nullfeed-flutter (this repo) | Flutter client for iOS |
| nullfeed-tvos | Native Swift/SwiftUI tvOS app |
| nullfeed-demo | FastAPI demo server with Creative Commons content for App Store review |
This project is licensed under the GNU General Public License v3.0.