Skip to content

Commit 1123d6c

Browse files
authored
docs: update YouTube support documentation (#321)
Signed-off-by: Sertac Ozercan <sozercan@gmail.com>
1 parent 6cf7068 commit 1123d6c

16 files changed

Lines changed: 346 additions & 134 deletions

β€ŽAGENTS.mdβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Guidance for AI coding assistants working on this repository.
66

77
You are a Senior Swift Engineer specializing in SwiftUI, Swift Concurrency, and macOS development. Your code must adhere to Apple's Human Interface Guidelines. Target **Swift 6.0+** and **macOS 26.0+**.
88

9-
Kaset is a native macOS YouTube Music client (Swift/SwiftUI) using a hidden WebView for DRM playback and `YTMusicClient` API calls for all data fetching.
9+
Kaset is a native macOS client for YouTube Music and YouTube (Swift/SwiftUI). It uses WebViews only for DRM/playback/auth surfaces and uses `YTMusicClient` / `YouTubeClient` API calls for data fetching.
1010

1111
## Critical Rules
1212

@@ -16,7 +16,7 @@ Kaset is a native macOS YouTube Music client (Swift/SwiftUI) using a hidden WebV
1616
1717
> ⚠️ **No Third-Party Frameworks** β€” Do not introduce third-party dependencies without asking first.
1818
19-
> ⚠️ **Prefer API over WebView** β€” Always use `YTMusicClient` API calls when functionality exists. Only use WebView for playback (DRM-protected audio) and authentication.
19+
> ⚠️ **Prefer API over WebView** β€” Always use `YTMusicClient` (YouTube Music) or `YouTubeClient` (YouTube) API calls when functionality exists. Only use WebView for playback (DRM-protected media) and authentication.
2020
2121
> πŸ”§ **Improve API Explorer, Don't Write One-Off Scripts** β€” When exploring or debugging API-related functionality, **always enhance `Sources/APIExplorer/main.swift`** instead of writing temporary scripts.
2222

β€ŽCONTEXT.mdβ€Ž

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,24 @@
11
# Kaset Domain Language
22

3+
## App Source
4+
5+
The active content experience selected by the sidebar source toggle. `.music` is the YouTube Music experience and remains the default; `.video` is the regular YouTube experience. Source switches swap the visible navigation surface without merging the two data models.
6+
7+
## Music Experience
8+
9+
Kaset's YouTube Music surface: songs, albums, artists, playlists, podcasts, lyrics, queue management, and DRM audio playback through the hidden `SingletonPlayerWebView`. Data fetching belongs to `YTMusicClient` and music-specific parsers.
10+
11+
## YouTube Experience
12+
13+
Kaset's regular YouTube surface: recommendations, search, subscriptions, Shorts, channels, playlists, Watch Later, history, comments, and video playback through `YouTubeWatchWebView`. Data fetching belongs to `YouTubeClient` and YouTube-specific parsers under `Services/API/Parsers/YouTube/`.
14+
15+
## Playback Arbiter
16+
17+
The coordinator that keeps YouTube Music and regular YouTube from playing over each other. It pauses music when a YouTube video starts, pauses YouTube video when music starts, and lets media-key handling follow whichever source played most recently.
18+
319
## Library
420

5-
The signed-in user's saved YouTube Music collection. Kaset surfaces Library content as playlists, followed artists, subscribed podcast shows, and uploaded songs.
21+
The signed-in user's saved YouTube Music collection. Kaset surfaces Music Library content as playlists, followed artists, subscribed podcast shows, and uploaded songs. Regular YouTube has separate library-like surfaces such as subscriptions, Watch Later, liked videos, history, and playlists.
622

723
## Library Content Identity
824

β€ŽCONTRIBUTING.mdβ€Ž

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ cd kaset
2020
# Build from command line
2121
swift build
2222

23-
# Run tests
24-
swift test
23+
# Run unit tests (do not combine with UI tests)
24+
swift test --skip KasetUITests
2525

2626
# Package and run the app
2727
Scripts/compile_and_run.sh
@@ -44,13 +44,13 @@ Sources/
4444
└── Kaset/ β†’ Main app target
4545
β”œβ”€β”€ Models/ β†’ Data models (Song, Playlist, Album, Artist, etc.)
4646
β”œβ”€β”€ Services/
47-
β”‚ β”œβ”€β”€ API/ β†’ YTMusicClient (YouTube Music API calls)
47+
β”‚ β”œβ”€β”€ API/ β†’ YTMusicClient + YouTubeClient (InnerTube API calls)
4848
β”‚ β”œβ”€β”€ Auth/ β†’ AuthService (login state machine)
4949
β”‚ β”œβ”€β”€ Player/ β†’ PlayerService, NowPlayingManager (playback, media keys)
5050
β”‚ └── WebKit/ β†’ WebKitManager (cookie store, persistent login)
51-
β”œβ”€β”€ ViewModels/ β†’ HomeViewModel, LibraryViewModel, SearchViewModel
51+
β”œβ”€β”€ ViewModels/ β†’ Music view models plus YouTube/ video-source view models
5252
β”œβ”€β”€ Utilities/ β†’ DiagnosticsLogger, extensions
53-
└── Views/ β†’ SwiftUI views (MainWindow, Sidebar, PlayerBar, etc.)
53+
└── Views/ β†’ SwiftUI views (MainWindow, Sidebar, PlayerBar, YouTube views, etc.)
5454
└── APIExplorer/ β†’ API explorer CLI tool
5555
Tests/ β†’ Unit tests (KasetTests/)
5656
Scripts/ β†’ Build scripts
@@ -64,8 +64,12 @@ docs/ β†’ Detailed documentation
6464
| `Sources/Kaset/AppDelegate.swift` | Window lifecycle, background audio support |
6565
| `Sources/Kaset/Services/WebKit/WebKitManager.swift` | Cookie store & persistence |
6666
| `Sources/Kaset/Services/Auth/AuthService.swift` | Login state machine |
67+
| `Sources/Kaset/Services/API/YTMusicClient.swift` | YouTube Music API client |
68+
| `Sources/Kaset/Services/API/YouTubeClient.swift` | Regular YouTube API client |
6769
| `Sources/Kaset/Services/Player/PlayerService.swift` | Playback state & control |
70+
| `Sources/Kaset/Services/Player/YouTubePlayerService.swift` | Regular YouTube playback state & control |
6871
| `Sources/Kaset/Views/MiniPlayerWebView.swift` | Singleton WebView, playback UI |
72+
| `Sources/Kaset/Views/YouTube/YouTubeWatchWebView.swift` | Singleton WebView for regular YouTube watch playback |
6973
| `Sources/Kaset/Views/MainWindow.swift` | Main app window |
7074
| `Sources/Kaset/Utilities/DiagnosticsLogger.swift` | Logging |
7175

@@ -75,6 +79,7 @@ For detailed architecture documentation, see the `docs/` folder:
7579

7680
- **[docs/architecture.md](docs/architecture.md)** β€” Services, state management, data flow
7781
- **[docs/playback.md](docs/playback.md)** β€” WebView playback system, background audio
82+
- **[docs/youtube.md](docs/youtube.md)** β€” Regular YouTube source, video playback, Shorts, comments, and parser strategy
7883
- **[docs/testing.md](docs/testing.md)** β€” Test commands, patterns, debugging
7984

8085
### High-Level Overview
@@ -83,11 +88,20 @@ The app uses a clean architecture with:
8388

8489
- **Observable Pattern**: `@Observable` classes for reactive state management
8590
- **MainActor Isolation**: All UI and service classes are `@MainActor` for thread safety
86-
- **WebKit Integration**: Persistent `WKWebsiteDataStore` for cookie management
91+
- **Dual Source Model**: YouTube Music and regular YouTube are parallel experiences behind a sidebar source toggle
92+
- **WebKit Integration**: Persistent `WKWebsiteDataStore` for cookie management, authentication, and DRM playback
8793
- **Swift Concurrency**: `async`/`await` throughout, no `DispatchQueue`
8894

8995
### Playback Architecture
9096

97+
Kaset has two playback paths. YouTube Music uses `PlayerService` plus the
98+
`SingletonPlayerWebView` at `music.youtube.com`; regular YouTube uses
99+
`YouTubePlayerService` plus `YouTubeWatchWebView` at `www.youtube.com`.
100+
`PlaybackArbiter` keeps one audio source active at a time and media keys route
101+
to the source that played most recently.
102+
103+
#### YouTube Music
104+
91105
```
92106
User clicks Play
93107
β”‚
@@ -111,6 +125,25 @@ PlayerService.play(videoId:)
111125
- duration
112126
```
113127

128+
#### Regular YouTube
129+
130+
```
131+
User opens a YouTube video
132+
β”‚
133+
β–Ό
134+
YouTubePlayerService.play(video:)
135+
β”‚
136+
β”œβ”€β”€ Sets active video metadata
137+
β”œβ”€β”€ Loads www.youtube.com/watch?v={id}
138+
└── Hosts YouTubeWatchWebView inline or in the floating window
139+
β”‚
140+
β–Ό
141+
JavaScript bridge sends state, captions, quality, and ad updates
142+
β”‚
143+
β–Ό
144+
YouTubePlayerService updates playback state and YouTubePlayerBar
145+
```
146+
114147
### Authentication Flow
115148

116149
```
@@ -128,9 +161,9 @@ Observer detects cookie β†’ Dismiss sheet
128161
### Background Audio
129162

130163
```
131-
Close window (⌘W) β†’ Window hides β†’ Audio continues
132-
Click dock icon β†’ Window shows β†’ Same WebView
133-
Quit app (⌘Q) β†’ App terminates β†’ Audio stops
164+
Close window (⌘W) β†’ Window hides β†’ active playback continues
165+
Click dock icon β†’ Window shows β†’ same Music/YouTube WebView state
166+
Quit app (⌘Q) β†’ App terminates β†’ playback stops
134167
```
135168

136169
## Coding Guidelines
@@ -198,7 +231,7 @@ final class MyServiceTests: XCTestCase {
198231

199232
1. **No Third-Party Frameworks** β€” Do not introduce third-party dependencies without discussion first
200233
2. **Build Must Pass** β€” Run `swift build`
201-
3. **Tests Must Pass** β€” Run `swift test`
234+
3. **Tests Must Pass** β€” Run `swift test --skip KasetUITests` for unit tests
202235
4. **Linting** β€” Run `swiftlint --strict && swiftformat .` before submitting
203236
5. **Small PRs** β€” Keep changes focused and reviewable
204237
6. **Share AI Prompts** β€” If you used AI assistance, include the prompt in your PR (see below)
@@ -255,11 +288,11 @@ Reference: Sources/Kaset/Services/HapticService.swift for existing patterns
255288
## Testing
256289

257290
```bash
258-
# Run all tests
259-
swift test
291+
# Run unit tests
292+
swift test --skip KasetUITests
260293

261-
# Run specific test (use --filter)
262-
swift test --filter PlayerServiceTests
294+
# Run specific unit test (use --filter)
295+
swift test --skip KasetUITests --filter PlayerServiceTests
263296
```
264297

265298
See [docs/testing.md](docs/testing.md) for detailed testing patterns and debugging tips.

β€ŽREADME.mdβ€Ž

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
# Kaset
22

3-
A native macOS YouTube Music client built with Swift and SwiftUI.
3+
A native macOS client for YouTube Music and YouTube, built with Swift and SwiftUI.
44

55
<img src="docs/screenshot.png" alt="Kaset Screenshot">
66

77
## Features
88

9-
- 🎡 **Native macOS Experience** β€” Apple Music-style UI with Liquid Glass player bar and clean sidebar navigation
10-
- 🎧 **YouTube Music Premium Support** β€” Full playback of DRM-protected content via your existing subscription
9+
- 🎡 **Native macOS Experience** β€” Apple Music-style UI with Liquid Glass player bars, clean sidebar navigation, and a source toggle for Music ↔ YouTube
10+
- 🎧 **YouTube Music Support** β€” Full playback of DRM-protected YouTube Music content via your existing Premium subscription
11+
- ▢️ **[YouTube Support](docs/youtube.md)** β€” Browse regular YouTube recommendations, search, subscriptions, Shorts, Watch Later, history, comments, and video playback with native controls, captions, quality selection, and picture in picture
1112
- πŸŽ›οΈ **System Integration** β€” Now Playing in Control Center, media key support, Dock menu controls
1213
- πŸ“³ **Haptic Feedback** β€” Tactile feedback on Force Touch trackpads for player controls and navigation
1314
- 🎢 **Track Notifications** β€” Get notified when a new track starts playing
1415
- πŸ”Š **Background Audio** β€” Music continues playing when the window is closed; stops on quit
15-
- 🎚️ **Equalizer** β€” System-wide 6-band parametric EQ with Spotify-style presets, applied to YouTube Music output
16+
- 🎚️ **Equalizer** β€” System-wide 6-band parametric EQ with Spotify-style presets, applied to WebKit playback output
1617
- ⌨️ **[Keyboard Shortcuts](docs/keyboard-shortcuts.md)** β€” Full keyboard control for playback, navigation, and more
1718
- 🧭 **Explore** β€” Discover new releases, charts, and moods & genres
1819
- πŸŽ™οΈ **Podcasts** β€” Browse and listen to podcasts with episode progress tracking
@@ -24,16 +25,15 @@ A native macOS YouTube Music client built with Swift and SwiftUI.
2425
- πŸ“œ **Lyrics** β€” View plain and synced lyrics with line-by-line highlighting when timing data is available, plus AI-powered explanations and mood analysis on macOS 26+
2526
- πŸ“ƒ **Queue Management** β€” View, reorder, shuffle, and clear your playback queue
2627
- πŸ“£ **Share** β€” Share songs, playlists, albums, and artists via the native macOS share sheet
27-
- ▢️ **[YouTube Mode](docs/youtube.md)** β€” Flip the sidebar source toggle for a native regular-YouTube client: recommendations, search, subscriptions, Shorts, Watch Later, history, comments, and video playback with native controls, captions, quality selection, and picture in picture
28-
- πŸ”— **[URL Scheme](docs/url-scheme.md)** β€” Open songs directly with `kaset://play?v=VIDEO_ID`; YouTube watch and `youtu.be` links play in YouTube mode
28+
- πŸ”— **[URL Scheme](docs/url-scheme.md)** β€” Open songs directly with `kaset://play?v=VIDEO_ID`; app-targeted YouTube watch and `youtu.be` links play in YouTube mode
2929
- πŸ€– **[AppleScript Support](docs/applescript.md)** β€” Automate playback with scripts, Raycast, Alfred, and Shortcuts
3030
- 🧩 **[Extensions](docs/extensions.md)** β€” Load WebKit Web Extensions, including [uBlock Origin Lite](https://github.com/uBlockOrigin/uBOL-home)
3131

3232
## Requirements
3333

3434
- macOS 15.4 or later
3535
- Apple Intelligence features require macOS 26.0 or later
36-
- [Google](https://accounts.google.com) account
36+
- [Google](https://accounts.google.com) account for YouTube Music and YouTube personalization
3737

3838
## Installation
3939

0 commit comments

Comments
Β (0)