NavidromeApp/project.yml

117 lines
3.4 KiB
YAML
Raw Permalink Normal View History

name: NavidromePlayer
options:
bundleIdPrefix: ca.dallasgroot.navidromeplayer
deploymentTarget:
2026-04-08 15:34:14 -07:00
iOS: "26.0"
watchOS: "26.0"
xcodeVersion: "26.0"
groupSortPosition: top
createIntermediateGroups: true
packages:
ZIPFoundation:
url: https://github.com/weichsel/ZIPFoundation
from: "0.9.19"
Performance audit, Now Playing widget, crossfade stability, cover art embedding, DJ profile bulk cache PERFORMANCE AUDIT - Removed 16 dead SubsonicClient methods (~117 lines) - Added NSCache memory tier to LibraryCache, AlbumCoverStore, ArtistCoverStore, RadioCoverStore - Replaced weak polynomial hash with FNV-1a 64-bit in ImageCache - Split PlaybackStateStore into save() (full queue) and savePosition() (time only) - Reused single SubsonicClient in OfflineManager instead of per-download allocation - Added periodic ImageCache disk trim every 50 writes - Changed AudioPreFetcher to fuzzy offline match (isSongAvailableOffline) - Removed dead code: hasCompanionLibrary, downloadedSongIds, isActive, CachedImageLoader.task - Fixed thread safety: inline JSONEncoder/JSONDecoder in LibraryCache (no shared instances) WIDGET EXTENSION (new target: NavidromeWidget) - v2 glassmorphism design: blurred album art background + frosted glass panel - Waveform scrubber: 40-bar Canvas with tap-to-seek (20 segments via SeekToIntent) - Color-adaptive theming: CIAreaAverage dominant color extraction with HSB contrast adjustment - Transport controls: previous/play-pause/next with interactive AppIntents - Up Next footer with crossfade countdown from Smart DJ profiles - Large widget: 3-item queue list with numbered rows - Small/Medium/Large sizes matching design mockups - App Group communication via WidgetSharedState (UserDefaults) - Darwin notification observer for widget→app commands - Foreground command pickup for suspended app recovery - Idempotency guards on all widget commands CROSSFADE & PLAYBACK FIXES - Fixed dual audio on single-song queue: guard nextSong.id == currentSong?.id in prepareNextForCrossfade - Fixed crossfade play path never calling pushWidgetState (returned before reaching it) - Fixed crossfade needsNextTrack callback missing queue persistence + widget push - Fixed toggleShuffle queue not persisted after PlaybackStateStore split - Added nowPlayingSyncTimer restart on foreground (Lock Screen seek bar drift) - Added AVPlayer currentTime/duration sync in resumeVisTimers before vis timer restart (fixes waveform distortion after background — confirmed by Apple Forums + SoundCloud engineering) COVER ART PIPELINE - Fixed pushWidgetState cover art size mismatch (300→600 to match fetchAndSetArtwork) - Added custom cover art key differentiation ("custom_" prefix forces re-blur) - Changed server art lookup from memoryOnlyImage to cachedImage (memory+disk fallback) - Added POST /library/cover-art-by-path endpoint (was missing — iOS fallback hit 404) - Added navidrome_id fallback on existing cover art endpoint - Added embed_cover_art_in_file/embed_cover_art_in_directory: mutagen writes cover art directly into FLAC/MP3/M4A/OGG metadata tags so Navidrome serves updated art - All three upload paths (by-id, by-path, upload-tracks) now embed + trigger_scan COMPANION API FIXES - Fixed _create_task recursion (was calling itself instead of asyncio.create_task) - Fixed navidrome_db NameError on /library/conflicts endpoint - Reduced WebSocket connect/disconnect logging (only first-client and all-disconnected) SMART DJ PROFILE PREFETCH - New endpoint: GET /smart-dj/profiles/export (bulk JSON, gzip automatic) - SmartDJCache.loadBulkCache() reads single file on launch (instant) - SmartDJCache.bulkImport() writes all profiles in one atomic file - CompanionAPIService.fetchAllProfiles() fetches entire profile set in one request - Wired into NavidromePlayerApp.task after server connect - SmartCrossfadeManager unchanged — already reads from SmartDJCache first WEBSOCKET NOISE REDUCTION - iOS: silent reconnect retries, only log milestones (#1, #5, every 20th) - iOS: log "reconnected after N attempts" on success, silent initial connect - Python: only log first client connect and all-clients-disconnected Files: 13 modified, 8 new (including companion-api/main.py)
2026-04-12 19:24:22 -07:00
ConfettiSwiftUI:
url: https://github.com/simibac/ConfettiSwiftUI
from: "3.0.0"
settings:
base:
SWIFT_VERSION: "5.9"
MARKETING_VERSION: "1.0.0"
CURRENT_PROJECT_VERSION: "15"
DEAD_CODE_STRIPPING: true
ENABLE_USER_SCRIPT_SANDBOXING: true
DEVELOPMENT_TEAM: E9C9AGS9K6
targets:
# ─────────────────────────────────────
# iOS App
# ─────────────────────────────────────
NavidromePlayer:
type: application
platform: iOS
2026-04-08 15:34:14 -07:00
deploymentTarget: "26.0"
sources:
- path: iOS
- path: Shared
resources:
- path: iOS/Resources
settings:
base:
2026-04-08 15:34:14 -07:00
PRODUCT_BUNDLE_IDENTIFIER: ca.dallasgroot.navidromeplayer.app
INFOPLIST_FILE: iOS/Resources/Info.plist
CODE_SIGN_ENTITLEMENTS: iOS/Resources/NavidromePlayer.entitlements
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
TARGETED_DEVICE_FAMILY: "1,2"
2026-04-08 15:34:14 -07:00
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true
dependencies:
- target: NavidromeWatch
2026-04-10 07:00:30 -07:00
embed: true
2026-04-12 13:39:13 -07:00
- target: NavidromeWidget
embed: true
- package: ZIPFoundation
Performance audit, Now Playing widget, crossfade stability, cover art embedding, DJ profile bulk cache PERFORMANCE AUDIT - Removed 16 dead SubsonicClient methods (~117 lines) - Added NSCache memory tier to LibraryCache, AlbumCoverStore, ArtistCoverStore, RadioCoverStore - Replaced weak polynomial hash with FNV-1a 64-bit in ImageCache - Split PlaybackStateStore into save() (full queue) and savePosition() (time only) - Reused single SubsonicClient in OfflineManager instead of per-download allocation - Added periodic ImageCache disk trim every 50 writes - Changed AudioPreFetcher to fuzzy offline match (isSongAvailableOffline) - Removed dead code: hasCompanionLibrary, downloadedSongIds, isActive, CachedImageLoader.task - Fixed thread safety: inline JSONEncoder/JSONDecoder in LibraryCache (no shared instances) WIDGET EXTENSION (new target: NavidromeWidget) - v2 glassmorphism design: blurred album art background + frosted glass panel - Waveform scrubber: 40-bar Canvas with tap-to-seek (20 segments via SeekToIntent) - Color-adaptive theming: CIAreaAverage dominant color extraction with HSB contrast adjustment - Transport controls: previous/play-pause/next with interactive AppIntents - Up Next footer with crossfade countdown from Smart DJ profiles - Large widget: 3-item queue list with numbered rows - Small/Medium/Large sizes matching design mockups - App Group communication via WidgetSharedState (UserDefaults) - Darwin notification observer for widget→app commands - Foreground command pickup for suspended app recovery - Idempotency guards on all widget commands CROSSFADE & PLAYBACK FIXES - Fixed dual audio on single-song queue: guard nextSong.id == currentSong?.id in prepareNextForCrossfade - Fixed crossfade play path never calling pushWidgetState (returned before reaching it) - Fixed crossfade needsNextTrack callback missing queue persistence + widget push - Fixed toggleShuffle queue not persisted after PlaybackStateStore split - Added nowPlayingSyncTimer restart on foreground (Lock Screen seek bar drift) - Added AVPlayer currentTime/duration sync in resumeVisTimers before vis timer restart (fixes waveform distortion after background — confirmed by Apple Forums + SoundCloud engineering) COVER ART PIPELINE - Fixed pushWidgetState cover art size mismatch (300→600 to match fetchAndSetArtwork) - Added custom cover art key differentiation ("custom_" prefix forces re-blur) - Changed server art lookup from memoryOnlyImage to cachedImage (memory+disk fallback) - Added POST /library/cover-art-by-path endpoint (was missing — iOS fallback hit 404) - Added navidrome_id fallback on existing cover art endpoint - Added embed_cover_art_in_file/embed_cover_art_in_directory: mutagen writes cover art directly into FLAC/MP3/M4A/OGG metadata tags so Navidrome serves updated art - All three upload paths (by-id, by-path, upload-tracks) now embed + trigger_scan COMPANION API FIXES - Fixed _create_task recursion (was calling itself instead of asyncio.create_task) - Fixed navidrome_db NameError on /library/conflicts endpoint - Reduced WebSocket connect/disconnect logging (only first-client and all-disconnected) SMART DJ PROFILE PREFETCH - New endpoint: GET /smart-dj/profiles/export (bulk JSON, gzip automatic) - SmartDJCache.loadBulkCache() reads single file on launch (instant) - SmartDJCache.bulkImport() writes all profiles in one atomic file - CompanionAPIService.fetchAllProfiles() fetches entire profile set in one request - Wired into NavidromePlayerApp.task after server connect - SmartCrossfadeManager unchanged — already reads from SmartDJCache first WEBSOCKET NOISE REDUCTION - iOS: silent reconnect retries, only log milestones (#1, #5, every 20th) - iOS: log "reconnected after N attempts" on success, silent initial connect - Python: only log first client connect and all-clients-disconnected Files: 13 modified, 8 new (including companion-api/main.py)
2026-04-12 19:24:22 -07:00
- package: ConfettiSwiftUI
# ─────────────────────────────────────
# watchOS App
# ─────────────────────────────────────
NavidromeWatch:
type: application
platform: watchOS
2026-04-08 15:34:14 -07:00
deploymentTarget: "26.0"
sources:
- path: watchOS
- path: Shared
resources:
- path: watchOS/Resources
settings:
base:
2026-04-08 15:34:14 -07:00
PRODUCT_BUNDLE_IDENTIFIER: ca.dallasgroot.navidromeplayer.app.watchkitapp
INFOPLIST_FILE: watchOS/Resources/Info.plist
CODE_SIGN_ENTITLEMENTS: watchOS/Resources/NavidromeWatch.entitlements
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
2026-04-08 15:34:14 -07:00
WATCHOS_DEPLOYMENT_TARGET: "26.0"
2026-04-10 07:00:30 -07:00
SKIP_INSTALL: true
2026-04-12 13:39:13 -07:00
# ─────────────────────────────────────
# Widget Extension
# ─────────────────────────────────────
NavidromeWidget:
2026-04-12 13:52:10 -07:00
type: app-extension
2026-04-12 13:39:13 -07:00
platform: iOS
deploymentTarget: "17.0"
sources:
- path: Widget
excludes:
- "*.entitlements"
2026-04-12 13:52:10 -07:00
- "Info.plist"
2026-04-12 13:39:13 -07:00
- path: Shared/Storage/WidgetSharedState.swift
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: ca.dallasgroot.navidromeplayer.app.widget
PRODUCT_NAME: NavidromeWidget
2026-04-12 13:52:10 -07:00
INFOPLIST_FILE: Widget/Info.plist
2026-04-12 13:39:13 -07:00
CODE_SIGN_ENTITLEMENTS: Widget/NavidromeWidget.entitlements
SWIFT_EMIT_LOC_STRINGS: "YES"
SKIP_INSTALL: true
schemes:
NavidromePlayer:
build:
targets:
NavidromePlayer: all
2026-04-08 15:34:14 -07:00
NavidromeWatch: all
2026-04-12 13:39:13 -07:00
NavidromeWidget: all
2026-04-08 15:34:14 -07:00
run:
config: Debug
test:
config: Debug
profile:
config: Release
analyze:
config: Debug
archive:
config: Release