A standalone iOS app that keeps up with your YouTube subscriptions — no Google account required.
SubFeed fetches your subscribed channels via YouTube's public RSS feeds, stores video metadata locally in SwiftData (SQLite), and presents a clean, filterable timeline. Completely standalone: no server, no login, no tracking.
- Subscribe to YouTube channels by handle (@channel), channel ID (UC...), URL, or OPML import
- Browse a unified latest-videos feed across all your subscriptions
- Filter by Shorts, watched status, duration, search text
- Sort by newest, oldest, channel, or video length
- Inline YouTube video playback with progress tracking (auto-mark watched at 20%)
- Favorite videos for keeps
- Mute channels to hide their videos from the main feed
- Group channels for organisation
- Export/import backups (JSON) and channel lists (OPML)
- Optional YouTube Data API key for Shorts verification and channel resolution
- iOS 18.0+
- Xcode 16.0+
- Swift 6.0
Use these commands when you want the shortest path from clone to verification:
xcodebuild -list -project SubFeed.xcodeproj
swift build
swift test
xcodebuild -project SubFeed.xcodeproj -scheme SubFeedApp -destination 'platform=iOS Simulator,name=iPhone 16' build
xcodebuild test -project SubFeed.xcodeproj -scheme SubFeedApp -destination 'platform=iOS Simulator,name=iPhone 16'YouTube RSS (feeds/videos.xml?channel_id=UC...)
│
▼
RSSFeedService (actor, URLSession)
│
▼
RSSXMLParser (Foundation XMLParser delegate)
│ Extracts: yt:videoId, title, published, channelId, duration, thumbnail
▼
FeedViewModel.refreshAllFeeds()
│ Dedup → merge metadata → insert new → SwiftData save
▼
SwiftData (StoredVideo, StoredChannel, WatchedVideoEntry, etc.)
│
▼
FeedViewModel.filteredVideos (computed, cached)
│ Filters: shorts, watched, muted, min duration, search
│ Sorts: newest, oldest, channel, duration
▼
SwiftUI (LatestFeedView, ChannelFeedView, FavoritesView)
| Layer | Files |
|---|---|
| Models | Sources/SubFeed/Models/ — StoredVideo, StoredChannel, AppSettingsModel, WatchedVideoEntry, FavoriteVideoEntry |
| Services | Sources/SubFeed/Services/ — RSSFeedService, RSSXMLParser, ShortVerifier, ChannelResolver, DataRetentionService, BackupArchive, CredentialStore |
| Views | Sources/SubFeedApp/ — LatestFeedView, ChannelFeedView, FavoritesView, SubscriptionsView, SettingsView, AddChannelView, VideoCard, KeywordFiltersSheet |
SubFeed— shared library (models, services, parsers)SubFeedApp— the iOS app target (SwiftUI views, app delegate)SubFeedTests— Swift Testing tests
Open SubFeed.xcodeproj in Xcode 16+, select the SubFeedApp scheme, and build for an iOS 18 simulator or device.
Or from the command line:
xcodebuild -list -project SubFeed.xcodeproj
xcodebuild -project SubFeed.xcodeproj -scheme SubFeedApp -destination 'platform=iOS Simulator,name=iPhone 16' buildxcodebuild test -project SubFeed.xcodeproj -scheme SubFeedApp -destination 'platform=iOS Simulator,name=iPhone 16'Tests cover: RSS parsing, Shorts detection, data retention, backup round-trip, credential migration, channel search, OPML import, and model validation.
- Standalone first: No server dependency. All data lives in on-device SwiftData.
- Keychain for secrets: YouTube API keys stored in iOS Keychain, never in plaintext database fields.
- API key via HTTP header: Uses
X-Goog-Api-Keyheader rather than query string for YouTube API calls. - Conservative Shorts detection in RSS parser, aggressive in filter: The parser only marks clear Shorts. The filter heuristic is broader to catch edge cases. API verification provides the definitive answer.
- 16:9 thumbnails only: The thumbnail fallback chain excludes 4:3 letterboxed variants (hqdefault.jpg, sddefault.jpg).
- 20% auto-watch threshold: Inline playback marks a video as watched once 20% has been viewed.
- Dedup from full database, not filtered view: To prevent silent video loss from unique constraint violations.
- API keys: iOS Keychain (Security framework), transmitted via
X-Goog-Api-KeyHTTP header - Backup exports: exclude sensitive fields (apiKey, serverToken)
- No analytics, no tracking, no third-party SDKs
- Zero network dependencies by default (optional YouTube API key)
Private. Not yet licensed for distribution.