react-native-audio-browser 0.2.0-next.2 → 0.2.0-next.21
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 +35 -21
- 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 +389 -164
- 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 +48 -0
- package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +315 -213
- package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +24 -5
- package/android/src/main/java/com/audiobrowser/browser/InertStyleDiagnostic.kt +267 -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 +56 -40
- package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +28 -23
- package/android/src/main/java/com/audiobrowser/util/StyleWire.kt +108 -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 +87 -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 +38 -0
- package/android/src/test/java/com/audiobrowser/browser/InertStyleDiagnosticTest.kt +277 -0
- package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +3 -2
- package/android/src/test/java/com/audiobrowser/browser/JsonStyleTest.kt +147 -0
- package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +128 -55
- package/android/src/test/java/com/audiobrowser/browser/StyleResolverTest.kt +154 -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 +41 -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/Browser/BrowserConfig.swift +102 -5
- package/ios/Browser/BrowserManager+URLResolution.swift +18 -14
- package/ios/Browser/BrowserManager.swift +230 -205
- package/ios/Browser/BrowserPathHelper.swift +44 -44
- package/ios/Browser/InertStyleDiagnostic.swift +279 -0
- package/ios/Browser/JsonModels.swift +264 -106
- package/ios/Browser/SearchDrillIn.swift +7 -7
- package/ios/Browser/SectionPresentation.swift +64 -0
- 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/CarPlayArtworkResolver.swift +8 -7
- package/ios/CarPlay/CarPlayController.swift +227 -85
- package/ios/CarPlay/CarPlayImageLoader.swift +42 -20
- package/ios/CarPlay/CarPlayListItemFactory.swift +289 -84
- package/ios/CarPlay/CarPlayNowPlayingManager.swift +15 -12
- package/ios/CarPlay/RNABMediaAddHandler.swift +6 -6
- package/ios/CarPlay/RNABMediaAffinityHandler.swift +2 -2
- package/ios/CarPlay/RNABMediaIntentHandler.swift +16 -16
- package/ios/Extension/Capability+RemoteCommand.swift +1 -1
- 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/Http/HttpClient.swift +8 -2
- package/ios/HybridAudioBrowser.swift +253 -100
- package/ios/Model/NitroTypeStubs.swift +125 -23
- package/ios/Model/PlayerUpdateOptions.swift +7 -0
- package/ios/Model/RemoteCommand.swift +18 -0
- package/ios/Model/TrackPlayerError.swift +2 -2
- package/ios/Option/SessionCategories.swift +3 -2
- package/ios/Player/MediaIntentCriteria.swift +17 -9
- package/ios/Player/MediaLoader.swift +33 -9
- package/ios/Player/NowPlayingUpdater.swift +54 -6
- package/ios/Player/PlaybackCoordinator.swift +13 -6
- package/ios/Player/PlaybackErrorHandler.swift +4 -4
- package/ios/Player/PlaybackTimer.swift +8 -2
- package/ios/Player/QueueManager.swift +46 -13
- package/ios/Player/RetryManager.swift +80 -18
- package/ios/Player/SeekCompletionHandler.swift +3 -1
- package/ios/Player/ShuffleOrder.swift +33 -0
- package/ios/Player/SleepTimerHandling.swift +13 -0
- package/ios/RemoteCommand/RemoteCommandCallbacks.swift +47 -0
- package/ios/RemoteCommand/RemoteCommandController.swift +62 -24
- package/ios/Tests/BrowserPathHelperTests.swift +50 -20
- package/ios/Tests/CarPlayArtworkResolverTests.swift +24 -41
- package/ios/Tests/InertStyleDiagnosticTests.swift +200 -0
- package/ios/Tests/JsonModelsTests.swift +150 -1
- package/ios/Tests/LRUCacheTests.swift +111 -0
- package/ios/Tests/LoadSeekCoordinatorTests.swift +3 -1
- package/ios/Tests/MediaIntentCriteriaTests.swift +2 -2
- package/ios/Tests/PlaybackCoordinatorTests.swift +1 -1
- package/ios/Tests/PlaybackErrorHandlerTests.swift +3 -1
- package/ios/Tests/PlaybackStateStoreTests.swift +4 -3
- package/ios/Tests/PlayerTimeObserverTests.swift +37 -0
- package/ios/Tests/QueueManagerTests.swift +122 -10
- package/ios/Tests/RemoteCommandControllerTests.swift +172 -0
- package/ios/Tests/RemoteCommandTests.swift +67 -0
- package/ios/Tests/ResolvedTrackCopyingTests.swift +39 -35
- package/ios/Tests/RetryManagerTests.swift +89 -0
- package/ios/Tests/SearchDrillInTests.swift +16 -16
- package/ios/Tests/SectionPresentationTests.swift +90 -0
- package/ios/Tests/SectionScopeTests.swift +87 -55
- package/ios/Tests/StyleResolverTests.swift +127 -0
- package/ios/Tests/Support/TestTypes.swift +8 -1
- package/ios/Tests/TabBarEntriesTests.swift +19 -19
- package/ios/Tests/TimedMetadataAVFoundationTests.swift +42 -0
- package/ios/Tests/TrackIdTemplateTests.swift +67 -0
- package/ios/Tests/TrackIdentityTests.swift +20 -0
- package/ios/Tests/TrackSelectorTests.swift +168 -33
- package/ios/TrackPlayer.swift +63 -35
- package/ios/TrackPlayerCallbacks.swift +5 -38
- package/ios/TrackSelector.swift +45 -30
- package/ios/Util/ArtworkImageFetcher.swift +16 -1
- package/ios/Util/LRUCache.swift +4 -1
- package/ios/Util/NetworkMonitor.swift +43 -26
- package/ios/Util/SFSymbolRenderer.swift +24 -2
- package/ios/Util/SVGProcessor.swift +9 -2
- 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 +200 -75
- 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/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/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 +56 -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 +200 -75
- 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/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/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 +56 -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 +380 -126
- package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
- package/lib/typescript/src/types/browser.d.ts +82 -57
- 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/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 +2 -0
- package/nitrogen/generated/android/c++/JAndroidOptions.hpp +10 -10
- package/nitrogen/generated/android/c++/{JFavoritesMatchMode.hpp → JArtworkRendering.hpp} +15 -15
- package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +8 -3
- package/nitrogen/generated/android/c++/JBrowseResult.hpp +16 -4
- package/nitrogen/generated/android/c++/JCarPlayPlayingIndicatorLocation.hpp +58 -0
- package/nitrogen/generated/android/c++/JCardImage.hpp +58 -0
- package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +8 -3
- package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +8 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +8 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +8 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +8 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +8 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +8 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +8 -2
- 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 +16 -4
- package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +8 -3
- package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +7 -10
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +8 -3
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +15 -3
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +8 -2
- package/nitrogen/generated/android/c++/JGridTile.hpp +61 -0
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +45 -25
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.hpp +1 -1
- package/nitrogen/generated/android/c++/JIOSOptions.hpp +9 -3
- package/nitrogen/generated/android/c++/JImageShape.hpp +58 -0
- package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +8 -3
- package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +36 -11
- package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +14 -2
- package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +15 -12
- package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +7 -10
- package/nitrogen/generated/android/c++/JNitroAndroidUpdateOptions.hpp +10 -10
- package/nitrogen/generated/android/c++/JNitroIOSUpdateOptions.hpp +9 -3
- package/nitrogen/generated/android/c++/JOptions.hpp +7 -10
- package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +8 -3
- package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +5 -11
- 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++/JResolvedTrack.hpp +57 -49
- package/nitrogen/generated/android/c++/JSection.hpp +116 -0
- package/nitrogen/generated/android/c++/JSectionStyle.hpp +96 -0
- package/nitrogen/generated/android/c++/JStyleDisplay.hpp +58 -0
- package/nitrogen/generated/android/c++/JTrack.hpp +25 -46
- package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +8 -2
- package/nitrogen/generated/android/c++/JTrackStyle.hpp +46 -18
- 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 +16 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidOptions.kt +3 -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/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/Func_std__shared_ptr_Promise_std__string__.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/GridTile.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HybridAudioBrowserSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSOptions.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageShape.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +8 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroAndroidUpdateOptions.kt +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroIOSUpdateOptions.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{NotificationButton.kt → RemoteButton.kt} +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteButtonLayout.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +12 -15
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoriteConfig.kt → Section.kt} +15 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SectionStyle.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StyleDisplay.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +6 -12
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackStyle.kt +35 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Variant_NullType_NotificationButtonLayout.kt → Variant_NullType_RemoteButtonLayout.kt} +9 -9
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.cpp +9 -0
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +244 -133
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +31 -16
- package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +33 -18
- package/nitrogen/generated/ios/swift/AndroidOptions.swift +12 -12
- package/nitrogen/generated/ios/swift/ArtworkRendering.swift +40 -0
- package/nitrogen/generated/ios/swift/CarPlayPlayingIndicatorLocation.swift +40 -0
- package/nitrogen/generated/ios/swift/CardImage.swift +40 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__string__.swift +54 -0
- package/nitrogen/generated/ios/swift/GridTile.swift +44 -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/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/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_NullType_NotificationButtonLayout.swift → Variant_NullType_RemoteButtonLayout.swift} +3 -3
- 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++/GridTile.hpp +80 -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++/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 +396 -134
- package/src/types/browser.ts +85 -59
- 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 +239 -82
- 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/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/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 +52 -0
- package/src/web/util/BrowserPathHelper.ts +61 -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 +581 -0
- package/website/guide/carplay.md +620 -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/CarPlay/ImageRowItem+CarPlay.swift +0 -19
- package/ios/Model/MediaURL.swift +0 -67
- package/nitrogen/generated/android/c++/JFavoriteConfig.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/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/shared/c++/FavoriteConfig.hpp +0 -84
- package/nitrogen/generated/shared/c++/ImageRowItem.hpp +0 -129
- package/nitrogen/generated/shared/c++/NotificationButtonLayout.hpp +0 -102
|
@@ -5,29 +5,39 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.NativeUpdatedValue = void 0;
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* The subscription object behind the library's **state** events — every
|
|
9
|
+
* `on<Thing>Changed`-style export (`onPlaybackChanged`, `onQueueChanged`, …)
|
|
10
|
+
* is one of these. Subscribe with {@link addListener}; the returned function
|
|
11
|
+
* unsubscribes. The emitter is not callable itself.
|
|
9
12
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* For discrete events without a current value (remote controls), use LazyNativeEmitter instead.
|
|
13
|
+
* It tracks a value that always has a *current* reading (playback state,
|
|
14
|
+
* progress, options): {@link lastValue} caches the most recent one so hooks —
|
|
15
|
+
* and you — can read it synchronously without a getter round-trip. Discrete
|
|
16
|
+
* events with no current value (remote-control presses) use
|
|
17
|
+
* `LazyNativeEmitter` instead.
|
|
16
18
|
*
|
|
17
19
|
* @example
|
|
18
20
|
* ```typescript
|
|
19
|
-
*
|
|
20
|
-
* (cb) => (nativeBrowser.onPlaybackChanged = cb)
|
|
21
|
-
* )
|
|
21
|
+
* import { onPlaybackChanged } from 'react-native-audio-browser'
|
|
22
22
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* }
|
|
23
|
+
* const unsubscribe = onPlaybackChanged.addListener((p) => {
|
|
24
|
+
* console.log(p.state)
|
|
25
|
+
* })
|
|
26
|
+
* // later:
|
|
27
|
+
* unsubscribe()
|
|
26
28
|
* ```
|
|
27
29
|
*/
|
|
28
30
|
class NativeUpdatedValue {
|
|
29
31
|
listeners = new Set();
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The most recent value delivered by native, or `undefined` before the
|
|
35
|
+
* first update. Subscription starts at module load, so this is safe to
|
|
36
|
+
* read synchronously at any time.
|
|
37
|
+
*/
|
|
30
38
|
lastValue = undefined;
|
|
39
|
+
|
|
40
|
+
/** @internal */
|
|
31
41
|
constructor(setter) {
|
|
32
42
|
// Install native callback immediately at module load
|
|
33
43
|
setter(data => {
|
|
@@ -37,6 +47,13 @@ class NativeUpdatedValue {
|
|
|
37
47
|
}
|
|
38
48
|
});
|
|
39
49
|
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Subscribes to value changes.
|
|
53
|
+
*
|
|
54
|
+
* @param callback - Invoked with each new value
|
|
55
|
+
* @returns A function that removes the listener
|
|
56
|
+
*/
|
|
40
57
|
addListener(callback) {
|
|
41
58
|
this.listeners.add(callback);
|
|
42
59
|
return () => this.listeners.delete(callback);
|
|
@@ -47,6 +64,7 @@ class NativeUpdatedValue {
|
|
|
47
64
|
*
|
|
48
65
|
* @param setter - Function that sets the native callback property
|
|
49
66
|
* @returns The subscription instance with lastValue and addListener
|
|
67
|
+
* @internal
|
|
50
68
|
*/
|
|
51
69
|
static emitterize(setter) {
|
|
52
70
|
return new NativeUpdatedValue(setter);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeUpdatedValue","listeners","Set","lastValue","undefined","constructor","setter","data","listener","addListener","callback","add","delete","emitterize","exports"],"sourceRoot":"../../../src","sources":["utils/NativeUpdatedValue.ts"],"mappings":";;;;;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMA,kBAAkB,CAAI;EACzBC,SAAS,GAAG,IAAIC,GAAG,CAAc,CAAC;
|
|
1
|
+
{"version":3,"names":["NativeUpdatedValue","listeners","Set","lastValue","undefined","constructor","setter","data","listener","addListener","callback","add","delete","emitterize","exports"],"sourceRoot":"../../../src","sources":["utils/NativeUpdatedValue.ts"],"mappings":";;;;;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMA,kBAAkB,CAAI;EACzBC,SAAS,GAAG,IAAIC,GAAG,CAAc,CAAC;;EAE1C;AACF;AACA;AACA;AACA;EACEC,SAAS,GAAkBC,SAAS;;EAEpC;EACAC,WAAWA,CAACC,MAA6C,EAAE;IACzD;IACAA,MAAM,CAAEC,IAAO,IAAK;MAClB,IAAI,CAACJ,SAAS,GAAGI,IAAI;MACrB,KAAK,MAAMC,QAAQ,IAAI,IAAI,CAACP,SAAS,EAAE;QACrCO,QAAQ,CAACD,IAAI,CAAC;MAChB;IACF,CAAC,CAAC;EACJ;;EAEA;AACF;AACA;AACA;AACA;AACA;EACEE,WAAWA,CAACC,QAAqB,EAAc;IAC7C,IAAI,CAACT,SAAS,CAACU,GAAG,CAACD,QAAQ,CAAC;IAC5B,OAAO,MAAM,IAAI,CAACT,SAAS,CAACW,MAAM,CAACF,QAAQ,CAAC;EAC9C;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;EACE,OAAOG,UAAUA,CACfP,MAA6C,EACtB;IACvB,OAAO,IAAIN,kBAAkB,CAACM,MAAM,CAAC;EACvC;AACF;AAACQ,OAAA,CAAAd,kBAAA,GAAAA,kBAAA","ignoreList":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getTrackIdentity = getTrackIdentity;
|
|
7
|
+
/**
|
|
8
|
+
* A track's identity: its opaque `id` when present (non-blank), falling back
|
|
9
|
+
* to the playable `src`. Two tracks refer to the same item exactly when their
|
|
10
|
+
* identities are equal. Browsable-only tracks (neither `id` nor `src`) have
|
|
11
|
+
* no identity — they are addressed by their `path` instead.
|
|
12
|
+
*
|
|
13
|
+
* This is the same comparison the library uses everywhere it matches tracks:
|
|
14
|
+
* favorites (`setFavorites`), the CarPlay / Android Auto "now playing" row
|
|
15
|
+
* indicator, and queue expansion and in-place skipping when a track is
|
|
16
|
+
* selected from browse content. Use it for your own bookkeeping — keying a
|
|
17
|
+
* favorites collection, deduplicating history — so your comparisons agree
|
|
18
|
+
* with the library's.
|
|
19
|
+
*/
|
|
20
|
+
// Decision record: ADR 0008 (docs/adr/).
|
|
21
|
+
function getTrackIdentity(track) {
|
|
22
|
+
return track.id?.length ? track.id : track.src;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=getTrackIdentity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["getTrackIdentity","track","id","length","src"],"sourceRoot":"../../../src","sources":["utils/getTrackIdentity.ts"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASA,gBAAgBA,CAACC,KAGhC,EAAsB;EACrB,OAAOA,KAAK,CAACC,EAAE,EAAEC,MAAM,GAAGF,KAAK,CAACC,EAAE,GAAGD,KAAK,CAACG,GAAG;AAChD","ignoreList":[]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useNativeValueRefreshedBy = useNativeValueRefreshedBy;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
/**
|
|
9
|
+
* Hook for a native-fetched value that must stay fresh across SEVERAL event
|
|
10
|
+
* sources — e.g. the active track, which changes on a queue transition
|
|
11
|
+
* (`onActiveTrackChanged`) but is also mutated in place by a favorite toggle
|
|
12
|
+
* (`onFavoriteChanged`).
|
|
13
|
+
*
|
|
14
|
+
* Unlike {@link useNativeUpdatedValue}, this never reads a cached event
|
|
15
|
+
* payload: every trigger re-reads `getter()`, and the mount effect re-reads
|
|
16
|
+
* once after the subscriptions attach (so an event firing between render and
|
|
17
|
+
* effect cannot be missed). The getters are cheap synchronous Nitro calls.
|
|
18
|
+
*
|
|
19
|
+
* @param getter - Synchronous native getter for the current value
|
|
20
|
+
* @param emitters - Event sources that invalidate the value (a stable,
|
|
21
|
+
* module-level array — identity changes resubscribe)
|
|
22
|
+
*/
|
|
23
|
+
function useNativeValueRefreshedBy(getter, emitters) {
|
|
24
|
+
const [value, setValue] = (0, _react.useState)(getter);
|
|
25
|
+
(0, _react.useEffect)(() => {
|
|
26
|
+
setValue(getter());
|
|
27
|
+
const cleanups = emitters.map(emitter => emitter.addListener(() => setValue(getter())));
|
|
28
|
+
return () => cleanups.forEach(cleanup => cleanup());
|
|
29
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
30
|
+
}, [getter, ...emitters]);
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=useNativeValueRefreshedBy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_react","require","useNativeValueRefreshedBy","getter","emitters","value","setValue","useState","useEffect","cleanups","map","emitter","addListener","forEach","cleanup"],"sourceRoot":"../../../src","sources":["utils/useNativeValueRefreshedBy.ts"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,yBAAyBA,CACvCC,MAAe,EACfC,QAAiC,EAC9B;EACH,MAAM,CAACC,KAAK,EAAEC,QAAQ,CAAC,GAAG,IAAAC,eAAQ,EAACJ,MAAM,CAAC;EAE1C,IAAAK,gBAAS,EAAC,MAAM;IACdF,QAAQ,CAACH,MAAM,CAAC,CAAC,CAAC;IAClB,MAAMM,QAAQ,GAAGL,QAAQ,CAACM,GAAG,CAAEC,OAAO,IACpCA,OAAO,CAACC,WAAW,CAAC,MAAMN,QAAQ,CAACH,MAAM,CAAC,CAAC,CAAC,CAC9C,CAAC;IACD,OAAO,MAAMM,QAAQ,CAACI,OAAO,CAAEC,OAAO,IAAKA,OAAO,CAAC,CAAC,CAAC;IACrD;EACF,CAAC,EAAE,CAACX,MAAM,EAAE,GAAGC,QAAQ,CAAC,CAAC;EAEzB,OAAOC,KAAK;AACd","ignoreList":[]}
|
|
@@ -4,11 +4,13 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.NativeAudioBrowser = void 0;
|
|
7
|
+
var _getTrackIdentity = require("../utils/getTrackIdentity");
|
|
7
8
|
var _BrowserManager = require("./browser/BrowserManager");
|
|
8
9
|
var _classifyTrackNavigation = require("./browser/classifyTrackNavigation");
|
|
9
10
|
var _FavoriteManager = require("./browser/FavoriteManager");
|
|
10
11
|
var _NavigationErrorManager = require("./browser/NavigationErrorManager");
|
|
11
12
|
var _SearchManager = require("./browser/SearchManager");
|
|
13
|
+
var _followMediaRedirect = require("./http/followMediaRedirect");
|
|
12
14
|
var _HttpClient = require("./http/HttpClient");
|
|
13
15
|
var _RequestConfigBuilder = require("./http/RequestConfigBuilder");
|
|
14
16
|
var _NowPlayingManager = require("./player/NowPlayingManager");
|
|
@@ -17,6 +19,7 @@ var _RemoteCommandController = require("./player/RemoteCommandController");
|
|
|
17
19
|
var _TrackPlayer = require("./TrackPlayer");
|
|
18
20
|
var _PlaybackTimer = require("./TrackPlayer/PlaybackTimer");
|
|
19
21
|
var _PlayingStateFactory = require("./TrackPlayer/PlayingStateFactory");
|
|
22
|
+
var _BrowserPathHelper = require("./util/BrowserPathHelper");
|
|
20
23
|
/**
|
|
21
24
|
* Web implementation of AudioBrowser (unified browser + player)
|
|
22
25
|
*/
|
|
@@ -42,7 +45,6 @@ class NativeAudioBrowser extends _TrackPlayer.QueuePlayer {
|
|
|
42
45
|
// Managers
|
|
43
46
|
|
|
44
47
|
// Player state
|
|
45
|
-
currentLoadId = 0;
|
|
46
48
|
progressTimer = new _PlaybackTimer.PlaybackTimer();
|
|
47
49
|
intervalTimer = new _PlaybackTimer.PlaybackTimer();
|
|
48
50
|
_online = typeof navigator !== 'undefined' ? navigator.onLine : true;
|
|
@@ -209,6 +211,13 @@ class NativeAudioBrowser extends _TrackPlayer.QueuePlayer {
|
|
|
209
211
|
this.onPlaybackError({
|
|
210
212
|
error: newState.error
|
|
211
213
|
});
|
|
214
|
+
} else if (oldState.state === 'error') {
|
|
215
|
+
// Leaving the error state clears it, as it does natively. The getter
|
|
216
|
+
// already reads undefined — consumers subscribe to the event, so without
|
|
217
|
+
// this a stale error outlives the next successful load.
|
|
218
|
+
this.onPlaybackError({
|
|
219
|
+
error: undefined
|
|
220
|
+
});
|
|
212
221
|
}
|
|
213
222
|
}
|
|
214
223
|
/**
|
|
@@ -296,16 +305,27 @@ class NativeAudioBrowser extends _TrackPlayer.QueuePlayer {
|
|
|
296
305
|
* Attempts to skip to a track already in the current queue.
|
|
297
306
|
* Used as an optimization to avoid re-expanding the queue.
|
|
298
307
|
*
|
|
299
|
-
* @param
|
|
308
|
+
* @param track The tapped track (its contextual path pins the exact copy)
|
|
309
|
+
* @param trackId The track's identity (id, falling back to src)
|
|
300
310
|
* @param parentPath The parent path to check against queueSourcePath
|
|
301
311
|
* @returns true if successfully skipped to existing track, false otherwise
|
|
302
312
|
*/
|
|
303
|
-
async trySkipToExistingQueueTrack(trackId, parentPath) {
|
|
313
|
+
async trySkipToExistingQueueTrack(track, trackId, parentPath) {
|
|
304
314
|
if (parentPath !== this.browserManager.queueSourcePath) {
|
|
305
315
|
return false;
|
|
306
316
|
}
|
|
317
|
+
|
|
318
|
+
// Exact-surface match first: a contextual path carries the tapped page
|
|
319
|
+
// position (__index), so path equality pins the exact copy when the page
|
|
320
|
+
// holds the same identity more than once. The identity match remains for
|
|
321
|
+
// index-less paths (e.g. pre-stamp persisted state); an index-stamped path
|
|
322
|
+
// with no exact match falls through to expansion, which re-scopes the
|
|
323
|
+
// queue to the tapped section.
|
|
307
324
|
const queue = this.getQueue();
|
|
308
|
-
|
|
325
|
+
let index = queue.findIndex(t => t.path != null && t.path === track.path);
|
|
326
|
+
if (index < 0 && track.path != null && _BrowserPathHelper.BrowserPathHelper.extractIndex(track.path) === undefined) {
|
|
327
|
+
index = queue.findIndex(t => (0, _getTrackIdentity.getTrackIdentity)(t) === trackId);
|
|
328
|
+
}
|
|
309
329
|
if (index < 0) {
|
|
310
330
|
return false;
|
|
311
331
|
}
|
|
@@ -344,11 +364,15 @@ class NativeAudioBrowser extends _TrackPlayer.QueuePlayer {
|
|
|
344
364
|
*/
|
|
345
365
|
async navigateTrackAsync(track) {
|
|
346
366
|
try {
|
|
367
|
+
// A disabled track is unavailable — it never plays, whichever surface
|
|
368
|
+
// or stale resume path delivered the selection (Track.disabled; mirrors
|
|
369
|
+
// iOS TrackSelector.select and Android navigateTrack).
|
|
370
|
+
if (track.disabled === true) return;
|
|
347
371
|
const nav = (0, _classifyTrackNavigation.classifyTrackNavigation)(track);
|
|
348
372
|
switch (nav.kind) {
|
|
349
373
|
case 'contextual':
|
|
350
374
|
// Optimization: skip to the track if it's already in the queue.
|
|
351
|
-
if (nav.trackId && (await this.trySkipToExistingQueueTrack(nav.trackId, nav.parentPath))) {
|
|
375
|
+
if (nav.trackId && (await this.trySkipToExistingQueueTrack(track, nav.trackId, nav.parentPath))) {
|
|
352
376
|
return;
|
|
353
377
|
}
|
|
354
378
|
// Otherwise expand the queue from the contextual URL, falling back to
|
|
@@ -365,7 +389,7 @@ class NativeAudioBrowser extends _TrackPlayer.QueuePlayer {
|
|
|
365
389
|
await this.playSingleTrack(track);
|
|
366
390
|
return;
|
|
367
391
|
case 'invalid':
|
|
368
|
-
throw new Error("Track must have either '
|
|
392
|
+
throw new Error("Track must have either 'path' or 'src' property");
|
|
369
393
|
}
|
|
370
394
|
} catch (error) {
|
|
371
395
|
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
@@ -380,7 +404,7 @@ class NativeAudioBrowser extends _TrackPlayer.QueuePlayer {
|
|
|
380
404
|
this.play();
|
|
381
405
|
});
|
|
382
406
|
}
|
|
383
|
-
async
|
|
407
|
+
async search(query) {
|
|
384
408
|
// Wrap query string in SearchParams (matches Android's search(query: String) overload)
|
|
385
409
|
return this.searchManager.search({
|
|
386
410
|
query,
|
|
@@ -438,68 +462,101 @@ class NativeAudioBrowser extends _TrackPlayer.QueuePlayer {
|
|
|
438
462
|
* Supports the transform callback for URL manipulation.
|
|
439
463
|
* Mirrors Android's MediaFactory.getMediaRequestConfig behavior.
|
|
440
464
|
*/
|
|
441
|
-
async
|
|
465
|
+
async resolveMediaRequest(src, track) {
|
|
466
|
+
// The *resolved* request layer, not `configuration.request`: a
|
|
467
|
+
// resolver-only config would otherwise reach media with no baseUrl and no
|
|
468
|
+
// headers. Browse, search and browse artwork all read it this way too.
|
|
469
|
+
//
|
|
470
|
+
// Caught, because unlike those three this one cannot fail the load: a
|
|
471
|
+
// resolver hiccup — a token refresh timing out — would otherwise take down
|
|
472
|
+
// a track whose `src` is already absolute and public and needed no layer at
|
|
473
|
+
// all. Native degrades the same way, `getMediaRequestConfig` returning null
|
|
474
|
+
// and the original URL playing on.
|
|
475
|
+
let request;
|
|
476
|
+
try {
|
|
477
|
+
request = await this.browserManager.resolvedRequestConfig();
|
|
478
|
+
} catch (e) {
|
|
479
|
+
console.error('Failed to resolve the request layer for media', e);
|
|
480
|
+
}
|
|
442
481
|
const {
|
|
443
|
-
request,
|
|
444
482
|
media
|
|
445
483
|
} = this.browserManager.configuration;
|
|
446
|
-
return _RequestConfigBuilder.RequestConfigBuilder.
|
|
484
|
+
return _RequestConfigBuilder.RequestConfigBuilder.resolveMediaRequest(src, request, media, track);
|
|
447
485
|
}
|
|
448
486
|
|
|
449
487
|
/**
|
|
450
|
-
*
|
|
451
|
-
* `current`
|
|
452
|
-
*
|
|
453
|
-
* the queue entry with it.
|
|
488
|
+
* The queue's own entry, so the queue stays the source of truth for what is
|
|
489
|
+
* playing. `current` preserves the track as queued — the resolved URL is
|
|
490
|
+
* passed to `load()` separately — so either is safe to re-feed.
|
|
454
491
|
*/
|
|
455
|
-
|
|
492
|
+
trackToReload() {
|
|
456
493
|
const index = this.queue.currentIndex;
|
|
457
|
-
const
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
super.reloadCurrent();
|
|
462
|
-
}
|
|
494
|
+
const queued = index !== undefined ? this.queue.getTrack(index) : undefined;
|
|
495
|
+
// The queue entry wins, so it stays the source of truth for what is
|
|
496
|
+
// playing; `current` is the fallback for a player loaded without one.
|
|
497
|
+
return queued ?? super.trackToReload();
|
|
463
498
|
}
|
|
464
|
-
load(track, callback) {
|
|
465
|
-
const element = this.requireElement();
|
|
466
|
-
|
|
467
|
-
// Clear now playing override when track changes (matches Android's PlayerListener.onMediaItemTransition)
|
|
468
|
-
this.nowPlayingManager.clearNowPlayingOverride();
|
|
469
499
|
|
|
470
|
-
|
|
471
|
-
|
|
500
|
+
/**
|
|
501
|
+
* Makes `track` the queue's current entry, emitting the change.
|
|
502
|
+
*
|
|
503
|
+
* Matches Android, where `load()` modifies the queue: an empty queue takes
|
|
504
|
+
* the track as its only entry, a populated one has its current entry
|
|
505
|
+
* replaced.
|
|
506
|
+
*/
|
|
507
|
+
syncQueueTo(track) {
|
|
472
508
|
if (this.queue.length === 0) {
|
|
473
509
|
this.queue.setTracks([track]);
|
|
474
510
|
this.queue.currentIndex = 0;
|
|
475
511
|
this.emitQueueChanged();
|
|
476
|
-
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
if (this.queue.currentIndex !== undefined && this.queue.getTrack(this.queue.currentIndex) !== track) {
|
|
477
515
|
this.queue.replaceTrack(this.queue.currentIndex, track);
|
|
478
516
|
this.emitQueueChanged();
|
|
479
517
|
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Everything native does in its media-item transition, all of it before any
|
|
522
|
+
* network work: announce the new track, publish its now-playing metadata,
|
|
523
|
+
* cut the outgoing one, and report `loading`.
|
|
524
|
+
*
|
|
525
|
+
* Android's `onMediaItemTransition` fires at `prepare()` and does exactly
|
|
526
|
+
* this, with its LOADING following from `onEvents`; resolution happens later
|
|
527
|
+
* still, inside `TransformingDataSource.open()`. Doing it here rather than
|
|
528
|
+
* after the URL resolves is what gives the resolution window a state, and
|
|
529
|
+
* keeps `activeTrack` ahead of `loading` — the order a consumer that reads
|
|
530
|
+
* `getActiveTrack()` on the loading edge depends on.
|
|
531
|
+
*/
|
|
532
|
+
transitionTo(track) {
|
|
533
|
+
const element = this.requireElement();
|
|
480
534
|
const lastTrack = this.current;
|
|
481
535
|
const lastPosition = element.currentTime;
|
|
482
536
|
const lastIndex = this.queue.lastIndex;
|
|
483
537
|
const currentIndex = this.queue.currentIndex;
|
|
484
538
|
|
|
485
|
-
//
|
|
486
|
-
//
|
|
487
|
-
|
|
488
|
-
|
|
539
|
+
// A re-prepare of the item already current is not a transition, and must
|
|
540
|
+
// not be announced as one: ExoPlayer's `prepare()` does not re-fire
|
|
541
|
+
// `onMediaItemTransition` for an unchanged media item, so a consumer that
|
|
542
|
+
// resets on a track change would have its UI wiped by every retry. The
|
|
543
|
+
// `lastTrack === track` payload was the tell.
|
|
544
|
+
const isTransition = this.current !== track;
|
|
489
545
|
|
|
490
|
-
//
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
546
|
+
// `current` first, so `getActiveTrack()` already reads the new track inside
|
|
547
|
+
// a handler and so `getNowPlaying()` publishes the new track's metadata. It
|
|
548
|
+
// also stops `getActiveTrackIndex()` — which moved with the queue already,
|
|
549
|
+
// synchronously — from disagreeing with it for the length of the
|
|
550
|
+
// resolution.
|
|
551
|
+
this.current = track;
|
|
552
|
+
|
|
553
|
+
// Separately guarded: a throwing consumer handler must not skip the
|
|
554
|
+
// publish, and neither may fail the load.
|
|
555
|
+
if (isTransition) {
|
|
556
|
+
// As Android's onMediaItemTransition does: a new item is a clean slate,
|
|
557
|
+
// a retry of the same one keeps what the consumer set.
|
|
558
|
+
this.nowPlayingManager.clearNowPlayingOverride();
|
|
559
|
+
try {
|
|
503
560
|
this.onPlaybackActiveTrackChanged({
|
|
504
561
|
lastTrack,
|
|
505
562
|
lastPosition,
|
|
@@ -507,24 +564,101 @@ class NativeAudioBrowser extends _TrackPlayer.QueuePlayer {
|
|
|
507
564
|
index: currentIndex,
|
|
508
565
|
track
|
|
509
566
|
});
|
|
510
|
-
|
|
511
|
-
|
|
567
|
+
} catch (error) {
|
|
568
|
+
console.error('Failed to announce the active track change:', error);
|
|
569
|
+
}
|
|
570
|
+
try {
|
|
571
|
+
// Once, here: duration reaches the media session through
|
|
572
|
+
// `updateProgress()` on each tick, so only metadata needs publishing.
|
|
573
|
+
// Android publishes from the same transition handler that announces.
|
|
512
574
|
const nowPlaying = this.getNowPlaying();
|
|
513
575
|
if (nowPlaying) {
|
|
514
576
|
this.publishNowPlaying(nowPlaying);
|
|
515
577
|
}
|
|
578
|
+
} catch (error) {
|
|
579
|
+
console.error('Failed to publish now-playing metadata:', error);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// Stop the outgoing track now rather than when Shaka eventually gets a URL.
|
|
584
|
+
// Announcing the new track while the old one is still audible is worse than
|
|
585
|
+
// the silence, and native has no such window — prepare() cuts the old item
|
|
586
|
+
// at the moment it announces. This adds no teardown: `player.load()`
|
|
587
|
+
// already unloads first (shaka player.js:1757-1762). It only moves when.
|
|
588
|
+
// Verified in a real browser to emit no `pause`, so no state comes of it.
|
|
589
|
+
this.requirePlayer().unload().catch(error => console.error('Failed to unload the previous track:', error));
|
|
590
|
+
|
|
591
|
+
// Loading covers the resolution too. Shaka dispatches its own `loading`
|
|
592
|
+
// once `player.load()` is called — after resolution — and the state setter
|
|
593
|
+
// drops that as a no-op. The `buffering` that follows is Shaka's to report.
|
|
594
|
+
this.dispatch({
|
|
595
|
+
type: 'trackLoading'
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
load(track, callback) {
|
|
599
|
+
// Before the queue is touched, so a load before `setupPlayer()` throws
|
|
600
|
+
// rather than half-applying.
|
|
601
|
+
this.requireElement();
|
|
602
|
+
this.syncQueueTo(track);
|
|
603
|
+
|
|
604
|
+
// Begun here, at the call, so a newer load supersedes this one immediately
|
|
605
|
+
// rather than once its own URL has resolved. Both continuations below carry
|
|
606
|
+
// it, as does `super.load()`.
|
|
607
|
+
const attempt = this.beginLoadAttempt();
|
|
608
|
+
// Read now: `reloadCurrent` holds the flag only for this synchronous call,
|
|
609
|
+
// and `super.load()` runs after the URL has resolved.
|
|
610
|
+
const reprepare = this._repreparing;
|
|
516
611
|
|
|
612
|
+
// Loading ends being stopped. `dispatch()` drops every event while
|
|
613
|
+
// `_isStopped`, to keep Shaka's teardown noise off the stopped state, so
|
|
614
|
+
// the `trackLoading` in `transitionTo` would be swallowed on the stop → play
|
|
615
|
+
// path and the resolution window would report nothing. `super.load()` clears
|
|
616
|
+
// this too, but only after the URL resolves.
|
|
617
|
+
this._isStopped = false;
|
|
618
|
+
|
|
619
|
+
// Set loading flag early so seekTo() calls during async URL resolution
|
|
620
|
+
// are captured as pending seeks rather than silently dropped
|
|
621
|
+
this._loadInProgress = true;
|
|
622
|
+
this._pendingSeek = undefined;
|
|
623
|
+
this.transitionTo(track);
|
|
624
|
+
|
|
625
|
+
// Resolve the media URL before loading (async but we don't await)
|
|
626
|
+
const doLoad = async () => {
|
|
627
|
+
const resolvedRequest = track.src ? await this.resolveMediaRequest(track.src, track) : undefined;
|
|
628
|
+
// Web-only, and forced: a progressive file plays via `mediaElement.src`,
|
|
629
|
+
// which cannot carry headers. Native sends them with the media request
|
|
630
|
+
// and follows the redirect inline, so it needs none of this.
|
|
631
|
+
const resolvedMedia = resolvedRequest ? await (0, _followMediaRedirect.followMediaRedirect)(resolvedRequest.path ?? track.src, resolvedRequest.headers, {
|
|
632
|
+
mediaLayerHeaders: resolvedRequest.mediaLayerHeaders
|
|
633
|
+
}) : undefined;
|
|
634
|
+
|
|
635
|
+
// Something took over while the URL was resolving — discard this result
|
|
636
|
+
if (!attempt.isCurrent) return;
|
|
637
|
+
super.load(track, loadedTrack => {
|
|
517
638
|
// Call the provided callback if any
|
|
518
639
|
if (callback) {
|
|
519
640
|
callback(loadedTrack);
|
|
520
641
|
}
|
|
642
|
+
}, {
|
|
643
|
+
headers: resolvedMedia?.headers,
|
|
644
|
+
src: resolvedMedia?.src,
|
|
645
|
+
attempt,
|
|
646
|
+
reprepare
|
|
521
647
|
});
|
|
522
648
|
};
|
|
523
649
|
|
|
524
650
|
// Execute async load without blocking, with error handling
|
|
525
651
|
doLoad().catch(error => {
|
|
526
|
-
//
|
|
527
|
-
|
|
652
|
+
// A backstop with no reachable trigger today, kept because an unhandled
|
|
653
|
+
// rejection would be worse than a dead branch. Every await inside
|
|
654
|
+
// `doLoad` catches internally; `shaka.Player.load` is `async`, so it
|
|
655
|
+
// rejects rather than throwing and its rejection is handled against the
|
|
656
|
+
// attempt inside `Player.load`; and `this.player` is only ever assigned,
|
|
657
|
+
// so `requirePlayer()` cannot start succeeding and then fail mid-load.
|
|
658
|
+
//
|
|
659
|
+
// No attempt check either, for the same reason it would be dead: nothing
|
|
660
|
+
// awaits between the guard above and `super.load()`, so the attempt
|
|
661
|
+
// cannot have changed. Add an await there and this needs the check back.
|
|
528
662
|
this._loadInProgress = false;
|
|
529
663
|
this._pendingSeek = undefined;
|
|
530
664
|
console.error('Error loading track:', error);
|
|
@@ -687,10 +821,8 @@ class NativeAudioBrowser extends _TrackPlayer.QueuePlayer {
|
|
|
687
821
|
this.clearSleepTimerIfFading();
|
|
688
822
|
}
|
|
689
823
|
stop() {
|
|
690
|
-
//
|
|
691
|
-
//
|
|
692
|
-
// and revives the state out of Stopped.
|
|
693
|
-
this.currentLoadId++;
|
|
824
|
+
// `Player.stop()` cancels the load attempt, so an in-flight load's
|
|
825
|
+
// continuation cannot re-arm the player and revive it out of Stopped.
|
|
694
826
|
super.stop();
|
|
695
827
|
this.clearSleepTimerIfFading();
|
|
696
828
|
}
|
|
@@ -716,11 +848,13 @@ class NativeAudioBrowser extends _TrackPlayer.QueuePlayer {
|
|
|
716
848
|
this.sleepTimer.clear();
|
|
717
849
|
this.pause();
|
|
718
850
|
this.onSleepTimerChanged(null);
|
|
719
|
-
|
|
851
|
+
// Nothing is loading, so the caller must still report the end — the
|
|
852
|
+
// element has stopped and its own `pause` is swallowed as end-of-track.
|
|
853
|
+
return false;
|
|
720
854
|
}
|
|
721
855
|
|
|
722
856
|
// Otherwise proceed with normal track end behavior
|
|
723
|
-
super.onTrackEnded();
|
|
857
|
+
return super.onTrackEnded();
|
|
724
858
|
}
|
|
725
859
|
|
|
726
860
|
// MARK: Queue management
|
|
@@ -762,13 +896,13 @@ class NativeAudioBrowser extends _TrackPlayer.QueuePlayer {
|
|
|
762
896
|
setActiveTrackFavorited(favorited) {
|
|
763
897
|
const track = this.getActiveTrack();
|
|
764
898
|
const index = this.getActiveTrackIndex();
|
|
765
|
-
if (!track ||
|
|
899
|
+
if (!track || (0, _getTrackIdentity.getTrackIdentity)(track) === undefined || index === undefined) return;
|
|
766
900
|
|
|
767
|
-
// Update favorites set via manager
|
|
901
|
+
// Update favorites set via manager (keyed by track identity)
|
|
768
902
|
if (favorited) {
|
|
769
|
-
this.favoriteManager.addFavorite(track
|
|
903
|
+
this.favoriteManager.addFavorite(track);
|
|
770
904
|
} else {
|
|
771
|
-
this.favoriteManager.removeFavorite(track
|
|
905
|
+
this.favoriteManager.removeFavorite(track);
|
|
772
906
|
}
|
|
773
907
|
|
|
774
908
|
// Create updated track with new favorited state
|
|
@@ -780,28 +914,19 @@ class NativeAudioBrowser extends _TrackPlayer.QueuePlayer {
|
|
|
780
914
|
// Replace the track in the queue
|
|
781
915
|
this.queue.replaceTrack(index, updatedTrack);
|
|
782
916
|
|
|
783
|
-
// Emit favorite changed
|
|
917
|
+
// Emit favorite changed only. A favorite toggle is an in-place mutation of
|
|
918
|
+
// the active track, not a transition — onPlaybackActiveTrackChanged and
|
|
919
|
+
// onPlaybackQueueChanged stay transition-only, and the useActiveTrack /
|
|
920
|
+
// useQueue hooks subscribe to onFavoriteChanged themselves.
|
|
784
921
|
this.onFavoriteChanged({
|
|
785
922
|
track: updatedTrack,
|
|
786
923
|
favorited
|
|
787
924
|
});
|
|
788
|
-
|
|
789
|
-
// Emit active track changed so useActiveTrack() hook updates
|
|
790
|
-
this.onPlaybackActiveTrackChanged({
|
|
791
|
-
lastIndex: index,
|
|
792
|
-
lastTrack: track,
|
|
793
|
-
lastPosition: this.element?.currentTime ?? 0,
|
|
794
|
-
index,
|
|
795
|
-
track: updatedTrack
|
|
796
|
-
});
|
|
797
|
-
|
|
798
|
-
// Emit queue changed so useQueue() hook updates
|
|
799
|
-
this.emitQueueChanged();
|
|
800
925
|
}
|
|
801
926
|
toggleActiveTrackFavorited() {
|
|
802
927
|
const track = this.getActiveTrack();
|
|
803
|
-
if (!track ||
|
|
804
|
-
const isFavorited = this.favoriteManager.isFavorited(track
|
|
928
|
+
if (!track || (0, _getTrackIdentity.getTrackIdentity)(track) === undefined) return;
|
|
929
|
+
const isFavorited = this.favoriteManager.isFavorited(track);
|
|
805
930
|
this.setActiveTrackFavorited(!isFavorited);
|
|
806
931
|
}
|
|
807
932
|
|