react-native-audio-browser 0.2.0-next.10 → 0.2.0-next.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/android/build.gradle +6 -5
- package/android/gradle.properties +1 -1
- package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +110 -25
- package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +254 -188
- package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +23 -3
- package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +77 -58
- package/android/src/main/java/com/audiobrowser/browser/SectionScope.kt +68 -26
- package/android/src/main/java/com/audiobrowser/browser/StyleResolver.kt +49 -0
- package/android/src/main/java/com/audiobrowser/extension/ResolvedTrackExt.kt +9 -7
- package/android/src/main/java/com/audiobrowser/extension/TappedTrack.kt +20 -0
- package/android/src/main/java/com/audiobrowser/extension/TrackIdentity.kt +15 -0
- package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +120 -67
- package/android/src/main/java/com/audiobrowser/player/NowPlayingUpdater.kt +21 -24
- package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +93 -73
- package/android/src/main/java/com/audiobrowser/player/Player.kt +48 -30
- package/android/src/main/java/com/audiobrowser/player/PlayerCapabilitiesExt.kt +2 -15
- package/android/src/main/java/com/audiobrowser/tls/AiaCertChaser.kt +46 -5
- package/android/src/main/java/com/audiobrowser/tls/AiaChasingExtendedTrustManager.kt +86 -27
- package/android/src/main/java/com/audiobrowser/tls/AiaChasingTrustManager.kt +58 -14
- package/android/src/main/java/com/audiobrowser/tls/AiaTls.kt +20 -6
- package/android/src/main/java/com/audiobrowser/tls/CachingCertificateFetcher.kt +249 -86
- package/android/src/main/java/com/audiobrowser/util/BrowserPathHelper.kt +44 -40
- package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +28 -23
- package/android/src/main/java/com/audiobrowser/util/StyleWire.kt +35 -0
- package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +45 -53
- package/android/src/test/java/com/audiobrowser/TestFixtures.kt +69 -30
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerFavoritesTest.kt +153 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerLayerResolutionTest.kt +6 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +345 -8
- package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +38 -0
- package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +1 -1
- package/android/src/test/java/com/audiobrowser/browser/JsonStyleTest.kt +91 -0
- package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +128 -53
- package/android/src/test/java/com/audiobrowser/browser/StyleResolverTest.kt +87 -0
- package/android/src/test/java/com/audiobrowser/extension/TappedTrackTest.kt +43 -0
- package/android/src/test/java/com/audiobrowser/extension/TrackIdentityTest.kt +41 -0
- package/android/src/test/java/com/audiobrowser/player/CapabilityControlsTest.kt +1 -2
- package/android/src/test/java/com/audiobrowser/player/NowPlayingUpdaterTest.kt +42 -2
- package/android/src/test/java/com/audiobrowser/player/PlaybackStateStoreTrackJsonTest.kt +55 -0
- package/android/src/test/java/com/audiobrowser/tls/AiaCertChaserTest.kt +152 -8
- package/android/src/test/java/com/audiobrowser/tls/AiaChasingTrustManagerTest.kt +218 -10
- package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherCallSiteTest.kt +322 -0
- package/android/src/test/java/com/audiobrowser/util/BrowserPathHelperTest.kt +41 -16
- package/android/src/test/java/com/audiobrowser/util/MediaExtrasBuilderTest.kt +161 -0
- package/android/src/test/java/com/audiobrowser/util/TrackFactoryMediaIdTest.kt +7 -7
- package/ios/Browser/BrowserConfig.swift +102 -5
- package/ios/Browser/BrowserManager+URLResolution.swift +18 -14
- package/ios/Browser/BrowserManager.swift +131 -143
- package/ios/Browser/BrowserPathHelper.swift +44 -44
- package/ios/Browser/JsonModels.swift +187 -106
- package/ios/Browser/SearchDrillIn.swift +6 -6
- package/ios/Browser/SectionPresentation.swift +34 -0
- package/ios/Browser/SectionScope.swift +58 -24
- package/ios/Browser/StyleResolver.swift +47 -0
- package/ios/Browser/TabBarEntries.swift +2 -2
- package/ios/Browser/TrackIdTemplate.swift +37 -0
- package/ios/CarPlay/CarPlayArtworkResolver.swift +8 -7
- package/ios/CarPlay/CarPlayController.swift +105 -67
- package/ios/CarPlay/CarPlayImageLoader.swift +38 -18
- package/ios/CarPlay/CarPlayListItemFactory.swift +217 -84
- package/ios/CarPlay/CarPlayNowPlayingManager.swift +15 -12
- package/ios/Extension/Capability+RemoteCommand.swift +1 -1
- package/ios/Extension/PlayerCapabilities+Favorite.swift +1 -15
- package/ios/Extension/ResolvedTrack+Copying.swift +11 -15
- package/ios/Extension/Section+Copying.swift +31 -0
- package/ios/Extension/Track+Copying.swift +6 -12
- package/ios/Extension/Track+Identity.swift +18 -0
- package/ios/HybridAudioBrowser.swift +113 -35
- package/ios/Model/NitroTypeStubs.swift +64 -23
- package/ios/Model/PlayerUpdateOptions.swift +7 -0
- package/ios/Player/NowPlayingUpdater.swift +1 -1
- package/ios/Player/PlaybackCoordinator.swift +2 -2
- package/ios/Player/RetryManager.swift +4 -3
- package/ios/Tests/BrowserPathHelperTests.swift +50 -20
- package/ios/Tests/CarPlayArtworkResolverTests.swift +24 -41
- package/ios/Tests/JsonModelsTests.swift +75 -1
- package/ios/Tests/PlaybackStateStoreTests.swift +4 -3
- package/ios/Tests/QueueManagerTests.swift +4 -4
- package/ios/Tests/ResolvedTrackCopyingTests.swift +37 -35
- package/ios/Tests/SearchDrillInTests.swift +16 -16
- package/ios/Tests/SectionPresentationTests.swift +61 -0
- package/ios/Tests/SectionScopeTests.swift +87 -55
- package/ios/Tests/StyleResolverTests.swift +67 -0
- package/ios/Tests/TabBarEntriesTests.swift +18 -18
- package/ios/Tests/TrackIdTemplateTests.swift +67 -0
- package/ios/Tests/TrackIdentityTests.swift +20 -0
- package/ios/Tests/TrackSelectorTests.swift +168 -33
- package/ios/TrackSelector.swift +45 -30
- package/ios/Util/ArtworkImageFetcher.swift +16 -1
- package/lib/commonjs/AudioBrowser.js +11 -0
- package/lib/commonjs/AudioBrowser.js.map +1 -1
- package/lib/commonjs/features/browser-config.js +11 -8
- package/lib/commonjs/features/browser-config.js.map +1 -1
- package/lib/commonjs/features/browser.js +2 -2
- package/lib/commonjs/features/favorites.js +13 -10
- package/lib/commonjs/features/favorites.js.map +1 -1
- package/lib/commonjs/features/playback/controls.js +4 -2
- package/lib/commonjs/features/playback/controls.js.map +1 -1
- package/lib/commonjs/features/playback/state.js +2 -3
- package/lib/commonjs/features/playback/state.js.map +1 -1
- package/lib/commonjs/features/player/options.js.map +1 -1
- package/lib/commonjs/features/player/setup.js +3 -1
- package/lib/commonjs/features/player/setup.js.map +1 -1
- package/lib/commonjs/features/player/validateOptions.js +2 -0
- package/lib/commonjs/features/player/validateOptions.js.map +1 -1
- package/lib/commonjs/features/queue/activeTrack.js +14 -3
- package/lib/commonjs/features/queue/activeTrack.js.map +1 -1
- package/lib/commonjs/features/queue/queue.js +11 -4
- package/lib/commonjs/features/queue/queue.js.map +1 -1
- package/lib/commonjs/utils/LazyNativeEmitter.js +21 -10
- package/lib/commonjs/utils/LazyNativeEmitter.js.map +1 -1
- package/lib/commonjs/utils/NativeUpdatedValue.js +31 -13
- package/lib/commonjs/utils/NativeUpdatedValue.js.map +1 -1
- package/lib/commonjs/utils/getTrackIdentity.js +24 -0
- package/lib/commonjs/utils/getTrackIdentity.js.map +1 -0
- package/lib/commonjs/utils/useNativeValueRefreshedBy.js +33 -0
- package/lib/commonjs/utils/useNativeValueRefreshedBy.js.map +1 -0
- package/lib/commonjs/web/NativeAudioBrowser.js +32 -24
- package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
- package/lib/commonjs/web/browser/BrowserManager.js +144 -87
- package/lib/commonjs/web/browser/BrowserManager.js.map +1 -1
- package/lib/commonjs/web/browser/FavoriteManager.js +30 -21
- package/lib/commonjs/web/browser/FavoriteManager.js.map +1 -1
- package/lib/commonjs/web/browser/assertBrowsePageShape.js +2 -2
- package/lib/commonjs/web/browser/assertBrowsePageShape.js.map +1 -1
- package/lib/commonjs/web/browser/classifyTrackNavigation.js +9 -9
- package/lib/commonjs/web/browser/classifyTrackNavigation.js.map +1 -1
- package/lib/commonjs/web/browser/sections.js +89 -0
- package/lib/commonjs/web/browser/sections.js.map +1 -0
- package/lib/commonjs/web/player/NowPlayingManager.js +4 -3
- package/lib/commonjs/web/player/NowPlayingManager.js.map +1 -1
- package/lib/commonjs/web/util/BrowserPathHelper.js +56 -11
- package/lib/commonjs/web/util/BrowserPathHelper.js.map +1 -1
- package/lib/module/AudioBrowser.js +1 -0
- package/lib/module/AudioBrowser.js.map +1 -1
- package/lib/module/features/browser-config.js +11 -8
- package/lib/module/features/browser-config.js.map +1 -1
- package/lib/module/features/browser.js +2 -2
- package/lib/module/features/favorites.js +13 -10
- package/lib/module/features/favorites.js.map +1 -1
- package/lib/module/features/playback/controls.js +4 -2
- package/lib/module/features/playback/controls.js.map +1 -1
- package/lib/module/features/playback/state.js +2 -3
- package/lib/module/features/playback/state.js.map +1 -1
- package/lib/module/features/player/options.js.map +1 -1
- package/lib/module/features/player/setup.js +3 -1
- package/lib/module/features/player/setup.js.map +1 -1
- package/lib/module/features/player/validateOptions.js +2 -0
- package/lib/module/features/player/validateOptions.js.map +1 -1
- package/lib/module/features/queue/activeTrack.js +14 -3
- package/lib/module/features/queue/activeTrack.js.map +1 -1
- package/lib/module/features/queue/queue.js +11 -4
- package/lib/module/features/queue/queue.js.map +1 -1
- package/lib/module/utils/LazyNativeEmitter.js +21 -10
- package/lib/module/utils/LazyNativeEmitter.js.map +1 -1
- package/lib/module/utils/NativeUpdatedValue.js +31 -13
- package/lib/module/utils/NativeUpdatedValue.js.map +1 -1
- package/lib/module/utils/getTrackIdentity.js +20 -0
- package/lib/module/utils/getTrackIdentity.js.map +1 -0
- package/lib/module/utils/useNativeValueRefreshedBy.js +29 -0
- package/lib/module/utils/useNativeValueRefreshedBy.js.map +1 -0
- package/lib/module/web/NativeAudioBrowser.js +32 -24
- package/lib/module/web/NativeAudioBrowser.js.map +1 -1
- package/lib/module/web/browser/BrowserManager.js +144 -87
- package/lib/module/web/browser/BrowserManager.js.map +1 -1
- package/lib/module/web/browser/FavoriteManager.js +31 -21
- package/lib/module/web/browser/FavoriteManager.js.map +1 -1
- package/lib/module/web/browser/assertBrowsePageShape.js +2 -2
- package/lib/module/web/browser/assertBrowsePageShape.js.map +1 -1
- package/lib/module/web/browser/classifyTrackNavigation.js +9 -9
- package/lib/module/web/browser/classifyTrackNavigation.js.map +1 -1
- package/lib/module/web/browser/sections.js +83 -0
- package/lib/module/web/browser/sections.js.map +1 -0
- package/lib/module/web/player/NowPlayingManager.js +4 -3
- package/lib/module/web/player/NowPlayingManager.js.map +1 -1
- package/lib/module/web/util/BrowserPathHelper.js +56 -11
- package/lib/module/web/util/BrowserPathHelper.js.map +1 -1
- package/lib/typescript/src/AudioBrowser.d.ts +1 -0
- package/lib/typescript/src/AudioBrowser.d.ts.map +1 -1
- package/lib/typescript/src/features/browser-config.d.ts.map +1 -1
- package/lib/typescript/src/features/browser.d.ts +2 -2
- package/lib/typescript/src/features/favorites.d.ts +13 -10
- package/lib/typescript/src/features/favorites.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/controls.d.ts +4 -2
- package/lib/typescript/src/features/playback/controls.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/state.d.ts +2 -3
- package/lib/typescript/src/features/playback/state.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts +1 -1
- package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts.map +1 -1
- package/lib/typescript/src/features/player/options.d.ts +21 -19
- package/lib/typescript/src/features/player/options.d.ts.map +1 -1
- package/lib/typescript/src/features/player/setup.d.ts.map +1 -1
- package/lib/typescript/src/features/player/validateOptions.d.ts +1 -8
- package/lib/typescript/src/features/player/validateOptions.d.ts.map +1 -1
- package/lib/typescript/src/features/queue/activeTrack.d.ts +8 -1
- package/lib/typescript/src/features/queue/activeTrack.d.ts.map +1 -1
- package/lib/typescript/src/features/queue/queue.d.ts +5 -2
- package/lib/typescript/src/features/queue/queue.d.ts.map +1 -1
- package/lib/typescript/src/types/browser-native.d.ts +2 -2
- package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
- package/lib/typescript/src/types/browser-nodes.d.ts +260 -127
- package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
- package/lib/typescript/src/types/browser.d.ts +33 -53
- package/lib/typescript/src/types/browser.d.ts.map +1 -1
- package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +16 -17
- package/lib/typescript/src/utils/LazyNativeEmitter.d.ts.map +1 -1
- package/lib/typescript/src/utils/NativeUpdatedValue.d.ts +24 -19
- package/lib/typescript/src/utils/NativeUpdatedValue.d.ts.map +1 -1
- package/lib/typescript/src/utils/getTrackIdentity.d.ts +18 -0
- package/lib/typescript/src/utils/getTrackIdentity.d.ts.map +1 -0
- package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts +21 -0
- package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts.map +1 -0
- package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +0 -1
- package/nitrogen/generated/android/c++/{JFavoritesMatchMode.hpp → JArtworkRendering.hpp} +15 -15
- package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +4 -3
- package/nitrogen/generated/android/c++/JBrowseResult.hpp +10 -4
- package/nitrogen/generated/android/c++/JCarPlayPlayingIndicatorLocation.hpp +58 -0
- package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +4 -3
- package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +4 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +4 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +4 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +4 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +4 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +4 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +4 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.hpp +10 -4
- package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +4 -3
- package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +2 -5
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +4 -3
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +9 -3
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +4 -2
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +21 -14
- package/nitrogen/generated/android/c++/JIOSOptions.hpp +9 -3
- package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +4 -3
- package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +16 -10
- package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +8 -2
- package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +6 -7
- package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +2 -5
- package/nitrogen/generated/android/c++/JNitroIOSUpdateOptions.hpp +9 -3
- package/nitrogen/generated/android/c++/JOptions.hpp +2 -5
- package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +4 -3
- package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +5 -11
- package/nitrogen/generated/android/c++/JResolvedTrack.hpp +49 -51
- package/nitrogen/generated/android/c++/JSection.hpp +114 -0
- package/nitrogen/generated/android/c++/JSectionStyle.hpp +69 -0
- package/nitrogen/generated/android/c++/JStyleDisplay.hpp +58 -0
- package/nitrogen/generated/android/c++/JTrack.hpp +19 -48
- package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +4 -2
- package/nitrogen/generated/android/c++/JTrackStyle.hpp +25 -18
- package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.hpp +10 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoritesMatchMode.kt → ArtworkRendering.kt} +5 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayPlayingIndicatorLocation.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSOptions.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +5 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroIOSUpdateOptions.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +12 -18
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Section.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoriteConfig.kt → SectionStyle.kt} +12 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StyleDisplay.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +6 -15
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackStyle.kt +23 -5
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +104 -82
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +16 -10
- package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +16 -10
- package/nitrogen/generated/ios/swift/ArtworkRendering.swift +40 -0
- package/nitrogen/generated/ios/swift/CarPlayPlayingIndicatorLocation.swift +40 -0
- package/nitrogen/generated/ios/swift/IOSOptions.swift +7 -2
- package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +5 -5
- package/nitrogen/generated/ios/swift/NitroIOSUpdateOptions.swift +12 -1
- package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +8 -27
- package/nitrogen/generated/ios/swift/ResolvedTrack.swift +54 -83
- package/nitrogen/generated/ios/swift/Section.swift +100 -0
- package/nitrogen/generated/ios/swift/SectionStyle.swift +64 -0
- package/nitrogen/generated/ios/swift/StyleDisplay.swift +40 -0
- package/nitrogen/generated/ios/swift/Track.swift +20 -73
- package/nitrogen/generated/ios/swift/TrackStyle.swift +28 -22
- package/nitrogen/generated/shared/c++/{FavoritesMatchMode.hpp → ArtworkRendering.hpp} +17 -17
- package/nitrogen/generated/shared/c++/CarPlayPlayingIndicatorLocation.hpp +76 -0
- package/nitrogen/generated/shared/c++/IOSOptions.hpp +9 -2
- package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +6 -6
- package/nitrogen/generated/shared/c++/NitroIOSUpdateOptions.hpp +9 -2
- package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +6 -9
- package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +30 -38
- package/nitrogen/generated/shared/c++/Section.hpp +106 -0
- package/nitrogen/generated/shared/c++/SectionStyle.hpp +96 -0
- package/nitrogen/generated/shared/c++/StyleDisplay.hpp +76 -0
- package/nitrogen/generated/shared/c++/Track.hpp +15 -31
- package/nitrogen/generated/shared/c++/TrackStyle.hpp +50 -34
- package/package.json +3 -2
- package/src/AudioBrowser.ts +1 -0
- package/src/features/browser-config.test.ts +21 -6
- package/src/features/browser-config.ts +11 -8
- package/src/features/browser.test.ts +1 -1
- package/src/features/browser.ts +2 -2
- package/src/features/favorites.ts +13 -10
- package/src/features/hook-wiring.test.ts +63 -15
- package/src/features/playback/controls.ts +4 -2
- package/src/features/playback/state.ts +2 -3
- package/src/features/playback/trackPlaybackTime.ts +1 -1
- package/src/features/player/options.ts +27 -19
- package/src/features/player/setup.test.ts +12 -3
- package/src/features/player/setup.ts +3 -1
- package/src/features/player/validateOptions.ts +2 -0
- package/src/features/queue/activeTrack.ts +14 -3
- package/src/features/queue/queue.ts +11 -4
- package/src/nitro-stub-drift.test.ts +277 -0
- package/src/public-surface.test.ts +40 -0
- package/src/specs/audio-browser.nitro.ts +4 -3
- package/src/style-resolution.test.ts +139 -0
- package/src/types/browser-native.ts +2 -2
- package/src/types/browser-nodes.ts +268 -136
- package/src/types/browser.ts +34 -55
- package/src/utils/LazyNativeEmitter.ts +20 -10
- package/src/utils/NativeUpdatedValue.ts +29 -13
- package/src/utils/getTrackIdentity.ts +20 -0
- package/src/utils/useNativeValueRefreshedBy.ts +38 -0
- package/src/web/NativeAudioBrowser.ts +37 -22
- package/src/web/browser/BrowserManager.ts +176 -95
- package/src/web/browser/FavoriteManager.test.ts +84 -0
- package/src/web/browser/FavoriteManager.ts +28 -23
- package/src/web/browser/assertBrowsePageShape.test.ts +1 -1
- package/src/web/browser/assertBrowsePageShape.ts +5 -3
- package/src/web/browser/classifyTrackNavigation.test.ts +10 -8
- package/src/web/browser/classifyTrackNavigation.ts +9 -9
- package/src/web/browser/parseSearchResponse.test.ts +8 -2
- package/src/web/browser/sections.test.ts +91 -0
- package/src/web/browser/sections.ts +72 -0
- package/src/web/player/NowPlayingManager.ts +4 -3
- package/src/web/util/BrowserPathHelper.test.ts +52 -0
- package/src/web/util/BrowserPathHelper.ts +61 -13
- package/ios/CarPlay/ImageRowItem+CarPlay.swift +0 -19
- package/nitrogen/generated/android/c++/JFavoriteConfig.hpp +0 -58
- package/nitrogen/generated/android/c++/JImageRowItem.hpp +0 -105
- package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.cpp +0 -26
- package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.hpp +0 -71
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +0 -68
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_FavoriteConfig.kt +0 -53
- package/nitrogen/generated/ios/swift/FavoriteConfig.swift +0 -29
- package/nitrogen/generated/ios/swift/FavoritesMatchMode.swift +0 -40
- package/nitrogen/generated/ios/swift/ImageRowItem.swift +0 -195
- package/nitrogen/generated/ios/swift/Variant_Bool_FavoriteConfig.swift +0 -18
- package/nitrogen/generated/shared/c++/FavoriteConfig.hpp +0 -84
- package/nitrogen/generated/shared/c++/ImageRowItem.hpp +0 -129
|
@@ -3,23 +3,24 @@ import Foundation
|
|
|
3
3
|
/// Utility for handling browser paths and contextual URLs in the media browser system.
|
|
4
4
|
///
|
|
5
5
|
/// Handles two types of special paths:
|
|
6
|
-
/// 1. System paths (prefixed with `/__`):
|
|
6
|
+
/// 1. System paths (prefixed with `/__`): root, search, and offline paths
|
|
7
7
|
/// 2. Contextual URLs: Embed parent context in track identifiers for playback integration
|
|
8
8
|
///
|
|
9
|
-
/// Contextual URL format: `{parentPath}?__trackId={
|
|
10
|
-
/// Example: "/library/radio?__trackId=song.mp3"
|
|
9
|
+
/// Contextual URL format: `{parentPath}?__trackId={trackIdentity}&__index={childIndex}`
|
|
10
|
+
/// Example: "/library/radio?__trackId=song.mp3&__index=2"
|
|
11
|
+
///
|
|
12
|
+
/// `__trackId` is the identity check; `__index` (the child's position on the
|
|
13
|
+
/// page at stamp time) is only a tie-breaker between surfaces that carry the
|
|
14
|
+
/// same identity — a stale index never selects a different track.
|
|
11
15
|
///
|
|
12
16
|
/// This allows:
|
|
13
|
-
/// - Playable-only tracks (tracks with `src` but no `
|
|
17
|
+
/// - Playable-only tracks (tracks with `src` but no `path`) to be referenced
|
|
14
18
|
/// - Cache lookup to work consistently
|
|
15
19
|
/// - Parent context to be preserved for queue restoration
|
|
16
20
|
enum BrowserPathHelper {
|
|
17
21
|
/// Root path for media browsing
|
|
18
22
|
static let rootPath = "/__root"
|
|
19
23
|
|
|
20
|
-
/// Recent media path for playback resumption
|
|
21
|
-
static let recentPath = "/__recent"
|
|
22
|
-
|
|
23
24
|
/// Search path prefix (full path is /__search?q=query)
|
|
24
25
|
static let searchPathPrefix = "/__search"
|
|
25
26
|
|
|
@@ -38,10 +39,12 @@ enum BrowserPathHelper {
|
|
|
38
39
|
/// Query parameter name for contextual track identifiers
|
|
39
40
|
private static let contextualTrackParam = "__trackId"
|
|
40
41
|
|
|
42
|
+
/// Query parameter name for the tapped child's page position (tie-breaker)
|
|
43
|
+
private static let contextualIndexParam = "__index"
|
|
44
|
+
|
|
41
45
|
/// Check if a path is a special system path (not a regular navigation path)
|
|
42
46
|
static func isSpecialPath(_ path: String) -> Bool {
|
|
43
47
|
path == rootPath ||
|
|
44
|
-
path == recentPath ||
|
|
45
48
|
path.hasPrefix("\(searchPathPrefix)?")
|
|
46
49
|
}
|
|
47
50
|
|
|
@@ -61,13 +64,13 @@ enum BrowserPathHelper {
|
|
|
61
64
|
|| path.contains("&\(contextualTrackParam)=")
|
|
62
65
|
}
|
|
63
66
|
|
|
64
|
-
/// Strips the __trackId
|
|
65
|
-
/// If the URL is not contextual, returns it unchanged.
|
|
67
|
+
/// Strips the contextual parameters (__trackId and __index) from a contextual
|
|
68
|
+
/// URL to get the parent path. If the URL is not contextual, returns it unchanged.
|
|
66
69
|
///
|
|
67
70
|
/// - Parameter url: The URL to process
|
|
68
|
-
/// - Returns: The URL without the
|
|
71
|
+
/// - Returns: The URL without the contextual parameters
|
|
69
72
|
///
|
|
70
|
-
/// Example: "/library/radio?__trackId=song.mp3" → "/library/radio"
|
|
73
|
+
/// Example: "/library/radio?__trackId=song.mp3&__index=2" → "/library/radio"
|
|
71
74
|
/// Example: "/search?q=jazz&__trackId=song.mp3" → "/search?q=jazz"
|
|
72
75
|
static func stripTrackId(_ url: String) -> String {
|
|
73
76
|
guard isContextual(url) else {
|
|
@@ -78,8 +81,10 @@ enum BrowserPathHelper {
|
|
|
78
81
|
return url
|
|
79
82
|
}
|
|
80
83
|
|
|
81
|
-
// Filter out
|
|
82
|
-
components.queryItems = components.queryItems?.filter {
|
|
84
|
+
// Filter out the contextual parameters
|
|
85
|
+
components.queryItems = components.queryItems?.filter {
|
|
86
|
+
$0.name != contextualTrackParam && $0.name != contextualIndexParam
|
|
87
|
+
}
|
|
83
88
|
|
|
84
89
|
// If no query items left, clear the query string entirely
|
|
85
90
|
if components.queryItems?.isEmpty == true {
|
|
@@ -89,21 +94,24 @@ enum BrowserPathHelper {
|
|
|
89
94
|
return components.string ?? url
|
|
90
95
|
}
|
|
91
96
|
|
|
92
|
-
/// Builds a contextual URL by appending a track identifier
|
|
97
|
+
/// Builds a contextual URL by appending a track identifier — and optionally
|
|
98
|
+
/// the tapped child's page position — to a parent path.
|
|
93
99
|
/// Handles existing query parameters correctly.
|
|
94
100
|
///
|
|
95
101
|
/// - Parameters:
|
|
96
102
|
/// - parentPath: The parent container path
|
|
97
|
-
/// - trackId: The track
|
|
98
|
-
///
|
|
103
|
+
/// - trackId: The track identity (`id` when non-blank, else `src`)
|
|
104
|
+
/// - index: The child's position on the page at stamp time (tie-breaker)
|
|
105
|
+
/// - Returns: A contextual URL combining parent path, track ID, and index
|
|
99
106
|
///
|
|
100
|
-
/// Example: build("/library", "song.mp3") → "/library?__trackId=song.mp3"
|
|
107
|
+
/// Example: build("/library", "song.mp3", index: 2) → "/library?__trackId=song.mp3&__index=2"
|
|
101
108
|
/// Example: build("/search?q=jazz", "song.mp3") → "/search?q=jazz&__trackId=song.mp3"
|
|
102
|
-
static func build(parentPath: String, trackId: String) -> String {
|
|
109
|
+
static func build(parentPath: String, trackId: String, index: Int? = nil) -> String {
|
|
103
110
|
let encodedTrackId =
|
|
104
|
-
trackId.addingPercentEncoding(withAllowedCharacters:
|
|
111
|
+
trackId.addingPercentEncoding(withAllowedCharacters: queryComponentAllowed) ?? trackId
|
|
105
112
|
let separator = parentPath.contains("?") ? "&" : "?"
|
|
106
|
-
|
|
113
|
+
let indexParam = index.map { "&\(contextualIndexParam)=\($0)" } ?? ""
|
|
114
|
+
return "\(parentPath)\(separator)\(contextualTrackParam)=\(encodedTrackId)\(indexParam)"
|
|
107
115
|
}
|
|
108
116
|
|
|
109
117
|
/// Extracts the track ID from a contextual URL.
|
|
@@ -125,6 +133,21 @@ enum BrowserPathHelper {
|
|
|
125
133
|
return components.queryItems?.first { $0.name == contextualTrackParam }?.value
|
|
126
134
|
}
|
|
127
135
|
|
|
136
|
+
/// Extracts the stamped page index from a contextual URL, or nil when the
|
|
137
|
+
/// URL is not contextual or carries no (valid, non-negative) index.
|
|
138
|
+
///
|
|
139
|
+
/// Example: "/library/radio?__trackId=song.mp3&__index=2" → 2
|
|
140
|
+
static func extractIndex(_ path: String) -> Int? {
|
|
141
|
+
guard isContextual(path),
|
|
142
|
+
let components = URLComponents(string: path),
|
|
143
|
+
let raw = components.queryItems?.first(where: { $0.name == contextualIndexParam })?.value,
|
|
144
|
+
let index = Int(raw), index >= 0
|
|
145
|
+
else {
|
|
146
|
+
return nil
|
|
147
|
+
}
|
|
148
|
+
return index
|
|
149
|
+
}
|
|
150
|
+
|
|
128
151
|
/// Appends query parameters to a URL, handling `?` vs `&` separator and percent-encoding.
|
|
129
152
|
///
|
|
130
153
|
/// - Parameters:
|
|
@@ -193,27 +216,4 @@ enum BrowserPathHelper {
|
|
|
193
216
|
|
|
194
217
|
return "\(normalizedBase)/\(normalizedPath)"
|
|
195
218
|
}
|
|
196
|
-
|
|
197
|
-
/// True if `segment` appears in `path` as a complete path segment — bounded on
|
|
198
|
-
/// the left by the string start or `/`, and on the right by the string end or
|
|
199
|
-
/// one of `/`, `?`, `#`.
|
|
200
|
-
static func containsSegment(_ path: String, _ segment: String) -> Bool {
|
|
201
|
-
guard !segment.isEmpty else { return false }
|
|
202
|
-
var searchStart = path.startIndex
|
|
203
|
-
while let range = path.range(of: segment, range: searchStart ..< path.endIndex) {
|
|
204
|
-
let beforeOk =
|
|
205
|
-
range.lowerBound == path.startIndex
|
|
206
|
-
|| path[path.index(before: range.lowerBound)] == "/"
|
|
207
|
-
let afterOk: Bool
|
|
208
|
-
if range.upperBound == path.endIndex {
|
|
209
|
-
afterOk = true
|
|
210
|
-
} else {
|
|
211
|
-
let next = path[range.upperBound]
|
|
212
|
-
afterOk = next == "/" || next == "?" || next == "#"
|
|
213
|
-
}
|
|
214
|
-
if beforeOk, afterOk { return true }
|
|
215
|
-
searchStart = range.upperBound
|
|
216
|
-
}
|
|
217
|
-
return false
|
|
218
|
-
}
|
|
219
219
|
}
|
|
@@ -62,41 +62,125 @@ extension JsonArtwork {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
///
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
65
|
+
/// A style declaration block on the wire (ADR 0011):
|
|
66
|
+
/// `{ display?, gridWrap?, artworkRendering? }`.
|
|
67
|
+
///
|
|
68
|
+
/// One JSON model serves both the `TrackStyle` and `SectionStyle` positions —
|
|
69
|
+
/// keys that don't exist at the narrower position simply don't map.
|
|
70
|
+
///
|
|
71
|
+
/// Decoding is tolerant by design: a stale payload — the retired string
|
|
72
|
+
/// styles, a wrong-typed field, an unknown enum value — must degrade to "no
|
|
73
|
+
/// declaration", never fail the page or the persisted playback state (the
|
|
74
|
+
/// decoders above this are strict, so a throw here would kill the whole
|
|
75
|
+
/// payload). `init(from:)` therefore never throws, and unknown enum values
|
|
76
|
+
/// map to nil at `toNitro` time.
|
|
77
|
+
struct JsonStyle: Codable, Equatable {
|
|
78
|
+
let display: String?
|
|
79
|
+
let gridWrap: Bool?
|
|
80
|
+
let artworkRendering: String?
|
|
77
81
|
|
|
78
82
|
init(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
display: String? = nil,
|
|
84
|
+
gridWrap: Bool? = nil,
|
|
85
|
+
artworkRendering: String? = nil,
|
|
86
|
+
) {
|
|
87
|
+
self.display = display
|
|
88
|
+
self.gridWrap = gridWrap
|
|
89
|
+
self.artworkRendering = artworkRendering
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
init(from decoder: Decoder) throws {
|
|
93
|
+
// A non-object value (the retired `style: 'grid'` string) decodes as an
|
|
94
|
+
// empty block rather than failing the parent.
|
|
95
|
+
guard let container = try? decoder.container(keyedBy: CodingKeys.self) else {
|
|
96
|
+
display = nil
|
|
97
|
+
gridWrap = nil
|
|
98
|
+
artworkRendering = nil
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
display = (try? container.decodeIfPresent(String.self, forKey: .display)) ?? nil
|
|
102
|
+
gridWrap = (try? container.decodeIfPresent(Bool.self, forKey: .gridWrap)) ?? nil
|
|
103
|
+
artworkRendering = (try? container.decodeIfPresent(String.self, forKey: .artworkRendering)) ?? nil
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
extension JsonStyle {
|
|
108
|
+
/// The wire strings map to Nitro enums here, tolerantly: an unknown value
|
|
109
|
+
/// (a future `display` mode, say) is no declaration, not an error. A block
|
|
110
|
+
/// that resolves to no declarations at all — `{}`, the tolerant decoder's
|
|
111
|
+
/// empty result for the retired string vocabulary, or all-unknown values —
|
|
112
|
+
/// maps to nil, so "no declaration" has one shape on every platform
|
|
113
|
+
/// (Android's lenient mapper makes the same collapse).
|
|
114
|
+
func toTrackStyle() -> TrackStyle? {
|
|
115
|
+
let display = display.flatMap { StyleDisplay(fromString: $0.lowercased()) }
|
|
116
|
+
let artworkRendering = artworkRendering.flatMap { ArtworkRendering(fromString: $0.lowercased()) }
|
|
117
|
+
guard display != nil || artworkRendering != nil else { return nil }
|
|
118
|
+
return TrackStyle(display: display, artworkRendering: artworkRendering)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
func toSectionStyle() -> SectionStyle? {
|
|
122
|
+
let display = display.flatMap { StyleDisplay(fromString: $0.lowercased()) }
|
|
123
|
+
let artworkRendering = artworkRendering.flatMap { ArtworkRendering(fromString: $0.lowercased()) }
|
|
124
|
+
guard display != nil || artworkRendering != nil || gridWrap != nil else { return nil }
|
|
125
|
+
// Argument order is the generated init's (own properties before
|
|
126
|
+
// inherited ones — Nitro flattens `extends` own-props-first).
|
|
127
|
+
return SectionStyle(
|
|
128
|
+
gridWrap: gridWrap,
|
|
129
|
+
display: display,
|
|
130
|
+
artworkRendering: artworkRendering,
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/// Snapshot a live track block back to its JSON model (for persistence).
|
|
135
|
+
/// An all-nil block snapshots as no block — the decoders collapse it to
|
|
136
|
+
/// "no declaration" anyway, so never persist the distinction.
|
|
137
|
+
init?(_ style: TrackStyle?) {
|
|
138
|
+
guard let style, style.display != nil || style.artworkRendering != nil else { return nil }
|
|
139
|
+
self.init(
|
|
140
|
+
display: Self.string(style.display),
|
|
141
|
+
artworkRendering: Self.string(style.artworkRendering),
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private static func string(_ display: StyleDisplay?) -> String? {
|
|
146
|
+
switch display {
|
|
147
|
+
case .list: "list"
|
|
148
|
+
case .grid: "grid"
|
|
149
|
+
case nil: nil
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private static func string(_ rendering: ArtworkRendering?) -> String? {
|
|
154
|
+
switch rendering {
|
|
155
|
+
case .original: "original"
|
|
156
|
+
case .stencil: "stencil"
|
|
157
|
+
case nil: nil
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/// JSON model for a page section (ADR 0010). Legacy `groupTitle`/`imageRow`
|
|
163
|
+
/// keys in payloads are simply unknown to these models and decode as
|
|
164
|
+
/// ignored dead weight.
|
|
165
|
+
struct JsonSection: Codable {
|
|
166
|
+
let title: String?
|
|
167
|
+
let subtitle: String?
|
|
168
|
+
let style: JsonStyle?
|
|
169
|
+
let path: String?
|
|
170
|
+
let children: [JsonTrack]
|
|
171
|
+
|
|
172
|
+
init(
|
|
173
|
+
title: String? = nil,
|
|
174
|
+
subtitle: String? = nil,
|
|
175
|
+
style: JsonStyle? = nil,
|
|
176
|
+
path: String? = nil,
|
|
177
|
+
children: [JsonTrack],
|
|
89
178
|
) {
|
|
90
|
-
self.id = id
|
|
91
|
-
self.url = url
|
|
92
|
-
self.src = src
|
|
93
|
-
self.artwork = artwork
|
|
94
179
|
self.title = title
|
|
95
|
-
self.
|
|
96
|
-
self.
|
|
97
|
-
self.
|
|
98
|
-
self.
|
|
99
|
-
self.request = request
|
|
180
|
+
self.subtitle = subtitle
|
|
181
|
+
self.style = style
|
|
182
|
+
self.path = path
|
|
183
|
+
self.children = children
|
|
100
184
|
}
|
|
101
185
|
}
|
|
102
186
|
|
|
@@ -116,59 +200,59 @@ struct JsonTrackRequest: Codable {
|
|
|
116
200
|
/// JSON model for resolved track (container with children).
|
|
117
201
|
struct JsonResolvedTrack: Codable {
|
|
118
202
|
let id: String?
|
|
119
|
-
let
|
|
203
|
+
let path: String
|
|
120
204
|
let title: String
|
|
121
205
|
let subtitle: String?
|
|
122
206
|
let artwork: JsonArtwork?
|
|
123
207
|
let artist: String?
|
|
124
|
-
let
|
|
208
|
+
let albumPath: String?
|
|
125
209
|
let album: String?
|
|
126
210
|
let description: String?
|
|
127
211
|
let genre: String?
|
|
128
212
|
let duration: Double?
|
|
213
|
+
let sections: [JsonSection]?
|
|
129
214
|
let children: [JsonTrack]?
|
|
130
215
|
let src: String?
|
|
131
|
-
let style:
|
|
132
|
-
let
|
|
133
|
-
let groupTitle: String?
|
|
216
|
+
let style: JsonStyle?
|
|
217
|
+
let disabled: Bool?
|
|
134
218
|
let live: Bool?
|
|
135
219
|
let carPlaySiriListButton: String?
|
|
136
220
|
|
|
137
221
|
init(
|
|
138
222
|
id: String? = nil,
|
|
139
|
-
|
|
223
|
+
path: String,
|
|
140
224
|
title: String,
|
|
141
225
|
subtitle: String? = nil,
|
|
142
226
|
artwork: JsonArtwork? = nil,
|
|
143
227
|
artist: String? = nil,
|
|
144
|
-
|
|
228
|
+
albumPath: String? = nil,
|
|
145
229
|
album: String? = nil,
|
|
146
230
|
description: String? = nil,
|
|
147
231
|
genre: String? = nil,
|
|
148
232
|
duration: Double? = nil,
|
|
233
|
+
sections: [JsonSection]? = nil,
|
|
149
234
|
children: [JsonTrack]? = nil,
|
|
150
235
|
src: String? = nil,
|
|
151
|
-
style:
|
|
152
|
-
|
|
153
|
-
groupTitle: String? = nil,
|
|
236
|
+
style: JsonStyle? = nil,
|
|
237
|
+
disabled: Bool? = nil,
|
|
154
238
|
live: Bool? = nil,
|
|
155
239
|
carPlaySiriListButton: String? = nil,
|
|
156
240
|
) {
|
|
157
|
-
self.
|
|
241
|
+
self.path = path
|
|
158
242
|
self.title = title
|
|
159
243
|
self.subtitle = subtitle
|
|
160
244
|
self.artwork = artwork
|
|
161
245
|
self.artist = artist
|
|
162
|
-
self.
|
|
246
|
+
self.albumPath = albumPath
|
|
163
247
|
self.album = album
|
|
164
248
|
self.description = description
|
|
165
249
|
self.genre = genre
|
|
166
250
|
self.duration = duration
|
|
251
|
+
self.sections = sections
|
|
167
252
|
self.children = children
|
|
168
253
|
self.src = src
|
|
169
254
|
self.style = style
|
|
170
|
-
self.
|
|
171
|
-
self.groupTitle = groupTitle
|
|
255
|
+
self.disabled = disabled
|
|
172
256
|
self.live = live
|
|
173
257
|
self.carPlaySiriListButton = carPlaySiriListButton
|
|
174
258
|
self.id = id
|
|
@@ -178,50 +262,46 @@ struct JsonResolvedTrack: Codable {
|
|
|
178
262
|
/// JSON model for individual tracks.
|
|
179
263
|
struct JsonTrack: Codable {
|
|
180
264
|
let id: String?
|
|
181
|
-
let
|
|
265
|
+
let path: String?
|
|
182
266
|
let title: String
|
|
183
267
|
let subtitle: String?
|
|
184
268
|
let artwork: JsonArtwork?
|
|
185
269
|
let artist: String?
|
|
186
|
-
let
|
|
270
|
+
let albumPath: String?
|
|
187
271
|
let album: String?
|
|
188
272
|
let description: String?
|
|
189
273
|
let genre: String?
|
|
190
274
|
let duration: Double?
|
|
191
275
|
let src: String?
|
|
192
276
|
let request: JsonTrackRequest?
|
|
193
|
-
let style:
|
|
194
|
-
let
|
|
195
|
-
let groupTitle: String?
|
|
277
|
+
let style: JsonStyle?
|
|
278
|
+
let disabled: Bool?
|
|
196
279
|
let live: Bool?
|
|
197
|
-
let imageRow: [JsonImageRowItem]?
|
|
198
280
|
|
|
199
281
|
init(
|
|
200
282
|
id: String? = nil,
|
|
201
|
-
|
|
283
|
+
path: String? = nil,
|
|
202
284
|
title: String,
|
|
203
285
|
subtitle: String? = nil,
|
|
204
286
|
artwork: JsonArtwork? = nil,
|
|
205
287
|
artist: String? = nil,
|
|
206
|
-
|
|
288
|
+
albumPath: String? = nil,
|
|
207
289
|
album: String? = nil,
|
|
208
290
|
description: String? = nil,
|
|
209
291
|
genre: String? = nil,
|
|
210
292
|
duration: Double? = nil,
|
|
211
293
|
src: String? = nil,
|
|
212
294
|
request: JsonTrackRequest? = nil,
|
|
213
|
-
style:
|
|
214
|
-
|
|
215
|
-
groupTitle: String? = nil,
|
|
295
|
+
style: JsonStyle? = nil,
|
|
296
|
+
disabled: Bool? = nil,
|
|
216
297
|
live: Bool? = nil,
|
|
217
|
-
imageRow: [JsonImageRowItem]? = nil,
|
|
218
298
|
) {
|
|
219
|
-
self.
|
|
299
|
+
self.path = path
|
|
220
300
|
self.title = title
|
|
221
301
|
self.subtitle = subtitle
|
|
222
302
|
self.artwork = artwork
|
|
223
303
|
self.artist = artist
|
|
224
|
-
self.
|
|
304
|
+
self.albumPath = albumPath
|
|
225
305
|
self.album = album
|
|
226
306
|
self.description = description
|
|
227
307
|
self.genre = genre
|
|
@@ -229,10 +309,8 @@ struct JsonTrack: Codable {
|
|
|
229
309
|
self.src = src
|
|
230
310
|
self.request = request
|
|
231
311
|
self.style = style
|
|
232
|
-
self.
|
|
233
|
-
self.groupTitle = groupTitle
|
|
312
|
+
self.disabled = disabled
|
|
234
313
|
self.live = live
|
|
235
|
-
self.imageRow = imageRow
|
|
236
314
|
self.id = id
|
|
237
315
|
}
|
|
238
316
|
}
|
|
@@ -250,26 +328,27 @@ struct JsonTrack: Codable {
|
|
|
250
328
|
|
|
251
329
|
extension JsonTrack {
|
|
252
330
|
/// Snapshot the persistable subset of a live Track (inverse of `toNitro()`).
|
|
331
|
+
/// The track's own declared style block and `disabled` persist (ADR 0011);
|
|
332
|
+
/// section/page-inherited values are never stamped onto tracks and
|
|
333
|
+
/// re-resolve at render, exactly as they do live.
|
|
253
334
|
init(from track: Track) {
|
|
254
335
|
self.init(
|
|
255
336
|
id: track.id,
|
|
256
|
-
|
|
337
|
+
path: track.path,
|
|
257
338
|
title: track.title,
|
|
258
339
|
subtitle: track.subtitle,
|
|
259
340
|
artwork: JsonArtwork(track.artwork),
|
|
260
341
|
artist: track.artist,
|
|
261
|
-
|
|
342
|
+
albumPath: track.albumPath,
|
|
262
343
|
album: track.album,
|
|
263
344
|
description: track.description,
|
|
264
345
|
genre: track.genre,
|
|
265
346
|
duration: track.duration,
|
|
266
347
|
src: track.src,
|
|
267
348
|
request: track.request.map(JsonTrackRequest.init(from:)),
|
|
268
|
-
style:
|
|
269
|
-
|
|
270
|
-
groupTitle: track.groupTitle,
|
|
349
|
+
style: JsonStyle(track.style),
|
|
350
|
+
disabled: track.disabled,
|
|
271
351
|
live: track.live,
|
|
272
|
-
imageRow: nil,
|
|
273
352
|
)
|
|
274
353
|
}
|
|
275
354
|
}
|
|
@@ -289,14 +368,16 @@ struct JsonTrack: Codable {
|
|
|
289
368
|
init(from track: Track) {
|
|
290
369
|
self.init(
|
|
291
370
|
id: track.id,
|
|
292
|
-
|
|
371
|
+
path: track.path,
|
|
293
372
|
title: track.title,
|
|
294
373
|
artwork: JsonArtwork(track.artwork),
|
|
295
374
|
artist: track.artist,
|
|
296
|
-
|
|
375
|
+
albumPath: track.albumPath,
|
|
297
376
|
album: track.album,
|
|
298
377
|
src: track.src,
|
|
299
378
|
request: track.request.map(JsonTrackRequest.init(from:)),
|
|
379
|
+
style: JsonStyle(track.style),
|
|
380
|
+
disabled: track.disabled,
|
|
300
381
|
live: track.live,
|
|
301
382
|
)
|
|
302
383
|
}
|
|
@@ -308,26 +389,14 @@ struct JsonTrack: Codable {
|
|
|
308
389
|
|
|
309
390
|
#if canImport(NitroModules)
|
|
310
391
|
|
|
311
|
-
|
|
312
|
-
func
|
|
313
|
-
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
extension JsonImageRowItem {
|
|
318
|
-
func toNitro() -> ImageRowItem {
|
|
319
|
-
ImageRowItem(
|
|
320
|
-
id: id,
|
|
321
|
-
url: url,
|
|
322
|
-
src: src,
|
|
323
|
-
artwork: artwork,
|
|
324
|
-
artworkSource: nil,
|
|
392
|
+
extension JsonSection {
|
|
393
|
+
func toNitro() -> Section {
|
|
394
|
+
Section(
|
|
325
395
|
title: title,
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
request: request?.toNitro(),
|
|
396
|
+
subtitle: subtitle,
|
|
397
|
+
style: style?.toSectionStyle(),
|
|
398
|
+
path: path,
|
|
399
|
+
children: children.map { $0.toNitro() },
|
|
331
400
|
)
|
|
332
401
|
}
|
|
333
402
|
}
|
|
@@ -335,28 +404,26 @@ struct JsonTrack: Codable {
|
|
|
335
404
|
extension JsonResolvedTrack {
|
|
336
405
|
func toNitro() -> ResolvedTrack {
|
|
337
406
|
ResolvedTrack(
|
|
338
|
-
|
|
407
|
+
path: path,
|
|
408
|
+
style: style?.toSectionStyle(),
|
|
409
|
+
sections: sections?.map { $0.toNitro() },
|
|
339
410
|
children: children?.map { $0.toNitro() },
|
|
340
411
|
carPlaySiriListButton: carPlaySiriListButton.flatMap { CarPlaySiriListButtonPosition(fromString: $0) },
|
|
341
412
|
id: id,
|
|
342
413
|
src: src,
|
|
343
414
|
artwork: artwork?.toNitro(),
|
|
344
415
|
artworkSource: nil, request: nil,
|
|
345
|
-
artworkCarPlayTinted: nil,
|
|
346
416
|
title: title,
|
|
347
417
|
subtitle: subtitle,
|
|
348
418
|
artist: artist,
|
|
349
|
-
|
|
419
|
+
albumPath: albumPath,
|
|
350
420
|
album: album,
|
|
351
421
|
description: description,
|
|
352
422
|
genre: genre,
|
|
353
423
|
duration: duration,
|
|
354
|
-
|
|
355
|
-
childrenStyle: childrenStyle?.toTrackStyle(),
|
|
424
|
+
disabled: disabled,
|
|
356
425
|
favorited: nil,
|
|
357
|
-
groupTitle: groupTitle,
|
|
358
426
|
live: live,
|
|
359
|
-
imageRow: nil,
|
|
360
427
|
)
|
|
361
428
|
}
|
|
362
429
|
}
|
|
@@ -365,26 +432,23 @@ struct JsonTrack: Codable {
|
|
|
365
432
|
func toNitro() -> Track {
|
|
366
433
|
Track(
|
|
367
434
|
id: id,
|
|
368
|
-
|
|
435
|
+
path: path,
|
|
369
436
|
src: src,
|
|
370
437
|
artwork: artwork?.toNitro(),
|
|
371
438
|
artworkSource: nil,
|
|
372
439
|
request: request?.toNitro(),
|
|
373
|
-
artworkCarPlayTinted: nil,
|
|
374
440
|
title: title,
|
|
375
441
|
subtitle: subtitle,
|
|
376
442
|
artist: artist,
|
|
377
|
-
|
|
443
|
+
albumPath: albumPath,
|
|
378
444
|
album: album,
|
|
379
445
|
description: description,
|
|
380
446
|
genre: genre,
|
|
381
447
|
duration: duration,
|
|
382
448
|
style: style?.toTrackStyle(),
|
|
383
|
-
|
|
449
|
+
disabled: disabled,
|
|
384
450
|
favorited: nil,
|
|
385
|
-
groupTitle: groupTitle,
|
|
386
451
|
live: live,
|
|
387
|
-
imageRow: imageRow?.map { $0.toNitro() },
|
|
388
452
|
)
|
|
389
453
|
}
|
|
390
454
|
}
|
|
@@ -396,15 +460,29 @@ struct JsonTrack: Codable {
|
|
|
396
460
|
func toNitro() -> Track {
|
|
397
461
|
Track(
|
|
398
462
|
id: id ?? "",
|
|
399
|
-
|
|
463
|
+
path: path,
|
|
400
464
|
src: src,
|
|
465
|
+
artwork: artwork?.toNitro(),
|
|
401
466
|
request: request.map { TrackRequest(userAgent: $0.userAgent, headers: $0.headers, query: $0.query) },
|
|
402
467
|
title: title,
|
|
403
468
|
artist: artist,
|
|
404
|
-
|
|
469
|
+
albumPath: albumPath,
|
|
405
470
|
album: album,
|
|
471
|
+
style: style?.toTrackStyle(),
|
|
472
|
+
disabled: disabled,
|
|
406
473
|
live: live,
|
|
407
|
-
|
|
474
|
+
)
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
extension JsonSection {
|
|
479
|
+
func toNitro() -> Section {
|
|
480
|
+
Section(
|
|
481
|
+
title: title,
|
|
482
|
+
subtitle: subtitle,
|
|
483
|
+
style: style?.toSectionStyle(),
|
|
484
|
+
path: path,
|
|
485
|
+
children: children.map { $0.toNitro() },
|
|
408
486
|
)
|
|
409
487
|
}
|
|
410
488
|
}
|
|
@@ -412,10 +490,13 @@ struct JsonTrack: Codable {
|
|
|
412
490
|
extension JsonResolvedTrack {
|
|
413
491
|
func toNitro() -> ResolvedTrack {
|
|
414
492
|
ResolvedTrack(
|
|
415
|
-
|
|
493
|
+
path: path,
|
|
494
|
+
style: style?.toSectionStyle(),
|
|
495
|
+
sections: sections?.map { $0.toNitro() },
|
|
416
496
|
children: children?.map { $0.toNitro() },
|
|
417
497
|
artwork: artwork?.toNitro(),
|
|
418
498
|
title: title,
|
|
499
|
+
disabled: disabled,
|
|
419
500
|
)
|
|
420
501
|
}
|
|
421
502
|
}
|