react-native-audio-browser 0.2.0-next.3 → 0.2.0-next.30
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 +36 -22
- package/android/build.gradle +35 -12
- package/android/gradle.properties +2 -2
- package/android/src/main/AndroidManifest.xml +3 -1
- package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +541 -278
- package/android/src/main/java/com/audiobrowser/AudioBrowserLifecycleModule.kt +38 -0
- package/android/src/main/java/com/audiobrowser/AudioBrowserPackage.kt +18 -2
- package/android/src/main/java/com/audiobrowser/ServiceBinding.kt +52 -0
- package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +315 -213
- package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +27 -9
- package/android/src/main/java/com/audiobrowser/browser/InertStyleDiagnostic.kt +288 -0
- package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +97 -58
- package/android/src/main/java/com/audiobrowser/browser/SectionScope.kt +70 -29
- package/android/src/main/java/com/audiobrowser/browser/StyleResolver.kt +60 -0
- package/android/src/main/java/com/audiobrowser/extension/ResolvedTrackExt.kt +20 -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/http/HttpClient.kt +20 -3
- package/android/src/main/java/com/audiobrowser/model/IcyTitle.kt +24 -0
- package/android/src/main/java/com/audiobrowser/model/PlaybackMetadata.kt +10 -6
- package/android/src/main/java/com/audiobrowser/model/PlayerUpdateOptions.kt +12 -12
- package/android/src/main/java/com/audiobrowser/player/CapabilityControls.kt +111 -58
- package/android/src/main/java/com/audiobrowser/player/CrossOriginHeaderStripper.kt +77 -0
- package/android/src/main/java/com/audiobrowser/player/MediaFactory.kt +28 -10
- package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +509 -230
- package/android/src/main/java/com/audiobrowser/player/MediaSessionCommandManager.kt +218 -252
- package/android/src/main/java/com/audiobrowser/player/NowPlayingUpdater.kt +21 -25
- package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +113 -78
- package/android/src/main/java/com/audiobrowser/player/Player.kt +81 -38
- package/android/src/main/java/com/audiobrowser/player/PlayerCapabilitiesExt.kt +2 -15
- package/android/src/main/java/com/audiobrowser/player/PlayerListener.kt +1 -1
- package/android/src/main/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicy.kt +2 -1
- package/android/src/main/java/com/audiobrowser/player/ShuffleOrderLedBy.kt +30 -0
- package/android/src/main/java/com/audiobrowser/tls/AiaCertChaser.kt +67 -11
- package/android/src/main/java/com/audiobrowser/tls/AiaChasingExtendedTrustManager.kt +168 -0
- package/android/src/main/java/com/audiobrowser/tls/AiaChasingTrustManager.kt +58 -14
- package/android/src/main/java/com/audiobrowser/tls/AiaTls.kt +35 -7
- package/android/src/main/java/com/audiobrowser/tls/CachingCertificateFetcher.kt +278 -59
- package/android/src/main/java/com/audiobrowser/util/ArtworkVariant.kt +7 -9
- package/android/src/main/java/com/audiobrowser/util/BrowserPathHelper.kt +62 -40
- package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +28 -23
- package/android/src/main/java/com/audiobrowser/util/StyleWire.kt +110 -0
- package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +56 -52
- package/android/src/main/res/values/strings.xml +25 -5
- package/android/src/test/java/com/audiobrowser/ServiceBindingTest.kt +100 -0
- package/android/src/test/java/com/audiobrowser/TestFixtures.kt +119 -33
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerFavoritesTest.kt +153 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerLayerResolutionTest.kt +15 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +346 -8
- package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +40 -2
- package/android/src/test/java/com/audiobrowser/browser/InertStyleDiagnosticTest.kt +301 -0
- package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +3 -2
- package/android/src/test/java/com/audiobrowser/browser/JsonStyleTest.kt +168 -0
- package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +128 -55
- package/android/src/test/java/com/audiobrowser/browser/StyleResolverTest.kt +160 -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/model/IcyTitleTest.kt +49 -0
- package/android/src/test/java/com/audiobrowser/player/BrowseTilesTest.kt +385 -0
- package/android/src/test/java/com/audiobrowser/player/CapabilityControlsTest.kt +101 -58
- package/android/src/test/java/com/audiobrowser/player/CrossOriginHeaderStripperTest.kt +94 -0
- package/android/src/test/java/com/audiobrowser/player/MediaSessionSlotMappingTest.kt +45 -0
- package/android/src/test/java/com/audiobrowser/player/NowPlayingUpdaterTest.kt +42 -2
- package/android/src/test/java/com/audiobrowser/player/PlaybackErrorClassifierTest.kt +3 -4
- package/android/src/test/java/com/audiobrowser/player/PlaybackStateStoreTrackJsonTest.kt +55 -0
- package/android/src/test/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicyTest.kt +3 -3
- package/android/src/test/java/com/audiobrowser/player/ShuffleOrderLedByTest.kt +79 -0
- package/android/src/test/java/com/audiobrowser/tls/AiaCertChaserTest.kt +197 -7
- package/android/src/test/java/com/audiobrowser/tls/AiaChasingTrustManagerTest.kt +325 -4
- package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherCallSiteTest.kt +322 -0
- package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherTest.kt +83 -0
- package/android/src/test/java/com/audiobrowser/util/BrowserPathHelperTest.kt +55 -16
- package/android/src/test/java/com/audiobrowser/util/MediaExtrasBuilderTest.kt +162 -0
- package/android/src/test/java/com/audiobrowser/util/TrackFactoryMediaIdTest.kt +7 -7
- package/ios/AVPlayerEngine.swift +330 -0
- package/ios/AVPlayerEngineCallbacks.swift +15 -0
- package/ios/Browser/BrowseGate.swift +58 -0
- package/ios/Browser/BrowserConfig.swift +117 -78
- package/ios/Browser/BrowserManager.swift +209 -603
- package/ios/Browser/BrowserPathHelper.swift +50 -46
- package/ios/Browser/InertStyleDiagnostic.swift +296 -0
- package/ios/Browser/JsonModels.swift +264 -106
- package/ios/Browser/NavigationErrorState.swift +41 -0
- package/ios/Browser/PageResolver.swift +227 -0
- package/ios/Browser/RequestLayer.swift +90 -0
- package/ios/Browser/{BrowserManager+URLResolution.swift → RequestPipeline.swift} +193 -121
- package/ios/Browser/SearchDrillIn.swift +7 -7
- package/ios/Browser/SectionScope.swift +58 -24
- package/ios/Browser/StyleResolver.swift +58 -0
- package/ios/Browser/TabBarEntries.swift +9 -3
- package/ios/Browser/TrackIdTemplate.swift +37 -0
- package/ios/CarPlay/CPInterfaceController+Safe.swift +100 -43
- package/ios/CarPlay/CarPlayArtworkResolver.swift +36 -83
- package/ios/CarPlay/CarPlayController.swift +42 -1296
- package/ios/CarPlay/CarPlayImageLoader.swift +78 -97
- package/ios/CarPlay/CarPlayListItemFactory.swift +303 -92
- package/ios/CarPlay/CarPlayNowPlayingManager.swift +129 -136
- package/ios/CarPlay/CarPlaySession+Navigator.swift +114 -0
- package/ios/CarPlay/CarPlaySession+PageLoader.swift +92 -0
- package/ios/CarPlay/CarPlaySession+Refresher.swift +43 -0
- package/ios/CarPlay/CarPlaySession+TabBar.swift +193 -0
- package/ios/CarPlay/CarPlaySession.swift +209 -0
- package/ios/CarPlay/CarPlayTemplates.swift +63 -0
- package/ios/CarPlay/HybridAudioBrowser+IntentFavorite.swift +20 -0
- package/ios/{Player → CarPlay}/MediaIntentCriteria.swift +17 -9
- package/ios/CarPlay/MediaIntentPlayback.swift +74 -0
- package/ios/CarPlay/RNABMediaAddHandler.swift +8 -24
- package/ios/CarPlay/RNABMediaAffinityHandler.swift +7 -23
- package/ios/CarPlay/RNABMediaIntentHandler.swift +18 -19
- package/ios/CarPlay/SectionPresentation.swift +77 -0
- package/ios/CarPlay/TopTemplateReplacer.swift +96 -0
- package/ios/Extension/Capability+RemoteCommand.swift +1 -1
- package/ios/Extension/NavigationError+Conversion.swift +14 -4
- package/ios/Extension/PlayerCapabilities+Favorite.swift +1 -15
- package/ios/Extension/ResolvedTrack+Copying.swift +13 -15
- package/ios/Extension/Section+Copying.swift +29 -0
- package/ios/Extension/String+IcyCharset.swift +21 -0
- package/ios/Extension/TimedMetadata+AVFoundation.swift +6 -4
- package/ios/Extension/Track+Copying.swift +8 -12
- package/ios/Extension/Track+Identity.swift +18 -0
- package/ios/Extension/UIApplication+ActiveScene.swift +27 -0
- package/ios/Extension/UIImage+Adaptive.swift +12 -0
- package/ios/Extension/URLError+Connectivity.swift +15 -0
- package/ios/Http/HttpClient.swift +66 -142
- package/ios/HybridAudioBrowser+Browser.swift +153 -0
- package/ios/HybridAudioBrowser+Options.swift +144 -0
- package/ios/HybridAudioBrowser+Player.swift +397 -0
- package/ios/HybridAudioBrowser+PlayerCallbacks.swift +190 -0
- package/ios/HybridAudioBrowser+Stubs.swift +46 -0
- package/ios/HybridAudioBrowser.swift +153 -1610
- package/ios/Model/NitroTypeStubs.swift +146 -24
- package/ios/Model/PlayerUpdateOptions.swift +8 -1
- package/ios/Model/RemoteCommand.swift +18 -0
- package/ios/Model/TrackPlayerError.swift +2 -2
- package/ios/NowPlayingInfo/NowPlayingInfoController.swift +18 -53
- package/ios/Observer/ItemObserver.swift +90 -0
- package/ios/Observer/PlayerObserver.swift +59 -0
- package/ios/Option/SessionCategories.swift +42 -92
- package/ios/Player/AudioSessionController.swift +177 -0
- package/ios/Player/DeferredSeek.swift +70 -0
- package/ios/Player/ErrorStatus.swift +27 -0
- package/ios/Player/MediaLoader.swift +62 -35
- package/ios/Player/NowPlayingUpdater.swift +197 -50
- package/ios/Player/PlaybackFailure.swift +125 -0
- package/ios/Player/PlaybackPersistence.swift +73 -0
- package/ios/Player/PlaybackTimer.swift +8 -2
- package/ios/Player/Player.swift +1078 -0
- package/ios/Player/{PlaybackCoordinatorCallbacks.swift → PlayerCallbacks.swift} +3 -4
- package/ios/Player/PlayerEngine.swift +87 -0
- package/ios/Player/PlayerStatusTypes.swift +2 -6
- package/ios/Player/QueueManager.swift +93 -67
- package/ios/Player/RetryLoop.swift +261 -0
- package/ios/Player/ShuffleOrder.swift +33 -0
- package/ios/Player/SleepTimerManager.swift +1 -1
- package/ios/RemoteCommand/RemoteCommandCallbacks.swift +46 -0
- package/ios/RemoteCommand/RemoteCommandController.swift +87 -331
- package/ios/Tests/BrowserPathHelperTests.swift +56 -15
- package/ios/Tests/CarPlayArtworkResolverTests.swift +60 -373
- package/ios/Tests/DeferredSeekTests.swift +70 -0
- package/ios/Tests/EmitterTests.swift +29 -0
- package/ios/Tests/GenerationMemoTests.swift +121 -0
- package/ios/Tests/InertStyleDiagnosticTests.swift +209 -0
- package/ios/Tests/JsonModelsTests.swift +164 -1
- package/ios/Tests/LRUCacheTests.swift +110 -0
- package/ios/Tests/MediaIntentCriteriaTests.swift +2 -2
- package/ios/Tests/MediaLoaderTests.swift +12 -48
- package/ios/Tests/ObserverTests.swift +88 -0
- package/ios/Tests/PlaybackErrorTests.swift +76 -0
- package/ios/Tests/PlaybackFailureTests.swift +189 -0
- package/ios/Tests/PlaybackPersistenceTests.swift +93 -0
- package/ios/Tests/PlayerPolicyTests.swift +420 -0
- package/ios/Tests/{PlaybackCoordinatorTests.swift → PlayerTests.swift} +300 -248
- package/ios/Tests/PlayingStateTests.swift +42 -0
- package/ios/Tests/QueueManagerTests.swift +196 -115
- package/ios/Tests/ReadyValueTests.swift +73 -0
- package/ios/Tests/RemoteCommandControllerTests.swift +152 -0
- package/ios/Tests/RemoteCommandTests.swift +65 -0
- package/ios/Tests/RequestLayerTests.swift +112 -0
- package/ios/Tests/ResolvedTrackCopyingTests.swift +39 -35
- package/ios/Tests/RetryLoopTests.swift +270 -0
- package/ios/Tests/SearchDrillInTests.swift +16 -16
- package/ios/Tests/SectionPresentationTests.swift +98 -0
- package/ios/Tests/SectionScopeTests.swift +87 -55
- package/ios/Tests/StyleResolverTests.swift +132 -0
- package/ios/Tests/Support/TestTypes.swift +108 -104
- package/ios/Tests/TabBarEntriesTests.swift +19 -19
- package/ios/Tests/TimedMetadataAVFoundationTests.swift +42 -0
- package/ios/Tests/TopTemplateReplacerTests.swift +172 -0
- package/ios/Tests/TrackIdTemplateTests.swift +67 -0
- package/ios/Tests/TrackIdentityTests.swift +20 -0
- package/ios/Tests/TrackSelectorTests.swift +168 -33
- package/ios/Tests/URLErrorConnectivityTests.swift +20 -0
- package/ios/TrackSelector.swift +46 -31
- package/ios/Util/ArtworkImageFetcher.swift +58 -1
- package/ios/Util/Emitter.swift +42 -0
- package/ios/Util/GenerationMemo.swift +36 -0
- package/ios/Util/LRUCache.swift +23 -159
- package/ios/Util/NetworkMonitor.swift +43 -26
- package/ios/Util/ReadyValue.swift +56 -0
- package/ios/Util/SFSymbolRenderer.swift +59 -31
- package/ios/Util/SVGProcessor.swift +9 -12
- package/lib/commonjs/AudioBrowser.js +8 -8
- package/lib/commonjs/AudioBrowser.js.map +1 -1
- package/lib/commonjs/CLAUDE.md +52 -0
- package/lib/commonjs/features/browser-config.js +12 -8
- package/lib/commonjs/features/browser-config.js.map +1 -1
- package/lib/commonjs/features/browser.js +11 -3
- package/lib/commonjs/features/browser.js.map +1 -1
- package/lib/commonjs/features/carConnection.js +1 -1
- package/lib/commonjs/features/equalizer.js +1 -1
- package/lib/commonjs/features/errors.js +3 -3
- package/lib/commonjs/features/favorites.js +14 -11
- package/lib/commonjs/features/favorites.js.map +1 -1
- package/lib/commonjs/features/gate.js +16 -1
- package/lib/commonjs/features/gate.js.map +1 -1
- package/lib/commonjs/features/metadata.js +20 -3
- package/lib/commonjs/features/metadata.js.map +1 -1
- package/lib/commonjs/features/network.js +1 -1
- package/lib/commonjs/features/nowPlaying.js +1 -1
- package/lib/commonjs/features/output.js +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/playWhenReady.js +1 -1
- package/lib/commonjs/features/playback/playing.js +1 -1
- package/lib/commonjs/features/playback/progress.js +3 -2
- package/lib/commonjs/features/playback/progress.js.map +1 -1
- package/lib/commonjs/features/playback/rate.js +8 -1
- package/lib/commonjs/features/playback/rate.js.map +1 -1
- package/lib/commonjs/features/playback/state.js +3 -4
- package/lib/commonjs/features/playback/state.js.map +1 -1
- package/lib/commonjs/features/playback/trackPlaybackTime.js +0 -6
- package/lib/commonjs/features/playback/trackPlaybackTime.js.map +1 -1
- package/lib/commonjs/features/playback/volume.js +1 -1
- package/lib/commonjs/features/player/options.js +48 -34
- package/lib/commonjs/features/player/options.js.map +1 -1
- package/lib/commonjs/features/player/setup.js +18 -9
- package/lib/commonjs/features/player/setup.js.map +1 -1
- package/lib/commonjs/features/player/validateOptions.js +23 -0
- package/lib/commonjs/features/player/validateOptions.js.map +1 -0
- package/lib/commonjs/features/queue/activeTrack.js +15 -4
- package/lib/commonjs/features/queue/activeTrack.js.map +1 -1
- package/lib/commonjs/features/queue/queue.js +13 -6
- package/lib/commonjs/features/queue/queue.js.map +1 -1
- package/lib/commonjs/features/queue/repeatMode.js +1 -1
- package/lib/commonjs/features/queue/shuffle.js +1 -1
- package/lib/commonjs/features/remoteControls.js +13 -92
- package/lib/commonjs/features/remoteControls.js.map +1 -1
- package/lib/commonjs/features/sleepTimer.js +13 -1
- package/lib/commonjs/features/sleepTimer.js.map +1 -1
- package/lib/commonjs/test-utils/reactNativeStub.js +65 -0
- package/lib/commonjs/test-utils/reactNativeStub.js.map +1 -0
- package/lib/commonjs/utils/LazyNativeEmitter.js +28 -14
- 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 +201 -76
- package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/LoadAttempt.js +37 -0
- package/lib/commonjs/web/TrackPlayer/LoadAttempt.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js +18 -2
- package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/Player.js +254 -39
- package/lib/commonjs/web/TrackPlayer/Player.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/PlayingStateFactory.js +1 -1
- package/lib/commonjs/web/TrackPlayer/QueueManager.js +14 -0
- package/lib/commonjs/web/TrackPlayer/QueueManager.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/QueuePlayer.js +33 -12
- package/lib/commonjs/web/TrackPlayer/QueuePlayer.js.map +1 -1
- package/lib/commonjs/web/browser/BrowserManager.js +175 -100
- 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/NavigationErrorManager.js +3 -1
- package/lib/commonjs/web/browser/NavigationErrorManager.js.map +1 -1
- package/lib/commonjs/web/browser/SearchManager.js +18 -23
- package/lib/commonjs/web/browser/SearchManager.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/http/RequestConfigBuilder.js +110 -27
- package/lib/commonjs/web/http/RequestConfigBuilder.js.map +1 -1
- package/lib/commonjs/web/http/followMediaRedirect.js +219 -0
- package/lib/commonjs/web/http/followMediaRedirect.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 +62 -11
- package/lib/commonjs/web/util/BrowserPathHelper.js.map +1 -1
- package/lib/module/AudioBrowser.js +2 -1
- package/lib/module/AudioBrowser.js.map +1 -1
- package/lib/module/CLAUDE.md +52 -0
- package/lib/module/features/browser-config.js +12 -8
- package/lib/module/features/browser-config.js.map +1 -1
- package/lib/module/features/browser.js +11 -3
- package/lib/module/features/browser.js.map +1 -1
- package/lib/module/features/carConnection.js +1 -1
- package/lib/module/features/equalizer.js +1 -1
- package/lib/module/features/errors.js +3 -3
- package/lib/module/features/favorites.js +14 -11
- package/lib/module/features/favorites.js.map +1 -1
- package/lib/module/features/gate.js +16 -1
- package/lib/module/features/gate.js.map +1 -1
- package/lib/module/features/metadata.js +20 -3
- package/lib/module/features/metadata.js.map +1 -1
- package/lib/module/features/network.js +1 -1
- package/lib/module/features/nowPlaying.js +1 -1
- package/lib/module/features/output.js +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/playWhenReady.js +1 -1
- package/lib/module/features/playback/playing.js +1 -1
- package/lib/module/features/playback/progress.js +3 -2
- package/lib/module/features/playback/progress.js.map +1 -1
- package/lib/module/features/playback/rate.js +8 -1
- package/lib/module/features/playback/rate.js.map +1 -1
- package/lib/module/features/playback/state.js +3 -4
- package/lib/module/features/playback/state.js.map +1 -1
- package/lib/module/features/playback/trackPlaybackTime.js +0 -5
- package/lib/module/features/playback/trackPlaybackTime.js.map +1 -1
- package/lib/module/features/playback/volume.js +1 -1
- package/lib/module/features/player/options.js +47 -32
- package/lib/module/features/player/options.js.map +1 -1
- package/lib/module/features/player/setup.js +17 -8
- package/lib/module/features/player/setup.js.map +1 -1
- package/lib/module/features/player/validateOptions.js +19 -0
- package/lib/module/features/player/validateOptions.js.map +1 -0
- package/lib/module/features/queue/activeTrack.js +15 -4
- package/lib/module/features/queue/activeTrack.js.map +1 -1
- package/lib/module/features/queue/queue.js +13 -6
- package/lib/module/features/queue/queue.js.map +1 -1
- package/lib/module/features/queue/repeatMode.js +1 -1
- package/lib/module/features/queue/shuffle.js +1 -1
- package/lib/module/features/remoteControls.js +13 -92
- package/lib/module/features/remoteControls.js.map +1 -1
- package/lib/module/features/sleepTimer.js +13 -1
- package/lib/module/features/sleepTimer.js.map +1 -1
- package/lib/module/test-utils/reactNativeStub.js +58 -0
- package/lib/module/test-utils/reactNativeStub.js.map +1 -0
- package/lib/module/utils/LazyNativeEmitter.js +28 -14
- 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 +201 -76
- package/lib/module/web/NativeAudioBrowser.js.map +1 -1
- package/lib/module/web/TrackPlayer/LoadAttempt.js +32 -0
- package/lib/module/web/TrackPlayer/LoadAttempt.js.map +1 -0
- package/lib/module/web/TrackPlayer/PlaybackStateMachine.js +18 -2
- package/lib/module/web/TrackPlayer/PlaybackStateMachine.js.map +1 -1
- package/lib/module/web/TrackPlayer/Player.js +254 -39
- package/lib/module/web/TrackPlayer/Player.js.map +1 -1
- package/lib/module/web/TrackPlayer/PlayingStateFactory.js +1 -1
- package/lib/module/web/TrackPlayer/QueueManager.js +14 -0
- package/lib/module/web/TrackPlayer/QueueManager.js.map +1 -1
- package/lib/module/web/TrackPlayer/QueuePlayer.js +33 -12
- package/lib/module/web/TrackPlayer/QueuePlayer.js.map +1 -1
- package/lib/module/web/browser/BrowserManager.js +175 -100
- 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/NavigationErrorManager.js +3 -1
- package/lib/module/web/browser/NavigationErrorManager.js.map +1 -1
- package/lib/module/web/browser/SearchManager.js +18 -23
- package/lib/module/web/browser/SearchManager.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/http/RequestConfigBuilder.js +110 -27
- package/lib/module/web/http/RequestConfigBuilder.js.map +1 -1
- package/lib/module/web/http/followMediaRedirect.js +215 -0
- package/lib/module/web/http/followMediaRedirect.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 +62 -11
- package/lib/module/web/util/BrowserPathHelper.js.map +1 -1
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/AudioBrowser.d.ts +1 -1
- 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 +10 -2
- package/lib/typescript/src/features/browser.d.ts.map +1 -1
- package/lib/typescript/src/features/carConnection.d.ts +1 -1
- package/lib/typescript/src/features/equalizer.d.ts +1 -1
- package/lib/typescript/src/features/errors.d.ts +3 -3
- package/lib/typescript/src/features/favorites.d.ts +14 -11
- package/lib/typescript/src/features/favorites.d.ts.map +1 -1
- package/lib/typescript/src/features/gate.d.ts +18 -2
- package/lib/typescript/src/features/gate.d.ts.map +1 -1
- package/lib/typescript/src/features/metadata.d.ts +20 -3
- package/lib/typescript/src/features/metadata.d.ts.map +1 -1
- package/lib/typescript/src/features/network.d.ts +1 -1
- package/lib/typescript/src/features/nowPlaying.d.ts +1 -1
- package/lib/typescript/src/features/output.d.ts +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/playWhenReady.d.ts +1 -1
- package/lib/typescript/src/features/playback/playing.d.ts +1 -1
- package/lib/typescript/src/features/playback/progress.d.ts +1 -1
- package/lib/typescript/src/features/playback/progress.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/rate.d.ts +8 -1
- package/lib/typescript/src/features/playback/rate.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/state.d.ts +3 -4
- 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/playback/volume.d.ts +1 -1
- package/lib/typescript/src/features/player/options.d.ts +108 -56
- package/lib/typescript/src/features/player/options.d.ts.map +1 -1
- package/lib/typescript/src/features/player/setup.d.ts +14 -4
- package/lib/typescript/src/features/player/setup.d.ts.map +1 -1
- package/lib/typescript/src/features/player/validateOptions.d.ts +2 -0
- package/lib/typescript/src/features/player/validateOptions.d.ts.map +1 -0
- package/lib/typescript/src/features/queue/activeTrack.d.ts +9 -2
- package/lib/typescript/src/features/queue/activeTrack.d.ts.map +1 -1
- package/lib/typescript/src/features/queue/queue.d.ts +7 -4
- package/lib/typescript/src/features/queue/queue.d.ts.map +1 -1
- package/lib/typescript/src/features/queue/repeatMode.d.ts +1 -1
- package/lib/typescript/src/features/queue/shuffle.d.ts +1 -1
- package/lib/typescript/src/features/remoteControls.d.ts +23 -22
- package/lib/typescript/src/features/remoteControls.d.ts.map +1 -1
- package/lib/typescript/src/features/sleepTimer.d.ts +1 -1
- package/lib/typescript/src/features/sleepTimer.d.ts.map +1 -1
- package/lib/typescript/src/test-utils/reactNativeStub.d.ts +36 -0
- package/lib/typescript/src/test-utils/reactNativeStub.d.ts.map +1 -0
- package/lib/typescript/src/types/browser-native.d.ts +3 -2
- package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
- package/lib/typescript/src/types/browser-nodes.d.ts +387 -126
- package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
- package/lib/typescript/src/types/browser.d.ts +93 -61
- package/lib/typescript/src/types/browser.d.ts.map +1 -1
- package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +19 -16
- 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/resolveAssetSource.d.ts +1 -2
- package/lib/typescript/src/utils/resolveAssetSource.d.ts.map +1 -1
- 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 +1 -2
- package/nitrogen/generated/android/AudioBrowserOnLoad.cpp +4 -2
- package/nitrogen/generated/android/c++/JAndroidAudioContentType.hpp +2 -2
- package/nitrogen/generated/android/c++/JAndroidAudioOffloadSettings.hpp +2 -2
- package/nitrogen/generated/android/c++/JAndroidOptions.hpp +12 -12
- package/nitrogen/generated/android/c++/JAndroidPlayerWakeMode.hpp +2 -2
- package/nitrogen/generated/android/c++/JAppKilledPlaybackBehavior.hpp +2 -2
- package/nitrogen/generated/android/c++/JArtworkRendering.hpp +58 -0
- package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +10 -5
- package/nitrogen/generated/android/c++/JArtworkVariants.hpp +2 -2
- package/nitrogen/generated/android/c++/JBatteryOptimizationStatus.hpp +2 -2
- package/nitrogen/generated/android/c++/JBatteryOptimizationStatusChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JBatteryWarningPendingChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JBrowseError.hpp +2 -2
- package/nitrogen/generated/android/c++/JBrowseResult.hpp +19 -7
- package/nitrogen/generated/android/c++/JBrowserSourceCallbackParam.hpp +2 -2
- package/nitrogen/generated/android/c++/JCarPlayNowPlayingButton.hpp +2 -2
- package/nitrogen/generated/android/c++/JCarPlayPlayingIndicatorLocation.hpp +58 -0
- package/nitrogen/generated/android/c++/JCarPlaySiriListButtonPosition.hpp +2 -2
- package/nitrogen/generated/android/c++/JCardImage.hpp +58 -0
- package/nitrogen/generated/android/c++/JChapterMetadata.hpp +2 -2
- package/nitrogen/generated/android/c++/JEqualizerSettings.hpp +10 -10
- package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +10 -5
- package/nitrogen/generated/android/c++/JFormatNavigationErrorParams.hpp +11 -5
- package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +10 -5
- package/nitrogen/generated/android/c++/JFormattedNavigationError.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___RequestConfig_std__optional_std__unordered_map_std__string__std__string__.hpp +9 -9
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +10 -5
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.hpp +4 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +10 -5
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +10 -5
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____RequestConfig_std__optional_std__unordered_map_std__string__std__string__.hpp +9 -9
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +10 -5
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +18 -12
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +10 -4
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__string__.hpp +102 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.hpp +18 -6
- package/nitrogen/generated/android/c++/JFunc_void.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_BatteryOptimizationStatusChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_BatteryWarningPendingChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_EqualizerSettings.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +10 -5
- package/nitrogen/generated/android/c++/JFunc_void_GateEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_NavigationErrorEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_NowPlayingMetadata.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +9 -12
- package/nitrogen/generated/android/c++/JFunc_void_Output.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_Playback.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +10 -5
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackErrorEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackPlayWhenReadyChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackProgressUpdatedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackQueueEndedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_PlayingState.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_RemoteJumpBackwardEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_RemoteJumpForwardEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_RemotePlayIdEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_RemotePlaySearchEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_RemoteSeekEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_RemoteSkipEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_RepeatModeChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_TimedMetadata.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_TrackMetadata.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_double.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_FormattedNavigationError_.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +17 -5
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_ChapterMetadata_.hpp +16 -16
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +24 -18
- package/nitrogen/generated/android/c++/JGate.hpp +2 -2
- package/nitrogen/generated/android/c++/JGateDecision.hpp +2 -2
- package/nitrogen/generated/android/c++/JGateEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JGateReason.hpp +2 -2
- package/nitrogen/generated/android/c++/JGridTile.hpp +64 -0
- package/nitrogen/generated/android/c++/JHttpMethod.hpp +2 -2
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +77 -53
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.hpp +3 -3
- package/nitrogen/generated/android/c++/JIOSCategory.hpp +2 -2
- package/nitrogen/generated/android/c++/JIOSCategoryMode.hpp +2 -2
- package/nitrogen/generated/android/c++/JIOSCategoryOptions.hpp +2 -2
- package/nitrogen/generated/android/c++/JIOSCategoryPolicy.hpp +2 -2
- package/nitrogen/generated/android/c++/JIOSOptions.hpp +17 -11
- package/nitrogen/generated/android/c++/JImageContext.hpp +2 -2
- package/nitrogen/generated/android/c++/JImageQueryParams.hpp +2 -2
- package/nitrogen/generated/android/c++/JImageShape.hpp +58 -0
- package/nitrogen/generated/android/c++/JImageSource.hpp +2 -2
- package/nitrogen/generated/android/c++/JMediaReference.hpp +2 -2
- package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +10 -5
- package/nitrogen/generated/android/c++/JMediaTransformParams.hpp +2 -2
- package/nitrogen/generated/android/c++/JNativeAndroidSetupOptions.hpp +2 -2
- package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +48 -21
- package/nitrogen/generated/android/c++/JNativeGateRequest.hpp +2 -2
- package/nitrogen/generated/android/c++/JNativeIOSSetupOptions.hpp +10 -10
- package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +16 -4
- package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +17 -14
- package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +9 -12
- package/nitrogen/generated/android/c++/JNavigationError.hpp +2 -2
- package/nitrogen/generated/android/c++/JNavigationErrorEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JNavigationErrorKind.hpp +58 -0
- package/nitrogen/generated/android/c++/JNavigationErrorType.hpp +2 -2
- package/nitrogen/generated/android/c++/JNitroAndroidUpdateOptions.hpp +12 -12
- package/nitrogen/generated/android/c++/JNitroIOSUpdateOptions.hpp +17 -11
- package/nitrogen/generated/android/c++/JNowPlayingMetadata.hpp +2 -2
- package/nitrogen/generated/android/c++/JNowPlayingUpdate.hpp +2 -2
- package/nitrogen/generated/android/c++/JOptions.hpp +9 -12
- package/nitrogen/generated/android/c++/JOutput.hpp +2 -2
- package/nitrogen/generated/android/c++/JOutputType.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlayback.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +10 -5
- package/nitrogen/generated/android/c++/JPlaybackError.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlaybackErrorEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlaybackErrorKind.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlaybackPlayWhenReadyChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlaybackProgressUpdatedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlaybackQueueEndedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlaybackState.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +7 -13
- package/nitrogen/generated/android/c++/JPlayingState.hpp +2 -2
- package/nitrogen/generated/android/c++/JProgress.hpp +2 -2
- package/nitrogen/generated/android/c++/{JNotificationButton.hpp → JRemoteButton.hpp} +19 -19
- package/nitrogen/generated/android/c++/JRemoteButtonLayout.hpp +86 -0
- package/nitrogen/generated/android/c++/JRemoteJumpBackwardEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JRemoteJumpForwardEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JRemotePlayIdEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JRemotePlaySearchEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JRemoteSeekEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JRemoteSkipEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JRepeatMode.hpp +2 -2
- package/nitrogen/generated/android/c++/JRepeatModeChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JRequestConfig.hpp +2 -2
- package/nitrogen/generated/android/c++/JResolvedTrack.hpp +67 -59
- package/nitrogen/generated/android/c++/JRetryConfig.hpp +2 -2
- package/nitrogen/generated/android/c++/JSearchMode.hpp +2 -2
- package/nitrogen/generated/android/c++/JSearchParams.hpp +2 -2
- package/nitrogen/generated/android/c++/JSection.hpp +116 -0
- package/nitrogen/generated/android/c++/JSectionStyle.hpp +96 -0
- package/nitrogen/generated/android/c++/JSleepTimer.hpp +4 -4
- package/nitrogen/generated/android/c++/JSleepTimerEndOfTrack.hpp +2 -2
- package/nitrogen/generated/android/c++/JSleepTimerTime.hpp +2 -2
- package/nitrogen/generated/android/c++/JStallReason.hpp +2 -2
- package/nitrogen/generated/android/c++/JStyleDisplay.hpp +58 -0
- package/nitrogen/generated/android/c++/JTimedMetadata.hpp +2 -2
- package/nitrogen/generated/android/c++/JTrack.hpp +27 -48
- package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +18 -12
- package/nitrogen/generated/android/c++/JTrackMetadata.hpp +2 -2
- package/nitrogen/generated/android/c++/JTrackRequest.hpp +2 -2
- package/nitrogen/generated/android/c++/JTrackStyle.hpp +47 -19
- package/nitrogen/generated/android/c++/JTransformableRequestConfig.hpp +2 -2
- package/nitrogen/generated/android/c++/JVariant_Boolean_AndroidAudioOffloadSettings.hpp +3 -3
- package/nitrogen/generated/android/c++/JVariant_Boolean_RetryConfig.hpp +3 -3
- package/nitrogen/generated/android/c++/JVariant_NullType_Double.hpp +3 -3
- package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.hpp +75 -0
- package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.hpp +20 -8
- package/nitrogen/generated/android/c++/JVariant_String_ArtworkVariants.hpp +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidAudioOffloadSettings.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidOptions.kt +20 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoritesMatchMode.kt → ArtworkRendering.kt} +5 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ArtworkRequestConfig.kt +37 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ArtworkVariants.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryOptimizationStatusChangedEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryWarningPendingChangedEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowseError.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowseResult.kt +16 -7
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowserSourceCallbackParam.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayPlayingIndicatorLocation.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CardImage.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ChapterMetadata.kt +19 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/EqualizerSettings.kt +27 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FavoriteChangedEvent.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormatNavigationErrorParams.kt +25 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormatNowPlayingParams.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormattedNavigationError.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___RequestConfig_std__optional_std__unordered_map_std__string__std__string__.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___Track.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_std__string____Track.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____RequestConfig_std__optional_std__unordered_map_std__string__std__string__.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__string__.kt +78 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_BatteryOptimizationStatusChangedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_BatteryWarningPendingChangedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_EqualizerSettings.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_FavoriteChangedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_GateEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_NavigationErrorEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_NowPlayingMetadata.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_Options.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_Output.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_Playback.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackActiveTrackChangedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackErrorEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackPlayWhenReadyChangedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackProgressUpdatedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackQueueEndedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlayingState.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteJumpBackwardEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteJumpForwardEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemotePlayIdEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemotePlaySearchEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSeekEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSkipEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RepeatModeChangedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_TimedMetadata.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_TrackMetadata.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_bool.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_double.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_FormattedNavigationError_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_ResolvedTrack_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__string.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__vector_ChapterMetadata_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__vector_Track_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Gate.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/GateDecision.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/GateEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/GridTile.kt +25 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HybridAudioBrowserSpec.kt +3 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSOptions.kt +25 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageContext.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageQueryParams.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageShape.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageSource.kt +19 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaRequestConfig.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaTransformParams.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeAndroidSetupOptions.kt +31 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +51 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeGateRequest.kt +17 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeIOSSetupOptions.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeRouteEntry.kt +27 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeSetupPlayerOptions.kt +29 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeUpdateOptions.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationError.kt +19 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorKind.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroAndroidUpdateOptions.kt +20 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroIOSUpdateOptions.kt +25 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingMetadata.kt +29 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingUpdate.kt +17 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Options.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Output.kt +17 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Playback.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackActiveTrackChangedEvent.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackError.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackErrorEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackPlayWhenReadyChangedEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackProgressUpdatedEvent.kt +19 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackQueueEndedEvent.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +37 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayingState.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Progress.kt +17 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{NotificationButton.kt → RemoteButton.kt} +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteButtonLayout.kt +61 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteJumpBackwardEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteJumpForwardEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemotePlayIdEvent.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemotePlaySearchEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSeekEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSkipEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RepeatModeChangedEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RequestConfig.kt +27 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +67 -15
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RetryConfig.kt +17 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchParams.kt +27 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Section.kt +66 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SectionStyle.kt +86 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimer.kt +18 -8
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimerEndOfTrack.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimerTime.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StyleDisplay.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TimedMetadata.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +55 -12
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackLoadEvent.kt +17 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackMetadata.kt +43 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackRequest.kt +17 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackStyle.kt +58 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TransformableRequestConfig.kt +31 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_AndroidAudioOffloadSettings.kt +16 -7
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_RetryConfig.kt +16 -7
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_NullType_Double.kt +16 -7
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Variant_NullType_NotificationButtonLayout.kt → Variant_NullType_RemoteButtonLayout.kt} +24 -15
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_ResolvedTrack_BrowseError_Promise_BrowseResult_.kt +18 -8
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_String_ArtworkVariants.kt +16 -7
- package/nitrogen/generated/ios/AudioBrowser+autolinking.rb +2 -0
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.cpp +38 -29
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +779 -665
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +34 -16
- package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +36 -18
- package/nitrogen/generated/ios/swift/AndroidOptions.swift +12 -12
- package/nitrogen/generated/ios/swift/ArtworkRendering.swift +40 -0
- package/nitrogen/generated/ios/swift/BrowseResult.swift +12 -0
- package/nitrogen/generated/ios/swift/CarPlayPlayingIndicatorLocation.swift +40 -0
- package/nitrogen/generated/ios/swift/CardImage.swift +40 -0
- package/nitrogen/generated/ios/swift/FormatNavigationErrorParams.swift +7 -2
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__string__.swift +54 -0
- package/nitrogen/generated/ios/swift/GridTile.swift +48 -0
- package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec_cxx.swift +2 -2
- package/nitrogen/generated/ios/swift/IOSOptions.swift +7 -2
- package/nitrogen/generated/ios/swift/ImageShape.swift +40 -0
- package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +52 -5
- package/nitrogen/generated/ios/swift/NavigationErrorKind.swift +40 -0
- package/nitrogen/generated/ios/swift/NitroAndroidUpdateOptions.swift +12 -12
- package/nitrogen/generated/ios/swift/NitroIOSUpdateOptions.swift +12 -1
- package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +8 -27
- package/nitrogen/generated/ios/swift/{NotificationButton.swift → RemoteButton.swift} +6 -6
- package/nitrogen/generated/ios/swift/RemoteButtonLayout.swift +57 -0
- package/nitrogen/generated/ios/swift/ResolvedTrack.swift +62 -73
- package/nitrogen/generated/ios/swift/Section.swift +82 -0
- package/nitrogen/generated/ios/swift/SectionStyle.swift +133 -0
- package/nitrogen/generated/ios/swift/SleepTimer.swift +13 -0
- package/nitrogen/generated/ios/swift/StyleDisplay.swift +40 -0
- package/nitrogen/generated/ios/swift/Track.swift +28 -63
- package/nitrogen/generated/ios/swift/TrackStyle.swift +86 -22
- package/nitrogen/generated/ios/swift/Variant_Bool_AndroidAudioOffloadSettings.swift +12 -0
- package/nitrogen/generated/ios/swift/Variant_Bool_RetryConfig.swift +12 -0
- package/nitrogen/generated/ios/swift/Variant_NullType_Double.swift +12 -0
- package/nitrogen/generated/ios/swift/Variant_NullType_RemoteButtonLayout.swift +30 -0
- package/nitrogen/generated/ios/swift/Variant_ResolvedTrack_BrowseError_Promise_BrowseResult_.swift +13 -0
- package/nitrogen/generated/ios/swift/Variant_String_ArtworkVariants.swift +12 -0
- package/nitrogen/generated/shared/c++/AndroidOptions.hpp +8 -8
- 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++/CardImage.hpp +76 -0
- package/nitrogen/generated/shared/c++/FormatNavigationErrorParams.hpp +9 -2
- package/nitrogen/generated/shared/c++/GridTile.hpp +84 -0
- package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/IOSOptions.hpp +9 -2
- package/nitrogen/generated/shared/c++/ImageShape.hpp +76 -0
- package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +10 -6
- package/nitrogen/generated/shared/c++/NavigationErrorKind.hpp +76 -0
- package/nitrogen/generated/shared/c++/NitroAndroidUpdateOptions.hpp +8 -8
- package/nitrogen/generated/shared/c++/NitroIOSUpdateOptions.hpp +9 -2
- package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +6 -9
- package/nitrogen/generated/shared/c++/{NotificationButton.hpp → RemoteButton.hpp} +19 -19
- package/nitrogen/generated/shared/c++/RemoteButtonLayout.hpp +94 -0
- package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +33 -37
- package/nitrogen/generated/shared/c++/Section.hpp +102 -0
- package/nitrogen/generated/shared/c++/SectionStyle.hpp +126 -0
- package/nitrogen/generated/shared/c++/StyleDisplay.hpp +76 -0
- package/nitrogen/generated/shared/c++/Track.hpp +18 -30
- package/nitrogen/generated/shared/c++/TrackStyle.hpp +73 -34
- package/package.json +24 -11
- package/src/AudioBrowser.ts +2 -1
- package/src/CLAUDE.md +52 -0
- package/src/features/battery.test.ts +79 -0
- package/src/features/browser-config.test.ts +21 -6
- package/src/features/browser-config.ts +12 -8
- package/src/features/browser.test.ts +1 -1
- package/src/features/browser.ts +11 -3
- package/src/features/carConnection.ts +1 -1
- package/src/features/equalizer.ts +1 -1
- package/src/features/errors.ts +3 -3
- package/src/features/favorites.ts +14 -11
- package/src/features/gate.ts +16 -1
- package/src/features/hook-wiring.test.ts +302 -0
- package/src/features/metadata.ts +20 -3
- package/src/features/network.ts +1 -1
- package/src/features/nowPlaying.ts +1 -1
- package/src/features/output.ts +1 -1
- package/src/features/playback/controls.ts +4 -2
- package/src/features/playback/playWhenReady.ts +1 -1
- package/src/features/playback/playing.ts +1 -1
- package/src/features/playback/progress.test.ts +169 -0
- package/src/features/playback/progress.ts +3 -2
- package/src/features/playback/rate.ts +8 -1
- package/src/features/playback/state.ts +3 -4
- package/src/features/playback/trackPlaybackTime.test.ts +16 -6
- package/src/features/playback/trackPlaybackTime.ts +1 -6
- package/src/features/playback/volume.ts +1 -1
- package/src/features/player/options.ts +126 -76
- package/src/features/player/setup.test.ts +24 -7
- package/src/features/player/setup.ts +22 -10
- package/src/features/player/validateOptions.ts +21 -0
- package/src/features/queue/activeTrack.ts +15 -4
- package/src/features/queue/queue.ts +13 -6
- package/src/features/queue/repeatMode.ts +1 -1
- package/src/features/queue/shuffle.ts +1 -1
- package/src/features/remoteControls.ts +13 -92
- package/src/features/sleepTimer.test.ts +172 -0
- package/src/features/sleepTimer.ts +9 -1
- package/src/nitro-stub-drift.test.ts +277 -0
- package/src/public-surface.test.ts +147 -0
- package/src/specs/audio-browser.nitro.ts +5 -4
- package/src/style-resolution.test.ts +210 -0
- package/src/test-utils/reactNativeStub.ts +60 -0
- package/src/types/browser-native.ts +7 -3
- package/src/types/browser-nodes.ts +403 -134
- package/src/types/browser.ts +97 -63
- package/src/utils/LazyNativeEmitter.ts +28 -15
- package/src/utils/NativeUpdatedValue.ts +29 -13
- package/src/utils/getTrackIdentity.ts +20 -0
- package/src/utils/useDebug.test.ts +182 -0
- package/src/utils/useNativeUpdatedValue.test.ts +103 -0
- package/src/utils/useNativeValueRefreshedBy.ts +38 -0
- package/src/web/NativeAudioBrowser.playWhenReady.test.ts +232 -2
- package/src/web/NativeAudioBrowser.ts +240 -83
- package/src/web/TrackPlayer/LoadAttempt.ts +29 -0
- package/src/web/TrackPlayer/PlaybackStateMachine.test.ts +60 -13
- package/src/web/TrackPlayer/PlaybackStateMachine.ts +22 -6
- package/src/web/TrackPlayer/Player.dispatch.test.ts +5 -3
- package/src/web/TrackPlayer/Player.load.test.ts +137 -1
- package/src/web/TrackPlayer/Player.ts +284 -37
- package/src/web/TrackPlayer/PlayingStateFactory.test.ts +1 -1
- package/src/web/TrackPlayer/PlayingStateFactory.ts +1 -1
- package/src/web/TrackPlayer/QueueManager.test.ts +29 -0
- package/src/web/TrackPlayer/QueueManager.ts +14 -0
- package/src/web/TrackPlayer/QueuePlayer.ts +33 -14
- package/src/web/__tests__/lifecycle.test.ts +345 -0
- package/src/web/__tests__/lifecycleHarness.ts +351 -0
- package/src/web/__tests__/loadEdgeCases.test.ts +246 -0
- package/src/web/__tests__/loadSupersession.test.ts +175 -0
- package/src/web/__tests__/retry.test.ts +169 -0
- package/src/web/browser/BrowserManager.ts +209 -111
- package/src/web/browser/FavoriteManager.test.ts +84 -0
- package/src/web/browser/FavoriteManager.ts +28 -23
- package/src/web/browser/NavigationErrorManager.ts +3 -1
- package/src/web/browser/SearchManager.test.ts +75 -0
- package/src/web/browser/SearchManager.ts +25 -28
- package/src/web/browser/__tests__/artwork-resolution.test.ts +117 -0
- package/src/web/browser/__tests__/layer-resolver.test.ts +35 -0
- package/src/web/browser/__tests__/search-artwork.test.ts +46 -0
- package/src/web/browser/__tests__/search-navigation.test.ts +76 -0
- 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/http/RequestConfigBuilder.test.ts +241 -1
- package/src/web/http/RequestConfigBuilder.ts +140 -33
- package/src/web/http/followMediaRedirect.test.ts +289 -0
- package/src/web/http/followMediaRedirect.ts +253 -0
- package/src/web/player/NowPlayingManager.ts +4 -3
- package/src/web/util/BrowserPathHelper.test.ts +68 -0
- package/src/web/util/BrowserPathHelper.ts +70 -13
- package/website/guide/android-auto.md +114 -0
- package/website/guide/android-certificates.md +409 -0
- package/website/guide/artwork.md +255 -0
- package/website/guide/audio-output.md +135 -0
- package/website/guide/automotive.md +86 -0
- package/website/guide/basic-usage.md +151 -0
- package/website/guide/battery.md +115 -0
- package/website/guide/browser.md +587 -0
- package/website/guide/carplay.md +650 -0
- package/website/guide/configuration.md +173 -0
- package/website/guide/equalizer.md +231 -0
- package/website/guide/errors.md +310 -0
- package/website/guide/favorites.md +154 -0
- package/website/guide/gate.md +143 -0
- package/website/guide/getting-started.md +46 -0
- package/website/guide/hooks.md +238 -0
- package/website/guide/live-streams.md +125 -0
- package/website/guide/metadata.md +239 -0
- package/website/guide/migrating-from-track-player.md +244 -0
- package/website/guide/native-callback-fetch.md +127 -0
- package/website/guide/network.md +86 -0
- package/website/guide/now-playing.md +175 -0
- package/website/guide/playback.md +328 -0
- package/website/guide/queue.md +300 -0
- package/website/guide/remote-controls.md +256 -0
- package/website/guide/search.md +255 -0
- package/website/guide/sleep-timer.md +268 -0
- package/website/guide/track.md +247 -0
- package/ios/Bridge.h +0 -8
- package/ios/Browser/MediaResolveComposer.swift +0 -114
- package/ios/CarPlay/ImageRowItem+CarPlay.swift +0 -19
- package/ios/Model/MediaURL.swift +0 -67
- package/ios/NowPlayingInfo/MediaItemProperty.swift +0 -78
- package/ios/NowPlayingInfo/NowPlayingInfoKeyValue.swift +0 -6
- package/ios/NowPlayingInfo/NowPlayingInfoProperty.swift +0 -220
- package/ios/Observer/PlayerItemNotificationObserver.swift +0 -119
- package/ios/Observer/PlayerItemPropertyObserver.swift +0 -133
- package/ios/Observer/PlayerStateObserver.swift +0 -50
- package/ios/Observer/PlayerTimeObserver.swift +0 -55
- package/ios/Option/PitchAlgorithms.swift +0 -17
- package/ios/Option/TimeEventFrequency.swift +0 -18
- package/ios/Player/LoadSeekCoordinator.swift +0 -99
- package/ios/Player/MediaLoaderDelegate.swift +0 -11
- package/ios/Player/PlaybackCoordinator.swift +0 -754
- package/ios/Player/PlaybackEffectHandler.swift +0 -54
- package/ios/Player/PlaybackErrorHandler.swift +0 -175
- package/ios/Player/PlaybackStateStore.swift +0 -27
- package/ios/Player/PlayingStateManager.swift +0 -33
- package/ios/Player/RetryManager.swift +0 -322
- package/ios/Player/SeekCompletionHandler.swift +0 -3
- package/ios/Player/SleepTimerHandling.swift +0 -15
- package/ios/Support/RNTrackPlayer-Bridging-Header.h +0 -7
- package/ios/Tests/LoadSeekCoordinatorTests.swift +0 -325
- package/ios/Tests/MediaResolveTests.swift +0 -126
- package/ios/Tests/OnceValueTests.swift +0 -79
- package/ios/Tests/PlaybackErrorHandlerTests.swift +0 -547
- package/ios/Tests/PlaybackStateStoreTests.swift +0 -48
- package/ios/Tests/PlayingStateManagerTests.swift +0 -57
- package/ios/Tests/RetryManagerTests.swift +0 -89
- package/ios/TrackPlayer.swift +0 -1014
- package/ios/TrackPlayerCallbacks.swift +0 -86
- package/ios/Util/MetadataAdapter.swift +0 -131
- package/ios/Util/OnceValue.swift +0 -104
- package/nitrogen/generated/android/c++/JFavoriteConfig.hpp +0 -58
- package/nitrogen/generated/android/c++/JFavoritesMatchMode.hpp +0 -58
- package/nitrogen/generated/android/c++/JImageRowItem.hpp +0 -105
- package/nitrogen/generated/android/c++/JNotificationButtonLayout.hpp +0 -94
- 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/c++/JVariant_NullType_NotificationButtonLayout.cpp +0 -26
- package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.hpp +0 -75
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FavoriteConfig.kt +0 -38
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +0 -68
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButtonLayout.kt +0 -50
- 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/NotificationButtonLayout.swift +0 -92
- package/nitrogen/generated/ios/swift/Variant_Bool_FavoriteConfig.swift +0 -18
- package/nitrogen/generated/ios/swift/Variant_NullType_NotificationButtonLayout.swift +0 -18
- package/nitrogen/generated/shared/c++/FavoriteConfig.hpp +0 -84
- package/nitrogen/generated/shared/c++/ImageRowItem.hpp +0 -129
- package/nitrogen/generated/shared/c++/NotificationButtonLayout.hpp +0 -102
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
package com.audiobrowser.browser
|
|
2
2
|
|
|
3
|
-
import com.audiobrowser.util.artworkOf
|
|
4
|
-
|
|
5
3
|
import android.util.LruCache
|
|
4
|
+
import androidx.media3.common.C
|
|
6
5
|
import androidx.media3.common.MediaItem
|
|
7
6
|
import androidx.media3.session.MediaSession
|
|
7
|
+
import com.audiobrowser.extension.identity
|
|
8
8
|
import com.audiobrowser.http.HttpClient
|
|
9
9
|
import com.audiobrowser.http.RequestConfigBuilder
|
|
10
10
|
import com.audiobrowser.util.BrowserPathHelper
|
|
11
11
|
import com.audiobrowser.util.TrackFactory
|
|
12
|
+
import com.audiobrowser.util.artworkOf
|
|
12
13
|
import com.margelo.nitro.audiobrowser.ArtworkRequestConfig
|
|
13
14
|
import com.margelo.nitro.audiobrowser.BrowserSourceCallbackParam
|
|
14
|
-
import com.margelo.nitro.audiobrowser.FavoritesMatchMode
|
|
15
15
|
import com.margelo.nitro.audiobrowser.Func_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____
|
|
16
16
|
import com.margelo.nitro.audiobrowser.ImageContext
|
|
17
17
|
import com.margelo.nitro.audiobrowser.MediaReference
|
|
@@ -20,8 +20,11 @@ import com.margelo.nitro.audiobrowser.NativeRouteEntry
|
|
|
20
20
|
import com.margelo.nitro.audiobrowser.RequestConfig
|
|
21
21
|
import com.margelo.nitro.audiobrowser.ResolvedTrack
|
|
22
22
|
import com.margelo.nitro.audiobrowser.SearchParams
|
|
23
|
+
import com.margelo.nitro.audiobrowser.Section
|
|
24
|
+
import com.margelo.nitro.audiobrowser.StyleDisplay
|
|
23
25
|
import com.margelo.nitro.audiobrowser.Track
|
|
24
26
|
import com.margelo.nitro.audiobrowser.TransformableRequestConfig
|
|
27
|
+
import com.margelo.nitro.core.Promise
|
|
25
28
|
import kotlinx.coroutines.Dispatchers
|
|
26
29
|
import kotlinx.coroutines.async
|
|
27
30
|
import kotlinx.coroutines.awaitAll
|
|
@@ -83,7 +86,7 @@ class BrowserManager {
|
|
|
83
86
|
}
|
|
84
87
|
}
|
|
85
88
|
|
|
86
|
-
// LRU cache for individual tracks - keyed by both
|
|
89
|
+
// LRU cache for individual tracks - keyed by both path and src for O(1) lookup
|
|
87
90
|
private val trackCache = LruCache<String, Track>(3000)
|
|
88
91
|
|
|
89
92
|
// LRU cache for resolved content - keyed by path
|
|
@@ -95,12 +98,12 @@ class BrowserManager {
|
|
|
95
98
|
// concurrent reader never sees one query matched with another query's results.
|
|
96
99
|
@Volatile private var lastSearch: Pair<String, Array<Track>>? = null
|
|
97
100
|
|
|
98
|
-
// Set of favorited track
|
|
101
|
+
// Set of favorited track identities (id when non-blank, else src — see Track.identity)
|
|
99
102
|
private var favoriteIds = setOf<String>()
|
|
100
103
|
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
private var
|
|
104
|
+
// Whether favoriting is enabled, propagated from the player's `favorite` capability.
|
|
105
|
+
// false = favoriting disabled (no row hearts). Set via setFavoriteEnabled.
|
|
106
|
+
private var favoriteEnabled: Boolean = false
|
|
104
107
|
|
|
105
108
|
// Navigation tracking to prevent race conditions
|
|
106
109
|
@Volatile private var currentNavigationId = 0
|
|
@@ -131,6 +134,12 @@ class BrowserManager {
|
|
|
131
134
|
private var resolvedRequestLayer: TransformableRequestConfig? = null
|
|
132
135
|
private var resolvedBrowseLayer: TransformableRequestConfig? = null
|
|
133
136
|
|
|
137
|
+
// The "view more" row title, cached on the same generation as the layers above — see
|
|
138
|
+
// viewMoreTitle(). Kept separate from them because it is resolved lazily (only a browse that
|
|
139
|
+
// actually appends a row asks for it), not eagerly alongside every request.
|
|
140
|
+
private var resolvedViewMoreTitleGeneration = -1
|
|
141
|
+
private var resolvedViewMoreTitle = DEFAULT_VIEW_MORE_TITLE
|
|
142
|
+
|
|
134
143
|
/** Test-only accessors for the resolver-layer cache state (see ensureLayersResolved). */
|
|
135
144
|
internal val layerGenerationForTest: Int
|
|
136
145
|
get() = layerGeneration
|
|
@@ -151,8 +160,8 @@ class BrowserManager {
|
|
|
151
160
|
val artworkResolutions = ArtworkResolutionRegistry()
|
|
152
161
|
|
|
153
162
|
/**
|
|
154
|
-
* Sets the favorited track
|
|
155
|
-
* this list during browsing.
|
|
163
|
+
* Sets the favorited track identities (id when non-blank, else src). Tracks will have their
|
|
164
|
+
* favorited field hydrated based on this list during browsing.
|
|
156
165
|
*/
|
|
157
166
|
fun setFavorites(favorites: List<String>) {
|
|
158
167
|
favoriteIds = favorites.toSet()
|
|
@@ -160,97 +169,125 @@ class BrowserManager {
|
|
|
160
169
|
}
|
|
161
170
|
|
|
162
171
|
/**
|
|
163
|
-
*
|
|
172
|
+
* Enables or disables favoriting (propagated from the `favorite` capability). false disables
|
|
164
173
|
* row-heart hydration.
|
|
165
174
|
*/
|
|
166
|
-
fun
|
|
167
|
-
|
|
175
|
+
fun setFavoriteEnabled(enabled: Boolean) {
|
|
176
|
+
favoriteEnabled = enabled
|
|
168
177
|
}
|
|
169
178
|
|
|
170
179
|
/**
|
|
171
|
-
* Updates the favorite state for a single track
|
|
172
|
-
* tapped in media controllers.
|
|
180
|
+
* Updates the favorite state for a single track identity (id when non-blank, else src). Called
|
|
181
|
+
* when the heart button is tapped in media controllers.
|
|
173
182
|
*/
|
|
174
|
-
fun updateFavorite(
|
|
183
|
+
fun updateFavorite(identity: String, favorited: Boolean) {
|
|
175
184
|
favoriteIds =
|
|
176
185
|
if (favorited) {
|
|
177
|
-
favoriteIds +
|
|
186
|
+
favoriteIds + identity
|
|
178
187
|
} else {
|
|
179
|
-
favoriteIds -
|
|
188
|
+
favoriteIds - identity
|
|
180
189
|
}
|
|
181
|
-
Timber.d("Updated favorite for '$
|
|
190
|
+
Timber.d("Updated favorite for '$identity' to $favorited (total: ${favoriteIds.size})")
|
|
182
191
|
}
|
|
183
192
|
|
|
184
193
|
/**
|
|
185
194
|
* Hydrates the favorited field on a track based on the favoriteIds set. No-op unless favoriting
|
|
186
|
-
* is enabled (the `favorite` capability). Only
|
|
187
|
-
* flag is set to true OR false so non-favorited tracks still show an (empty)
|
|
188
|
-
* overwrite API-provided values.
|
|
195
|
+
* is enabled (the `favorite` capability). Only tracks with an identity (id or src) are
|
|
196
|
+
* favoritable; the flag is set to true OR false so non-favorited tracks still show an (empty)
|
|
197
|
+
* heart. Doesn't overwrite API-provided values.
|
|
189
198
|
*/
|
|
190
199
|
private fun hydrateFavorite(track: Track): Track {
|
|
191
|
-
|
|
200
|
+
if (!favoriteEnabled) return track
|
|
192
201
|
// Don't overwrite API-provided favorites
|
|
193
202
|
if (track.favorited != null) return track
|
|
194
|
-
// Only
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
val isFavorited = isFavorite(src, match)
|
|
203
|
+
// Only identity-bearing tracks are favoritable
|
|
204
|
+
if (track.identity == null) return track
|
|
198
205
|
|
|
199
|
-
return track.copy(favorited =
|
|
206
|
+
return track.copy(favorited = isFavorite(track))
|
|
200
207
|
}
|
|
201
208
|
|
|
202
|
-
/** Whether [
|
|
203
|
-
private fun isFavorite(
|
|
204
|
-
|
|
205
|
-
FavoritesMatchMode.EXACT -> favoriteIds.contains(src)
|
|
206
|
-
FavoritesMatchMode.PARTIAL -> favoriteIds.any { BrowserPathHelper.containsSegment(src, it) }
|
|
207
|
-
}
|
|
209
|
+
/** Whether [track]'s identity is in the favorites set. */
|
|
210
|
+
private fun isFavorite(track: Track): Boolean =
|
|
211
|
+
track.identity?.let { favoriteIds.contains(it) } == true
|
|
208
212
|
|
|
209
|
-
/**
|
|
213
|
+
/**
|
|
214
|
+
* Hydrates favorites on all tracks of a resolved page. Pages reach hydration normalized (ADR
|
|
215
|
+
* 0010), so `sections` is the only structure to walk.
|
|
216
|
+
*/
|
|
210
217
|
private fun hydrateChildren(resolvedTrack: ResolvedTrack): ResolvedTrack {
|
|
211
|
-
val
|
|
212
|
-
|
|
213
|
-
|
|
218
|
+
val sections = resolvedTrack.sections ?: return resolvedTrack
|
|
219
|
+
return resolvedTrack.copy(
|
|
220
|
+
sections =
|
|
221
|
+
sections
|
|
222
|
+
.map { section ->
|
|
223
|
+
section.copy(children = section.children.map { hydrateFavorite(it) }.toTypedArray())
|
|
224
|
+
}
|
|
225
|
+
.toTypedArray()
|
|
226
|
+
)
|
|
214
227
|
}
|
|
215
228
|
|
|
216
|
-
/** Cache a track by id,
|
|
229
|
+
/** Cache a track by id, path, and src for O(1) lookup from any mediaId form. */
|
|
217
230
|
private fun cacheTrack(track: Track) {
|
|
218
231
|
track.id?.takeUnless { it.isBlank() }?.let { trackCache.put(it, track) }
|
|
219
|
-
track.
|
|
232
|
+
track.path?.let { trackCache.put(it, track) }
|
|
220
233
|
track.src?.let { trackCache.put(it, track) }
|
|
221
234
|
}
|
|
222
235
|
|
|
223
236
|
private fun cacheChildren(resolvedTrack: ResolvedTrack) {
|
|
224
|
-
resolvedTrack.
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
237
|
+
resolvedTrack.flattenedChildren?.forEach { cacheTrack(it) }
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Pages already warned about by warnIfGridPageLacksPromise — the mismatch
|
|
241
|
+
// re-observes on every onGetChildren serve, and once is a diagnostic while
|
|
242
|
+
// every-scroll is noise. Concurrent: onGetChildren serves run on the IO
|
|
243
|
+
// pool, several in flight at once.
|
|
244
|
+
private val promiseWarnedPaths = java.util.concurrent.ConcurrentHashMap.newKeySet<String>()
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Dev diagnostic (ADR 0011): a page serving grid sections under a browsable handle that declared
|
|
248
|
+
* no `style.display` promise still renders its parent-level layout as a list on Android Auto —
|
|
249
|
+
* the parent hint is emitted only when declared, never derived from resolved pages and never
|
|
250
|
+
* back-filled. Warns at the one site where the mismatch is observable; a cache miss for the
|
|
251
|
+
* handle (cold start straight into the page) just skips the check.
|
|
252
|
+
*
|
|
253
|
+
* Only an all-grid page warns: the parent-level hint lays out the WHOLE page, so on a mixed page
|
|
254
|
+
* (a teaser shelf above list sections) there is no correct promise to advise — grid would tile
|
|
255
|
+
* the list sections too.
|
|
256
|
+
*/
|
|
257
|
+
fun warnIfGridPageLacksPromise(path: String, sections: List<Section>) {
|
|
258
|
+
if (sections.isEmpty() || !sections.all { it.style?.display == StyleDisplay.GRID }) return
|
|
259
|
+
val handle = trackCache.get(path) ?: return
|
|
260
|
+
if (handle.src != null) return // rendered playable — opens no page, promises nothing
|
|
261
|
+
if (handle.style?.display == null && promiseWarnedPaths.add(path)) {
|
|
262
|
+
Timber.w(
|
|
263
|
+
"Page '%s' serves grid sections, but its browsable handle declares no style.display — " +
|
|
264
|
+
"Android Auto's parent-level hint was not emitted, so this page renders as a list " +
|
|
265
|
+
"there. Declare `style: { display: 'grid' }` on the handle track.",
|
|
266
|
+
path,
|
|
267
|
+
)
|
|
232
268
|
}
|
|
233
269
|
}
|
|
234
270
|
|
|
235
271
|
/**
|
|
236
|
-
* Get a cached Track by mediaId (stable id,
|
|
272
|
+
* Get a cached Track by mediaId (stable id, path, or src), or null if not cached. Used by Media3
|
|
237
273
|
* to rehydrate MediaItem shells with full track metadata. Re-hydrates favorites in case
|
|
238
274
|
* setFavoriteStates was called after caching.
|
|
239
275
|
*/
|
|
240
276
|
fun getCachedTrack(mediaId: String): Track? {
|
|
241
|
-
// Try direct lookup first (matches
|
|
277
|
+
// Try direct lookup first (matches path or src)
|
|
242
278
|
trackCache.get(mediaId)?.let { track ->
|
|
243
279
|
val hydratedTrack = hydrateFavorite(track)
|
|
244
280
|
Timber.d("Cache HIT for mediaId='$mediaId' → '${track.title}'")
|
|
245
281
|
return hydratedTrack
|
|
246
282
|
}
|
|
247
283
|
|
|
248
|
-
// Try extracting src from contextual
|
|
284
|
+
// Try extracting the track identity (id when non-blank, else src) from a contextual path —
|
|
285
|
+
// the cache is keyed by id AND src, so either identity form resolves.
|
|
249
286
|
val trackId = BrowserPathHelper.extractTrackId(mediaId)
|
|
250
287
|
if (trackId != null) {
|
|
251
288
|
trackCache.get(trackId)?.let { track ->
|
|
252
289
|
val hydratedTrack = hydrateFavorite(track)
|
|
253
|
-
Timber.d("Cache HIT (extracted
|
|
290
|
+
Timber.d("Cache HIT (extracted identity) for mediaId='$mediaId' → '${track.title}'")
|
|
254
291
|
return hydratedTrack
|
|
255
292
|
}
|
|
256
293
|
}
|
|
@@ -260,19 +297,19 @@ class BrowserManager {
|
|
|
260
297
|
}
|
|
261
298
|
|
|
262
299
|
/**
|
|
263
|
-
* Resolves a tapped mediaId to the contextual
|
|
300
|
+
* Resolves a tapped mediaId to the contextual path to expand a queue from, or null when there is
|
|
264
301
|
* none. A contextual mediaId is its own; a stable-id mediaId (see TrackFactory.buildMediaItem)
|
|
265
|
-
* resolves through the track cache to the contextual
|
|
302
|
+
* resolves through the track cache to the contextual path of the container it was most recently
|
|
266
303
|
* browsed in — a legacy car controller round-trips only the mediaId, so the cache is what
|
|
267
304
|
* remembers which list the row came from.
|
|
268
305
|
*/
|
|
269
|
-
fun
|
|
306
|
+
fun contextualPathFor(mediaId: String): String? {
|
|
270
307
|
if (BrowserPathHelper.isContextual(mediaId)) return mediaId
|
|
271
|
-
return getCachedTrack(mediaId)?.
|
|
308
|
+
return getCachedTrack(mediaId)?.path?.takeIf { BrowserPathHelper.isContextual(it) }
|
|
272
309
|
}
|
|
273
310
|
|
|
274
311
|
/**
|
|
275
|
-
* Resolves a single Media3 MediaItem to a Track. Prefers the track cache (keyed by id,
|
|
312
|
+
* Resolves a single Media3 MediaItem to a Track. Prefers the track cache (keyed by id, path, and
|
|
276
313
|
* src).
|
|
277
314
|
*
|
|
278
315
|
* A cache miss is legitimately reachable: a controller can replay a mediaId this process never
|
|
@@ -305,26 +342,24 @@ class BrowserManager {
|
|
|
305
342
|
// A mediaId distinct from the playable uri is the track's stable id —
|
|
306
343
|
// keep it so the item's identity (car now-playing row match) survives.
|
|
307
344
|
id = mediaId.takeIf { it != fallbackSrc },
|
|
308
|
-
|
|
345
|
+
path = null,
|
|
309
346
|
src = fallbackSrc,
|
|
310
347
|
artwork = artworkOf(metadata.artworkUri?.toString()),
|
|
311
348
|
artworkSource = null,
|
|
312
349
|
request = null,
|
|
313
|
-
artworkCarPlayTinted = null,
|
|
314
350
|
title = metadata.title?.toString() ?: mediaId,
|
|
315
351
|
subtitle = metadata.artist?.toString(),
|
|
316
352
|
artist = null,
|
|
317
|
-
|
|
353
|
+
albumPath = null,
|
|
318
354
|
album = metadata.albumTitle?.toString(),
|
|
319
355
|
description = metadata.description?.toString(),
|
|
320
356
|
genre = metadata.genre?.toString(),
|
|
321
357
|
duration = null,
|
|
322
358
|
style = null,
|
|
323
|
-
|
|
359
|
+
disabled = null,
|
|
324
360
|
favorited = null,
|
|
325
|
-
groupTitle = null,
|
|
326
361
|
live = null,
|
|
327
|
-
|
|
362
|
+
icyCharset = null,
|
|
328
363
|
)
|
|
329
364
|
)
|
|
330
365
|
}
|
|
@@ -362,17 +397,19 @@ class BrowserManager {
|
|
|
362
397
|
if (searchQuery != null) {
|
|
363
398
|
Timber.d("Handling search playback request for query: $searchQuery")
|
|
364
399
|
|
|
365
|
-
// Execute search (will hit cache if already performed)
|
|
400
|
+
// Execute search (will hit cache if already performed). Disabled
|
|
401
|
+
// tracks never play, so they never enter a search-built queue.
|
|
366
402
|
val searchResults = search(searchQuery)
|
|
367
|
-
val searchTracks =
|
|
403
|
+
val searchTracks =
|
|
404
|
+
searchResults.flattenedChildren?.filterNot { it.disabled == true }?.toTypedArray()
|
|
368
405
|
|
|
369
406
|
if (searchTracks != null && searchTracks.isNotEmpty()) {
|
|
370
407
|
// Find the selected track in search results (mediaId is the stable id
|
|
371
|
-
// when the track has one, else
|
|
408
|
+
// when the track has one, else path/src — see TrackFactory)
|
|
372
409
|
val mediaId = mediaItem.mediaId
|
|
373
410
|
val selectedIndex =
|
|
374
411
|
searchTracks.indexOfFirst { track ->
|
|
375
|
-
track.id == mediaId || track.
|
|
412
|
+
track.id == mediaId || track.path == mediaId || track.src == mediaId
|
|
376
413
|
}
|
|
377
414
|
|
|
378
415
|
if (selectedIndex >= 0) {
|
|
@@ -399,12 +436,12 @@ class BrowserManager {
|
|
|
399
436
|
val mediaId = mediaItems[0].mediaId
|
|
400
437
|
// A failed search match falls through to plain resolution, never to browse
|
|
401
438
|
// expansion — the user asked for that one result, not a browsed list.
|
|
402
|
-
val
|
|
439
|
+
val contextualPath = if (searchQuery == null) contextualPathFor(mediaId) else null
|
|
403
440
|
|
|
404
|
-
if (
|
|
405
|
-
Timber.d("Attempting queue expansion for mediaId='$mediaId' via '$
|
|
441
|
+
if (contextualPath != null) {
|
|
442
|
+
Timber.d("Attempting queue expansion for mediaId='$mediaId' via '$contextualPath'")
|
|
406
443
|
|
|
407
|
-
val expanded =
|
|
444
|
+
val expanded = expandQueueFromContextualPath(contextualPath)
|
|
408
445
|
|
|
409
446
|
if (expanded != null) {
|
|
410
447
|
val (tracks, selectedIndex) = expanded
|
|
@@ -424,20 +461,56 @@ class BrowserManager {
|
|
|
424
461
|
// No expansion - resolve from cache (with a minimal-track fallback for replayed mediaIds)
|
|
425
462
|
val resolvedTracks = mediaItems.map { resolveMediaItemToTrack(it) }
|
|
426
463
|
|
|
464
|
+
// A disabled track is unavailable — it never plays, even by a stale or
|
|
465
|
+
// replayed mediaId (Track.disabled). Refusal fails the future: Media3
|
|
466
|
+
// surfaces an error to the controller and the current playback stays
|
|
467
|
+
// untouched (an empty item list would clear the live timeline instead).
|
|
468
|
+
//
|
|
469
|
+
// Media3's legacy path — how Android Auto and Assistant actually request
|
|
470
|
+
// playback (onPlayFromMediaId et al.) — passes C.INDEX_UNSET, meaning
|
|
471
|
+
// "the default item", i.e. the first. Normalize before the guard, or the
|
|
472
|
+
// refusal is dead on exactly the path that serves cars.
|
|
473
|
+
val effectiveStartIndex = if (startIndex == C.INDEX_UNSET) 0 else startIndex
|
|
474
|
+
val startTrack = resolvedTracks.getOrNull(effectiveStartIndex)
|
|
475
|
+
if (startTrack != null && startTrack.disabled == true) {
|
|
476
|
+
Timber.w("Refusing playback of disabled track: ${startTrack.title}")
|
|
477
|
+
throw IllegalStateException("Refusing playback of disabled track: ${startTrack.title}")
|
|
478
|
+
}
|
|
479
|
+
val playableTracks = resolvedTracks.filterNot { it.disabled == true }
|
|
480
|
+
if (playableTracks.isEmpty()) {
|
|
481
|
+
// Belt over the start-item guard: never hand Media3 an empty timeline.
|
|
482
|
+
Timber.w("Refusing playback: every requested track is disabled")
|
|
483
|
+
throw IllegalStateException("Refusing playback: every requested track is disabled")
|
|
484
|
+
}
|
|
485
|
+
// Positional, not indexOf: value equality would alias a duplicated track
|
|
486
|
+
// (the same station twice in a queue) to its first copy. An unset index
|
|
487
|
+
// stays unset — Media3's "default item" semantics pass through as they
|
|
488
|
+
// did before the filter existed.
|
|
489
|
+
val adjustedStartIndex =
|
|
490
|
+
when {
|
|
491
|
+
startIndex == C.INDEX_UNSET -> C.INDEX_UNSET
|
|
492
|
+
startTrack == null -> 0
|
|
493
|
+
else -> resolvedTracks.take(effectiveStartIndex).count { it.disabled != true }
|
|
494
|
+
}
|
|
495
|
+
|
|
427
496
|
// Convert to Media3 MediaItems
|
|
428
|
-
val resolvedMediaItems =
|
|
497
|
+
val resolvedMediaItems = playableTracks.map { track -> TrackFactory.toMedia3(track) }
|
|
429
498
|
|
|
430
|
-
return MediaSession.MediaItemsWithStartPosition(
|
|
499
|
+
return MediaSession.MediaItemsWithStartPosition(
|
|
500
|
+
resolvedMediaItems,
|
|
501
|
+
adjustedStartIndex,
|
|
502
|
+
startPositionMs,
|
|
503
|
+
)
|
|
431
504
|
}
|
|
432
505
|
|
|
433
506
|
/**
|
|
434
|
-
* Validates that a track has either
|
|
507
|
+
* Validates that a track has either path or src for stable identification. Throws
|
|
435
508
|
* IllegalStateException if validation fails.
|
|
436
509
|
*/
|
|
437
510
|
private fun validateTrack(track: Track, context: String) {
|
|
438
|
-
if (track.
|
|
511
|
+
if (track.path == null && track.src == null) {
|
|
439
512
|
throw IllegalStateException(
|
|
440
|
-
"$context must have either '
|
|
513
|
+
"$context must have either 'path' or 'src' property for stable identification. Track: ${track.title}"
|
|
441
514
|
)
|
|
442
515
|
}
|
|
443
516
|
}
|
|
@@ -445,12 +518,12 @@ class BrowserManager {
|
|
|
445
518
|
suspend fun resolve(path: String, useCache: Boolean = true): ResolvedTrack {
|
|
446
519
|
Timber.d("=== RESOLVE: path='$path' (useCache=$useCache) ===")
|
|
447
520
|
|
|
448
|
-
// Strip __trackId from contextual
|
|
521
|
+
// Strip __trackId from contextual paths (e.g., "/library/radio?__trackId=song.mp3" →
|
|
449
522
|
// "/library/radio")
|
|
450
|
-
// This allows resolving the parent container for tracks referenced by contextual
|
|
523
|
+
// This allows resolving the parent container for tracks referenced by contextual path
|
|
451
524
|
val normalizedPath = BrowserPathHelper.stripTrackId(path)
|
|
452
525
|
if (normalizedPath != path) {
|
|
453
|
-
Timber.d("Stripped __trackId from contextual
|
|
526
|
+
Timber.d("Stripped __trackId from contextual path: '$normalizedPath'")
|
|
454
527
|
}
|
|
455
528
|
|
|
456
529
|
// Check content cache first
|
|
@@ -458,7 +531,7 @@ class BrowserManager {
|
|
|
458
531
|
contentCache.get(normalizedPath)?.let { cached ->
|
|
459
532
|
Timber.d("Content cache HIT for path='$normalizedPath'")
|
|
460
533
|
// Re-key the track cache even on a hit: an id-keyed lookup (stable-id
|
|
461
|
-
// mediaId → contextual
|
|
534
|
+
// mediaId → contextual path, see contextualPathFor) must reflect the
|
|
462
535
|
// most recently *browsed* container, which a cached re-display
|
|
463
536
|
// otherwise wouldn't re-register.
|
|
464
537
|
cacheChildren(cached)
|
|
@@ -484,11 +557,11 @@ class BrowserManager {
|
|
|
484
557
|
* (e.g., via notifyContentChanged).
|
|
485
558
|
*
|
|
486
559
|
* @param path The container path to invalidate (e.g., "/library/radio")
|
|
487
|
-
* @throws IllegalArgumentException if passed a contextual
|
|
560
|
+
* @throws IllegalArgumentException if passed a contextual path (contains __trackId)
|
|
488
561
|
*/
|
|
489
562
|
fun invalidateContentCache(path: String) {
|
|
490
563
|
require(!BrowserPathHelper.isContextual(path)) {
|
|
491
|
-
"invalidateContentCache() expects a container path, not a contextual
|
|
564
|
+
"invalidateContentCache() expects a container path, not a contextual path: $path"
|
|
492
565
|
}
|
|
493
566
|
contentCache.remove(path)
|
|
494
567
|
Timber.d("Invalidated content cache for path='$path'")
|
|
@@ -497,6 +570,10 @@ class BrowserManager {
|
|
|
497
570
|
/** Clears all cached content. */
|
|
498
571
|
fun clearContentCache() {
|
|
499
572
|
contentCache.evictAll()
|
|
573
|
+
// The search slot is content too: a locale switch or a re-auth changes titles, src, artwork
|
|
574
|
+
// and availability, and nothing else ever evicts it, so a repeated query returned
|
|
575
|
+
// pre-invalidation results forever. (Matches the Swift twin's clearContentCache.)
|
|
576
|
+
lastSearch = null
|
|
500
577
|
// Bump the layer generation so request/browse resolver thunks are re-resolved on the next
|
|
501
578
|
// request (invalidateAllContent → clearContentCache is the documented re-resolve trigger).
|
|
502
579
|
layerGeneration += 1
|
|
@@ -525,81 +602,71 @@ class BrowserManager {
|
|
|
525
602
|
effectiveArtworkConfig = config.artwork
|
|
526
603
|
}
|
|
527
604
|
|
|
528
|
-
//
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
605
|
+
// Normalize to the canonical sectioned shape (children sugar → one untitled
|
|
606
|
+
// section — ADR 0010), then generate contextual paths and transform artwork
|
|
607
|
+
// URLs. The output never carries `children`.
|
|
608
|
+
val sections = resolvedTrack.normalizedSections ?: return resolvedTrack
|
|
609
|
+
// Dev diagnostic (ADR 0011) — before the blocks are folded, while each level is
|
|
610
|
+
// still attributable. Every page passes here whatever its source, and only on a
|
|
611
|
+
// cache miss. No-op outside debug builds.
|
|
612
|
+
InertStyleDiagnostic.warn(path, resolvedTrack.style, sections)
|
|
613
|
+
// The contextual index is the flat page position — children concatenated in
|
|
614
|
+
// section order (ADR 0009/0010).
|
|
615
|
+
var flatIndex = 0
|
|
616
|
+
// One scope for the whole page: every child's transform (which can suspend
|
|
617
|
+
// on artwork resolution) launches up front across all sections, then the
|
|
618
|
+
// sections reassemble — a slow section doesn't serialize the ones after it.
|
|
619
|
+
val transformedSections = coroutineScope {
|
|
620
|
+
sections
|
|
621
|
+
.map { section ->
|
|
622
|
+
val base = flatIndex
|
|
623
|
+
flatIndex += section.children.size
|
|
624
|
+
section to
|
|
625
|
+
section.children.mapIndexed { offset, track ->
|
|
534
626
|
async {
|
|
535
|
-
|
|
536
|
-
//
|
|
537
|
-
|
|
538
|
-
// identity; on Android Auto it expands into them).
|
|
539
|
-
if (track.imageRow.isNullOrEmpty()) validateTrack(track, "Child track")
|
|
627
|
+
val index = base + offset
|
|
628
|
+
// Validate that track has stable identifier.
|
|
629
|
+
validateTrack(track, "Child track")
|
|
540
630
|
|
|
541
631
|
var transformedTrack = track
|
|
542
632
|
|
|
543
|
-
// Generate contextual
|
|
633
|
+
// Generate contextual paths for playable tracks
|
|
544
634
|
// Always regenerate to reflect the current browsing context, not the original
|
|
545
635
|
// context
|
|
546
636
|
// (e.g., a track favorited from an album should use /favorites context when browsed
|
|
547
637
|
// there)
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
638
|
+
// The flat page position rides along as a duplicate-identity tie-breaker.
|
|
639
|
+
val trackIdentity = track.identity
|
|
640
|
+
if (track.src != null && trackIdentity != null) {
|
|
641
|
+
val contextualPath = BrowserPathHelper.build(path, trackIdentity, index)
|
|
642
|
+
transformedTrack = transformedTrack.copy(path = contextualPath)
|
|
551
643
|
|
|
552
644
|
Timber.d(
|
|
553
|
-
"[$path] Child[$index] '${track.title}': Playable,
|
|
645
|
+
"[$path] Child[$index] '${track.title}': Playable, contextualPath=$contextualPath (identity=$trackIdentity)"
|
|
554
646
|
)
|
|
555
647
|
} else {
|
|
556
648
|
Timber.d(
|
|
557
|
-
"[$path] Child[$index] '${track.title}': Browsable with
|
|
649
|
+
"[$path] Child[$index] '${track.title}': Browsable with path=${track.path}"
|
|
558
650
|
)
|
|
559
651
|
}
|
|
560
652
|
|
|
561
|
-
// Playable image-row items get contextual URLs like any list
|
|
562
|
-
// row, so a tile tap expands into its section's queue instead
|
|
563
|
-
// of a queue of one (ADR 0006).
|
|
564
|
-
transformedTrack.imageRow?.let { items ->
|
|
565
|
-
transformedTrack =
|
|
566
|
-
transformedTrack.copy(
|
|
567
|
-
imageRow =
|
|
568
|
-
items
|
|
569
|
-
.map { item ->
|
|
570
|
-
if (item.url == null && item.src != null) {
|
|
571
|
-
item.copy(url = BrowserPathHelper.build(path, item.src))
|
|
572
|
-
} else {
|
|
573
|
-
item
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
.toTypedArray()
|
|
577
|
-
)
|
|
578
|
-
}
|
|
579
|
-
|
|
580
653
|
// Transform artwork URL. At browse-time there is no display size info.
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
)
|
|
589
|
-
|
|
590
|
-
transformedTrack
|
|
654
|
+
transformArtworkUrl(
|
|
655
|
+
transformedTrack,
|
|
656
|
+
effectiveArtworkConfig,
|
|
657
|
+
path,
|
|
658
|
+
index,
|
|
659
|
+
ImageContext(null, null),
|
|
660
|
+
)
|
|
591
661
|
}
|
|
592
662
|
}
|
|
593
|
-
.awaitAll()
|
|
594
663
|
}
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
return if (transformedChildren != null) {
|
|
599
|
-
resolvedTrack.copy(children = transformedChildren.toTypedArray())
|
|
600
|
-
} else {
|
|
601
|
-
resolvedTrack
|
|
664
|
+
.map { (section, transformedChildren) ->
|
|
665
|
+
section.copy(children = transformedChildren.awaitAll().toTypedArray())
|
|
666
|
+
}
|
|
602
667
|
}
|
|
668
|
+
|
|
669
|
+
return resolvedTrack.copy(sections = transformedSections.toTypedArray(), children = null)
|
|
603
670
|
}
|
|
604
671
|
|
|
605
672
|
/**
|
|
@@ -658,55 +725,68 @@ class BrowserManager {
|
|
|
658
725
|
}
|
|
659
726
|
|
|
660
727
|
/**
|
|
661
|
-
* Expands a contextual
|
|
728
|
+
* Expands a contextual path into a queue of playable tracks.
|
|
662
729
|
*
|
|
663
730
|
* Used when navigating to a track to load it with its full album/playlist context. Returns only
|
|
664
731
|
* the selected track if singleTrack is true.
|
|
665
732
|
*
|
|
666
|
-
* @param
|
|
733
|
+
* @param contextualPath The contextual path (e.g., "/album?__trackId=song.mp3")
|
|
667
734
|
* @return Pair of (tracks array, selected track index), or null if expansion fails
|
|
668
735
|
*/
|
|
669
|
-
suspend fun
|
|
670
|
-
val trackId = BrowserPathHelper.extractTrackId(
|
|
736
|
+
suspend fun expandQueueFromContextualPath(contextualPath: String): Pair<Array<Track>, Int>? {
|
|
737
|
+
val trackId = BrowserPathHelper.extractTrackId(contextualPath) ?: return null
|
|
671
738
|
|
|
672
|
-
Timber.d("Expanding queue from contextual
|
|
739
|
+
Timber.d("Expanding queue from contextual path: $contextualPath (trackId=$trackId)")
|
|
673
740
|
|
|
674
741
|
try {
|
|
675
742
|
// Resolve the parent container to get all siblings
|
|
676
|
-
val parentPath = BrowserPathHelper.stripTrackId(
|
|
743
|
+
val parentPath = BrowserPathHelper.stripTrackId(contextualPath)
|
|
677
744
|
val parentResolvedTrack = resolve(parentPath)
|
|
678
|
-
val
|
|
745
|
+
val sections = parentResolvedTrack.normalizedSections
|
|
679
746
|
|
|
680
|
-
if (
|
|
747
|
+
if (sections.isNullOrEmpty()) {
|
|
681
748
|
Timber.w("Parent has no children, cannot expand queue")
|
|
682
749
|
return null
|
|
683
750
|
}
|
|
684
751
|
|
|
685
|
-
// Queue scope is the tapped section, not the whole page (ADR 0006).
|
|
686
|
-
//
|
|
687
|
-
//
|
|
688
|
-
//
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
// Filter to only playable tracks (tracks with src)
|
|
698
|
-
|
|
752
|
+
// Queue scope is the tapped section, not the whole page (ADR 0006). The
|
|
753
|
+
// stamped flat index pins which section (and which copy) was tapped when
|
|
754
|
+
// the same identity appears more than once; it is only a tie-breaker — a
|
|
755
|
+
// stale index falls back to the first identity match. An id that no
|
|
756
|
+
// longer appears on the page at all aborts the expansion — the caller
|
|
757
|
+
// falls back to the stored single track; silently queueing the changed
|
|
758
|
+
// list would resume the wrong station.
|
|
759
|
+
val tappedIndex = BrowserPathHelper.extractIndex(contextualPath)
|
|
760
|
+
val scoped = SectionScope.scoped(sections, trackId, tappedIndex) ?: return null
|
|
761
|
+
val sectionTracks = scoped.section.children.toList()
|
|
762
|
+
val tappedOffset = scoped.tappedOffset
|
|
763
|
+
|
|
764
|
+
// Filter to only playable tracks (tracks with src). A disabled track is
|
|
765
|
+
// unavailable — queue expansion excludes it, so auto-advance never meets
|
|
766
|
+
// one.
|
|
767
|
+
val playableTracks =
|
|
768
|
+
sectionTracks.filter { track -> track.src != null && track.disabled != true }
|
|
699
769
|
|
|
700
770
|
if (playableTracks.isEmpty()) {
|
|
701
771
|
Timber.w("Parent has no playable tracks, cannot expand queue")
|
|
702
772
|
return null
|
|
703
773
|
}
|
|
704
774
|
|
|
705
|
-
// Find the index of the selected track in the playable tracks array
|
|
706
|
-
|
|
775
|
+
// Find the index of the selected track in the playable tracks array:
|
|
776
|
+
// the pinned copy when the stamp survived, else the first identity match
|
|
777
|
+
val selectedIndex =
|
|
778
|
+
if (
|
|
779
|
+
tappedOffset != null &&
|
|
780
|
+
sectionTracks[tappedOffset].src != null &&
|
|
781
|
+
sectionTracks[tappedOffset].disabled != true
|
|
782
|
+
) {
|
|
783
|
+
sectionTracks.take(tappedOffset + 1).count { it.src != null && it.disabled != true } - 1
|
|
784
|
+
} else {
|
|
785
|
+
playableTracks.indexOfFirst { track -> track.identity == trackId }
|
|
786
|
+
}
|
|
707
787
|
|
|
708
788
|
if (selectedIndex < 0) {
|
|
709
|
-
Timber.w("Track with
|
|
789
|
+
Timber.w("Track with identity='$trackId' not found in playable children")
|
|
710
790
|
return null
|
|
711
791
|
}
|
|
712
792
|
|
|
@@ -717,11 +797,11 @@ class BrowserManager {
|
|
|
717
797
|
}
|
|
718
798
|
|
|
719
799
|
Timber.d(
|
|
720
|
-
"singleTrack=false - returning ${playableTracks.size} playable tracks (from ${
|
|
800
|
+
"singleTrack=false - returning ${playableTracks.size} playable tracks (from ${sectionTracks.size} in section), starting at index $selectedIndex"
|
|
721
801
|
)
|
|
722
802
|
return Pair(playableTracks.toTypedArray(), selectedIndex)
|
|
723
803
|
} catch (e: Exception) {
|
|
724
|
-
Timber.e(e, "Error expanding queue from contextual
|
|
804
|
+
Timber.e(e, "Error expanding queue from contextual path: $contextualPath")
|
|
725
805
|
return null
|
|
726
806
|
}
|
|
727
807
|
}
|
|
@@ -797,6 +877,8 @@ class BrowserManager {
|
|
|
797
877
|
*
|
|
798
878
|
* @param query The search query string
|
|
799
879
|
* @return Array of playable tracks, or null if no results or search not configured
|
|
880
|
+
* @throws Exception when the search itself fails — a zero-result page means "found nothing",
|
|
881
|
+
* never "couldn't ask"
|
|
800
882
|
*/
|
|
801
883
|
suspend fun searchPlayable(query: String): Array<Track>? {
|
|
802
884
|
return searchPlayable(
|
|
@@ -820,10 +902,15 @@ class BrowserManager {
|
|
|
820
902
|
*
|
|
821
903
|
* @param params The structured search parameters
|
|
822
904
|
* @return Array of playable tracks, or null if no results or search not configured
|
|
905
|
+
* @throws Exception when the search itself fails — a zero-result page means "found nothing",
|
|
906
|
+
* never "couldn't ask"
|
|
823
907
|
*/
|
|
824
908
|
suspend fun searchPlayable(params: SearchParams): Array<Track>? {
|
|
825
909
|
val searchResults = search(params)
|
|
826
|
-
|
|
910
|
+
// Voice search never matches a disabled track (Track.disabled) — filtered
|
|
911
|
+
// before the first result is picked, so an unavailable one can't capture
|
|
912
|
+
// the play.
|
|
913
|
+
val tracks = searchResults.flattenedChildren?.filter { it.disabled != true }?.toTypedArray()
|
|
827
914
|
|
|
828
915
|
if (tracks.isNullOrEmpty()) {
|
|
829
916
|
return null
|
|
@@ -833,13 +920,13 @@ class BrowserManager {
|
|
|
833
920
|
|
|
834
921
|
// Check if result is browsable-only (container/route) vs playable
|
|
835
922
|
// If it's browsable but also playable (has src or playable=true), treat it as playable
|
|
836
|
-
val
|
|
923
|
+
val firstResultPath = firstResult.path
|
|
837
924
|
val tracksToFilter =
|
|
838
|
-
if (firstResult.src == null &&
|
|
839
|
-
Timber.d("First search result is browsable-only, resolving: $
|
|
840
|
-
val resolvedTrack = resolve(
|
|
841
|
-
resolvedTrack.
|
|
842
|
-
?.filter { it.src != null }
|
|
925
|
+
if (firstResult.src == null && firstResultPath != null) {
|
|
926
|
+
Timber.d("First search result is browsable-only, resolving: $firstResultPath")
|
|
927
|
+
val resolvedTrack = resolve(firstResultPath)
|
|
928
|
+
resolvedTrack.flattenedChildren
|
|
929
|
+
?.filter { it.src != null && it.disabled != true }
|
|
843
930
|
?.takeIf { it.isNotEmpty() }
|
|
844
931
|
?.toTypedArray() ?: tracks
|
|
845
932
|
} else {
|
|
@@ -854,6 +941,8 @@ class BrowserManager {
|
|
|
854
941
|
*
|
|
855
942
|
* @param query The search query string
|
|
856
943
|
* @return ResolvedTrack containing search results as children
|
|
944
|
+
* @throws Exception when the search itself fails — a zero-result page means "found nothing",
|
|
945
|
+
* never "couldn't ask"
|
|
857
946
|
*/
|
|
858
947
|
suspend fun search(query: String): ResolvedTrack {
|
|
859
948
|
return search(
|
|
@@ -877,6 +966,8 @@ class BrowserManager {
|
|
|
877
966
|
*
|
|
878
967
|
* @param params The structured search parameters
|
|
879
968
|
* @return ResolvedTrack containing search results as children
|
|
969
|
+
* @throws Exception when the search itself fails — a zero-result page means "found nothing",
|
|
970
|
+
* never "couldn't ask"
|
|
880
971
|
*/
|
|
881
972
|
suspend fun search(params: SearchParams): ResolvedTrack {
|
|
882
973
|
Timber.d("Executing fresh search for: ${params.query} (mode=${params.mode})")
|
|
@@ -884,34 +975,35 @@ class BrowserManager {
|
|
|
884
975
|
val searchPath = BrowserPathHelper.createSearchPath(params.query)
|
|
885
976
|
|
|
886
977
|
try {
|
|
887
|
-
// Execute search. Drop results without a stable identifier (
|
|
978
|
+
// Execute search. Drop results without a stable identifier (path or src): search results come
|
|
888
979
|
// from server/JS data that doesn't pass through validateTrack like browse children do, and
|
|
889
980
|
// downstream conversion (TrackFactory.toMedia3) and browsable-result resolution require one.
|
|
890
981
|
val searchResults =
|
|
891
982
|
resolveSearch(params)
|
|
892
983
|
.filter { track ->
|
|
893
|
-
val valid = track.
|
|
984
|
+
val valid = track.path != null || track.src != null
|
|
894
985
|
if (!valid) {
|
|
895
|
-
Timber.w("Dropping search result without
|
|
986
|
+
Timber.w("Dropping search result without path or src: '${track.title}'")
|
|
896
987
|
}
|
|
897
988
|
valid
|
|
898
989
|
}
|
|
899
990
|
.toTypedArray()
|
|
900
991
|
|
|
901
|
-
//
|
|
992
|
+
// Search results are a flat list; as a resolved page they are one
|
|
993
|
+
// untitled section (ADR 0010).
|
|
902
994
|
val searchResolvedTrack =
|
|
903
995
|
ResolvedTrack(
|
|
904
996
|
id = null,
|
|
905
|
-
|
|
997
|
+
path = searchPath,
|
|
906
998
|
title = "Search: ${params.query}",
|
|
907
|
-
|
|
999
|
+
sections = arrayOf(untitledSection(searchResults)),
|
|
1000
|
+
children = null,
|
|
908
1001
|
carPlaySiriListButton = null,
|
|
909
1002
|
artwork = null,
|
|
910
1003
|
artworkSource = null,
|
|
911
1004
|
request = null,
|
|
912
|
-
artworkCarPlayTinted = null,
|
|
913
1005
|
artist = null,
|
|
914
|
-
|
|
1006
|
+
albumPath = null,
|
|
915
1007
|
description = null,
|
|
916
1008
|
subtitle = null,
|
|
917
1009
|
album = null,
|
|
@@ -919,11 +1011,10 @@ class BrowserManager {
|
|
|
919
1011
|
duration = null,
|
|
920
1012
|
src = null,
|
|
921
1013
|
style = null,
|
|
922
|
-
|
|
1014
|
+
disabled = null,
|
|
923
1015
|
favorited = null,
|
|
924
|
-
groupTitle = null,
|
|
925
1016
|
live = null,
|
|
926
|
-
|
|
1017
|
+
icyCharset = null,
|
|
927
1018
|
)
|
|
928
1019
|
|
|
929
1020
|
// Cache search results for getCachedSearchResults()
|
|
@@ -937,37 +1028,10 @@ class BrowserManager {
|
|
|
937
1028
|
|
|
938
1029
|
return searchResolvedTrack
|
|
939
1030
|
} catch (e: Exception) {
|
|
1031
|
+
// Propagates, like the iOS `search`: a caller that cannot tell a failed search from one
|
|
1032
|
+
// that found nothing renders a server error as "No results found".
|
|
940
1033
|
Timber.e(e, "Error during search for query: ${params.query}")
|
|
941
|
-
|
|
942
|
-
// Return empty search result on error
|
|
943
|
-
val emptySearchResult =
|
|
944
|
-
ResolvedTrack(
|
|
945
|
-
id = null,
|
|
946
|
-
url = searchPath,
|
|
947
|
-
title = "Search: ${params.query}",
|
|
948
|
-
children = emptyArray(),
|
|
949
|
-
carPlaySiriListButton = null,
|
|
950
|
-
artwork = null,
|
|
951
|
-
artworkSource = null,
|
|
952
|
-
request = null,
|
|
953
|
-
artworkCarPlayTinted = null,
|
|
954
|
-
artist = null,
|
|
955
|
-
albumUrl = null,
|
|
956
|
-
description = null,
|
|
957
|
-
subtitle = null,
|
|
958
|
-
album = null,
|
|
959
|
-
genre = null,
|
|
960
|
-
duration = null,
|
|
961
|
-
src = null,
|
|
962
|
-
style = null,
|
|
963
|
-
childrenStyle = null,
|
|
964
|
-
favorited = null,
|
|
965
|
-
groupTitle = null,
|
|
966
|
-
live = null,
|
|
967
|
-
imageRow = null,
|
|
968
|
-
)
|
|
969
|
-
|
|
970
|
-
return emptySearchResult
|
|
1034
|
+
throw e
|
|
971
1035
|
}
|
|
972
1036
|
}
|
|
973
1037
|
|
|
@@ -1041,7 +1105,7 @@ class BrowserManager {
|
|
|
1041
1105
|
// Validate tabs have stable identifiers
|
|
1042
1106
|
tabs.forEachIndexed { index, tab ->
|
|
1043
1107
|
validateTrack(tab, "Tab")
|
|
1044
|
-
Timber.d("[TABS] Tab[$index] '${tab.title}':
|
|
1108
|
+
Timber.d("[TABS] Tab[$index] '${tab.title}': path=${tab.path}")
|
|
1045
1109
|
}
|
|
1046
1110
|
|
|
1047
1111
|
this.tabs = tabs
|
|
@@ -1057,6 +1121,14 @@ class BrowserManager {
|
|
|
1057
1121
|
|
|
1058
1122
|
/** Internal path used for search */
|
|
1059
1123
|
internal const val SEARCH_ROUTE_PATH = "__search__"
|
|
1124
|
+
|
|
1125
|
+
/**
|
|
1126
|
+
* Title of the appended "view more" row when the consumer sets no
|
|
1127
|
+
* [BrowserConfig.viewMoreTitle]. English in code, like [defaultFormattedError]'s error copy — a
|
|
1128
|
+
* default that renders beats a section whose `path` is unreachable, and it still resolves when
|
|
1129
|
+
* the JS runtime is gone.
|
|
1130
|
+
*/
|
|
1131
|
+
internal const val DEFAULT_VIEW_MORE_TITLE = "View more"
|
|
1060
1132
|
}
|
|
1061
1133
|
|
|
1062
1134
|
/**
|
|
@@ -1179,7 +1251,8 @@ class BrowserManager {
|
|
|
1179
1251
|
Timber.d("Resolving tabs via route entry")
|
|
1180
1252
|
val resolvedTrack = resolveRouteEntry(tabsEntry, TABS_ROUTE_PATH, emptyMap())
|
|
1181
1253
|
|
|
1182
|
-
|
|
1254
|
+
// Tabs are a flat list, not a page — a sectioned tabs source flattens.
|
|
1255
|
+
return resolvedTrack.flattenedChildren?.toTypedArray() ?: emptyArray()
|
|
1183
1256
|
}
|
|
1184
1257
|
|
|
1185
1258
|
/**
|
|
@@ -1231,6 +1304,33 @@ class BrowserManager {
|
|
|
1231
1304
|
return resolvedRequestLayer
|
|
1232
1305
|
}
|
|
1233
1306
|
|
|
1307
|
+
/**
|
|
1308
|
+
* The title for the "view more" row appended to a pathed section on a surface whose header cannot
|
|
1309
|
+
* be tapped (Android Auto).
|
|
1310
|
+
*
|
|
1311
|
+
* Resolved from [BrowserConfig.viewMoreTitle] once per content generation — the same generation
|
|
1312
|
+
* the resolver layers use, so `invalidateAllContent()` re-reads it and an app that switched
|
|
1313
|
+
* language mid-drive gets the new copy without reconfiguring. Falls back to
|
|
1314
|
+
* [DEFAULT_VIEW_MORE_TITLE] when unset, blank, or throwing: a row with the default copy still
|
|
1315
|
+
* reaches the section's page, an untitled one does not.
|
|
1316
|
+
*/
|
|
1317
|
+
internal suspend fun viewMoreTitle(): String {
|
|
1318
|
+
val generation = layerGeneration
|
|
1319
|
+
if (resolvedViewMoreTitleGeneration == generation) return resolvedViewMoreTitle
|
|
1320
|
+
val title =
|
|
1321
|
+
try {
|
|
1322
|
+
config.viewMoreTitle?.invoke()?.await()?.takeIf { it.isNotBlank() }
|
|
1323
|
+
} catch (e: Exception) {
|
|
1324
|
+
Timber.e(e, "viewMoreTitle callback failed; falling back to the default")
|
|
1325
|
+
null
|
|
1326
|
+
} ?: DEFAULT_VIEW_MORE_TITLE
|
|
1327
|
+
// A newer generation started while awaiting — use this result, but don't cache it as current.
|
|
1328
|
+
if (generation != layerGeneration) return title
|
|
1329
|
+
resolvedViewMoreTitle = title
|
|
1330
|
+
resolvedViewMoreTitleGeneration = generation
|
|
1331
|
+
return title
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1234
1334
|
/**
|
|
1235
1335
|
* Builds the HTTP request for an API-backed path by layering request (shared) → kind
|
|
1236
1336
|
* (browse/search) → route configs. Each layer's transform receives the previous layer's output; a
|
|
@@ -1429,6 +1529,8 @@ data class BrowserConfig(
|
|
|
1429
1529
|
// Behavior
|
|
1430
1530
|
val singleTrack: Boolean = false,
|
|
1431
1531
|
val androidControllerOfflineError: Boolean = true,
|
|
1532
|
+
// Titles the "view more" row appended to a pathed section. See BrowserManager.viewMoreTitle.
|
|
1533
|
+
val viewMoreTitle: (() -> Promise<String>)? = null,
|
|
1432
1534
|
) {
|
|
1433
1535
|
/** Returns true if search functionality is configured (either callback or config). */
|
|
1434
1536
|
val hasSearch: Boolean
|