Skip to content

Commit 2139d7b

Browse files
committed
docs: update docs
Signed-off-by: Sertac Ozercan <sozercan@gmail.com>
1 parent 543edd5 commit 2139d7b

File tree

3 files changed

+323
-11
lines changed

3 files changed

+323
-11
lines changed

AGENTS.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,9 @@ For detailed information, see the `docs/` folder:
4949

5050
## Before You Start
5151

52-
1. **Read [PLAN.md](PLAN.md)** — Contains the phased implementation plan
53-
2. **Understand the playback architecture** — See [docs/playback.md](docs/playback.md)
54-
3. **Check ADRs for past decisions** — See [docs/adr/](docs/adr/) before proposing architectural changes
55-
4. **Consult API documentation before implementing API features** — See [docs/api-discovery.md](docs/api-discovery.md) for endpoint reference
52+
1. **Understand the playback architecture** — See [docs/playback.md](docs/playback.md)
53+
2. **Check ADRs for past decisions** — See [docs/adr/](docs/adr/) before proposing architectural changes
54+
3. **Consult API documentation before implementing API features** — See [docs/api-discovery.md](docs/api-discovery.md) for endpoint reference
5655

5756
### API Discovery Workflow
5857

docs/api-discovery.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,19 +155,19 @@ Browse endpoints use `POST /browse` with a `browseId` parameter.
155155
|-----------|------|------|-------------|--------|
156156
| `FEmusic_home` | Home | 🌐 | Personalized recommendations, mixes, quick picks | `HomeResponseParser` |
157157
| `FEmusic_explore` | Explore | 🌐 | New releases, charts, moods shortcuts | `HomeResponseParser` |
158-
| `FEmusic_charts` | Charts | 🌐 | Top songs, albums by country/genre | `ChartsParser` |
159-
| `FEmusic_moods_and_genres` | Moods & Genres | 🌐 | Browse by mood/genre grids | `MoodsAndGenresParser` |
160-
| `FEmusic_new_releases` | New Releases | 🌐 | Recent albums, singles, videos | `NewReleasesParser` |
161-
| `FEmusic_library_landing` | Library Landing | 🔐 | All library content (playlists, podcasts, artists) | `LibraryParser` |
158+
| `FEmusic_charts` | Charts | 🌐 | Top songs, albums by country/genre | `HomeResponseParser` |
159+
| `FEmusic_moods_and_genres` | Moods & Genres | 🌐 | Browse by mood/genre grids | `HomeResponseParser` |
160+
| `FEmusic_new_releases` | New Releases | 🌐 | Recent albums, singles, videos | `HomeResponseParser` |
161+
| `FEmusic_library_landing` | Library Landing | 🔐 | All library content (playlists, podcasts, artists) | `PlaylistParser.parseLibraryContent` |
162162
| `FEmusic_liked_playlists` | Library Playlists | 🔐 | User's saved/created playlists | `PlaylistParser` |
163163
| `VLLM` | Liked Songs | 🔐 | All songs user has liked (with pagination) | `PlaylistParser` |
164164
| `VL{playlistId}` | Playlist Detail | 🌐 | Playlist tracks and metadata | `PlaylistParser` |
165165
| `UC{channelId}` | Artist Detail | 🌐 | Artist page with songs, albums | `ArtistParser` |
166-
| `MPLYt{id}` | Lyrics | 🌐 | Song lyrics text | Custom parser |
166+
| `MPLYt{id}` | Lyrics | 🌐 | Song lyrics text | `LyricsParser` |
167167
| `FEmusic_podcasts` | Podcasts Discovery | 🌐 | Podcast shows and episodes carousel | `PodcastParser` |
168168
| `MPSPP{id}` | Podcast Show Detail | 🌐 | Podcast episodes with playback progress | `PodcastParser` |
169169

170-
> **Note**: `VLLM` is a special case of `VL{playlistId}` where `LM` is the Liked Music playlist ID. Do NOT use `FEmusic_liked_videos` — it returns only ~13 songs without pagination.
170+
> **Note**: Charts, Moods & Genres, and New Releases all use `HomeResponseParser` since they share the same section-based response structure. `VLLM` is a special case of `VL{playlistId}` where `LM` is the Liked Music playlist ID. Do NOT use `FEmusic_liked_videos` — it returns only ~13 songs without pagination.
171171
172172
#### Home (`FEmusic_home`)
173173

docs/architecture.md

Lines changed: 314 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,118 @@ Manages user-curated Favorites section on Home view:
244244
- `Views/macOS/SharedViews/FavoritesSection.swift` — Horizontal scrolling UI
245245
- `Views/macOS/SharedViews/FavoritesContextMenu.swift` — Shared context menu items
246246

