kushalpandya/Petrichor
49.2
Weak · 1 October 2026
48k
lines of production code
Swift
primary language
2
measurements over time
What this system is
Petrichor is an offline macOS music player that manages local audio libraries and internet radio streams through a comprehensive metadata engine and SQLite-backed database. It provides playback capabilities including gapless audio, crossfading, spatial audio, and ReplayGain normalization, alongside features like smart playlists, synced lyrics, and Last.fm scrobbling. The system supports deep macOS integration via a miniplayer, immersive mode, and Siri/Shortcuts automation, while handling library maintenance tasks such as duplicate merging and artwork optimization.
How it got here
2025 — Petrichor initial release and architecture
26 changes.
This period marks the initial release of Petrichor, an offline macOS music player, involving the complete migration from a basic SwiftUI scaffold to a robust, GRDB-backed architecture. The work focused on implementing core playback features, a comprehensive library management system with duplicate handling, and a redesigned immersive user interface with integrated internet radio and Last.fm scrobbling.
2026 — CrescendoKit migration and automation
7 changes.
The project replaced its audio engine and metadata parsing with the new CrescendoKit backend to improve playback reliability, performance, and feature support. This core infrastructure update was accompanied by significant UI enhancements, including a new mini-player with lyrics and dynamic tinting, as well as the addition of Siri, Shortcuts, and Spotlight automation capabilities.
Features
Add Mini Player with embedded play queue and lyrics
A new standalone, borderless Mini Player window is now available, providing an edge-to-edge album artwork view with playback controls and a floating toolbar to toggle an embedded play queue or lyrics panel. The window is user-resizable while maintaining a square aspect ratio for the artwork, supports persistent frame positioning across sessions, and includes customization options for appearance (such as artwork-derived color tinting for controls and backgrounds) and playback visuals.
Views/MiniPlayer · high confidence
Add Siri, Shortcuts, and Spotlight automation support
Users can now control playback and browse the library using system automation tools. This adds App Intents for transport commands (play, pause, skip, seek, volume, shuffle, repeat, favorite) and content actions (playing artists, albums, genres, decades, and playlists). It also exposes a 'Get Current Track' intent for Shortcuts workflows and registers curated Siri phrases for quick voice access to playback and library browsing.
Managers/Automation · high confidence
Initial release of Petrichor, an offline macOS music player
Introduces Petrichor, a new offline music player for macOS featuring a comprehensive library browser, support for over 40 audio formats via the CrescendoKit engine, and playback capabilities including gapless playback, crossfading, spatial audio, and an equalizer. The app includes a miniplayer and immersive mode, smart playlists, internet radio streaming, Last.fm scrobbling, and synced lyrics. It also provides native macOS integration with menubar controls, automatic updates via Sparkle, and a built-in problem reporting tool.
(repo-wide) · high confidence
Introduce Discover tab with curated music recommendations
The app now includes a Discover section in the Library sidebar, featuring carousels for Featured picks, Fresh Music, Most Loved, and Recently Played tracks. This new capability manages its own caching, refresh intervals, and artwork generation (collages) to ensure tiles display immediately and stay current. Users can manually refresh Featured and Fresh Music sections, and the system automatically handles smart playlist evaluation and sticky selection preservation across app launches.
Managers/Library · high confidence
Introduce Home tab with Discover, pinned items, and entity browsing
A new Home tab has been added, featuring a sidebar for navigation and a main content area. The sidebar includes a Discover section that displays Featured, Recently Played, and Most Loved recommendations alongside a Fresh Music track list, as well as support for pinning artists, albums, genres, and playlists. Users can browse their library by entity type (Artists, Albums, etc.) via the EntityTypeView, which supports sorting and grouping. The Home view also manages a detail overlay for viewing entity specifics and integrates Internet Radio support if enabled.
Views/Home · high confidence
Introduce hierarchical folder navigation in the Folders sidebar
The Folders sidebar now displays a collapsible tree of folders, allowing users to navigate nested directory structures rather than a flat list. Selecting a folder in this hierarchy updates the main content area to show only the tracks within that specific folder, with the ability to expand and collapse sub-folders directly in the sidebar.
Views/Folders · high confidence
Introduces configurable library filtering, track table columns, and playback settings enums
This change adds a suite of new model enums that enable richer library organization and playback control. Users can now filter their library by Artists, Albums, Composers, Genres, Decades, and Years via the new LibraryFilterType enum, which supports localized display names and stable persistence. The track list view gains a configurable table with columns for Title, Duration, and Track Number (TrackTableColumn), allowing users to customize which metadata is visible. Additionally, library management is enhanced with AutoScanInterval (including a new 'Manually' option) and DiscoverUpdateInterval settings, while playback behavior is refined with RepeatMode and ReplayGainMode enums for loudness normalization.
Models/Enums · high confidence
Introduces new shared UI components for the redesigned interface
Adds a suite of reusable SwiftUI components to Views/Components that power the app's visual overhaul. This includes ActivityAnimation for consistent loading indicators, EntityGridView and EntityListView for optimized grid and list entity displays with artwork caching, and DetailHeaderControls for unified header actions like pinning and playback. The update also introduces FloatingControlCluster and PanelToolbarButton for the mini player and immersive mode, FocusStableMaterial to maintain visual fidelity across window focus states, and NoMusicEmptyStateView to handle empty library and onboarding contexts. These components replace ad-hoc implementations to provide a unified, performant, and consistent user experience across the library, home, and player views.
Views/Components · high confidence
Library categorization, discovery, and maintenance overhaul
The database layer now supports granular library filtering by genre and decade, with categories displayed in the Library sidebar and Discover carousels using denormalized track data to ensure consistent counts. A new background migration system automatically converts stored album, artist, track, and playlist artwork to the more efficient HEIC format without blocking the UI. The app also introduces manual merging of duplicate artists, albums, and composers to reduce fragmentation, alongside robust cleanup logic that removes orphaned database entries when tracks or folders are deleted. Additionally, the database now persists Internet radio stations and their collections, enabling users to save and manage online streams alongside their local library.
Managers/Database · high confidence
New UI components for artwork management, notifications, and playback controls
This change introduces a suite of new SwiftUI widgets in the Views/Components/Widgets directory to enhance the user interface. Users can now manage media artwork via ArtworkImageWell, which supports drag-and-drop, paste, and file selection for album art, and ArtworkInputField for text-based input. Playback and system interaction are improved with AirPlayRoutePicker for selecting AirPlay 2 output devices and VerticalSlider for visualizing and adjusting volume or EQ levels with real-time dB feedback. Navigation is streamlined with TabbedButtons, offering customizable tab-style selection with fade or transform animations, while MarqueeText handles scrolling text for long labels. Additionally, NotificationTray provides a persistent, persisted history of app activity and status messages, allowing users to track background tasks and view info, warning, or error notifications.
Views/Components/Widgets · high confidence
New Utilities module for app info, diagnostics, and asset handling
The Utilities folder now contains a dedicated set of modules that centralize app metadata, diagnostic reporting, and asset management. AppInfo.swift provides dynamic version and build details, while DiagnosticSnapshot.swift generates structured JSON payloads (including hardware and library stats) for the new in-app Problem Reporting feature. FilesystemUtils.swift introduces SHA256 folder hashing and slow-filesystem detection to improve library scanning reliability, and ImageUtils.swift adds HEIC compression and dominant color extraction to support the new artwork color gradients. Additionally, KeychainManager.swift secures Last.fm session keys, and URLSchemeHandler.swift manages the authentication callbacks required for scrobbling.
Utilities · high confidence
New build script for signed DMG installers with notarization support
A new \Scripts/build-installer.sh\ script has been added to automate the creation of signed DMG installers for Petrichor. The script handles building the app from source, applying code signing (supporting both Developer ID and automatic signing), and generating the DMG. It includes preflight checks for required tools and validates that API keys defined in \Secrets.xcconfig\ are present to prevent silent integration failures. The build process optionally supports Apple Notary for macOS distribution and allows bypassing notarization for development builds.
Scripts · high confidence
New in-app problem reporting and acknowledgements views
Users can now submit feedback directly from the app via a new 'Report a Problem' window accessible from the Help menu, which collects issue details, contact information, and optional diagnostic logs before handing them off to the backend. Additionally, a new 'Acknowledgements' view has been added to display third-party license information in a formatted, scrollable window, accessible via the Settings \> About section and the Help menu.
Views/Support · high confidence
New managers for artist info, folder hierarchy, internet radio, lyrics, menu bar, and playback
The app introduces several new manager classes to support new capabilities: ArtistBioManager fetches artist images and bios from MusicBrainz, Wikidata, TMDB, and Last.fm; FolderHierarchyBuilder constructs the tree view for the Folders sidebar; InternetRadioManager handles station lists and radio-browser integration; LyricsManager fetches lyrics from LRCLIB; MenuBarManager provides background playback controls; and PlaybackManager (along with PlaybackQueueMirror and PlaybackRadio extensions) coordinates track and stream playback, queue mirroring, and radio state.
Managers · high confidence
New playlist management sheets and UI components
Users can now create, edit, and export playlists through a set of new SwiftUI sheets. This includes a unified editor for regular playlists with tabbed views for managing track lists and searching for new songs, a smart playlist editor that allows configuring dynamic rules, match types, and limits, and a station collection editor for grouping internet radio stations. Additionally, a new export sheet enables users to select and export specific playlists, while a dedicated artwork sheet allows customizing playlist images via local files, URLs, or automatic collage generation. These changes are supported by shared UI components for headers, footers, and name fields to ensure a consistent editing experience.
Views/Playlists/Sheets · high confidence
New track table views with grouping, sorting, and internet radio support
The TrackViews component now includes a new SwiftUI-based TrackTableView that supports grouping tracks by album and disc, customizable column sorting (including track number, disc number, and favorites), and persistent column customization. Additionally, a new StationTableView has been added to display internet radio stations with similar sorting and customization capabilities, while TrackListView provides a list-based alternative for nested scrolling contexts.
Views/Components/TrackViews · high confidence
Removals
Removal of initial SwiftUI app structure and assets
The initial SwiftUI application scaffold has been removed, including the main app entry point (PetrichorApp.swift), the primary content view (ContentView.swift), and the app icon asset catalog (AppIcon.appiconset). This change eliminates the default 'Hello, world!' interface and associated icon resources from the Petrichor module.
Petrichor · high confidence
Architecture
Migrate project to Xcode 26.1 with new build structure and dependencies
The Xcode project has been upgraded to version 26.1, introducing a reorganized folder structure with synchronized groups for Core, Application, Managers, Models, Views, Utilities, Configuration, and Resources. The build configuration now isolates debug and release app data, renaming the debug output to "Petrichor Dev.app". Three new Swift packages—GRDB, Sparkle, and CrescendoKit—have been integrated as framework dependencies, and the previous entitlements file has been replaced with a workspace settings file.
Petrichor.xcodeproj · high confidence
Behavioural changes
Configuration for new integrations and sandboxing
The app now includes configuration for Last.fm scrobbling, Internet Radio station browsing, and in-app problem reporting, alongside the necessary entitlements to support the sandboxed environment.
Configuration · high confidence
Core data models migrated to GRDB with expanded metadata and deduplication support
The core library models (Album, Artist, Track, Folder, etc.) have been rewritten to use GRDB for SQLite persistence, replacing the previous storage mechanism. This change introduces comprehensive metadata fields, including external identifiers (Discogs, MusicBrainz, Spotify, Apple Music) and detailed audio format properties (codec, bitrate, sample rate, lossless status) accessible via the new AudioFormatDescribing protocol. To improve library accuracy, the models now support album and artist aliasing via dedicated Alias tables for merging duplicates, and include specific fields for tracking duplicate tracks. Additionally, new models for Equalizer presets and Discover entities have been added to support audio customization and the redesigned discovery interface.
Models/Core · high confidence
Improved artist matching and new localization support
The app now bundles a known artists database to improve name recognition and matching accuracy, alongside the addition of Simplified Chinese (zh-Hans) localization strings and a new Acknowledgements document for third-party dependencies.
Resources · high confidence
Improved artist name parsing and lyrics loading with online fallback
The Core module now features a new ArtistParser that uses a bundled known-artists database and library context to correctly handle ambiguous separators (like ' / ' or ' & ') in artist names, preventing incorrect splits for names like 'AC/DC'. Additionally, the LyricsLoader and LyricsStore have been updated to support fetching timed lyrics from an online source when only untimed lyrics are available, and to robustly handle various file encodings (including CJK) for both external and embedded lyrics.
Core · high confidence
New CrescendoKit playback backend replaces SFBAudioEngine
The Core/Playback module now uses the new CrescendoKit backend (CrescendoPlaybackBackend) instead of the previous SFBAudioEngine. This change introduces a modern AVFoundation-based engine that supports internet radio streams, crossfade between tracks, and ReplayGain, while also reducing CPU usage. The diff shows the new backend implementation and the updated PlaybackEngine facade that manages queue, state, and now-playing metadata via the new CrescendoPlayer.
Core/Playback · high confidence
Now-playing controls and artwork tinting refactored for improved legibility
The NowPlaying component has been refactored to centralize artwork-derived color logic and improve control legibility. A new NowPlayingArtwork helper enum now manages dominant color extraction, background gradients, and luminance calculations, allowing the NowPlayingControlsView to dynamically tint transport buttons (play/pause, shuffle, repeat) based on album art while ensuring sufficient contrast for both light and dark backgrounds. This change replaces scattered tinting logic with a shared, cached system that honors appearance settings, resulting in more consistent and readable playback controls across the mini player and immersive mode surfaces.
Views/Components/NowPlaying · high confidence
Playback state persistence and app lifecycle management
The application now saves and restores the playback session (current track, queue, position, and transport settings) across launches and backgrounding, replacing the previous UserDefaults-based storage with a dedicated file-based store. Closing the main window no longer quits the app by default; instead, it hides the window and moves the app to the menu bar, respecting the user's preference for background running. Additionally, the app now integrates Sparkle for automatic updates in production builds and captures diagnostic snapshots during launch and termination to aid in troubleshooting.
Application · high confidence
Playlist management refactored into modular extensions
The PlaylistManager logic has been reorganized into distinct Swift extensions to improve maintainability and scalability. This change introduces dedicated modules for M3U import/export (PMImportExport), pinning items to the Home sidebar (PMPinnedItems), playback control and queue management (PMPlayback, PMQueue), regular playlist CRUD operations (PMRegularPlaylists), smart playlist evaluation and persistence (PMSmartPlaylistEvaluator, PMSmartPlaylists), station collection management (PMStationCollections), and track metadata updates (PMTrackUpdate). Users benefit from more robust playlist import/export with detailed result reporting, the ability to pin playlists to the Home sidebar, and improved performance and reliability in smart playlist evaluation and queue handling.
Managers/Playlist · high confidence
Redesigned Library sidebar with unified filtering, sorting, and duplicate merging
The Library view now features a completely rewritten sidebar (\LibrarySidebarView\ and \LibraryTypeSidebarView\) that supports global search with debouncing, dynamic filtering by type (artists, albums, etc.), and sort direction controls. The interface includes a new \MergeEntitySheet\ allowing users to identify and merge duplicate artists, albums, or composers into a single canonical entry. Selection logic has been unified to handle pending navigations and sync state across tabs, while the main content area (\LibraryView\) integrates these filters to update the track list in real-time.
Views/Library · high confidence
Redesigned Playlists tab with sidebar, detail view, and station collection support
The Playlists tab has been rebuilt with a dedicated sidebar for managing playlists and a new detail view for browsing their contents. Users can now create, reorder, and delete playlists (with confirmation) via the sidebar, and access import/export options. The detail view displays playlist tracks with sorting and column configuration, supports dynamic artwork-based gradient backgrounds, and includes a new view for Internet Radio station collections, allowing users to manage radio stations alongside regular playlists.
Views/Playlists · high confidence
Redesigned Settings interface with new playback and integration options
The Settings window has been reorganized into five distinct tabs: General, Appearance, Library, Integrations, and About. The General tab now includes controls for crossfade (with duration adjustment), ReplayGain normalization (with source and preamp settings), automatic app updates, and duplicate track hiding. The Appearance tab allows users to customize color modes (Light, Dark, Auto), toggle album-artwork-based color tints for the interface and player, and adjust the player bar background style. The Library tab consolidates folder management, auto-scan intervals, and configurable Discover section settings (refresh interval and track count). The Integrations tab adds Last.fm scrobbling and favorite syncing, along with toggles for online lyrics fetching and artist info updates. The About tab displays library statistics and provides links to acknowledgements, the help wiki, and the website.
Views/Settings · high confidence
Redesigned main window with immersive playback and unified sidebar
The main application window has been completely restructured to support a new immersive playback mode, a dynamic right sidebar, and a unified tab-based navigation system. Users can now toggle an immersive view that overlays the main interface with large album art and lyrics, while the right sidebar independently displays the play queue, track details, or synchronized lyrics. The main content area now uses a tabbed interface (Home, Library, Playlists, Folders) with configurable visibility for the Folders tab, and the player bar features artwork-tinted gradients, a native progress bar, and controls for volume, queue, and immersive mode.
Views/Main · high confidence
Sidebar UI refactored with new row component and reordering support
The sidebar interface has been rebuilt using new \SidebarItemRow\ and \SidebarListView\ components, introducing support for dragging and reordering items within the Home and Playlists sections. The new row component adds tooltips for truncated titles and subtitles, displays song or station counts as subtitles, and uses accent colors for hover states. Additionally, the Home sidebar now includes fixed entries for Discover, Tracks, and Internet Radio, alongside support for pinned folders and categories.
Views/Components/Sidebar · high confidence
Switched metadata engine to Crescendo with improved artwork handling
The app now uses the new CrescendoKit backend for reading audio metadata, replacing the previous engine. This change ensures more accurate track information extraction and fixes issues where tracks occasionally displayed incorrect artwork by prioritizing tagged front covers and handling external artwork fallbacks. Users will see more reliable metadata, including better duration validation for MPEG files and normalized ratings, while the system efficiently caches compressed artwork to improve performance.
Core/Metadata · high confidence
Dependencies
Update Swift Package Manager dependency versions
The Swift Package Manager resolved dependencies have been updated: GRDB.swift is upgraded to version 7.11.1, CrescendoKit is pinned to version 1.2.3, and Sparkle is updated to version 2.10.0.
(dependencies) · high confidence
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
How this codebase got here
Score
- CAI 48 → 49 (+1.6)
- Rubric changed (rubric-2026.09.11 → rubric-2026.09.18) — scores are not directly comparable.
Lenses
- Code Health 88 → 88 (-0.4)
- Architecture 95 → 97 (+2.1)
- Maturity 58 → 58 (-0.0)
- Readiness 31 → 36 (+5.0)
- Security 61 → 61 (+0.0)
- Domain Modelling 56 → 56 (-0.1)
- Performance 61 (new)
Resolved (17)
- Change coupling: FoldersView.swift ↔ PlaylistsView.swift (Views/Folders/FoldersView.swift)
- Change coupling: HomeView.swift ↔ PlaylistsView.swift (Views/Home/HomeView.swift)
- Change coupling: TrackTableView.swift ↔ EntityDetailView.swift (Views/Components/TrackViews/TrackTableView.swift)
- Change-coupling hub: LibraryView.swift → FoldersView.swift, PlaylistDetailView.swift, PlaylistsView.swift (Views/Library/LibraryView.swift)
- ClassTooLong: PlaylistDetailView (Views/Playlists/PlaylistDetailView.swift)
- Dependency hygiene PARTLY measured — SwiftPM pinning read, dependency currency NOT established
- Documentation: no usage examples (README.md)
- Duplicated block (10–11 lines × 2) (Views/Playlists/PlaylistDetailView.swift)
- Duplicated block (1–14 lines × 6) (Managers/Database/DMSetup.swift)
- Duplicated block (5–8 lines × 4) (Managers/Database/DMSetup.swift)
- Hotspot: Application/AppDelegate.swift (Application/AppDelegate.swift)
- Hotspot: Managers/ArtistBioManager.swift (Managers/ArtistBioManager.swift)
- Hotspot: Managers/InternetRadioManager.swift (Managers/InternetRadioManager.swift)
- Hotspot: Managers/ScrobbleManager.swift (Managers/ScrobbleManager.swift)
- Hotspot: Models/Core/Playlist.swift (Models/Core/Playlist.swift)
- Hotspot: Views/Components/TrackViews/TrackTableOptionsDropdown.swift (Views/Components/TrackViews/TrackTableOptionsDropdown.swift)
- Hotspot: Views/Main/TrackDetailView.swift (Views/Main/TrackDetailView.swift)
New (54)
- Change coupling: FoldersView.swift ↔ LibraryView.swift (Views/Folders/FoldersView.swift)
- Change-coupling hub: PlaylistsView.swift → FoldersView.swift, HomeView.swift, LibraryView.swift (Views/Playlists/PlaylistsView.swift)
- ContentView.body (cognitive 27) (Views/Main/ContentView.swift)
- ContentView.body (cyclomatic 26) (Views/Main/ContentView.swift)
- Duplicated block (10 lines × 2) (Models/Core/FullTrack.swift)
- Duplicated block (10 lines × 2) (Models/Core/SmartPlaylistField.swift)
- Duplicated block (10 lines × 2) (Views/Components/NowPlaying/NowPlayingControlsView.swift)
- Duplicated block (10 lines × 2) (Views/Home/EntityDetailView.swift)
- Duplicated block (11 lines × 2) (Models/Enums/LibraryFilterType.swift)
- Duplicated block (11 lines × 6) (Models/Enums/LibraryFilterType.swift)
- Duplicated block (12 lines × 2) (Views/Playlists/Sheets/RegularPlaylistEditorSheet.swift)
- Duplicated block (12 lines × 3) (Views/Folders/FoldersView.swift)
- Duplicated block (13 lines × 2) (Views/Folders/FoldersView.swift)
- Duplicated block (14 lines × 2) (Views/Components/NowPlaying/NowPlayingControlsView.swift)
- Duplicated block (14 lines × 2) (Views/Components/TrackViews/StationTableView.swift)
- Duplicated block (14 lines × 2) (Views/Folders/FoldersView.swift)
- Duplicated block (14 lines × 2) (Views/Main/PlayerView.swift)
- Duplicated block (16 lines × 2) (Views/Components/TrackViews/TrackTableOptionsDropdown.swift)
- Duplicated block (19 lines × 2) (Views/Main/TrackDetailView.swift)
- Duplicated block (1–5 lines × 6) (Managers/Database/DMSetup.swift)
- …and 34 more
Changes since last survey
- 9 commits — 7 feature/other, 2 fixes
By area
- Managers/Library — 2 commits
- Petrichor.xcodeproj/project.pbxproj — 2 commits
- Views/Components — 2 commits
- Core/LyricsLoader.swift — 1 commit
- Managers/Database — 1 commit
- Views/Main — 1 commit
Notable commits
- fix: Fixes tracks list navigation not working via arrow keys (#392)
- fix: fix: fetch timed lyrics when only untimed lyrics are available (#377)
- change: Automatically pick up folder renames (#390)
- change: Prepare for v1.7.1 release (#391)
- change: Prepare for v1.7.2 release (#397)
- change: Prevent crashes from duplicate normalized track paths (#386)
- change: Prevent library data loss when folders are unavailable (#395)
- change: Prevent occasional app crash on opening immersive mode (#396)
- change: Update Pin/Unpin button icon for usability (#387)
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
Survey your own repository
kushalpandya/Petrichor was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.
About this page
- The score is its most recent published measurement, taken on 1 October 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
- Measured at commit 0baf8691dfbf7a1fc1f43ca075b026f2bedc976c — the exact code this score is about.
- Scored under rubric-2026.09.18 — the same rubric and the same method as every other entry in this index.
- Measured by watchdog.canine.dev using codehealth-analyzer preprod-e569280dd5e2.