4.6 KiB
4.6 KiB
AGENTS.md
This repository is the native macOS SwiftUI port of BearWave, originally a Linux/KDE internet radio app.
Do not treat it as a Qt compatibility port. The current repo is a native macOS desktop app focused on internet radio.
What This Repo Is
- SwiftPM macOS app targeting
macOS 26 - SwiftUI desktop UI
AVPlayer-based playback for radio streams- Radio Browser as the station source
- Local persistence for favorites, recents, manual stations, station folders, and resume state
Architecture Overview
Sources/BearWaveApp/BearWaveApp.swiftApp scene entrypoint, window sizing, commands, menu bar extra, settings sceneSources/BearWaveCore/App/AppModel.swiftTop-level app coordinator; ownsStationLibrary,PlaybackController, and artwork servicesSources/BearWaveCore/Stores/StationLibrary.swiftSource of truth for station pages, search results, favorites, recents, manual entries, and station foldersSources/BearWaveCore/Stores/PersistenceStore.swiftJSON-based persistence for radio stateSources/BearWaveCore/Services/RadioBrowserClient.swiftRadio Browser API wrapper plus local search normalization and rankingSources/BearWaveCore/Services/PlaybackController.swiftSharedAVPlayerwrapper with explicit playback states, retries, stream metadata viaAVPlayerItemMetadataOutput, and Now Playing updatesSources/BearWaveCore/Services/StationArtworkLoader.swiftFavicon and artwork fetch with disk cacheSources/BearWaveCore/Services/NowPlayingArtworkResolver.swiftArtwork resolution for current playback stateSources/BearWaveCore/Views/Sidebar, station list, station detail, player bar, settings, menu bar, mini player
Current Product Behavior
- Dedicated pages:
Top,Germany,Netherlands,World,Search Results,Favorites,Recent,Manual - Search is global and stays independent from the current browse page
- Search ranking intentionally filters naive mid-word matches such as
slammatchingIslamabad - Playback UI exposes explicit states: connecting, buffering, playing, paused, stopped, failed
- A right-side detail panel shows station metadata and current stream metadata when available
- Player controls remain radio-focused: play/pause, stop, volume
- Mini Player is available via
Cmd+M - Mini Player target size is
555x110 - Station folders support create, rename, delete, and station assignment
- Menu bar extra remains active while playback continues
Build and Run Conventions
Use these commands unless there is a strong reason not to:
swift build --disable-index-store
CLANG_MODULE_CACHE_PATH=/private/tmp/bearwave-clang-cache swift run --disable-index-store BearWaveChecks
./script/build_and_run.sh
The run script:
- kills the previous process
- builds via SwiftPM
- stages a local
.appintodist/ - copies SwiftPM resource bundles manually
- copies
.lprojlocalization directories into the bundle - launches the app bundle
Do not remove the manual resource-bundle copy step from script/build_and_run.sh
unless the bundle pipeline is replaced deliberately.
Important Constraints
- Prefer the internal SSD workspace:
/Users/sebastian/Development/radioappmac - Do not assume the mounted share copy is current.
- The staged app bundle uses ATS exceptions so that
http://radio streams can play. - Debug signing and sandbox behavior are intentionally pragmatic and not yet release-ready.
PlaybackControllerusesAVPlayerItemMetadataOutputfor stream metadata.MediaPlayeris imported with@preconcurrency.MPMediaItemArtworkis built from aCGImage-backed request handler.- Main window launch width is dynamic:
1255on smaller displays,1600on wide displays. - Mini Player target size is
555x110.
What To Preserve
- Keep the project native-first for macOS.
- Keep search global and ranking strict.
- Keep explicit playback states; do not regress to a plain boolean model.
- Keep the current split between
BearWaveAppandBearWaveCore. - Keep the build/run script compatible with local staged app execution.
Good Next Steps
- Improve release packaging, signing, and notarization
- Add more playback diagnostics per stream failure mode
- Expand tests around playback-state transitions and search ranking
- Add cache eviction for memory and disk caches
- Keep folders clearly positioned as lightweight saved-station organization
Bad Changes
- Reintroducing page-coupled search behavior
- Replacing explicit playback states with only
isPlaying - Moving back toward Qt/KDE abstractions in this repo
- Assuming every stream will provide usable metadata or artwork