247+
### NotificationService
248+
249+
**File**: `Core/Services/Notification/NotificationService.swift`
250+
251+
Posts local notifications when the current track changes:
252+
253+
- Observes `PlayerService.currentTrack` for changes
254+
- Posts silent alerts with track title and artist
255+
- Respects user preference via `SettingsManager.showNowPlayingNotifications`
256+
- Requests notification authorization on init
257+
258+
**Usage**: Instantiated in `MainWindow` and kept alive for app lifetime.
259+
260+
### NetworkMonitor
261+
262+
**File**: `Core/Services/NetworkMonitor.swift`
263+
264+
Monitors network connectivity using `NWPathMonitor`:
265+
266+
| Property | Type | Description |
267+
|----------|------|-------------|
268+
| `isConnected` | `Bool` | Whether network is available |
269+
| `isExpensive` | `Bool` | Cellular or hotspot connection |
270+
| `isConstrained` | `Bool` | Low Data Mode enabled |
271+
| `interfaceType` | `InterfaceType` | WiFi, cellular, wired, etc. |
272+
| `statusDescription` | `String` | Human-readable status |
273+
274+
**Note**: Uses `DispatchQueue` for `NWPathMonitor` callbacks (no async/await API from Apple).
275+
276+
### SettingsManager
277+
278+
**File**: `Core/Services/SettingsManager.swift`
279+
280+
Manages user preferences persisted via `UserDefaults`:
281+
282+
| Setting | Type | Default | Description |
283+
|---------|------|---------|-------------|
284+
| `showNowPlayingNotifications` | `Bool` | `true` | Track change notifications |
285+
| `defaultLaunchPage` | `LaunchPage` | `.home` | Initial page on app launch |
286+
| `hapticFeedbackEnabled` | `Bool` | `true` | Force Touch feedback |
287+
| `rememberPlaybackSettings` | `Bool` | `true` | Persist shuffle/repeat state |
288+
289+
**LaunchPage Options**: Home, Explore, Charts, Moods & Genres, New Releases, Liked Music, Playlists, Last Used
290+
291+
### ShareService
292+
293+
**File**: `Core/Services/ShareService.swift`
294+
295+
Provides share sheet functionality via the `Shareable` protocol:
296+
297+
```swift
298+
protocol Shareable {
299+
var shareTitle: String { get }
300+
var shareSubtitle: String? { get }
301+
var shareURL: URL? { get }
302+
}
303+
```
304+
305+
**Conforming Types**: `Song`, `Playlist`, `Album`, `Artist`
306+
307+
**Share Text Format**: "Title by Artist" or just "Title" for artists.
308+
309+
### SongLikeStatusManager
310+
311+
**File**: `Core/Services/SongLikeStatusManager.swift`
312+
313+
Caches and syncs like/dislike status for songs:
314+
315+
| Method | Description |
316+
|--------|-------------|
317+
| `status(for:)` | Get cached status for video ID or Song |
318+
| `isLiked(_:)` | Check if song is liked |
319+
| `setStatus(_:for:)` | Update cache (optimistic update) |
320+
| `rate(_:status:)` | Sync rating with YouTube Music API |
321+
322+
**Optimistic Updates**: Updates cache immediately, rolls back on API failure.
323+
324+
### URLHandler
325+
326+
**File**: `Core/Services/URLHandler.swift`
327+
328+
Parses YouTube Music and custom `kaset://` URLs:
329+
330+
| URL Pattern | ParsedContent |
331+
|-------------|---------------|
332+
| `music.youtube.com/watch?v=xxx` | `.song(videoId:)` |
333+
| `music.youtube.com/playlist?list=xxx` | `.playlist(id:)` |
334+
| `music.youtube.com/browse/MPRExxx` | `.album(id:)` |
335+
| `music.youtube.com/channel/UCxxx` | `.artist(id:)` |
336+
| `kaset://play?v=xxx` | `.song(videoId:)` |
337+
| `kaset://playlist?list=xxx` | `.playlist(id:)` |
338+
| `kaset://album?id=xxx` | `.album(id:)` |
339+
| `kaset://artist?id=xxx` | `.artist(id:)` |
340+
341+
**Usage**: Called from `KasetApp.onOpenURL` to handle deep links.
342+
343+
### UpdaterService
344+
345+
**File**: `Core/Services/UpdaterService.swift`
346+
347+
Manages application updates via Sparkle framework:
348+
349+
| Property | Type | Description |
350+
|----------|------|-------------|
351+
| `automaticChecksEnabled` | `Bool` | Auto-check on launch |
352+
| `canCheckForUpdates` | `Bool` | Whether check is allowed now |
353+
354+
**Key Methods**:
355+
- `checkForUpdates()` — Manually trigger update check
356+
357+
See [ADR-0007: Sparkle Auto-Updates](adr/0007-sparkle-auto-updates.md) for design details.
358+
247359
### AppDelegate
248360

