react-native-audio-browser 0.2.0-next.3 → 0.2.0-next.31
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 +189 -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 +189 -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
|
@@ -20,9 +20,11 @@ import com.audiobrowser.browser.CallbackException
|
|
|
20
20
|
import com.audiobrowser.browser.ContentNotFoundException
|
|
21
21
|
import com.audiobrowser.browser.HttpStatusException
|
|
22
22
|
import com.audiobrowser.browser.NetworkException
|
|
23
|
+
import com.audiobrowser.browser.flattenedChildren
|
|
23
24
|
import com.audiobrowser.browser.handleTrackLoad
|
|
24
25
|
import com.audiobrowser.browser.resolveMediaUrl
|
|
25
26
|
import com.audiobrowser.extension.NumberExt.Companion.toSeconds
|
|
27
|
+
import com.audiobrowser.extension.indexOfTappedTrack
|
|
26
28
|
import com.audiobrowser.model.PlayerSetupOptions
|
|
27
29
|
import com.audiobrowser.model.PlayerUpdateOptions
|
|
28
30
|
import com.audiobrowser.player.Player
|
|
@@ -35,6 +37,7 @@ import com.audiobrowser.util.SystemVolumeMonitor
|
|
|
35
37
|
import com.facebook.proguard.annotations.DoNotStrip
|
|
36
38
|
import com.google.common.util.concurrent.ListenableFuture
|
|
37
39
|
import com.margelo.nitro.NitroModules
|
|
40
|
+
import com.margelo.nitro.audiobrowser.ArtworkRequestConfig
|
|
38
41
|
import com.margelo.nitro.audiobrowser.BatteryOptimizationStatus
|
|
39
42
|
import com.margelo.nitro.audiobrowser.BatteryOptimizationStatusChangedEvent
|
|
40
43
|
import com.margelo.nitro.audiobrowser.BatteryWarningPendingChangedEvent
|
|
@@ -50,6 +53,7 @@ import com.margelo.nitro.audiobrowser.HybridAudioBrowserSpec
|
|
|
50
53
|
import com.margelo.nitro.audiobrowser.MediaRequestConfig
|
|
51
54
|
import com.margelo.nitro.audiobrowser.NativeBrowserConfiguration
|
|
52
55
|
import com.margelo.nitro.audiobrowser.NativeGateRequest
|
|
56
|
+
import com.margelo.nitro.audiobrowser.NativeRouteEntry
|
|
53
57
|
import com.margelo.nitro.audiobrowser.NativeSetupPlayerOptions
|
|
54
58
|
import com.margelo.nitro.audiobrowser.NativeUpdateOptions
|
|
55
59
|
import com.margelo.nitro.audiobrowser.NavigationError
|
|
@@ -82,31 +86,106 @@ import com.margelo.nitro.audiobrowser.SleepTimer
|
|
|
82
86
|
import com.margelo.nitro.audiobrowser.TimedMetadata
|
|
83
87
|
import com.margelo.nitro.audiobrowser.Track
|
|
84
88
|
import com.margelo.nitro.audiobrowser.TrackMetadata
|
|
89
|
+
import com.margelo.nitro.audiobrowser.TransformableRequestConfig
|
|
90
|
+
import com.margelo.nitro.core.NullType
|
|
85
91
|
import com.margelo.nitro.core.Promise
|
|
86
92
|
import java.util.concurrent.TimeUnit
|
|
93
|
+
import java.util.concurrent.atomic.AtomicReference
|
|
87
94
|
import kotlin.coroutines.resume
|
|
88
95
|
import kotlin.coroutines.resumeWithException
|
|
89
96
|
import kotlin.coroutines.suspendCoroutine
|
|
97
|
+
import kotlin.time.Duration.Companion.seconds
|
|
90
98
|
import kotlinx.coroutines.CancellationException
|
|
99
|
+
import kotlinx.coroutines.CoroutineScope
|
|
91
100
|
import kotlinx.coroutines.Job
|
|
92
101
|
import kotlinx.coroutines.MainScope
|
|
102
|
+
import kotlinx.coroutines.async
|
|
103
|
+
import kotlinx.coroutines.cancel
|
|
93
104
|
import kotlinx.coroutines.cancelChildren
|
|
94
|
-
import kotlinx.coroutines.delay
|
|
95
105
|
import kotlinx.coroutines.launch
|
|
96
106
|
import kotlinx.coroutines.runBlocking
|
|
107
|
+
import kotlinx.coroutines.withTimeoutOrNull
|
|
97
108
|
import timber.log.Timber
|
|
98
109
|
|
|
99
110
|
@Keep
|
|
100
111
|
@DoNotStrip
|
|
101
112
|
class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
102
113
|
|
|
103
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* Nitro calls this only when JS calls `dispose()` explicitly — never on runtime teardown, which
|
|
116
|
+
* is what [AudioBrowserLifecycleModule] is for. Both routes land here.
|
|
117
|
+
*
|
|
118
|
+
* The Service outlives this object, so everything registered in `init` or on connect has to be
|
|
119
|
+
* undone. Left alone, the running [Player] goes on invoking callbacks into a dead JSI runtime,
|
|
120
|
+
* and every reload strands another ServiceConnection and lifecycle observer, each retaining a
|
|
121
|
+
* BrowserManager.
|
|
122
|
+
*
|
|
123
|
+
* Runs the teardown on main: the state below is written from main-thread coroutines
|
|
124
|
+
* ([onServiceConnected], [onServiceDisconnected]), while dispose itself arrives on the JS thread
|
|
125
|
+
* or the teardown callback's thread.
|
|
126
|
+
*/
|
|
104
127
|
override fun dispose() {
|
|
128
|
+
current.compareAndSet(this, null)
|
|
105
129
|
systemVolumeMonitor.destroy()
|
|
106
130
|
outputMonitor.destroy()
|
|
131
|
+
// Only when still ours: on a reload the replacement may already own the slot.
|
|
132
|
+
carConnectionTarget.compareAndSet(onCarConnectedChanged, null)
|
|
133
|
+
|
|
134
|
+
// The runtime behind the config's JS functions is going away, but anything still holding
|
|
135
|
+
// this instance (an in-flight browse coroutine, the running player) can invoke them after
|
|
136
|
+
// it's gone — each invoke then throws instead of answering, so browse takes its error path
|
|
137
|
+
// rather than its fallback.
|
|
138
|
+
dropStaleJSCallbacks()
|
|
139
|
+
|
|
140
|
+
handler.post {
|
|
141
|
+
connectedService?.let { service ->
|
|
142
|
+
// Identity-guarded: both instances bind to the same singleton Service, so a late dispose
|
|
143
|
+
// must not strip the wiring a replacement has already installed.
|
|
144
|
+
if (service.player.getCallbacks() === callbacks) service.player.setCallbacks(null)
|
|
145
|
+
if (service.player.browser === this) {
|
|
146
|
+
service.player.browser = null
|
|
147
|
+
service.player.forgetBrowserRegistration()
|
|
148
|
+
// The formatter wraps a JS callback from this instance's runtime (installed by our
|
|
149
|
+
// setup(); browser still being ours means no replacement has run setup yet). Without
|
|
150
|
+
// this, every track change until the next setup() throws into the updater's fallback.
|
|
151
|
+
service.player.nowPlaying.formatter = null
|
|
152
|
+
}
|
|
153
|
+
if (service.onBatteryWarningPendingChanged === onBatteryWarningPending) {
|
|
154
|
+
service.onBatteryWarningPendingChanged = null
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
connectedService = null
|
|
158
|
+
|
|
159
|
+
// Dropping the reference disconnects nothing — the controller stays in the session's
|
|
160
|
+
// connected list, holding a binder and a listener.
|
|
161
|
+
mediaBrowserFuture?.let { MediaBrowser.releaseFuture(it) }
|
|
162
|
+
mediaBrowserFuture = null
|
|
163
|
+
setupPromise = null
|
|
164
|
+
|
|
165
|
+
serviceBinding.unbind(this)
|
|
166
|
+
|
|
167
|
+
ProcessLifecycleOwner.get().lifecycle.removeObserver(lifecycleObserver)
|
|
168
|
+
// After the observer removal, so this post is not the one dropped.
|
|
169
|
+
handler.removeCallbacksAndMessages(null)
|
|
170
|
+
mainScope.cancel()
|
|
171
|
+
}
|
|
107
172
|
super.dispose()
|
|
108
173
|
}
|
|
109
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Demotes the config to data-only (deep strip of every JS function field) and reverts the JS
|
|
177
|
+
* callbacks stored outside the config tree ([resolveGate]; the now-playing formatter is cleared
|
|
178
|
+
* in [dispose]'s service block, identity-guarded). Stale paths then degrade the same way as a
|
|
179
|
+
* config that never had callbacks — static request/browse layers, default error copy, fail-closed
|
|
180
|
+
* gate — instead of throwing into the error path. Mirrors iOS `dropStaleJSCallbacks`, where the
|
|
181
|
+
* same invoke is fatal rather than a throw.
|
|
182
|
+
*/
|
|
183
|
+
private fun dropStaleJSCallbacks() {
|
|
184
|
+
_configuration = _configuration.strippingJSCallbacks()
|
|
185
|
+
browserManager.config = buildConfig()
|
|
186
|
+
resolveGate = defaultResolveGate
|
|
187
|
+
}
|
|
188
|
+
|
|
110
189
|
private val mainScope = MainScope()
|
|
111
190
|
private var navigationJob: Job? = null
|
|
112
191
|
private val handler = Handler(Looper.getMainLooper())
|
|
@@ -129,8 +208,9 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
129
208
|
singleTrack = null,
|
|
130
209
|
handleTrackLoad = null,
|
|
131
210
|
androidControllerOfflineError = null,
|
|
211
|
+
viewMoreTitle = null,
|
|
132
212
|
carPlayLoadingTitle = null,
|
|
133
|
-
|
|
213
|
+
resolveAlbumPath = null,
|
|
134
214
|
formatNavigationError = null,
|
|
135
215
|
)
|
|
136
216
|
|
|
@@ -149,7 +229,18 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
149
229
|
private var updateOptions: PlayerUpdateOptions = PlayerUpdateOptions()
|
|
150
230
|
private var mediaBrowserFuture: ListenableFuture<MediaBrowser>? = null
|
|
151
231
|
private var setupOptions = PlayerSetupOptions()
|
|
152
|
-
|
|
232
|
+
// Written only on the main thread (ServiceConnection callbacks, dispose); read from main or,
|
|
233
|
+
// in a few places, straight from the JS thread. @Volatile gives those reads visibility — they
|
|
234
|
+
// must still tolerate staleness in both directions (a just-detached service, or null while
|
|
235
|
+
// onServiceConnected is pending). Keep writes on main; no read-modify-write.
|
|
236
|
+
@Volatile private var connectedService: Service? = null
|
|
237
|
+
|
|
238
|
+
private val serviceBinding = ServiceBinding(context)
|
|
239
|
+
|
|
240
|
+
/** Held rather than inlined so [dispose] can tell its own wiring from a replacement's. */
|
|
241
|
+
private val onBatteryWarningPending: (Boolean) -> Unit = { pending ->
|
|
242
|
+
post { onBatteryWarningPendingChanged(BatteryWarningPendingChangedEvent(pending)) }
|
|
243
|
+
}
|
|
153
244
|
private var setupPromise: ((Unit) -> Unit)? = null
|
|
154
245
|
|
|
155
246
|
// Initial player state staged before the player exists — from setup options or the imperative
|
|
@@ -168,14 +259,14 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
168
259
|
override var onFormattedNavigationError: (FormattedNavigationError?) -> Unit = {}
|
|
169
260
|
|
|
170
261
|
// MARK: Gate callbacks (native→JS; set from JS, native CALLS them)
|
|
171
|
-
// Default resolver: only reachable
|
|
172
|
-
//
|
|
262
|
+
// Default resolver: only reachable while hasResolver=true but no live runtime has the real
|
|
263
|
+
// `resolveGate` bound — the init window before JS assigns it, or after [dispose] reverts a dead
|
|
264
|
+
// runtime's resolver. It DENIES by default
|
|
173
265
|
// (gated=true) so an active gate never serves content during that window — same fail-closed
|
|
174
266
|
// direction as the resolver-error path in [gateDecision]. The static-gate fast path skips it
|
|
175
267
|
// entirely once a resolver-less gate is set.
|
|
176
|
-
override var resolveGate: (request: NativeGateRequest) -> Promise<Promise<GateDecision>> =
|
|
177
|
-
|
|
178
|
-
}
|
|
268
|
+
override var resolveGate: (request: NativeGateRequest) -> Promise<Promise<GateDecision>> =
|
|
269
|
+
defaultResolveGate
|
|
179
270
|
override var onGate: (event: GateEvent) -> Unit = {}
|
|
180
271
|
|
|
181
272
|
// MARK: Player callbacks
|
|
@@ -239,12 +330,14 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
239
330
|
}
|
|
240
331
|
|
|
241
332
|
init {
|
|
333
|
+
current.set(this)
|
|
334
|
+
|
|
242
335
|
// Auto-bind to service if it's already running
|
|
243
336
|
launchInScope {
|
|
244
337
|
try {
|
|
245
338
|
Timber.d("Attempting to auto-bind to existing AudioBrowserService from AudioBrowser")
|
|
246
339
|
val intent = Intent(context, Service::class.java)
|
|
247
|
-
val bound =
|
|
340
|
+
val bound = serviceBinding.bind(intent, this@AudioBrowser)
|
|
248
341
|
Timber.d("Auto-bind result: $bound")
|
|
249
342
|
|
|
250
343
|
if (!bound) {
|
|
@@ -286,6 +379,7 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
286
379
|
routes = _configuration.routes,
|
|
287
380
|
singleTrack = _configuration.singleTrack ?: false,
|
|
288
381
|
androidControllerOfflineError = _configuration.androidControllerOfflineError ?: true,
|
|
382
|
+
viewMoreTitle = _configuration.viewMoreTitle,
|
|
289
383
|
)
|
|
290
384
|
}
|
|
291
385
|
|
|
@@ -319,8 +413,8 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
319
413
|
browserManager.config = buildConfig()
|
|
320
414
|
val tabs = browserManager.queryTabs()
|
|
321
415
|
if (tabs.isNotEmpty()) {
|
|
322
|
-
Timber.d("Using first tab as default path: ${tabs[0].
|
|
323
|
-
tabs[0].
|
|
416
|
+
Timber.d("Using first tab as default path: ${tabs[0].path}")
|
|
417
|
+
tabs[0].path
|
|
324
418
|
} else {
|
|
325
419
|
Timber.d("Using root path as default: /")
|
|
326
420
|
"/"
|
|
@@ -375,8 +469,14 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
375
469
|
browserManager.config = buildConfig()
|
|
376
470
|
|
|
377
471
|
// Notify player that browser configuration is ready (routes/tabs available)
|
|
378
|
-
// This allows Android Auto to start browsing content
|
|
379
|
-
|
|
472
|
+
// This allows Android Auto to start browsing content.
|
|
473
|
+
// This reaches MediaSession.getConnectedControllers, which asserts the
|
|
474
|
+
// main thread, and this setter runs on the JS thread. Hop without
|
|
475
|
+
// blocking -- runBlockingOnMain would deadlock here for the same reason
|
|
476
|
+
// described for the navigation below (JS callbacks can't run while the
|
|
477
|
+
// JS thread waits). Ordering with navigationJob is preserved: both are
|
|
478
|
+
// queued on mainScope.
|
|
479
|
+
launchInScope { connectedService?.player?.notifyBrowserConfigurationReady() }
|
|
380
480
|
|
|
381
481
|
clearNavigationError()
|
|
382
482
|
|
|
@@ -408,121 +508,56 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
408
508
|
|
|
409
509
|
override fun getFormattedNavigationError(): FormattedNavigationError? = formattedNavigationError
|
|
410
510
|
|
|
411
|
-
/**
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
private fun httpStatusText(statusCode: Int): String {
|
|
433
|
-
return when (statusCode) {
|
|
434
|
-
400 -> "Bad Request"
|
|
435
|
-
401 -> "Unauthorized"
|
|
436
|
-
403 -> "Forbidden"
|
|
437
|
-
404 -> "Not Found"
|
|
438
|
-
405 -> "Method Not Allowed"
|
|
439
|
-
408 -> "Request Timeout"
|
|
440
|
-
429 -> "Too Many Requests"
|
|
441
|
-
500 -> "Internal Server Error"
|
|
442
|
-
502 -> "Bad Gateway"
|
|
443
|
-
503 -> "Service Unavailable"
|
|
444
|
-
504 -> "Gateway Timeout"
|
|
445
|
-
else -> "Server Error"
|
|
511
|
+
/**
|
|
512
|
+
* Resolves a navigation error to its display form: the app's `formatNavigationError` for the
|
|
513
|
+
* given [path] when one is configured, else the built-in default. Shared by [setNavigationError]
|
|
514
|
+
* and the Android Auto empty tile so in-app and in-car copy cannot drift (ADR 0001).
|
|
515
|
+
*/
|
|
516
|
+
internal suspend fun resolveFormattedError(
|
|
517
|
+
error: NavigationError,
|
|
518
|
+
path: String,
|
|
519
|
+
): FormattedNavigationError {
|
|
520
|
+
val default = defaultFormattedError(error)
|
|
521
|
+
val formatter = _configuration.formatNavigationError ?: return default
|
|
522
|
+
return formattedOrDefault(mainScope, default) {
|
|
523
|
+
formatter(
|
|
524
|
+
FormatNavigationErrorParams(
|
|
525
|
+
error,
|
|
526
|
+
default,
|
|
527
|
+
path,
|
|
528
|
+
BrowserPathHelper.navigationErrorKind(path),
|
|
529
|
+
)
|
|
530
|
+
)
|
|
531
|
+
.await()
|
|
446
532
|
}
|
|
447
533
|
}
|
|
448
534
|
|
|
449
|
-
private fun setNavigationError(
|
|
450
|
-
code: NavigationErrorType,
|
|
451
|
-
message: String,
|
|
452
|
-
path: String,
|
|
453
|
-
statusCode: Double? = null,
|
|
454
|
-
statusCodeSuccess: Boolean? = null,
|
|
455
|
-
) {
|
|
456
|
-
val navError = NavigationError(code, message, statusCode, statusCodeSuccess)
|
|
535
|
+
private fun setNavigationError(navError: NavigationError, path: String) {
|
|
457
536
|
navigationError = navError
|
|
458
537
|
onNavigationError(NavigationErrorEvent(navigationError))
|
|
459
538
|
|
|
460
|
-
//
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
if (
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
} else {
|
|
475
|
-
formattedNavigationError = defaultFormatted
|
|
476
|
-
onFormattedNavigationError(formattedNavigationError)
|
|
539
|
+
// No formatter means no hop, and the field and event land in this turn: a same-turn
|
|
540
|
+
// getFormattedNavigationError, or a clearNavigationError right after, must not race a
|
|
541
|
+
// launch that has yet to run.
|
|
542
|
+
if (_configuration.formatNavigationError == null) {
|
|
543
|
+
val default = defaultFormattedError(navError)
|
|
544
|
+
formattedNavigationError = default
|
|
545
|
+
onFormattedNavigationError(default)
|
|
546
|
+
return
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
mainScope.launch {
|
|
550
|
+
val formatted = resolveFormattedError(navError, path)
|
|
551
|
+
formattedNavigationError = formatted
|
|
552
|
+
onFormattedNavigationError(formatted)
|
|
477
553
|
}
|
|
478
554
|
}
|
|
479
555
|
|
|
480
|
-
/**
|
|
556
|
+
/** Raises the navigation error [e] maps to, for a failed navigation to [path]. */
|
|
481
557
|
private fun handleBrowserException(e: Exception, path: String, logContext: String) {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
setNavigationError(
|
|
486
|
-
NavigationErrorType.HTTP_ERROR,
|
|
487
|
-
e.message ?: "Server error",
|
|
488
|
-
path,
|
|
489
|
-
e.statusCode.toDouble(),
|
|
490
|
-
e.statusCode in 200..299,
|
|
491
|
-
)
|
|
492
|
-
}
|
|
493
|
-
is NetworkException -> {
|
|
494
|
-
Timber.e(e, "Network error $logContext")
|
|
495
|
-
setNavigationError(
|
|
496
|
-
NavigationErrorType.NETWORK_ERROR,
|
|
497
|
-
e.message ?: "Network request failed",
|
|
498
|
-
path,
|
|
499
|
-
)
|
|
500
|
-
}
|
|
501
|
-
is ContentNotFoundException -> {
|
|
502
|
-
Timber.e(e, "Content not found $logContext")
|
|
503
|
-
setNavigationError(
|
|
504
|
-
NavigationErrorType.CONTENT_NOT_FOUND,
|
|
505
|
-
e.message ?: "Content not found",
|
|
506
|
-
path,
|
|
507
|
-
)
|
|
508
|
-
}
|
|
509
|
-
is CallbackException -> {
|
|
510
|
-
Timber.e(e, "Callback error $logContext")
|
|
511
|
-
setNavigationError(
|
|
512
|
-
NavigationErrorType.CALLBACK_ERROR,
|
|
513
|
-
e.message ?: "An error occurred",
|
|
514
|
-
path,
|
|
515
|
-
)
|
|
516
|
-
}
|
|
517
|
-
else -> {
|
|
518
|
-
Timber.e(e, "Unexpected error $logContext")
|
|
519
|
-
setNavigationError(
|
|
520
|
-
NavigationErrorType.UNKNOWN_ERROR,
|
|
521
|
-
e.message ?: "An unexpected error occurred",
|
|
522
|
-
path,
|
|
523
|
-
)
|
|
524
|
-
}
|
|
525
|
-
}
|
|
558
|
+
val navError = navigationErrorFor(e)
|
|
559
|
+
Timber.e(e, "${navError.code} $logContext")
|
|
560
|
+
setNavigationError(navError, path)
|
|
526
561
|
}
|
|
527
562
|
|
|
528
563
|
private fun clearNavigationError() {
|
|
@@ -558,26 +593,38 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
558
593
|
}
|
|
559
594
|
|
|
560
595
|
override fun navigateTrack(track: Track) {
|
|
596
|
+
// A disabled track is unavailable — it never plays, whichever surface or
|
|
597
|
+
// stale resume path delivered the selection (Track.disabled; mirrors iOS
|
|
598
|
+
// TrackSelector.select). Refused before any state changes: an inert tap
|
|
599
|
+
// must not clear an unrelated navigation error or cancel an in-flight
|
|
600
|
+
// navigation.
|
|
601
|
+
if (track.disabled == true) {
|
|
602
|
+
Timber.d("Ignoring selection of disabled track: ${track.title}")
|
|
603
|
+
return
|
|
604
|
+
}
|
|
605
|
+
|
|
561
606
|
clearNavigationError()
|
|
562
607
|
|
|
563
608
|
// Cancel previous navigation to avoid race conditions
|
|
564
609
|
navigationJob?.cancel()
|
|
565
610
|
|
|
566
|
-
val
|
|
611
|
+
val path = track.path
|
|
567
612
|
navigationJob =
|
|
568
613
|
mainScope.launch {
|
|
569
614
|
try {
|
|
570
615
|
when {
|
|
571
|
-
// Check if this is a contextual
|
|
572
|
-
|
|
573
|
-
Timber.d("Navigating to contextual track
|
|
616
|
+
// Check if this is a contextual path (playable-only track with queue context)
|
|
617
|
+
path != null && BrowserPathHelper.isContextual(path) -> {
|
|
618
|
+
Timber.d("Navigating to contextual track path: $path")
|
|
574
619
|
|
|
575
|
-
val parentPath = BrowserPathHelper.stripTrackId(
|
|
576
|
-
val trackId = BrowserPathHelper.extractTrackId(
|
|
620
|
+
val parentPath = BrowserPathHelper.stripTrackId(path)
|
|
621
|
+
val trackId = BrowserPathHelper.extractTrackId(path)
|
|
577
622
|
|
|
578
|
-
// Check if queue already came from this parent path - just skip
|
|
623
|
+
// Check if queue already came from this parent path - just skip
|
|
624
|
+
// to the tapped surface (exact path first, identity for
|
|
625
|
+
// index-less paths — see indexOfTappedTrack)
|
|
579
626
|
if (trackId != null && parentPath == player.queueSourcePath) {
|
|
580
|
-
val index = player.tracks.
|
|
627
|
+
val index = player.tracks.indexOfTappedTrack(path, trackId)
|
|
581
628
|
if (index >= 0) {
|
|
582
629
|
Timber.d("Queue already from $parentPath, skipping to index $index")
|
|
583
630
|
handleTrackLoad(
|
|
@@ -595,8 +642,8 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
595
642
|
}
|
|
596
643
|
}
|
|
597
644
|
|
|
598
|
-
// Expand the queue from the contextual
|
|
599
|
-
val expanded = browserManager.
|
|
645
|
+
// Expand the queue from the contextual path
|
|
646
|
+
val expanded = browserManager.expandQueueFromContextualPath(path)
|
|
600
647
|
|
|
601
648
|
if (expanded != null) {
|
|
602
649
|
val (tracks, startIndex) = expanded
|
|
@@ -631,9 +678,9 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
631
678
|
}
|
|
632
679
|
}
|
|
633
680
|
// Navigate to browsable track to show browsing UI
|
|
634
|
-
|
|
635
|
-
Timber.d("Navigating to browsable track: $
|
|
636
|
-
browserManager.navigate(
|
|
681
|
+
path != null -> {
|
|
682
|
+
Timber.d("Navigating to browsable track: $path")
|
|
683
|
+
browserManager.navigate(path)
|
|
637
684
|
}
|
|
638
685
|
// If track is playable (has src), load it into player
|
|
639
686
|
track.src != null -> {
|
|
@@ -648,22 +695,36 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
648
695
|
)
|
|
649
696
|
}
|
|
650
697
|
else -> {
|
|
651
|
-
throw IllegalArgumentException("Track must have either
|
|
698
|
+
throw IllegalArgumentException("Track must have either a 'path' or an 'src' property")
|
|
652
699
|
}
|
|
653
700
|
}
|
|
654
701
|
} catch (e: CancellationException) {
|
|
655
702
|
throw e // Rethrow to properly cancel
|
|
656
703
|
} catch (e: Exception) {
|
|
657
|
-
handleBrowserException(e,
|
|
704
|
+
handleBrowserException(e, path ?: track.src ?: "", "navigating to track: ${track.title}")
|
|
658
705
|
}
|
|
659
706
|
}
|
|
660
707
|
}
|
|
661
708
|
|
|
662
|
-
override fun
|
|
709
|
+
override fun search(query: String): Promise<Array<Track>> {
|
|
663
710
|
return Promise.async(mainScope) {
|
|
664
711
|
Timber.d("Searching for: $query")
|
|
665
|
-
|
|
666
|
-
|
|
712
|
+
// Rejects with the error the browse surface would raise, but leaves the navigation error
|
|
713
|
+
// itself unset: a search is not a navigation, and its failure must not replace the
|
|
714
|
+
// displayed page's state (mirrors HybridAudioBrowser.search).
|
|
715
|
+
val searchResults =
|
|
716
|
+
try {
|
|
717
|
+
browserManager.search(query)
|
|
718
|
+
} catch (e: CancellationException) {
|
|
719
|
+
throw e
|
|
720
|
+
} catch (e: Exception) {
|
|
721
|
+
Timber.e(e, "Search failed for query: $query")
|
|
722
|
+
throw NavigationErrorException(navigationErrorFor(e))
|
|
723
|
+
}
|
|
724
|
+
// Flattened, not `children`: a resolved page carries its rows in
|
|
725
|
+
// `sections` (ADR 0010) and search builds exactly one untitled section,
|
|
726
|
+
// so `children` is always null here and this returned nothing at all.
|
|
727
|
+
searchResults.flattenedChildren?.toTypedArray() ?: emptyArray()
|
|
667
728
|
}
|
|
668
729
|
}
|
|
669
730
|
|
|
@@ -677,8 +738,9 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
677
738
|
// Invalidate cached content so future navigations fetch fresh data
|
|
678
739
|
browserManager.invalidateContentCache(path)
|
|
679
740
|
|
|
680
|
-
// Notify external media controllers (Android Auto)
|
|
681
|
-
|
|
741
|
+
// Notify external media controllers (Android Auto). Reaches MediaSession,
|
|
742
|
+
// which asserts the main thread; this override runs on the JS thread.
|
|
743
|
+
launchInScope { connectedService?.player?.notifyContentChanged(path) }
|
|
682
744
|
|
|
683
745
|
// If we're currently viewing this path, refresh the content
|
|
684
746
|
if (browserManager.getPath() == path) {
|
|
@@ -692,8 +754,10 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
692
754
|
// Clear all cached content so every path re-fetches fresh data
|
|
693
755
|
browserManager.clearContentCache()
|
|
694
756
|
|
|
695
|
-
// Notify external media controllers (Android Auto) to refresh subscribed paths
|
|
696
|
-
|
|
757
|
+
// Notify external media controllers (Android Auto) to refresh subscribed paths.
|
|
758
|
+
// Reaches MediaSession, which asserts the main thread; this override runs on
|
|
759
|
+
// the JS thread.
|
|
760
|
+
launchInScope { connectedService?.player?.invalidateAllContent() }
|
|
697
761
|
|
|
698
762
|
// Refresh whatever the browser is currently viewing
|
|
699
763
|
mainScope.launch { browserManager.refresh() }
|
|
@@ -734,14 +798,16 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
734
798
|
// Re-query every subscribed parent so a connected controller (Android
|
|
735
799
|
// Auto) swaps its lists for the gate tile without reconnecting. Notify
|
|
736
800
|
// only — the content cache stays warm for when the gate clears.
|
|
737
|
-
|
|
801
|
+
// MediaSession asserts the main thread; this override runs on the JS thread.
|
|
802
|
+
launchInScope { connectedService?.player?.invalidateAllContent() }
|
|
738
803
|
}
|
|
739
804
|
|
|
740
805
|
override fun clearGate() {
|
|
741
806
|
if (!gateState.active) return
|
|
742
807
|
// Single atomic assignment — readers never see a half-cleared triple.
|
|
743
808
|
gateState = GateState(active = false, chrome = null, hasResolver = false)
|
|
744
|
-
|
|
809
|
+
// MediaSession asserts the main thread; this override runs on the JS thread.
|
|
810
|
+
launchInScope { connectedService?.player?.invalidateAllContent() }
|
|
745
811
|
}
|
|
746
812
|
|
|
747
813
|
/**
|
|
@@ -781,7 +847,7 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
781
847
|
override var onCarConnectedChanged: (Boolean) -> Unit = {}
|
|
782
848
|
set(value) {
|
|
783
849
|
field = value
|
|
784
|
-
carConnectionTarget
|
|
850
|
+
carConnectionTarget.set(value)
|
|
785
851
|
// Immediately notify current state (the car may have connected before
|
|
786
852
|
// this JS runtime subscribed) — mirrors the iOS behavior.
|
|
787
853
|
value(carConnected)
|
|
@@ -811,12 +877,7 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
811
877
|
// Service not connected yet, bind to service
|
|
812
878
|
suspendCoroutine<Unit> { continuation ->
|
|
813
879
|
Timber.d("Binding to AudioBrowserService")
|
|
814
|
-
val bound =
|
|
815
|
-
context.bindService(
|
|
816
|
-
Intent(context, Service::class.java),
|
|
817
|
-
this@AudioBrowser,
|
|
818
|
-
Context.BIND_AUTO_CREATE,
|
|
819
|
-
)
|
|
880
|
+
val bound = serviceBinding.bind(Intent(context, Service::class.java), this@AudioBrowser)
|
|
820
881
|
|
|
821
882
|
if (!bound) {
|
|
822
883
|
continuation.resumeWithException(
|
|
@@ -832,8 +893,17 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
832
893
|
|
|
833
894
|
override fun updateOptions(options: NativeUpdateOptions) {
|
|
834
895
|
updateOptions.updateFromBridge(options)
|
|
835
|
-
// Only update the options if the service is around
|
|
836
|
-
|
|
896
|
+
// Only update the options if the service is around.
|
|
897
|
+
// applyOptions touches the Media3 player, which asserts it is only ever
|
|
898
|
+
// driven from the main thread ("Player callback method is called from a
|
|
899
|
+
// wrong thread"). Nitro invokes this from the JS thread, so hop.
|
|
900
|
+
//
|
|
901
|
+
// The hop blocks rather than launching because `updateOptions` is a single
|
|
902
|
+
// mutable holder: updateFromBridge mutates it in place on the JS thread and
|
|
903
|
+
// applyOptions reads it on main. Blocking is what keeps the two ordered.
|
|
904
|
+
connectedService?.let { service ->
|
|
905
|
+
runBlockingOnMain { service.player.applyOptions(updateOptions) }
|
|
906
|
+
}
|
|
837
907
|
}
|
|
838
908
|
|
|
839
909
|
override fun getOptions(): Options {
|
|
@@ -847,25 +917,27 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
847
917
|
// ============================================================================
|
|
848
918
|
|
|
849
919
|
override fun load(track: Track) {
|
|
920
|
+
// Throws without a player, as on iOS: a track asked for and silently dropped hides a mistake.
|
|
921
|
+
val player = player
|
|
850
922
|
launchInScope { player.load(track) }
|
|
851
923
|
}
|
|
852
924
|
|
|
853
|
-
override fun reset() =
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
925
|
+
override fun reset() =
|
|
926
|
+
commandPlayer("reset") { player ->
|
|
927
|
+
player.stop()
|
|
928
|
+
player.clear()
|
|
929
|
+
// clear() while IDLE emits no engine event, so the state machine never
|
|
930
|
+
// leaves STOPPED — a reset queue is "nothing loaded".
|
|
931
|
+
player.setPlaybackState(PlaybackState.NONE)
|
|
932
|
+
}
|
|
861
933
|
|
|
862
|
-
override fun play() =
|
|
934
|
+
override fun play() = commandPlayer("play") { it.play() }
|
|
863
935
|
|
|
864
|
-
override fun pause() =
|
|
936
|
+
override fun pause() = commandPlayer("pause") { it.pause() }
|
|
865
937
|
|
|
866
|
-
override fun togglePlayback() =
|
|
938
|
+
override fun togglePlayback() = commandPlayer("togglePlayback") { it.togglePlayback() }
|
|
867
939
|
|
|
868
|
-
override fun stop() =
|
|
940
|
+
override fun stop() = commandPlayer("stop") { it.stop() }
|
|
869
941
|
|
|
870
942
|
override fun setPlayWhenReady(playWhenReady: Boolean) = runBlockingOnMain {
|
|
871
943
|
// Pre-setup this stages the intent for the player to come up with — never throws.
|
|
@@ -877,35 +949,41 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
877
949
|
connectedService?.player?.playWhenReady ?: pendingPlayWhenReady ?: false
|
|
878
950
|
}
|
|
879
951
|
|
|
880
|
-
override fun seekTo(position: Double) =
|
|
881
|
-
|
|
882
|
-
|
|
952
|
+
override fun seekTo(position: Double) =
|
|
953
|
+
commandPlayer("seekTo") { player ->
|
|
954
|
+
player.seekTo((position * 1000).toLong(), TimeUnit.MILLISECONDS)
|
|
955
|
+
}
|
|
883
956
|
|
|
884
|
-
override fun seekBy(offset: Double) =
|
|
885
|
-
|
|
886
|
-
|
|
957
|
+
override fun seekBy(offset: Double) =
|
|
958
|
+
commandPlayer("seekBy") { player ->
|
|
959
|
+
player.seekBy((offset * 1000).toLong(), TimeUnit.MILLISECONDS)
|
|
960
|
+
}
|
|
887
961
|
|
|
888
|
-
override fun seekToLiveEdge() =
|
|
962
|
+
override fun seekToLiveEdge() = commandPlayer("seekToLiveEdge") { it.seekToLiveEdge() }
|
|
889
963
|
|
|
890
|
-
override fun setVolume(level: Double) =
|
|
964
|
+
override fun setVolume(level: Double) = commandPlayer("setVolume") { it.volume = level.toFloat() }
|
|
891
965
|
|
|
892
|
-
override fun getVolume(): Double =
|
|
966
|
+
override fun getVolume(): Double = readPlayer(1.0) { it.volume.toDouble() }
|
|
893
967
|
|
|
894
|
-
override fun setRate(rate: Double) =
|
|
968
|
+
override fun setRate(rate: Double) =
|
|
969
|
+
commandPlayer("setRate") { it.playbackSpeed = rate.toFloat() }
|
|
895
970
|
|
|
896
|
-
override fun getRate(): Double =
|
|
971
|
+
override fun getRate(): Double = readPlayer(1.0) { it.playbackSpeed.toDouble() }
|
|
897
972
|
|
|
898
|
-
override fun getProgress(): Progress =
|
|
899
|
-
Progress(
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
973
|
+
override fun getProgress(): Progress =
|
|
974
|
+
readPlayer(Progress(duration = 0.0, position = 0.0, buffered = 0.0)) { player ->
|
|
975
|
+
Progress(
|
|
976
|
+
duration = player.duration.toSeconds(),
|
|
977
|
+
position = player.position.toSeconds(),
|
|
978
|
+
buffered = player.bufferedPosition.toSeconds(),
|
|
979
|
+
)
|
|
980
|
+
}
|
|
905
981
|
|
|
906
|
-
override fun getPlayback(): Playback =
|
|
982
|
+
override fun getPlayback(): Playback =
|
|
983
|
+
readPlayer(Playback(PlaybackState.NONE, null)) { it.getPlayback() }
|
|
907
984
|
|
|
908
|
-
override fun getPlayingState(): PlayingState =
|
|
985
|
+
override fun getPlayingState(): PlayingState =
|
|
986
|
+
readPlayer(PlayingState(playing = false, buffering = false)) { it.getPlayingState() }
|
|
909
987
|
|
|
910
988
|
override fun getRepeatMode(): RepeatMode = runBlockingOnMain {
|
|
911
989
|
connectedService?.player?.repeatMode ?: pendingRepeatMode ?: RepeatMode.OFF
|
|
@@ -916,118 +994,121 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
916
994
|
connectedService?.player?.let { it.repeatMode = mode } ?: run { pendingRepeatMode = mode }
|
|
917
995
|
}
|
|
918
996
|
|
|
919
|
-
override fun getShuffleEnabled(): Boolean =
|
|
997
|
+
override fun getShuffleEnabled(): Boolean = readPlayer(false) { it.shuffleMode }
|
|
920
998
|
|
|
921
|
-
override fun setShuffleEnabled(enabled: Boolean) =
|
|
922
|
-
player.shuffleMode = enabled
|
|
923
|
-
}
|
|
999
|
+
override fun setShuffleEnabled(enabled: Boolean) =
|
|
1000
|
+
commandPlayer("setShuffleEnabled") { player -> player.shuffleMode = enabled }
|
|
924
1001
|
|
|
925
|
-
override fun setPlaybackIntervalEnabled(enabled: Boolean) =
|
|
926
|
-
|
|
927
|
-
|
|
1002
|
+
override fun setPlaybackIntervalEnabled(enabled: Boolean) =
|
|
1003
|
+
commandPlayer("setPlaybackIntervalEnabled") { player ->
|
|
1004
|
+
player.setPlaybackIntervalEnabled(enabled)
|
|
1005
|
+
}
|
|
928
1006
|
|
|
929
|
-
override fun getPlaybackError(): PlaybackError? =
|
|
1007
|
+
override fun getPlaybackError(): PlaybackError? = readPlayer(null) { it.playbackError }
|
|
930
1008
|
|
|
931
|
-
override fun retry() =
|
|
1009
|
+
override fun retry() = commandPlayer("retry") { it.prepare() }
|
|
932
1010
|
|
|
933
1011
|
// ============================================================================
|
|
934
1012
|
// MARK: Queue Management
|
|
935
1013
|
// ============================================================================
|
|
936
1014
|
|
|
937
|
-
override fun add(tracks: Array<Track>, insertBeforeIndex: Double?) =
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1015
|
+
override fun add(tracks: Array<Track>, insertBeforeIndex: Double?) =
|
|
1016
|
+
commandPlayer("add") { player ->
|
|
1017
|
+
val inputIndex = insertBeforeIndex?.toInt() ?: -1
|
|
1018
|
+
player.add(tracks, inputIndex)
|
|
1019
|
+
}
|
|
941
1020
|
|
|
942
|
-
override fun move(fromIndex: Double, toIndex: Double) =
|
|
943
|
-
player.move(fromIndex.toInt(), toIndex.toInt())
|
|
944
|
-
}
|
|
1021
|
+
override fun move(fromIndex: Double, toIndex: Double) =
|
|
1022
|
+
commandPlayer("move") { player -> player.move(fromIndex.toInt(), toIndex.toInt()) }
|
|
945
1023
|
|
|
946
|
-
override fun remove(indexes: DoubleArray) =
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
1024
|
+
override fun remove(indexes: DoubleArray) =
|
|
1025
|
+
commandPlayer("remove") { player ->
|
|
1026
|
+
val indexList = indexes.map { it.toInt() }
|
|
1027
|
+
player.remove(indexList)
|
|
1028
|
+
}
|
|
950
1029
|
|
|
951
|
-
override fun removeUpcomingTracks() =
|
|
1030
|
+
override fun removeUpcomingTracks() =
|
|
1031
|
+
commandPlayer("removeUpcomingTracks") { it.removeUpcomingTracks() }
|
|
952
1032
|
|
|
953
|
-
override fun skip(index: Double, initialPosition: Double?) =
|
|
954
|
-
|
|
1033
|
+
override fun skip(index: Double, initialPosition: Double?) =
|
|
1034
|
+
commandPlayer("skip") { player ->
|
|
1035
|
+
player.skipTo(index.toInt())
|
|
955
1036
|
|
|
956
|
-
|
|
957
|
-
|
|
1037
|
+
if (initialPosition != null && initialPosition >= 0) {
|
|
1038
|
+
player.seekTo((initialPosition * 1000).toLong(), TimeUnit.MILLISECONDS)
|
|
1039
|
+
}
|
|
958
1040
|
}
|
|
959
|
-
}
|
|
960
1041
|
|
|
961
|
-
override fun skipToNext(initialPosition: Double?) =
|
|
962
|
-
|
|
1042
|
+
override fun skipToNext(initialPosition: Double?) =
|
|
1043
|
+
commandPlayer("skipToNext") { player ->
|
|
1044
|
+
player.next()
|
|
963
1045
|
|
|
964
|
-
|
|
965
|
-
|
|
1046
|
+
if (initialPosition != null && initialPosition >= 0) {
|
|
1047
|
+
player.seekTo((initialPosition * 1000).toLong(), TimeUnit.MILLISECONDS)
|
|
1048
|
+
}
|
|
966
1049
|
}
|
|
967
|
-
}
|
|
968
1050
|
|
|
969
|
-
override fun skipToPrevious(initialPosition: Double?) =
|
|
970
|
-
|
|
1051
|
+
override fun skipToPrevious(initialPosition: Double?) =
|
|
1052
|
+
commandPlayer("skipToPrevious") { player ->
|
|
1053
|
+
player.previous()
|
|
971
1054
|
|
|
972
|
-
|
|
973
|
-
|
|
1055
|
+
if (initialPosition != null && initialPosition >= 0) {
|
|
1056
|
+
player.seekTo((initialPosition * 1000).toLong(), TimeUnit.MILLISECONDS)
|
|
1057
|
+
}
|
|
974
1058
|
}
|
|
975
|
-
}
|
|
976
1059
|
|
|
977
1060
|
override fun setQueue(tracks: Array<Track>, startIndex: Double?, startPosition: Double?) =
|
|
978
|
-
|
|
1061
|
+
commandPlayer("setQueue") { player ->
|
|
979
1062
|
player.setQueue(tracks, startIndex?.toInt() ?: 0, ((startPosition ?: 0.0) * 1000).toLong())
|
|
980
1063
|
}
|
|
981
1064
|
|
|
982
|
-
override fun setActiveTrackFavorited(favorited: Boolean) =
|
|
983
|
-
|
|
984
|
-
|
|
1065
|
+
override fun setActiveTrackFavorited(favorited: Boolean): Unit =
|
|
1066
|
+
commandPlayer("setActiveTrackFavorited") { player ->
|
|
1067
|
+
// Applied-result is for MediaSession honesty; the JS API stays fire-and-forget.
|
|
1068
|
+
player.setActiveTrackFavorited(favorited)
|
|
1069
|
+
}
|
|
985
1070
|
|
|
986
|
-
override fun toggleActiveTrackFavorited() =
|
|
987
|
-
|
|
988
|
-
}
|
|
1071
|
+
override fun toggleActiveTrackFavorited(): Unit =
|
|
1072
|
+
commandPlayer("toggleActiveTrackFavorited") { it.toggleActiveTrackFavorited() }
|
|
989
1073
|
|
|
990
|
-
override fun getQueue(): Array<Track> =
|
|
1074
|
+
override fun getQueue(): Array<Track> = readPlayer(emptyArray()) { it.tracks }
|
|
991
1075
|
|
|
992
|
-
override fun getTrack(index: Double): Track? =
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1076
|
+
override fun getTrack(index: Double): Track? =
|
|
1077
|
+
readPlayer(null) { player ->
|
|
1078
|
+
try {
|
|
1079
|
+
player.getTrack(index.toInt())
|
|
1080
|
+
} catch (e: IllegalArgumentException) {
|
|
1081
|
+
null
|
|
1082
|
+
}
|
|
997
1083
|
}
|
|
998
|
-
}
|
|
999
1084
|
|
|
1000
|
-
override fun getActiveTrackIndex(): Double? =
|
|
1001
|
-
player.currentIndex?.toDouble()
|
|
1002
|
-
}
|
|
1085
|
+
override fun getActiveTrackIndex(): Double? = readPlayer(null) { it.currentIndex?.toDouble() }
|
|
1003
1086
|
|
|
1004
|
-
override fun getActiveTrack(): Track? =
|
|
1087
|
+
override fun getActiveTrack(): Track? = readPlayer(null) { it.currentTrack }
|
|
1005
1088
|
|
|
1006
1089
|
// ============================================================================
|
|
1007
1090
|
// MARK: Now Playing Metadata
|
|
1008
1091
|
// ============================================================================
|
|
1009
1092
|
|
|
1010
|
-
override fun updateNowPlaying(update: NowPlayingUpdate?) =
|
|
1011
|
-
player.nowPlaying.updateNowPlaying(update)
|
|
1012
|
-
}
|
|
1093
|
+
override fun updateNowPlaying(update: NowPlayingUpdate?) =
|
|
1094
|
+
commandPlayer("updateNowPlaying") { player -> player.nowPlaying.updateNowPlaying(update) }
|
|
1013
1095
|
|
|
1014
|
-
override fun flashNowPlaying(update: NowPlayingUpdate, durationMs: Double) =
|
|
1015
|
-
|
|
1016
|
-
|
|
1096
|
+
override fun flashNowPlaying(update: NowPlayingUpdate, durationMs: Double) =
|
|
1097
|
+
commandPlayer("flashNowPlaying") { player ->
|
|
1098
|
+
player.nowPlaying.flashNowPlaying(update, durationMs)
|
|
1099
|
+
}
|
|
1017
1100
|
|
|
1018
|
-
override fun clearNowPlayingFlash() =
|
|
1019
|
-
player.nowPlaying.clearNowPlayingFlash()
|
|
1020
|
-
}
|
|
1101
|
+
override fun clearNowPlayingFlash() =
|
|
1102
|
+
commandPlayer("clearNowPlayingFlash") { player -> player.nowPlaying.clearNowPlayingFlash() }
|
|
1021
1103
|
|
|
1022
|
-
override fun getNowPlaying(): NowPlayingMetadata? =
|
|
1023
|
-
player.nowPlaying.getNowPlaying()
|
|
1024
|
-
}
|
|
1104
|
+
override fun getNowPlaying(): NowPlayingMetadata? =
|
|
1105
|
+
readPlayer(null) { player -> player.nowPlaying.getNowPlaying() }
|
|
1025
1106
|
|
|
1026
1107
|
// ============================================================================
|
|
1027
1108
|
// MARK: Network Connectivity
|
|
1028
1109
|
// ============================================================================
|
|
1029
1110
|
|
|
1030
|
-
override fun getOnline(): Boolean =
|
|
1111
|
+
override fun getOnline(): Boolean = readPlayer(true) { it.getOnline() }
|
|
1031
1112
|
|
|
1032
1113
|
// ============================================================================
|
|
1033
1114
|
// MARK: System Volume
|
|
@@ -1053,35 +1134,32 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
1053
1134
|
// MARK: Equalizer (Android only)
|
|
1054
1135
|
// ============================================================================
|
|
1055
1136
|
|
|
1056
|
-
override fun getEqualizerSettings(): EqualizerSettings? =
|
|
1057
|
-
player.equalizer.getSettings()
|
|
1058
|
-
}
|
|
1137
|
+
override fun getEqualizerSettings(): EqualizerSettings? =
|
|
1138
|
+
readPlayer(null) { player -> player.equalizer.getSettings() }
|
|
1059
1139
|
|
|
1060
|
-
override fun setEqualizerEnabled(enabled: Boolean) =
|
|
1061
|
-
player.equalizer.setEnabled(enabled)
|
|
1062
|
-
}
|
|
1140
|
+
override fun setEqualizerEnabled(enabled: Boolean) =
|
|
1141
|
+
commandPlayer("setEqualizerEnabled") { player -> player.equalizer.setEnabled(enabled) }
|
|
1063
1142
|
|
|
1064
|
-
override fun setEqualizerPreset(preset: String) =
|
|
1065
|
-
player.equalizer.setPreset(preset)
|
|
1066
|
-
}
|
|
1143
|
+
override fun setEqualizerPreset(preset: String) =
|
|
1144
|
+
commandPlayer("setEqualizerPreset") { player -> player.equalizer.setPreset(preset) }
|
|
1067
1145
|
|
|
1068
|
-
override fun setEqualizerLevels(levels: DoubleArray) =
|
|
1069
|
-
player.equalizer.setLevels(levels)
|
|
1070
|
-
}
|
|
1146
|
+
override fun setEqualizerLevels(levels: DoubleArray) =
|
|
1147
|
+
commandPlayer("setEqualizerLevels") { player -> player.equalizer.setLevels(levels) }
|
|
1071
1148
|
|
|
1072
1149
|
// ============================================================================
|
|
1073
1150
|
// MARK: Sleep Timer
|
|
1074
1151
|
// ============================================================================
|
|
1075
1152
|
|
|
1076
|
-
override fun getSleepTimer(): SleepTimer =
|
|
1153
|
+
override fun getSleepTimer(): SleepTimer =
|
|
1154
|
+
readPlayer(SleepTimer.create(NullType.NULL)) { it.sleepTimer.get() }
|
|
1077
1155
|
|
|
1078
|
-
override fun setSleepTimer(seconds: Double, fadeDuration: Double?) =
|
|
1079
|
-
player.sleepTimer.setAfter(seconds, fadeDuration)
|
|
1080
|
-
}
|
|
1156
|
+
override fun setSleepTimer(seconds: Double, fadeDuration: Double?) =
|
|
1157
|
+
commandPlayer("setSleepTimer") { player -> player.sleepTimer.setAfter(seconds, fadeDuration) }
|
|
1081
1158
|
|
|
1082
|
-
override fun setSleepTimerToEndOfTrack() =
|
|
1159
|
+
override fun setSleepTimerToEndOfTrack() =
|
|
1160
|
+
commandPlayer("setSleepTimerToEndOfTrack") { it.sleepTimer.setEndOfTrack() }
|
|
1083
1161
|
|
|
1084
|
-
override fun clearSleepTimer(): Boolean =
|
|
1162
|
+
override fun clearSleepTimer(): Boolean = readPlayer(false) { it.sleepTimer.clear() }
|
|
1085
1163
|
|
|
1086
1164
|
// ============================================================================
|
|
1087
1165
|
// MARK: Battery Optimization (Android only)
|
|
@@ -1175,13 +1253,7 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
1175
1253
|
}
|
|
1176
1254
|
|
|
1177
1255
|
// Wire up battery warning callback from service
|
|
1178
|
-
connectedService?.onBatteryWarningPendingChanged =
|
|
1179
|
-
post {
|
|
1180
|
-
this@AudioBrowser.onBatteryWarningPendingChanged(
|
|
1181
|
-
BatteryWarningPendingChangedEvent(pending)
|
|
1182
|
-
)
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1256
|
+
connectedService?.onBatteryWarningPendingChanged = onBatteryWarningPending
|
|
1185
1257
|
|
|
1186
1258
|
val sessionToken = SessionToken(context, ComponentName(context, Service::class.java))
|
|
1187
1259
|
mediaBrowserFuture = MediaBrowser.Builder(context, sessionToken).buildAsync()
|
|
@@ -1228,6 +1300,29 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
1228
1300
|
private val service: Service
|
|
1229
1301
|
get() = connectedService ?: throw Exception("Player not initialized")
|
|
1230
1302
|
|
|
1303
|
+
/**
|
|
1304
|
+
* The player while its service is connected: not before setupPlayer, nor while the service
|
|
1305
|
+
* restarts.
|
|
1306
|
+
*/
|
|
1307
|
+
private val connectedPlayer: Player?
|
|
1308
|
+
get() = connectedService?.player
|
|
1309
|
+
|
|
1310
|
+
/** What [read] gets from the player, or without one [fallback], the answer iOS gives then. */
|
|
1311
|
+
private fun <T> readPlayer(fallback: T, read: suspend (Player) -> T): T = runBlockingOnMain {
|
|
1312
|
+
val player = connectedPlayer ?: return@runBlockingOnMain fallback
|
|
1313
|
+
read(player)
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
/** Runs [command] on the player; without one it is dropped with a warning, as iOS drops it. */
|
|
1317
|
+
private fun commandPlayer(name: String, command: suspend (Player) -> Unit) = runBlockingOnMain {
|
|
1318
|
+
val player = connectedPlayer
|
|
1319
|
+
if (player == null) {
|
|
1320
|
+
Timber.w("$name before the player is set up, or while its service restarts: ignored")
|
|
1321
|
+
} else {
|
|
1322
|
+
command(player)
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1231
1326
|
internal val player
|
|
1232
1327
|
get() = service.player
|
|
1233
1328
|
|
|
@@ -1436,9 +1531,27 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
1436
1531
|
// callback registers as the single notification target (mirrors the iOS
|
|
1437
1532
|
// static + shared-instance pattern).
|
|
1438
1533
|
@Volatile private var carConnected = false
|
|
1439
|
-
@Volatile
|
|
1534
|
+
// Compare-and-set, not @Volatile: a disposing instance clears the slot only if it still owns
|
|
1535
|
+
// it, and a replacement may be claiming it at the same moment.
|
|
1536
|
+
private val carConnectionTarget = AtomicReference<((Boolean) -> Unit)?>(null)
|
|
1440
1537
|
private var carConnectionObserverStarted = false
|
|
1441
1538
|
|
|
1539
|
+
/**
|
|
1540
|
+
* The instance the current JS runtime is using. Nitro hands out no registry, and the teardown
|
|
1541
|
+
* callback has nothing to dispose without one.
|
|
1542
|
+
*/
|
|
1543
|
+
private val current = AtomicReference<AudioBrowser?>(null)
|
|
1544
|
+
|
|
1545
|
+
/** Called by [AudioBrowserLifecycleModule] when the React instance is torn down. */
|
|
1546
|
+
internal fun disposeCurrent() {
|
|
1547
|
+
current.getAndSet(null)?.dispose()
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
/** Shared by the [resolveGate] initializer and [dispose], which reverts to it. */
|
|
1551
|
+
private val defaultResolveGate: (NativeGateRequest) -> Promise<Promise<GateDecision>> = {
|
|
1552
|
+
Promise.resolved(Promise.resolved(GateDecision(gated = true, gate = null)))
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1442
1555
|
private fun startCarConnectionObserver(context: Context, handler: Handler) {
|
|
1443
1556
|
// Posted to main: LiveData observation is main-thread only, and the
|
|
1444
1557
|
// single-start guard is then only ever touched from one thread.
|
|
@@ -1449,9 +1562,159 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
|
|
|
1449
1562
|
val connected = type != CarConnection.CONNECTION_TYPE_NOT_CONNECTED
|
|
1450
1563
|
if (connected == carConnected) return@observeForever
|
|
1451
1564
|
carConnected = connected
|
|
1452
|
-
carConnectionTarget?.invoke(connected)
|
|
1565
|
+
carConnectionTarget.get()?.invoke(connected)
|
|
1453
1566
|
}
|
|
1454
1567
|
}
|
|
1455
1568
|
}
|
|
1456
1569
|
}
|
|
1457
1570
|
}
|
|
1571
|
+
|
|
1572
|
+
// MARK: Deep JS-callback stripping (used by dispose)
|
|
1573
|
+
// Functions live at every level of the config, not just the top; each type's strip nils its own.
|
|
1574
|
+
|
|
1575
|
+
private fun NativeBrowserConfiguration.strippingJSCallbacks() =
|
|
1576
|
+
copy(
|
|
1577
|
+
requestResolver = null,
|
|
1578
|
+
browseResolver = null,
|
|
1579
|
+
handleTrackLoad = null,
|
|
1580
|
+
viewMoreTitle = null,
|
|
1581
|
+
resolveAlbumPath = null,
|
|
1582
|
+
formatNavigationError = null,
|
|
1583
|
+
request = request?.strippingJSCallbacks(),
|
|
1584
|
+
browse = browse?.strippingJSCallbacks(),
|
|
1585
|
+
media = media?.strippingJSCallbacks(),
|
|
1586
|
+
artwork = artwork?.strippingJSCallbacks(),
|
|
1587
|
+
nowPlayingArtwork = nowPlayingArtwork?.strippingJSCallbacks(),
|
|
1588
|
+
routes = routes?.map { it.strippingJSCallbacks() }?.toTypedArray(),
|
|
1589
|
+
)
|
|
1590
|
+
|
|
1591
|
+
private fun TransformableRequestConfig.strippingJSCallbacks() =
|
|
1592
|
+
copy(transform = null, transformSync = null)
|
|
1593
|
+
|
|
1594
|
+
private fun MediaRequestConfig.strippingJSCallbacks() =
|
|
1595
|
+
copy(resolve = null, resolveSync = null, transform = null, transformSync = null)
|
|
1596
|
+
|
|
1597
|
+
private fun ArtworkRequestConfig.strippingJSCallbacks() =
|
|
1598
|
+
copy(resolve = null, resolveSync = null, transform = null, transformSync = null)
|
|
1599
|
+
|
|
1600
|
+
private fun NativeRouteEntry.strippingJSCallbacks() =
|
|
1601
|
+
copy(
|
|
1602
|
+
browseCallback = null,
|
|
1603
|
+
browseConfig = browseConfig?.strippingJSCallbacks(),
|
|
1604
|
+
searchCallback = null,
|
|
1605
|
+
searchConfig = searchConfig?.strippingJSCallbacks(),
|
|
1606
|
+
media = media?.strippingJSCallbacks(),
|
|
1607
|
+
artwork = artwork?.strippingJSCallbacks(),
|
|
1608
|
+
)
|
|
1609
|
+
|
|
1610
|
+
/**
|
|
1611
|
+
* Ceiling on the app's `formatNavigationError` hop. Same budget [Player.awaitBrowser] gives the JS
|
|
1612
|
+
* side, the only other JS wait a browse serve already blocks on.
|
|
1613
|
+
*/
|
|
1614
|
+
private val FORMATTER_TIMEOUT = 10.seconds
|
|
1615
|
+
|
|
1616
|
+
/**
|
|
1617
|
+
* The navigation error an exception raises. Shared by [AudioBrowser]'s failed navigations, the
|
|
1618
|
+
* rejection [AudioBrowser.search] hands JS, and the Android Auto browse-error tile, so one failure
|
|
1619
|
+
* is named one way wherever it surfaces.
|
|
1620
|
+
*/
|
|
1621
|
+
internal fun navigationErrorFor(e: Exception): NavigationError =
|
|
1622
|
+
when (e) {
|
|
1623
|
+
is HttpStatusException ->
|
|
1624
|
+
NavigationError(
|
|
1625
|
+
NavigationErrorType.HTTP_ERROR,
|
|
1626
|
+
e.message ?: "Server error",
|
|
1627
|
+
e.statusCode.toDouble(),
|
|
1628
|
+
e.statusCode in 200..299,
|
|
1629
|
+
)
|
|
1630
|
+
is NetworkException ->
|
|
1631
|
+
NavigationError(
|
|
1632
|
+
NavigationErrorType.NETWORK_ERROR,
|
|
1633
|
+
e.message ?: "Network request failed",
|
|
1634
|
+
null,
|
|
1635
|
+
null,
|
|
1636
|
+
)
|
|
1637
|
+
is ContentNotFoundException ->
|
|
1638
|
+
NavigationError(
|
|
1639
|
+
NavigationErrorType.CONTENT_NOT_FOUND,
|
|
1640
|
+
e.message ?: "Content not found",
|
|
1641
|
+
null,
|
|
1642
|
+
null,
|
|
1643
|
+
)
|
|
1644
|
+
is CallbackException ->
|
|
1645
|
+
NavigationError(
|
|
1646
|
+
NavigationErrorType.CALLBACK_ERROR,
|
|
1647
|
+
e.message ?: "An error occurred",
|
|
1648
|
+
null,
|
|
1649
|
+
null,
|
|
1650
|
+
)
|
|
1651
|
+
else ->
|
|
1652
|
+
NavigationError(
|
|
1653
|
+
NavigationErrorType.UNKNOWN_ERROR,
|
|
1654
|
+
e.message ?: "An unexpected error occurred",
|
|
1655
|
+
null,
|
|
1656
|
+
null,
|
|
1657
|
+
)
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
/** Carries a [NavigationError] across a rejected Promise, whose JS error keeps its message. */
|
|
1661
|
+
class NavigationErrorException(val error: NavigationError) : Exception(error.message)
|
|
1662
|
+
|
|
1663
|
+
/**
|
|
1664
|
+
* The built-in display copy for a navigation error, and the fallback when the app's is unusable.
|
|
1665
|
+
*/
|
|
1666
|
+
internal fun defaultFormattedError(error: NavigationError): FormattedNavigationError {
|
|
1667
|
+
val title =
|
|
1668
|
+
when (error.code) {
|
|
1669
|
+
NavigationErrorType.CONTENT_NOT_FOUND -> "Content Not Found"
|
|
1670
|
+
NavigationErrorType.NETWORK_ERROR -> "Network Error"
|
|
1671
|
+
NavigationErrorType.HTTP_ERROR -> {
|
|
1672
|
+
// Use system-localized HTTP status text (e.g., "Not Found", "Service Unavailable")
|
|
1673
|
+
error.statusCode?.let { httpStatusText(it.toInt()) } ?: "Server Error"
|
|
1674
|
+
}
|
|
1675
|
+
NavigationErrorType.CALLBACK_ERROR -> "Error"
|
|
1676
|
+
NavigationErrorType.UNKNOWN_ERROR -> "Error"
|
|
1677
|
+
// Not a failure — a container that resolved with no children. Neutral copy. See ADR 0001.
|
|
1678
|
+
NavigationErrorType.EMPTY_CONTENT -> "Nothing here"
|
|
1679
|
+
NavigationErrorType.TIMEOUT -> "Couldn't load"
|
|
1680
|
+
}
|
|
1681
|
+
// Omit an empty message so it renders as title-only (e.g. the empty-content case).
|
|
1682
|
+
return FormattedNavigationError(title, error.message.takeIf { it.isNotEmpty() })
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
/**
|
|
1686
|
+
* The formatter hop's fallback rule: the app's answer when it produces one, [default] when it
|
|
1687
|
+
* answers null, throws, or outruns [FORMATTER_TIMEOUT]. Kept off the JS edge so the rule is
|
|
1688
|
+
* exercisable without a Nitro Promise.
|
|
1689
|
+
*
|
|
1690
|
+
* The hop runs in [scope] and is awaited through its [kotlinx.coroutines.Deferred], because Nitro's
|
|
1691
|
+
* `Promise.await` parks in a plain `suspendCoroutine`: cancelling it does not unpark it. Awaiting
|
|
1692
|
+
* the Deferred is cancellable, so the timeout leaves the orphan to finish unobserved instead of
|
|
1693
|
+
* holding the caller open until JS answers — which for a browse serve would be forever.
|
|
1694
|
+
*/
|
|
1695
|
+
internal suspend fun formattedOrDefault(
|
|
1696
|
+
scope: CoroutineScope,
|
|
1697
|
+
default: FormattedNavigationError,
|
|
1698
|
+
format: suspend () -> FormattedNavigationError?,
|
|
1699
|
+
): FormattedNavigationError {
|
|
1700
|
+
val hop = scope.async { runCatching { format() }.getOrNull() }
|
|
1701
|
+
return withTimeoutOrNull(FORMATTER_TIMEOUT) { hop.await() } ?: default
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
/** Returns localized HTTP status text for the given status code */
|
|
1705
|
+
private fun httpStatusText(statusCode: Int): String {
|
|
1706
|
+
return when (statusCode) {
|
|
1707
|
+
400 -> "Bad Request"
|
|
1708
|
+
401 -> "Unauthorized"
|
|
1709
|
+
403 -> "Forbidden"
|
|
1710
|
+
404 -> "Not Found"
|
|
1711
|
+
405 -> "Method Not Allowed"
|
|
1712
|
+
408 -> "Request Timeout"
|
|
1713
|
+
429 -> "Too Many Requests"
|
|
1714
|
+
500 -> "Internal Server Error"
|
|
1715
|
+
502 -> "Bad Gateway"
|
|
1716
|
+
503 -> "Service Unavailable"
|
|
1717
|
+
504 -> "Gateway Timeout"
|
|
1718
|
+
else -> "Server Error"
|
|
1719
|
+
}
|
|
1720
|
+
}
|