249361
**File**: `App/AppDelegate.swift`
@@ -418,10 +530,97 @@ DiagnosticsLogger.player.info("Loading video: \(videoId)")
418530
DiagnosticsLogger.auth.error("Cookie extraction failed")
419531
```
420532

421-
**Categories**: `.player`, `.auth`, `.api`, `.webKit`, `.haptic`
533+
**Categories**: `.player`, `.auth`, `.api`, `.webKit`, `.haptic`, `.notification`
422534

423535
**Levels**: `.debug`, `.info`, `.warning`, `.error`
424536

537+
## Utilities
538+
539+
The `Core/Utilities/` folder contains shared helper components.
540+
541+
### ImageCache
542+
543+
**File**: `Core/Utilities/ImageCache.swift`
544+
545+
Thread-safe actor with memory and disk caching:
546+
547+
| Feature | Description |
548+
|---------|-------------|
549+
| Memory cache | 200 items, 50MB limit via `NSCache` |
550+
| Disk cache | 200MB limit with LRU eviction |
551+
| Downsampling | Images resized to display size before caching |
552+
| Prefetch | Structured cancellation for SwiftUI `.task` lifecycle |
553+
554+
**Key Methods**:
555+
- `image(for:targetSize:)` — Fetch and cache image
556+
- `prefetch(urls:targetSize:maxConcurrent:)` — Batch prefetch for lists
557+
558+
### ColorExtractor
559+
560+
**File**: `Core/Utilities/ColorExtractor.swift`
561+
562+
Extracts dominant colors from album art for dynamic theming:
563+
564+
- Uses `CIAreaAverage` filter for color extraction
565+
- Caches extracted colors to avoid repeated processing
566+
- Used by `AccentBackground` for gradient overlays
567+
568+
### AnimationConfiguration
569+
570+
**File**: `Core/Utilities/AnimationConfiguration.swift`
571+
572+
Standardized animation timing for consistent motion design:
573+
574+
| Animation | Duration | Curve | Used For |
575+
|-----------|----------|-------|----------|
576+
| `.standard` | 0.25s | `.easeInOut` | General transitions |
577+
| `.quick` | 0.15s | `.easeOut` | Button feedback |
578+
| `.slow` | 0.4s | `.easeInOut` | Panel reveals |
579+
580+
### AccessibilityIdentifiers
581+
582+
**File**: `Core/Utilities/AccessibilityIdentifiers.swift`
583+
584+
Centralized UI test identifiers organized by feature:
585+
586+
```swift
587+
enum AccessibilityID {
588+
enum Player { static let playButton = "player.playButton" }
589+
enum Queue { static let container = "queue.container" }
590+
// ...
591+
}
592+
```
593+
594+
**Benefits**: Prevents string duplication, enables IDE autocomplete in tests.
595+
596+
### IntelligenceModifier
597+
598+
**File**: `Core/Utilities/IntelligenceModifier.swift`
599+
600+
SwiftUI modifier to hide AI features when unavailable:
601+
602+
```swift
603+
.requiresIntelligence() // Hides view if Apple Intelligence unavailable
604+
```
605+
606+
Checks `FoundationModelsService.shared.isAvailable` and applies opacity/disabled state.
607+
608+
### RetryPolicy
609+
610+
**File**: `Core/Utilities/RetryPolicy.swift`
611+
612+
Exponential backoff for network retries:
613+
614+
```swift
615+
try await RetryPolicy.execute(
616+
maxAttempts: 3,
617+
initialDelay: .seconds(1),
618+
shouldRetry: { ($0 as? YTMusicError)?.isRetryable ?? false }
619+
) {
620+
try await client.fetchData()
621+
}
622+
```
623+
425624
## Performance Guidelines
426625

427626
This section documents performance patterns and optimizations used throughout the codebase.
@@ -625,6 +824,41 @@ User Input (natural language)
625824
| `AIErrorHandler` | `Core/Services/AI/` | User-friendly error messages |
626825
| `RequiresIntelligenceModifier` | `Core/Utilities/` | Hide AI features when unavailable |
627826

827+
### AI Tools
828+
829+
Tools ground AI responses in real data from the YouTube Music catalog, preventing hallucination.
830+
831+
**MusicSearchTool** (`Core/Services/AI/Tools/MusicSearchTool.swift`)
832+
833+
Searches the YouTube Music catalog for songs, artists, and albums:
834+
835+
```swift
836+
@Generable
837+
struct MusicSearchResult {
838+
let songs: [SongResult]
839+
let artists: [ArtistResult]
840+
let albums: [AlbumResult]
841+
}
842+
```
843+
844+
**QueueTool** (`Core/Services/AI/Tools/QueueTool.swift`)
845+
846+
Provides access to the current playback queue for AI-driven queue management:
847+
848+
- Returns current queue contents
849+
- Used by `QueueIntent` for natural language queue manipulation
850+
- Enables commands like "remove duplicates" or "play upbeat songs next"
851+
852+
### @Generable Models
853+
854+
Type-safe structured outputs for AI responses:
855+
856+
| Model | File | Purpose |
857+
|-------|------|---------|
858+
| `MusicIntent` | `Core/Models/AI/MusicIntent.swift` | Parsed user commands (play, pause, search, etc.) |
859+
| `LyricsSummary` | `Core/Models/AI/LyricsSummary.swift` | Lyrics explanation with themes and mood |
860+
| `PlaylistChanges` | `Core/Models/AI/PlaylistChanges.swift` | Queue refinement operations |
861+
628862
### AI Features
629863

630864
| Feature | Trigger | Model Used |
@@ -642,6 +876,85 @@ User Input (natural language)
642876
4. **Graceful Degradation**: Use `.requiresIntelligence()` modifier to hide unavailable features.
643877
5. **Error Handling**: Use `AIErrorHandler` for user-friendly messages.
644878

879+
## UI Components
880+
881+
This section documents key SwiftUI views and their integration patterns.
882+
883+
### QueueView
884+
885+
**File**: `Views/macOS/QueueView.swift`
886+
887+
Right sidebar panel displaying the playback queue:
888+
889+
- Shows "Up Next" header with shuffle/clear actions
890+
- Displays queue items with drag-to-reorder support
891+
- AI-powered "Refine" button for natural language queue editing
892+
- Uses `.glassEffect(.regular.interactive())` with `.glassEffectTransition(.materialize)`
893+
894+
**Integration**: Toggled via `PlayerService.showQueue`, placed outside `NavigationSplitView` in `MainWindow`.
895+
896+
### LyricsView
897+
898+
**File**: `Views/macOS/LyricsView.swift`
899+
900+
Right sidebar panel displaying song lyrics:
901+
902+
- Fetches lyrics via `YTMusicClient.getLyrics(videoId:)`
903+
- "Explain" button triggers AI-powered `LyricsSummary` generation
904+
- Scrollable text with synchronized highlighting (when available)
905+
- Width: 280px, animated show/hide
906+
907+
**Integration**: Toggled via `PlayerService.showLyrics`, persists across all navigation states.
908+
909+
### CommandBarView
910+
911+
**File**: `Views/macOS/CommandBarView.swift`
912+
913+
Spotlight-style command palette triggered by ⌘K:
914+
915+
- Natural language input parsed via `MusicIntent`
916+
- Shows suggestions and action previews
917+
- Supports commands: play, pause, skip, search, queue management
918+
- Floating overlay with glass effect
919+
920+
**Trigger**: `@Environment(\.showCommandBar)` environment key.
921+
922+
### ToastView
923+
924+
**File**: `Views/macOS/ToastView.swift`
925+
926+
Temporary notification overlay for user feedback:
927+
928+
| Toast Type | Duration | Purpose |
929+
|------------|----------|---------|
930+
| Success | 2s | Action completed (e.g., "Added to library") |
931+
| Error | 3s | Action failed with message |
932+
| Info | 2s | Informational feedback |
933+
934+
**Usage**: Managed via environment or direct state binding.
935+
936+
### SharedViews
937+
938+
**Directory**: `Views/macOS/SharedViews/`
939+
940+
Reusable components used across the app:
941+
942+
| Component | Purpose |
943+
|-----------|---------|
944+
| `ErrorView` | Standardized error display with retry button |
945+
| `LoadingView` | Skeleton loading states |
946+
| `SkeletonView` | Shimmer placeholder for loading content |
947+
| `EqualizerView` | Animated bars for "now playing" indicator |
948+
| `HomeSectionItemCard` | Card component for carousel items |
949+
| `InteractiveCardStyle` | Hover/press effects for cards |
950+
| `NavigationDestinationsModifier` | Centralized navigation destination handling |
951+
| `ShareContextMenu` | Context menu for sharing content |
952+
| `StartRadioContextMenu` | Context menu for starting radio/mix |
953+
| `FavoritesSection` | Horizontal scrolling favorites row |
954+
| `FavoritesContextMenu` | Context menu for favorites management |
955+
| `SongActionsHelper` | Common song action handlers |
956+
| `AnimationModifiers` | Reusable animation view modifiers |
957+
645958
### PlayerBar
646959

647960
**File**: `Views/macOS/PlayerBar.swift`

0 commit comments

Comments
 (0)