react-native-audio-browser 0.1.1 → 0.2.0-next.2
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/AudioBrowser.podspec +1 -1
- package/README.md +180 -2
- package/android/build.gradle +10 -0
- package/android/gradle.properties +1 -1
- package/android/src/main/AndroidManifest.xml +15 -0
- package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +401 -141
- package/android/src/main/java/com/audiobrowser/Callbacks.kt +4 -6
- package/android/src/main/java/com/audiobrowser/Service.kt +67 -18
- package/android/src/main/java/com/audiobrowser/browser/ArtworkResolutionRegistry.kt +37 -0
- package/android/src/main/java/com/audiobrowser/browser/BrowseArtworkRegistry.kt +34 -0
- package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +443 -178
- package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +300 -0
- package/android/src/main/java/com/audiobrowser/browser/JsonArtwork.kt +79 -0
- package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +41 -4
- package/android/src/main/java/com/audiobrowser/browser/SectionScope.kt +43 -0
- package/android/src/main/java/com/audiobrowser/browser/TrackLoadHandler.kt +4 -4
- package/android/src/main/java/com/audiobrowser/extension/ResolvedTrackExt.kt +35 -0
- package/android/src/main/java/com/audiobrowser/http/RequestConfigBuilder.kt +109 -97
- package/android/src/main/java/com/audiobrowser/model/PlaybackMetadata.kt +6 -10
- package/android/src/main/java/com/audiobrowser/model/PlayerSetupOptions.kt +40 -8
- package/android/src/main/java/com/audiobrowser/model/PlayerUpdateOptions.kt +31 -37
- package/android/src/main/java/com/audiobrowser/player/AutomaticBufferManager.kt +4 -1
- package/android/src/main/java/com/audiobrowser/player/CapabilityControls.kt +119 -0
- package/android/src/main/java/com/audiobrowser/player/DynamicLoadControl.kt +18 -1
- package/android/src/main/java/com/audiobrowser/player/EqualizerController.kt +153 -0
- package/android/src/main/java/com/audiobrowser/player/InterceptingPlayer.kt +141 -0
- package/android/src/main/java/com/audiobrowser/player/MediaFactory.kt +15 -3
- package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +415 -131
- package/android/src/main/java/com/audiobrowser/player/MediaSessionCommandManager.kt +154 -276
- package/android/src/main/java/com/audiobrowser/player/NowPlayingUpdater.kt +348 -0
- package/android/src/main/java/com/audiobrowser/player/PlaybackErrorClassifier.kt +129 -0
- package/android/src/main/java/com/audiobrowser/player/PlaybackStateMachine.kt +85 -0
- package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +27 -5
- package/android/src/main/java/com/audiobrowser/player/PlaybackTimer.kt +56 -0
- package/android/src/main/java/com/audiobrowser/player/Player.kt +452 -576
- package/android/src/main/java/com/audiobrowser/player/PlayerCapabilitiesExt.kt +20 -0
- package/android/src/main/java/com/audiobrowser/player/PlayerEngineFactory.kt +130 -0
- package/android/src/main/java/com/audiobrowser/player/PlayerListener.kt +190 -67
- package/android/src/main/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicy.kt +117 -53
- package/android/src/main/java/com/audiobrowser/player/SleepTimer.kt +37 -3
- package/android/src/main/java/com/audiobrowser/player/SleepTimerManager.kt +80 -0
- package/android/src/main/java/com/audiobrowser/player/StuckRecoveryPolicy.kt +50 -0
- package/android/src/main/java/com/audiobrowser/player/TransformingDataSource.kt +85 -40
- package/android/src/main/java/com/audiobrowser/player/VolumeFader.kt +81 -0
- package/android/src/main/java/com/audiobrowser/tls/AiaCertChaser.kt +141 -0
- package/android/src/main/java/com/audiobrowser/tls/AiaChasingTrustManager.kt +37 -0
- package/android/src/main/java/com/audiobrowser/tls/AiaTls.kt +41 -0
- package/android/src/main/java/com/audiobrowser/tls/CachingCertificateFetcher.kt +209 -0
- package/android/src/main/java/com/audiobrowser/util/ArtworkContentProvider.kt +161 -0
- package/android/src/main/java/com/audiobrowser/util/ArtworkUris.kt +28 -0
- package/android/src/main/java/com/audiobrowser/util/ArtworkVariant.kt +26 -0
- package/android/src/main/java/com/audiobrowser/util/BrowserPathHelper.kt +24 -0
- package/android/src/main/java/com/audiobrowser/util/CoilArtworkLoader.kt +49 -0
- package/android/src/main/java/com/audiobrowser/util/CoilArtworkLoaderHolder.kt +36 -0
- package/android/src/main/java/com/audiobrowser/util/CoilBitmapLoader.kt +23 -300
- package/android/src/main/java/com/audiobrowser/util/EqualizerManager.kt +13 -23
- package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +2 -2
- package/android/src/main/java/com/audiobrowser/util/MetadataAdapter.kt +4 -3
- package/android/src/main/java/com/audiobrowser/util/OutputMonitor.kt +211 -0
- package/android/src/main/java/com/audiobrowser/util/OutputSwitcher.kt +58 -0
- package/android/src/main/java/com/audiobrowser/util/PlayingStateFactory.kt +2 -1
- package/android/src/main/java/com/audiobrowser/util/RatingFavorites.kt +14 -0
- package/android/src/main/java/com/audiobrowser/util/SvgArtworkRenderer.kt +6 -111
- package/android/src/main/java/com/audiobrowser/util/SystemVolumeMonitor.kt +22 -8
- package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +111 -80
- package/android/src/main/res/values/strings.xml +4 -0
- package/android/src/test/java/com/audiobrowser/TestFixtures.kt +166 -0
- package/android/src/test/java/com/audiobrowser/browser/ArtworkResolutionRegistryTest.kt +46 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowseArtworkRegistryTest.kt +39 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerBuildApiRequestTest.kt +114 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerLayerResolutionTest.kt +141 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +4 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +177 -0
- package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +54 -0
- package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +96 -0
- package/android/src/test/java/com/audiobrowser/browser/SimpleRouterTest.kt +1 -2
- package/android/src/test/java/com/audiobrowser/http/RequestConfigBuilderTest.kt +72 -0
- package/android/src/test/java/com/audiobrowser/player/CapabilityControlsTest.kt +159 -0
- package/android/src/test/java/com/audiobrowser/player/DynamicLoadControlTest.kt +56 -0
- package/android/src/test/java/com/audiobrowser/player/EqualizerControllerTest.kt +216 -0
- package/android/src/test/java/com/audiobrowser/player/NowPlayingUpdaterTest.kt +442 -0
- package/android/src/test/java/com/audiobrowser/player/PlaybackErrorClassifierTest.kt +191 -0
- package/android/src/test/java/com/audiobrowser/player/PlaybackStateMachineTest.kt +198 -0
- package/android/src/test/java/com/audiobrowser/player/PlaybackTimerTest.kt +137 -0
- package/android/src/test/java/com/audiobrowser/player/PlayerEngineFactoryTest.kt +36 -0
- package/android/src/test/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicyTest.kt +268 -0
- package/android/src/test/java/com/audiobrowser/player/SessionErrorMaskTest.kt +68 -0
- package/android/src/test/java/com/audiobrowser/player/StuckRecoveryPolicyTest.kt +40 -0
- package/android/src/test/java/com/audiobrowser/player/TransformingDataSourceTest.kt +193 -0
- package/android/src/test/java/com/audiobrowser/tls/AiaCertChaserTest.kt +107 -0
- package/android/src/test/java/com/audiobrowser/tls/AiaChasingTrustManagerTest.kt +73 -0
- package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherTest.kt +75 -0
- package/android/src/test/java/com/audiobrowser/tls/CertFixtures.kt +18 -0
- package/android/src/test/java/com/audiobrowser/util/ArtworkContentProviderTest.kt +163 -0
- package/android/src/test/java/com/audiobrowser/util/ArtworkUrisTest.kt +34 -0
- package/android/src/test/java/com/audiobrowser/util/BrowserPathHelperTest.kt +28 -0
- package/android/src/test/java/com/audiobrowser/util/CoilArtworkLoaderHolderTest.kt +53 -0
- package/android/src/test/java/com/audiobrowser/util/CoilArtworkLoaderTest.kt +58 -0
- package/android/src/test/java/com/audiobrowser/util/FakeImageLoader.kt +57 -0
- package/android/src/test/java/com/audiobrowser/util/PlayingStateFactoryTest.kt +40 -0
- package/android/src/test/java/com/audiobrowser/util/RatingFavoritesTest.kt +34 -0
- package/android/src/test/java/com/audiobrowser/util/TrackFactoryBrowseTest.kt +50 -0
- package/android/src/test/java/com/audiobrowser/util/TrackFactoryMediaIdTest.kt +63 -0
- package/android/src/test/java/com/audiobrowser/util/TrackFactoryRatingTest.kt +35 -0
- package/android/src/test/resources/certs/isrg-root-x1.pem +31 -0
- package/android/src/test/resources/certs/letsencrypt-r13.der +0 -0
- package/android/src/test/resources/certs/letsencrypt-r13.pem +29 -0
- package/android/src/test/resources/certs/stationplaylist-leaf.pem +34 -0
- package/ios/Browser/BrowserConfig.swift +41 -11
- package/ios/Browser/BrowserManager+URLResolution.swift +213 -93
- package/ios/Browser/BrowserManager.swift +303 -110
- package/ios/Browser/BrowserPathHelper.swift +32 -3
- package/ios/Browser/JsonModels.swift +287 -66
- package/ios/Browser/MediaResolveComposer.swift +114 -0
- package/ios/Browser/SearchDrillIn.swift +44 -0
- package/ios/Browser/SectionScope.swift +35 -0
- package/ios/Browser/TabBarEntries.swift +15 -0
- package/ios/CarPlay/CPInterfaceController+Safe.swift +126 -0
- package/ios/CarPlay/CarPlayArtworkResolver.swift +6 -6
- package/ios/CarPlay/CarPlayController.swift +739 -149
- package/ios/CarPlay/CarPlayImageLoader.swift +57 -8
- package/ios/CarPlay/CarPlayListItemFactory.swift +44 -35
- package/ios/CarPlay/CarPlayNowPlayingManager.swift +180 -36
- package/ios/CarPlay/ImageRowItem+CarPlay.swift +19 -0
- package/ios/CarPlay/RNABAudioBrowser.h +15 -10
- package/ios/CarPlay/RNABAudioBrowser.m +15 -14
- package/ios/CarPlay/RNABCarPlaySceneDelegate.m +2 -0
- package/ios/CarPlay/RNABMediaAddHandler.swift +75 -0
- package/ios/CarPlay/RNABMediaAffinityHandler.swift +69 -0
- package/ios/CarPlay/RNABMediaIntentHandler.swift +53 -43
- package/ios/Extension/Capability+RemoteCommand.swift +7 -9
- package/ios/Extension/ChapterMetadata+AVFoundation.swift +1 -1
- package/ios/Extension/NavigationError+Conversion.swift +8 -1
- package/ios/Extension/PlayerCapabilities+Favorite.swift +20 -0
- package/ios/Extension/RequestConfig+Copying.swift +31 -0
- package/ios/Extension/ResolvedTrack+Copying.swift +10 -4
- package/ios/Extension/TimedMetadata+AVFoundation.swift +1 -1
- package/ios/Extension/Track+AVPlayer.swift +4 -4
- package/ios/Extension/Track+Copying.swift +9 -3
- package/ios/Extension/TrackMetadata+AVFoundation.swift +1 -1
- package/ios/Extension/Variant+Artwork.swift +49 -0
- package/ios/HybridAudioBrowser.swift +750 -173
- package/ios/Model/NitroTypeStubs.swift +299 -224
- package/ios/Model/PlayerUpdateOptions.swift +23 -23
- package/ios/Model/RemoteCommand.swift +6 -6
- package/ios/Model/TrackPlayerError.swift +82 -18
- package/ios/NowPlayingInfo/NowPlayingInfoController.swift +99 -121
- package/ios/NowPlayingInfo/SilentAudioPrimer.swift +73 -0
- package/ios/Observer/PlayerItemNotificationObserver.swift +45 -5
- package/ios/Observer/PlayerItemPropertyObserver.swift +27 -4
- package/ios/Observer/PlayerTimeObserver.swift +3 -53
- package/ios/Option/SessionCategories.swift +33 -11
- package/ios/Player/AirPlayStallJudgement.swift +25 -0
- package/ios/Player/EndOfTrackJudgement.swift +32 -0
- package/ios/Player/LoadSeekCoordinator.swift +16 -1
- package/ios/Player/MediaIntentCriteria.swift +139 -0
- package/ios/Player/MediaLoader.swift +31 -11
- package/ios/Player/NowPlayingUpdater.swift +119 -26
- package/ios/Player/PersistedPlaybackState.swift +11 -0
- package/ios/Player/PlaybackCoordinator.swift +285 -51
- package/ios/Player/PlaybackCoordinatorCallbacks.swift +6 -1
- package/ios/Player/PlaybackEffectHandler.swift +19 -9
- package/ios/Player/PlaybackErrorHandler.swift +97 -13
- package/ios/Player/PlaybackStateMachine.swift +18 -13
- package/ios/Player/PlaybackStateStore.swift +27 -0
- package/ios/Player/PlaybackTimer.swift +61 -0
- package/ios/Player/PlayingStateManager.swift +3 -2
- package/ios/Player/QueueManager.swift +67 -61
- package/ios/Player/RetryManager.swift +97 -21
- package/ios/Player/SleepTimerHandling.swift +8 -0
- package/ios/Player/SleepTimerManager.swift +72 -11
- package/ios/Player/VolumeFader.swift +77 -0
- package/ios/RemoteCommand/RemoteCommandController.swift +31 -15
- package/ios/Tests/AirPlayStallJudgementTests.swift +52 -0
- package/ios/Tests/BrowserPathHelperTests.swift +28 -0
- package/ios/Tests/CarPlayArtworkResolverTests.swift +39 -39
- package/ios/Tests/ChapterMetadataAVFoundationTests.swift +2 -2
- package/ios/Tests/EndOfTrackJudgementTests.swift +35 -0
- package/ios/Tests/JsonModelsTests.swift +58 -0
- package/ios/Tests/LoadSeekCoordinatorTests.swift +38 -7
- package/ios/Tests/MediaIntentCriteriaTests.swift +170 -0
- package/ios/Tests/MediaLoaderAssetOptionsTests.swift +46 -0
- package/ios/Tests/MediaLoaderTests.swift +32 -20
- package/ios/Tests/MediaResolveTests.swift +126 -0
- package/ios/Tests/OnceValueTests.swift +79 -0
- package/ios/Tests/PlaybackCoordinatorTests.swift +787 -13
- package/ios/Tests/PlaybackErrorHandlerTests.swift +380 -46
- package/ios/Tests/PlaybackStateMachineTests.swift +33 -8
- package/ios/Tests/PlaybackStateStoreTests.swift +48 -0
- package/ios/Tests/PlaybackTimerTests.swift +55 -0
- package/ios/Tests/PlayingStateManagerTests.swift +57 -0
- package/ios/Tests/QueueManagerTests.swift +149 -18
- package/ios/Tests/ResolvedTrackCopyingTests.swift +15 -8
- package/ios/Tests/RetryManagerTests.swift +89 -0
- package/ios/Tests/SearchDrillInTests.swift +63 -0
- package/ios/Tests/SectionScopeTests.swift +82 -0
- package/ios/Tests/SleepTimerManagerTests.swift +107 -0
- package/ios/Tests/Support/ManualSleepTimerScheduler.swift +47 -0
- package/ios/Tests/Support/TestTypes.swift +61 -20
- package/ios/Tests/TabBarEntriesTests.swift +71 -0
- package/ios/Tests/TrackSelectorTests.swift +15 -15
- package/ios/TrackPlayer.swift +380 -58
- package/ios/TrackPlayerCallbacks.swift +0 -6
- package/ios/TrackSelector.swift +5 -5
- package/ios/Util/ArtworkImageFetcher.swift +4 -2
- package/ios/Util/NetworkMonitor.swift +7 -3
- package/ios/Util/OnceValue.swift +34 -0
- package/lib/commonjs/features/browser-config.js +227 -0
- package/lib/commonjs/features/browser-config.js.map +1 -0
- package/lib/commonjs/features/browser.js +59 -158
- package/lib/commonjs/features/browser.js.map +1 -1
- package/lib/commonjs/features/carConnection.js +42 -0
- package/lib/commonjs/features/carConnection.js.map +1 -0
- package/lib/commonjs/features/errors.js +34 -2
- package/lib/commonjs/features/errors.js.map +1 -1
- package/lib/commonjs/features/gate.js +149 -0
- package/lib/commonjs/features/gate.js.map +1 -0
- package/lib/commonjs/features/index.js +22 -0
- package/lib/commonjs/features/index.js.map +1 -1
- package/lib/commonjs/features/metadata.js.map +1 -1
- package/lib/commonjs/features/nowPlaying.js +35 -0
- package/lib/commonjs/features/nowPlaying.js.map +1 -1
- package/lib/commonjs/features/output.js +37 -23
- package/lib/commonjs/features/output.js.map +1 -1
- package/lib/commonjs/features/playback/controls.js +9 -0
- package/lib/commonjs/features/playback/controls.js.map +1 -1
- package/lib/commonjs/features/playback/index.js +11 -0
- package/lib/commonjs/features/playback/index.js.map +1 -1
- package/lib/commonjs/features/playback/progress.js +28 -12
- package/lib/commonjs/features/playback/progress.js.map +1 -1
- package/lib/commonjs/features/playback/trackPlaybackTime.js +92 -0
- package/lib/commonjs/features/playback/trackPlaybackTime.js.map +1 -0
- package/lib/commonjs/features/playback/volume.js +1 -1
- package/lib/commonjs/features/player/options.js +49 -13
- package/lib/commonjs/features/player/options.js.map +1 -1
- package/lib/commonjs/features/player/setup.js +249 -3
- package/lib/commonjs/features/player/setup.js.map +1 -1
- package/lib/commonjs/features/queue/queue.js +10 -3
- package/lib/commonjs/features/queue/queue.js.map +1 -1
- package/lib/commonjs/features/remoteControls.js +1 -12
- package/lib/commonjs/features/remoteControls.js.map +1 -1
- package/lib/commonjs/features/sleepTimer.js +9 -4
- package/lib/commonjs/features/sleepTimer.js.map +1 -1
- package/lib/commonjs/native.js +5 -0
- package/lib/commonjs/native.js.map +1 -1
- package/lib/commonjs/native.web.js +4 -1
- package/lib/commonjs/native.web.js.map +1 -1
- package/lib/commonjs/utils/LazyNativeEmitter.js +0 -3
- package/lib/commonjs/utils/LazyNativeEmitter.js.map +1 -1
- package/lib/commonjs/utils/NativeUpdatedValue.js +0 -3
- package/lib/commonjs/utils/NativeUpdatedValue.js.map +1 -1
- package/lib/commonjs/utils/artwork.js +31 -0
- package/lib/commonjs/utils/artwork.js.map +1 -0
- package/lib/commonjs/web/NativeAudioBrowser.js +301 -124
- package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js +71 -0
- package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/PlaybackTimer.js +34 -0
- package/lib/commonjs/web/TrackPlayer/PlaybackTimer.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/Player.js +90 -26
- package/lib/commonjs/web/TrackPlayer/Player.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/PlayingStateFactory.js +21 -0
- package/lib/commonjs/web/TrackPlayer/PlayingStateFactory.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/QueueManager.js +273 -0
- package/lib/commonjs/web/TrackPlayer/QueueManager.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/QueuePlayer.js +158 -0
- package/lib/commonjs/web/TrackPlayer/QueuePlayer.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/RepeatMode.js +1 -1
- package/lib/commonjs/web/TrackPlayer/RepeatMode.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/SleepTimer.js +34 -3
- package/lib/commonjs/web/TrackPlayer/SleepTimer.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/VolumeFader.js +75 -0
- package/lib/commonjs/web/TrackPlayer/VolumeFader.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/index.js +13 -5
- package/lib/commonjs/web/TrackPlayer/index.js.map +1 -1
- package/lib/commonjs/web/browser/BrowserManager.js +176 -50
- package/lib/commonjs/web/browser/BrowserManager.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 +11 -9
- package/lib/commonjs/web/browser/SearchManager.js.map +1 -1
- package/lib/commonjs/web/browser/assertBrowsePageShape.js +22 -0
- package/lib/commonjs/web/browser/assertBrowsePageShape.js.map +1 -0
- package/lib/commonjs/web/browser/classifyTrackNavigation.js +41 -0
- package/lib/commonjs/web/browser/classifyTrackNavigation.js.map +1 -0
- package/lib/commonjs/web/browser/parseSearchResponse.js +20 -0
- package/lib/commonjs/web/browser/parseSearchResponse.js.map +1 -0
- package/lib/commonjs/web/http/HttpClient.js +4 -23
- package/lib/commonjs/web/http/HttpClient.js.map +1 -1
- package/lib/commonjs/web/http/RequestConfigBuilder.js +107 -58
- package/lib/commonjs/web/http/RequestConfigBuilder.js.map +1 -1
- package/lib/commonjs/web/playbackErrorKind.js +57 -0
- package/lib/commonjs/web/playbackErrorKind.js.map +1 -0
- package/lib/commonjs/web/player/MediaSessionManager.js +121 -0
- package/lib/commonjs/web/player/MediaSessionManager.js.map +1 -0
- package/lib/commonjs/web/player/NowPlayingManager.js +6 -5
- package/lib/commonjs/web/player/NowPlayingManager.js.map +1 -1
- package/lib/commonjs/web/player/OptionsManager.js +9 -17
- package/lib/commonjs/web/player/OptionsManager.js.map +1 -1
- package/lib/commonjs/web/player/RemoteCommandController.js +96 -0
- package/lib/commonjs/web/player/RemoteCommandController.js.map +1 -0
- package/lib/module/features/browser-config.js +221 -0
- package/lib/module/features/browser-config.js.map +1 -0
- package/lib/module/features/browser.js +53 -156
- package/lib/module/features/browser.js.map +1 -1
- package/lib/module/features/carConnection.js +37 -0
- package/lib/module/features/carConnection.js.map +1 -0
- package/lib/module/features/errors.js +34 -2
- package/lib/module/features/errors.js.map +1 -1
- package/lib/module/features/gate.js +144 -0
- package/lib/module/features/gate.js.map +1 -0
- package/lib/module/features/index.js +2 -0
- package/lib/module/features/index.js.map +1 -1
- package/lib/module/features/metadata.js.map +1 -1
- package/lib/module/features/nowPlaying.js +33 -0
- package/lib/module/features/nowPlaying.js.map +1 -1
- package/lib/module/features/output.js +32 -19
- package/lib/module/features/output.js.map +1 -1
- package/lib/module/features/playback/controls.js +8 -0
- package/lib/module/features/playback/controls.js.map +1 -1
- package/lib/module/features/playback/index.js +1 -0
- package/lib/module/features/playback/index.js.map +1 -1
- package/lib/module/features/playback/progress.js +28 -12
- package/lib/module/features/playback/progress.js.map +1 -1
- package/lib/module/features/playback/trackPlaybackTime.js +88 -0
- package/lib/module/features/playback/trackPlaybackTime.js.map +1 -0
- package/lib/module/features/playback/volume.js +1 -1
- package/lib/module/features/player/options.js +48 -13
- package/lib/module/features/player/options.js.map +1 -1
- package/lib/module/features/player/setup.js +249 -3
- package/lib/module/features/player/setup.js.map +1 -1
- package/lib/module/features/queue/queue.js +10 -3
- package/lib/module/features/queue/queue.js.map +1 -1
- package/lib/module/features/remoteControls.js +0 -11
- package/lib/module/features/remoteControls.js.map +1 -1
- package/lib/module/features/sleepTimer.js +9 -4
- package/lib/module/features/sleepTimer.js.map +1 -1
- package/lib/module/native.js +5 -0
- package/lib/module/native.js.map +1 -1
- package/lib/module/native.web.js +4 -1
- package/lib/module/native.web.js.map +1 -1
- package/lib/module/utils/LazyNativeEmitter.js +0 -3
- package/lib/module/utils/LazyNativeEmitter.js.map +1 -1
- package/lib/module/utils/NativeUpdatedValue.js +0 -3
- package/lib/module/utils/NativeUpdatedValue.js.map +1 -1
- package/lib/module/utils/artwork.js +26 -0
- package/lib/module/utils/artwork.js.map +1 -0
- package/lib/module/web/NativeAudioBrowser.js +302 -125
- package/lib/module/web/NativeAudioBrowser.js.map +1 -1
- package/lib/module/web/TrackPlayer/PlaybackStateMachine.js +67 -0
- package/lib/module/web/TrackPlayer/PlaybackStateMachine.js.map +1 -0
- package/lib/module/web/TrackPlayer/PlaybackTimer.js +29 -0
- package/lib/module/web/TrackPlayer/PlaybackTimer.js.map +1 -0
- package/lib/module/web/TrackPlayer/Player.js +90 -26
- package/lib/module/web/TrackPlayer/Player.js.map +1 -1
- package/lib/module/web/TrackPlayer/PlayingStateFactory.js +17 -0
- package/lib/module/web/TrackPlayer/PlayingStateFactory.js.map +1 -0
- package/lib/module/web/TrackPlayer/QueueManager.js +269 -0
- package/lib/module/web/TrackPlayer/QueueManager.js.map +1 -0
- package/lib/module/web/TrackPlayer/QueuePlayer.js +154 -0
- package/lib/module/web/TrackPlayer/QueuePlayer.js.map +1 -0
- package/lib/module/web/TrackPlayer/RepeatMode.js +1 -1
- package/lib/module/web/TrackPlayer/RepeatMode.js.map +1 -1
- package/lib/module/web/TrackPlayer/SleepTimer.js +34 -3
- package/lib/module/web/TrackPlayer/SleepTimer.js.map +1 -1
- package/lib/module/web/TrackPlayer/VolumeFader.js +70 -0
- package/lib/module/web/TrackPlayer/VolumeFader.js.map +1 -0
- package/lib/module/web/TrackPlayer/index.js +2 -1
- package/lib/module/web/TrackPlayer/index.js.map +1 -1
- package/lib/module/web/browser/BrowserManager.js +176 -50
- package/lib/module/web/browser/BrowserManager.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 +11 -9
- package/lib/module/web/browser/SearchManager.js.map +1 -1
- package/lib/module/web/browser/assertBrowsePageShape.js +18 -0
- package/lib/module/web/browser/assertBrowsePageShape.js.map +1 -0
- package/lib/module/web/browser/classifyTrackNavigation.js +38 -0
- package/lib/module/web/browser/classifyTrackNavigation.js.map +1 -0
- package/lib/module/web/browser/parseSearchResponse.js +16 -0
- package/lib/module/web/browser/parseSearchResponse.js.map +1 -0
- package/lib/module/web/http/HttpClient.js +4 -23
- package/lib/module/web/http/HttpClient.js.map +1 -1
- package/lib/module/web/http/RequestConfigBuilder.js +107 -58
- package/lib/module/web/http/RequestConfigBuilder.js.map +1 -1
- package/lib/module/web/playbackErrorKind.js +52 -0
- package/lib/module/web/playbackErrorKind.js.map +1 -0
- package/lib/module/web/player/MediaSessionManager.js +116 -0
- package/lib/module/web/player/MediaSessionManager.js.map +1 -0
- package/lib/module/web/player/NowPlayingManager.js +7 -5
- package/lib/module/web/player/NowPlayingManager.js.map +1 -1
- package/lib/module/web/player/OptionsManager.js +9 -17
- package/lib/module/web/player/OptionsManager.js.map +1 -1
- package/lib/module/web/player/RemoteCommandController.js +92 -0
- package/lib/module/web/player/RemoteCommandController.js.map +1 -0
- package/lib/typescript/src/features/browser-config.d.ts +12 -0
- package/lib/typescript/src/features/browser-config.d.ts.map +1 -0
- package/lib/typescript/src/features/browser.d.ts +40 -1
- package/lib/typescript/src/features/browser.d.ts.map +1 -1
- package/lib/typescript/src/features/carConnection.d.ts +20 -0
- package/lib/typescript/src/features/carConnection.d.ts.map +1 -0
- package/lib/typescript/src/features/errors.d.ts +58 -3
- package/lib/typescript/src/features/errors.d.ts.map +1 -1
- package/lib/typescript/src/features/gate.d.ts +77 -0
- package/lib/typescript/src/features/gate.d.ts.map +1 -0
- package/lib/typescript/src/features/index.d.ts +2 -0
- package/lib/typescript/src/features/index.d.ts.map +1 -1
- package/lib/typescript/src/features/metadata.d.ts +6 -4
- package/lib/typescript/src/features/metadata.d.ts.map +1 -1
- package/lib/typescript/src/features/nowPlaying.d.ts +27 -0
- package/lib/typescript/src/features/nowPlaying.d.ts.map +1 -1
- package/lib/typescript/src/features/output.d.ts +28 -18
- package/lib/typescript/src/features/output.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/controls.d.ts +5 -0
- package/lib/typescript/src/features/playback/controls.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/index.d.ts +1 -0
- package/lib/typescript/src/features/playback/index.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/progress.d.ts +3 -0
- package/lib/typescript/src/features/playback/progress.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts +34 -0
- package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts.map +1 -0
- package/lib/typescript/src/features/playback/volume.d.ts +1 -1
- package/lib/typescript/src/features/player/options.d.ts +92 -93
- package/lib/typescript/src/features/player/options.d.ts.map +1 -1
- package/lib/typescript/src/features/player/setup.d.ts +206 -167
- package/lib/typescript/src/features/player/setup.d.ts.map +1 -1
- package/lib/typescript/src/features/queue/queue.d.ts +9 -2
- package/lib/typescript/src/features/queue/queue.d.ts.map +1 -1
- package/lib/typescript/src/features/remoteControls.d.ts +0 -13
- package/lib/typescript/src/features/remoteControls.d.ts.map +1 -1
- package/lib/typescript/src/features/sleepTimer.d.ts +18 -3
- package/lib/typescript/src/features/sleepTimer.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/native.d.ts +1 -2
- package/lib/typescript/src/native.d.ts.map +1 -1
- package/lib/typescript/src/specs/audio-browser.nitro.d.ts +17 -225
- package/lib/typescript/src/specs/audio-browser.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types/browser-native.d.ts +9 -3
- package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
- package/lib/typescript/src/types/browser-nodes.d.ts +145 -13
- package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
- package/lib/typescript/src/types/browser.d.ts +349 -85
- package/lib/typescript/src/types/browser.d.ts.map +1 -1
- package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +0 -2
- package/lib/typescript/src/utils/LazyNativeEmitter.d.ts.map +1 -1
- package/lib/typescript/src/utils/NativeUpdatedValue.d.ts +0 -2
- package/lib/typescript/src/utils/NativeUpdatedValue.d.ts.map +1 -1
- package/lib/typescript/src/utils/artwork.d.ts +19 -0
- package/lib/typescript/src/utils/artwork.d.ts.map +1 -0
- package/lib/typescript/src/utils/resolveAssetSource.d.ts.map +1 -1
- package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +3 -1
- package/nitrogen/generated/android/AudioBrowserOnLoad.cpp +24 -10
- package/nitrogen/generated/android/c++/JAndroidAudioContentType.hpp +6 -6
- package/nitrogen/generated/android/c++/JAndroidOptions.hpp +1 -11
- package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +33 -1
- package/nitrogen/generated/android/c++/JArtworkVariants.hpp +61 -0
- package/nitrogen/generated/android/c++/JBrowseResult.hpp +5 -0
- package/nitrogen/generated/android/c++/JCarPlayNowPlayingButton.hpp +3 -3
- package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +6 -0
- package/nitrogen/generated/android/c++/JFavoriteConfig.hpp +58 -0
- package/nitrogen/generated/android/c++/JFavoritesMatchMode.hpp +58 -0
- package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +100 -0
- package/nitrogen/generated/android/c++/JFormattedNavigationError.hpp +3 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.hpp +112 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___RequestConfig_std__optional_std__unordered_map_std__string__std__string__.hpp +121 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +123 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +133 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +121 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.hpp +139 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +6 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.hpp +134 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +8 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +6 -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 +131 -0
- package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +6 -0
- package/nitrogen/generated/android/c++/JFunc_void_GateEvent.hpp +79 -0
- package/nitrogen/generated/android/c++/JFunc_void_NowPlayingMetadata.hpp +0 -10
- package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +9 -4
- package/nitrogen/generated/android/c++/JFunc_void_Output.hpp +80 -0
- package/nitrogen/generated/android/c++/JFunc_void_Playback.hpp +2 -0
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +6 -0
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackErrorEvent.hpp +2 -0
- package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +10 -10
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +6 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +6 -0
- package/nitrogen/generated/android/c++/JGate.hpp +62 -0
- package/nitrogen/generated/android/c++/JGateDecision.hpp +64 -0
- package/nitrogen/generated/android/c++/{JThumbsRating.hpp → JGateEvent.hpp} +16 -15
- package/nitrogen/generated/android/c++/JGateReason.hpp +58 -0
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +236 -212
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.hpp +25 -22
- package/nitrogen/generated/android/c++/JIOSOptions.hpp +95 -0
- package/nitrogen/generated/android/c++/JImageRowItem.hpp +33 -3
- package/nitrogen/generated/android/c++/JMediaReference.hpp +58 -0
- package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +33 -1
- package/nitrogen/generated/android/c++/{JPartialAndroidSetupPlayerOptions.hpp → JNativeAndroidSetupOptions.hpp} +10 -10
- package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +61 -28
- package/nitrogen/generated/android/c++/JNativeGateRequest.hpp +74 -0
- package/nitrogen/generated/android/c++/{JPartialIOSSetupPlayerOptions.hpp → JNativeIOSSetupOptions.hpp} +10 -10
- package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +20 -9
- package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +182 -0
- package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +16 -19
- package/nitrogen/generated/android/c++/JNavigationErrorType.hpp +6 -0
- package/nitrogen/generated/android/c++/JNitroAndroidUpdateOptions.hpp +1 -11
- package/nitrogen/generated/android/c++/JNitroIOSUpdateOptions.hpp +96 -0
- package/nitrogen/generated/android/c++/JNotificationButton.hpp +3 -3
- package/nitrogen/generated/android/c++/JNowPlayingMetadata.hpp +3 -17
- package/nitrogen/generated/android/c++/JNowPlayingUpdate.hpp +7 -3
- package/nitrogen/generated/android/c++/JOptions.hpp +14 -9
- package/nitrogen/generated/android/c++/{JIosOutput.hpp → JOutput.hpp} +15 -15
- package/nitrogen/generated/android/c++/JOutputType.hpp +82 -0
- package/nitrogen/generated/android/c++/JPlayback.hpp +2 -0
- package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +6 -0
- package/nitrogen/generated/android/c++/JPlaybackError.hpp +18 -3
- package/nitrogen/generated/android/c++/JPlaybackErrorEvent.hpp +2 -0
- package/nitrogen/generated/android/c++/JPlaybackErrorKind.hpp +76 -0
- package/nitrogen/generated/android/c++/JPlaybackState.hpp +3 -3
- package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +11 -5
- package/nitrogen/generated/android/c++/JResolvedTrack.hpp +23 -5
- package/nitrogen/generated/android/c++/JRetryConfig.hpp +11 -7
- package/nitrogen/generated/android/c++/JSearchMode.hpp +27 -9
- package/nitrogen/generated/android/c++/JSearchParams.hpp +9 -3
- package/nitrogen/generated/android/c++/JStallReason.hpp +58 -0
- package/nitrogen/generated/android/c++/JTrack.hpp +23 -5
- package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +6 -0
- package/nitrogen/generated/android/c++/JTrackRequest.hpp +93 -0
- package/nitrogen/generated/android/c++/JTransformableRequestConfig.hpp +14 -1
- package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.hpp +71 -0
- package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.cpp +41 -0
- package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.hpp +121 -0
- package/nitrogen/generated/android/c++/JVariant_String_ArtworkVariants.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_String_ArtworkVariants.hpp +70 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidAudioContentType.kt +4 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidOptions.kt +2 -8
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ArtworkRequestConfig.kt +10 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ArtworkVariants.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayNowPlayingButton.kt +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{ThumbsRating.kt → FavoriteConfig.kt} +6 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{RatingType.kt → FavoritesMatchMode.kt} +5 -10
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormatNowPlayingParams.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormattedNavigationError.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.kt +80 -0
- 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 +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___Track.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_std__string____Track.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.kt → Func_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.kt} +12 -12
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Func_void_RemoteSetRatingEvent.kt → Func_void_GateEvent.kt} +9 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Func_void_IosOutput.kt → Func_void_Output.kt} +9 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_bool.kt +9 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{HeartRating.kt → Gate.kt} +9 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{PercentageRating.kt → GateDecision.kt} +9 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{StarRating.kt → GateEvent.kt} +6 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/GateReason.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HybridAudioBrowserSpec.kt +103 -109
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSOptions.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +24 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaReference.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaRequestConfig.kt +10 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{PartialAndroidSetupPlayerOptions.kt → NativeAndroidSetupOptions.kt} +5 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +18 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{RemoteSetRatingEvent.kt → NativeGateRequest.kt} +12 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{PartialIOSSetupPlayerOptions.kt → NativeIOSSetupOptions.kt} +5 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeRouteEntry.kt +4 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeSetupPlayerOptions.kt +66 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeUpdateOptions.kt +6 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorType.kt +3 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroAndroidUpdateOptions.kt +2 -8
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroIOSUpdateOptions.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButton.kt +5 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingMetadata.kt +3 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingUpdate.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Options.kt +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{IosOutput.kt → Output.kt} +6 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/OutputType.kt +31 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackError.kt +12 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackErrorKind.kt +29 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackState.kt +6 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +12 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RetryConfig.kt +7 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchMode.kt +12 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchParams.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StallReason.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +12 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackRequest.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TransformableRequestConfig.kt +7 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_FavoriteConfig.kt +53 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_ResolvedTrack_BrowseError_Promise_BrowseResult_.kt +65 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_String_ArtworkVariants.kt +53 -0
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.cpp +139 -28
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +1098 -447
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +60 -39
- package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +170 -112
- package/nitrogen/generated/ios/swift/AndroidAudioContentType.swift +8 -8
- package/nitrogen/generated/ios/swift/AndroidOptions.swift +2 -12
- package/nitrogen/generated/ios/swift/ArtworkRequestConfig.swift +95 -1
- package/nitrogen/generated/ios/swift/ArtworkVariants.swift +34 -0
- package/nitrogen/generated/ios/swift/CarPlayNowPlayingButton.swift +4 -4
- package/nitrogen/generated/ios/swift/FavoriteConfig.swift +29 -0
- package/nitrogen/generated/ios/swift/FavoritesMatchMode.swift +40 -0
- package/nitrogen/generated/ios/swift/FormatNowPlayingParams.swift +67 -0
- package/nitrogen/generated/ios/swift/FormattedNavigationError.swift +17 -4
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.swift +54 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_RequestConfig___RequestConfig_std__optional_std__unordered_map_std__string__std__string__.swift +69 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_RequestConfig___Track.swift +54 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.swift +60 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__optional_std__string____Track.swift +60 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.swift +61 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.swift +61 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.swift +77 -0
- package/nitrogen/generated/ios/swift/Func_void_GateDecision.swift +46 -0
- package/nitrogen/generated/ios/swift/{Func_void_RemoteSetRatingEvent.swift → Func_void_GateEvent.swift} +10 -10
- package/nitrogen/generated/ios/swift/{Func_void_IosOutput.swift → Func_void_Output.swift} +10 -10
- package/nitrogen/generated/ios/swift/Func_void_TransformableRequestConfig.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_bool.swift +5 -5
- package/nitrogen/generated/ios/swift/Func_void_std__optional_NowPlayingUpdate_.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string_.swift +53 -0
- package/nitrogen/generated/ios/swift/{Func_void_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError___.swift → Func_void_std__shared_ptr_Promise_GateDecision__.swift} +17 -17
- package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_TransformableRequestConfig__.swift +66 -0
- package/nitrogen/generated/ios/swift/Func_void_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError____.swift +81 -0
- package/nitrogen/generated/ios/swift/Gate.swift +47 -0
- package/nitrogen/generated/ios/swift/GateDecision.swift +40 -0
- package/nitrogen/generated/ios/swift/GateEvent.swift +29 -0
- package/nitrogen/generated/ios/swift/GateReason.swift +40 -0
- package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec.swift +20 -14
- package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec_cxx.swift +230 -197
- package/nitrogen/generated/ios/swift/IOSOptions.swift +51 -0
- package/nitrogen/generated/ios/swift/ImageRowItem.swift +121 -2
- package/nitrogen/generated/ios/swift/MediaReference.swift +40 -0
- package/nitrogen/generated/ios/swift/MediaRequestConfig.swift +107 -1
- package/nitrogen/generated/ios/swift/{PartialAndroidSetupPlayerOptions.swift → NativeAndroidSetupOptions.swift} +5 -5
- package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +161 -22
- package/nitrogen/generated/ios/swift/NativeGateRequest.swift +58 -0
- package/nitrogen/generated/ios/swift/{PartialIOSSetupPlayerOptions.swift → NativeIOSSetupOptions.swift} +5 -5
- package/nitrogen/generated/ios/swift/NativeRouteEntry.swift +19 -19
- package/nitrogen/generated/ios/swift/NativeSetupPlayerOptions.swift +206 -0
- package/nitrogen/generated/ios/swift/NativeUpdateOptions.swift +12 -25
- package/nitrogen/generated/ios/swift/NavigationErrorType.swift +8 -0
- package/nitrogen/generated/ios/swift/NitroAndroidUpdateOptions.swift +1 -30
- package/nitrogen/generated/ios/swift/NitroIOSUpdateOptions.swift +90 -0
- package/nitrogen/generated/ios/swift/NotificationButton.swift +4 -4
- package/nitrogen/generated/ios/swift/NowPlayingMetadata.swift +1 -48
- package/nitrogen/generated/ios/swift/NowPlayingUpdate.swift +19 -1
- package/nitrogen/generated/ios/swift/Options.swift +10 -4
- package/nitrogen/generated/ios/swift/{IosOutput.swift → Output.swift} +7 -7
- package/nitrogen/generated/ios/swift/OutputType.swift +72 -0
- package/nitrogen/generated/ios/swift/PlaybackError.swift +43 -2
- package/nitrogen/generated/ios/swift/PlaybackErrorKind.swift +64 -0
- package/nitrogen/generated/ios/swift/PlaybackState.swift +4 -4
- package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +27 -8
- package/nitrogen/generated/ios/swift/ResolvedTrack.swift +74 -8
- package/nitrogen/generated/ios/swift/RetryConfig.swift +35 -4
- package/nitrogen/generated/ios/swift/SearchMode.swift +36 -12
- package/nitrogen/generated/ios/swift/SearchParams.swift +7 -2
- package/nitrogen/generated/ios/swift/StallReason.swift +40 -0
- package/nitrogen/generated/ios/swift/Track.swift +74 -8
- package/nitrogen/generated/ios/swift/TrackRequest.swift +106 -0
- package/nitrogen/generated/ios/swift/TransformableRequestConfig.swift +60 -1
- package/nitrogen/generated/ios/swift/Variant_Bool_FavoriteConfig.swift +18 -0
- package/nitrogen/generated/ios/swift/Variant_ResolvedTrack_BrowseError_Promise_BrowseResult_.swift +19 -0
- package/nitrogen/generated/ios/swift/Variant_String_ArtworkVariants.swift +18 -0
- package/nitrogen/generated/shared/c++/AndroidAudioContentType.hpp +10 -10
- package/nitrogen/generated/shared/c++/AndroidOptions.hpp +1 -12
- package/nitrogen/generated/shared/c++/ArtworkRequestConfig.hpp +10 -2
- package/nitrogen/generated/shared/c++/ArtworkVariants.hpp +87 -0
- package/nitrogen/generated/shared/c++/CarPlayNowPlayingButton.hpp +6 -6
- package/nitrogen/generated/shared/c++/EqualizerSettings.hpp +0 -2
- package/nitrogen/generated/shared/c++/{StarRating.hpp → FavoriteConfig.hpp} +18 -17
- package/nitrogen/generated/shared/c++/FavoritesMatchMode.hpp +76 -0
- package/nitrogen/generated/shared/c++/FormatNowPlayingParams.hpp +110 -0
- package/nitrogen/generated/shared/c++/FormattedNavigationError.hpp +6 -5
- package/nitrogen/generated/shared/c++/{HeartRating.hpp → Gate.hpp} +21 -16
- package/nitrogen/generated/shared/c++/{ThumbsRating.hpp → GateDecision.hpp} +23 -17
- package/nitrogen/generated/shared/c++/{PercentageRating.hpp → GateEvent.hpp} +18 -17
- package/nitrogen/generated/shared/c++/GateReason.hpp +76 -0
- package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.cpp +21 -18
- package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.hpp +44 -35
- package/nitrogen/generated/shared/c++/IOSOptions.hpp +91 -0
- package/nitrogen/generated/shared/c++/ImageRowItem.hpp +33 -2
- package/nitrogen/generated/shared/c++/MediaReference.hpp +76 -0
- package/nitrogen/generated/shared/c++/MediaRequestConfig.hpp +10 -2
- package/nitrogen/generated/shared/c++/{PartialAndroidSetupPlayerOptions.hpp → NativeAndroidSetupOptions.hpp} +11 -11
- package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +31 -15
- package/nitrogen/generated/shared/c++/NativeGateRequest.hpp +97 -0
- package/nitrogen/generated/shared/c++/{PartialIOSSetupPlayerOptions.hpp → NativeIOSSetupOptions.hpp} +11 -11
- package/nitrogen/generated/shared/c++/NativeRouteEntry.hpp +5 -5
- package/nitrogen/generated/shared/c++/NativeSetupPlayerOptions.hpp +138 -0
- package/nitrogen/generated/shared/c++/NativeUpdateOptions.hpp +9 -7
- package/nitrogen/generated/shared/c++/NavigationErrorType.hpp +8 -0
- package/nitrogen/generated/shared/c++/NitroAndroidUpdateOptions.hpp +1 -12
- package/nitrogen/generated/shared/c++/NitroIOSUpdateOptions.hpp +92 -0
- package/nitrogen/generated/shared/c++/NotificationButton.hpp +8 -8
- package/nitrogen/generated/shared/c++/NowPlayingMetadata.hpp +3 -19
- package/nitrogen/generated/shared/c++/NowPlayingUpdate.hpp +6 -2
- package/nitrogen/generated/shared/c++/Options.hpp +8 -8
- package/nitrogen/generated/shared/c++/{IosOutput.hpp → Output.hpp} +18 -18
- package/nitrogen/generated/shared/c++/OutputType.hpp +108 -0
- package/nitrogen/generated/shared/c++/PlaybackError.hpp +18 -3
- package/nitrogen/generated/shared/c++/PlaybackErrorKind.hpp +100 -0
- package/nitrogen/generated/shared/c++/PlaybackState.hpp +9 -9
- package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +9 -6
- package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +24 -5
- package/nitrogen/generated/shared/c++/RetryConfig.hpp +10 -6
- package/nitrogen/generated/shared/c++/SearchMode.hpp +39 -15
- package/nitrogen/generated/shared/c++/SearchParams.hpp +9 -2
- package/nitrogen/generated/shared/c++/StallReason.hpp +76 -0
- package/nitrogen/generated/shared/c++/Track.hpp +24 -5
- package/nitrogen/generated/shared/c++/TrackRequest.hpp +93 -0
- package/nitrogen/generated/shared/c++/TransformableRequestConfig.hpp +6 -2
- package/package.json +11 -6
- package/src/codegen-no-config-variant.test.ts +70 -0
- package/src/features/browser-config.test.ts +110 -0
- package/src/features/browser-config.ts +293 -0
- package/src/features/browser.test.ts +19 -0
- package/src/features/browser.ts +58 -201
- package/src/features/carConnection.ts +36 -0
- package/src/features/errors.ts +68 -2
- package/src/features/gate.test.ts +72 -0
- package/src/features/gate.ts +155 -0
- package/src/features/index.ts +2 -0
- package/src/features/metadata.ts +6 -12
- package/src/features/nowPlaying.ts +36 -0
- package/src/features/output.ts +35 -22
- package/src/features/playback/controls.ts +8 -0
- package/src/features/playback/index.ts +1 -0
- package/src/features/playback/progress.ts +31 -12
- package/src/features/playback/trackPlaybackTime.test.ts +66 -0
- package/src/features/playback/trackPlaybackTime.ts +106 -0
- package/src/features/playback/volume.ts +1 -1
- package/src/features/player/options.test.ts +38 -0
- package/src/features/player/options.ts +140 -75
- package/src/features/player/setup.test.ts +117 -0
- package/src/features/player/setup.ts +390 -175
- package/src/features/queue/queue.test.ts +36 -0
- package/src/features/queue/queue.ts +15 -4
- package/src/features/remoteControls.ts +0 -23
- package/src/features/sleepTimer.ts +23 -4
- package/src/native.ts +5 -0
- package/src/native.web.ts +4 -1
- package/src/specs/audio-browser.nitro.ts +131 -41
- package/src/types/browser-native.ts +19 -6
- package/src/types/browser-nodes.ts +160 -13
- package/src/types/browser.ts +377 -89
- package/src/utils/LazyNativeEmitter.ts +0 -2
- package/src/utils/NativeUpdatedValue.ts +0 -2
- package/src/utils/artwork.ts +30 -0
- package/src/web/NativeAudioBrowser.playWhenReady.test.ts +301 -0
- package/src/web/NativeAudioBrowser.ts +365 -158
- package/src/web/TrackPlayer/PlaybackStateMachine.test.ts +139 -0
- package/src/web/TrackPlayer/PlaybackStateMachine.ts +82 -0
- package/src/web/TrackPlayer/PlaybackTimer.test.ts +67 -0
- package/src/web/TrackPlayer/PlaybackTimer.ts +33 -0
- package/src/web/TrackPlayer/Player.dispatch.test.ts +229 -0
- package/src/web/TrackPlayer/Player.load.test.ts +86 -0
- package/src/web/TrackPlayer/Player.ts +113 -39
- package/src/web/TrackPlayer/PlayingStateFactory.test.ts +51 -0
- package/src/web/TrackPlayer/PlayingStateFactory.ts +24 -0
- package/src/web/TrackPlayer/QueueManager.test.ts +289 -0
- package/src/web/TrackPlayer/QueueManager.ts +302 -0
- package/src/web/TrackPlayer/QueuePlayer.ts +188 -0
- package/src/web/TrackPlayer/RepeatMode.ts +1 -1
- package/src/web/TrackPlayer/SleepTimer.ts +38 -3
- package/src/web/TrackPlayer/VolumeFader.ts +74 -0
- package/src/web/TrackPlayer/index.ts +2 -1
- package/src/web/browser/BrowserManager.ts +231 -62
- package/src/web/browser/NavigationErrorManager.ts +3 -1
- package/src/web/browser/SearchManager.ts +11 -15
- package/src/web/browser/__tests__/layer-resolver.test.ts +69 -0
- package/src/web/browser/assertBrowsePageShape.test.ts +27 -0
- package/src/web/browser/assertBrowsePageShape.ts +27 -0
- package/src/web/browser/classifyTrackNavigation.test.ts +41 -0
- package/src/web/browser/classifyTrackNavigation.ts +35 -0
- package/src/web/browser/parseSearchResponse.test.ts +25 -0
- package/src/web/browser/parseSearchResponse.ts +15 -0
- package/src/web/http/HttpClient.ts +5 -35
- package/src/web/http/RequestConfigBuilder.test.ts +59 -0
- package/src/web/http/RequestConfigBuilder.ts +120 -63
- package/src/web/playbackErrorKind.test.ts +55 -0
- package/src/web/playbackErrorKind.ts +56 -0
- package/src/web/player/MediaSessionManager.test.ts +220 -0
- package/src/web/player/MediaSessionManager.ts +151 -0
- package/src/web/player/NowPlayingManager.test.ts +46 -0
- package/src/web/player/NowPlayingManager.ts +6 -5
- package/src/web/player/OptionsManager.ts +12 -18
- package/src/web/player/RemoteCommandController.test.ts +171 -0
- package/src/web/player/RemoteCommandController.ts +166 -0
- package/android/src/main/java/com/audiobrowser/player/PlaybackProgressUpdateManager.kt +0 -59
- package/android/src/main/java/com/audiobrowser/util/RatingFactory.kt +0 -72
- package/android/src/main/java/com/audiobrowser/util/ResolvedTrackFactory.kt +0 -36
- package/android/src/test/java/com/audiobrowser/player/PlaybackProgressUpdateManagerTest.kt +0 -146
- package/ios/CarPlay/Track+CarPlay.swift +0 -63
- package/ios/NowPlayingInfo/NowPlayingInfoCenter.swift +0 -9
- package/ios/Player/PlaybackProgressUpdateManager.swift +0 -68
- package/ios/Tests/PlaybackProgressUpdateManagerTests.swift +0 -166
- package/lib/commonjs/features/rating.js +0 -2
- package/lib/commonjs/features/rating.js.map +0 -1
- package/lib/commonjs/types/player.js +0 -2
- package/lib/commonjs/types/player.js.map +0 -1
- package/lib/commonjs/web/SimpleRouter.test.js +0 -174
- package/lib/commonjs/web/SimpleRouter.test.js.map +0 -1
- package/lib/commonjs/web/TrackPlayer/PlaylistPlayer.js +0 -293
- package/lib/commonjs/web/TrackPlayer/PlaylistPlayer.js.map +0 -1
- package/lib/module/features/rating.js +0 -2
- package/lib/module/features/rating.js.map +0 -1
- package/lib/module/types/player.js +0 -2
- package/lib/module/types/player.js.map +0 -1
- package/lib/module/web/SimpleRouter.test.js +0 -174
- package/lib/module/web/SimpleRouter.test.js.map +0 -1
- package/lib/module/web/TrackPlayer/PlaylistPlayer.js +0 -288
- package/lib/module/web/TrackPlayer/PlaylistPlayer.js.map +0 -1
- package/lib/typescript/src/features/rating.d.ts +0 -14
- package/lib/typescript/src/features/rating.d.ts.map +0 -1
- package/lib/typescript/src/native.web.d.ts +0 -3
- package/lib/typescript/src/native.web.d.ts.map +0 -1
- package/lib/typescript/src/types/player.d.ts +0 -64
- package/lib/typescript/src/types/player.d.ts.map +0 -1
- package/lib/typescript/src/web/NativeAudioBrowser.d.ts +0 -188
- package/lib/typescript/src/web/NativeAudioBrowser.d.ts.map +0 -1
- package/lib/typescript/src/web/SimpleRouter.d.ts +0 -40
- package/lib/typescript/src/web/SimpleRouter.d.ts.map +0 -1
- package/lib/typescript/src/web/SimpleRouter.test.d.ts +0 -2
- package/lib/typescript/src/web/SimpleRouter.test.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/Event.d.ts +0 -11
- package/lib/typescript/src/web/TrackPlayer/Event.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/Player.d.ts +0 -59
- package/lib/typescript/src/web/TrackPlayer/Player.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/PlaylistPlayer.d.ts +0 -39
- package/lib/typescript/src/web/TrackPlayer/PlaylistPlayer.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/RepeatMode.d.ts +0 -6
- package/lib/typescript/src/web/TrackPlayer/RepeatMode.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/SetupNotCalledError.d.ts +0 -4
- package/lib/typescript/src/web/TrackPlayer/SetupNotCalledError.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/SleepTimer.d.ts +0 -34
- package/lib/typescript/src/web/TrackPlayer/SleepTimer.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/State.d.ts +0 -13
- package/lib/typescript/src/web/TrackPlayer/State.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/index.d.ts +0 -5
- package/lib/typescript/src/web/TrackPlayer/index.d.ts.map +0 -1
- package/lib/typescript/src/web/browser/BrowserManager.d.ts +0 -154
- package/lib/typescript/src/web/browser/BrowserManager.d.ts.map +0 -1
- package/lib/typescript/src/web/browser/FavoriteManager.d.ts +0 -42
- package/lib/typescript/src/web/browser/FavoriteManager.d.ts.map +0 -1
- package/lib/typescript/src/web/browser/NavigationErrorManager.d.ts +0 -40
- package/lib/typescript/src/web/browser/NavigationErrorManager.d.ts.map +0 -1
- package/lib/typescript/src/web/browser/SearchManager.d.ts +0 -22
- package/lib/typescript/src/web/browser/SearchManager.d.ts.map +0 -1
- package/lib/typescript/src/web/http/HttpClient.d.ts +0 -25
- package/lib/typescript/src/web/http/HttpClient.d.ts.map +0 -1
- package/lib/typescript/src/web/http/RequestConfigBuilder.d.ts +0 -98
- package/lib/typescript/src/web/http/RequestConfigBuilder.d.ts.map +0 -1
- package/lib/typescript/src/web/player/NowPlayingManager.d.ts +0 -34
- package/lib/typescript/src/web/player/NowPlayingManager.d.ts.map +0 -1
- package/lib/typescript/src/web/player/OptionsManager.d.ts +0 -32
- package/lib/typescript/src/web/player/OptionsManager.d.ts.map +0 -1
- package/lib/typescript/src/web/util/BrowserPathHelper.d.ts +0 -69
- package/lib/typescript/src/web/util/BrowserPathHelper.d.ts.map +0 -1
- package/lib/typescript/src/web/util/shuffle.d.ts +0 -8
- package/lib/typescript/src/web/util/shuffle.d.ts.map +0 -1
- package/nitrogen/generated/android/c++/JAndroidUpdateOptions.hpp +0 -86
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.hpp +0 -147
- package/nitrogen/generated/android/c++/JFunc_void_IosOutput.hpp +0 -80
- package/nitrogen/generated/android/c++/JFunc_void_RemoteSetRatingEvent.hpp +0 -87
- package/nitrogen/generated/android/c++/JHeartRating.hpp +0 -57
- package/nitrogen/generated/android/c++/JIosOutputType.hpp +0 -85
- package/nitrogen/generated/android/c++/JPartialSetupPlayerOptions.hpp +0 -96
- package/nitrogen/generated/android/c++/JPercentageRating.hpp +0 -57
- package/nitrogen/generated/android/c++/JRatingType.hpp +0 -73
- package/nitrogen/generated/android/c++/JRemoteSetRatingEvent.hpp +0 -66
- package/nitrogen/generated/android/c++/JStarRating.hpp +0 -57
- package/nitrogen/generated/android/c++/JUpdateOptions.hpp +0 -105
- package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.cpp +0 -34
- package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.hpp +0 -105
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidUpdateOptions.kt +0 -50
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IosOutputType.kt +0 -32
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialSetupPlayerOptions.kt +0 -47
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/UpdateOptions.kt +0 -53
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.kt +0 -77
- package/nitrogen/generated/ios/swift/AndroidUpdateOptions.swift +0 -119
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.swift +0 -68
- package/nitrogen/generated/ios/swift/HeartRating.swift +0 -29
- package/nitrogen/generated/ios/swift/IosOutputType.swift +0 -76
- package/nitrogen/generated/ios/swift/PartialSetupPlayerOptions.swift +0 -101
- package/nitrogen/generated/ios/swift/PercentageRating.swift +0 -29
- package/nitrogen/generated/ios/swift/RatingType.swift +0 -60
- package/nitrogen/generated/ios/swift/RemoteSetRatingEvent.swift +0 -58
- package/nitrogen/generated/ios/swift/StarRating.swift +0 -29
- package/nitrogen/generated/ios/swift/ThumbsRating.swift +0 -29
- package/nitrogen/generated/ios/swift/UpdateOptions.swift +0 -143
- package/nitrogen/generated/ios/swift/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.swift +0 -20
- package/nitrogen/generated/shared/c++/AndroidUpdateOptions.hpp +0 -109
- package/nitrogen/generated/shared/c++/IosOutputType.hpp +0 -112
- package/nitrogen/generated/shared/c++/PartialSetupPlayerOptions.hpp +0 -104
- package/nitrogen/generated/shared/c++/RatingType.hpp +0 -96
- package/nitrogen/generated/shared/c++/RemoteSetRatingEvent.hpp +0 -94
- package/nitrogen/generated/shared/c++/UpdateOptions.hpp +0 -111
- package/src/features/rating.ts +0 -17
- package/src/types/player.ts +0 -69
- package/src/web/TrackPlayer/PlaylistPlayer.ts +0 -346
|
@@ -1,35 +1,41 @@
|
|
|
1
1
|
package com.audiobrowser.player
|
|
2
2
|
|
|
3
3
|
import android.os.Bundle
|
|
4
|
-
import androidx.media3.common.HeartRating
|
|
5
4
|
import androidx.media3.common.MediaItem
|
|
6
5
|
import androidx.media3.common.MediaMetadata
|
|
7
6
|
import androidx.media3.common.Rating
|
|
8
7
|
import androidx.media3.session.LibraryResult
|
|
8
|
+
import androidx.media3.session.MediaConstants
|
|
9
9
|
import androidx.media3.session.MediaLibraryService
|
|
10
10
|
import androidx.media3.session.MediaSession
|
|
11
|
-
import androidx.media3.session.MediaConstants
|
|
12
11
|
import androidx.media3.session.SessionCommand
|
|
13
12
|
import androidx.media3.session.SessionError
|
|
14
13
|
import androidx.media3.session.SessionResult
|
|
15
|
-
import com.audiobrowser.AudioBrowser
|
|
16
14
|
import com.audiobrowser.browser.handleTrackLoad
|
|
15
|
+
import com.audiobrowser.extension.toTrack
|
|
17
16
|
import com.audiobrowser.util.BrowserPathHelper
|
|
18
|
-
import com.audiobrowser.util.
|
|
19
|
-
import com.audiobrowser.util.ResolvedTrackFactory
|
|
17
|
+
import com.audiobrowser.util.RatingFavorites
|
|
20
18
|
import com.audiobrowser.util.TrackFactory
|
|
21
|
-
import com.margelo.nitro.audiobrowser.Track
|
|
22
19
|
import com.google.common.collect.ImmutableList
|
|
23
20
|
import com.google.common.util.concurrent.Futures
|
|
24
21
|
import com.google.common.util.concurrent.ListenableFuture
|
|
25
|
-
import com.margelo.nitro.audiobrowser.
|
|
22
|
+
import com.margelo.nitro.audiobrowser.Gate
|
|
23
|
+
import com.margelo.nitro.audiobrowser.GateEvent
|
|
24
|
+
import com.margelo.nitro.audiobrowser.GateReason
|
|
25
|
+
import com.margelo.nitro.audiobrowser.MediaReference
|
|
26
|
+
import com.margelo.nitro.audiobrowser.NativeGateRequest
|
|
26
27
|
import com.margelo.nitro.audiobrowser.NotificationButtonLayout
|
|
27
28
|
import com.margelo.nitro.audiobrowser.PlayerCapabilities
|
|
28
|
-
import com.margelo.nitro.audiobrowser.
|
|
29
|
+
import com.margelo.nitro.audiobrowser.SearchParams
|
|
30
|
+
import com.margelo.nitro.audiobrowser.Track
|
|
31
|
+
import kotlinx.coroutines.CancellationException
|
|
29
32
|
import kotlinx.coroutines.CoroutineScope
|
|
30
33
|
import kotlinx.coroutines.Dispatchers
|
|
31
34
|
import kotlinx.coroutines.SupervisorJob
|
|
35
|
+
import kotlinx.coroutines.TimeoutCancellationException
|
|
36
|
+
import kotlinx.coroutines.cancel
|
|
32
37
|
import kotlinx.coroutines.guava.future
|
|
38
|
+
import kotlinx.coroutines.launch
|
|
33
39
|
import kotlinx.coroutines.withContext
|
|
34
40
|
import timber.log.Timber
|
|
35
41
|
|
|
@@ -42,7 +48,9 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
42
48
|
internal val commandManager = MediaSessionCommandManager()
|
|
43
49
|
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
|
44
50
|
|
|
45
|
-
// Track which controllers are subscribed to which media IDs
|
|
51
|
+
// Track which controllers are subscribed to which media IDs.
|
|
52
|
+
// Mutated on the Media3 application thread (onSubscribe/onUnsubscribe) but read from other
|
|
53
|
+
// threads (network observer, JS-triggered notifies) — guard all access with synchronized(this).
|
|
46
54
|
private val parentIdSubscriptions =
|
|
47
55
|
mutableMapOf<String, MutableSet<MediaSession.ControllerInfo>>()
|
|
48
56
|
private var mediaLibrarySession: MediaLibraryService.MediaLibrarySession? = null
|
|
@@ -51,7 +59,8 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
51
59
|
* Recommended artwork size in pixels from the connected media browser (e.g., Android Auto).
|
|
52
60
|
* Updated when onGetLibraryRoot is called with EXTRAS_KEY_MEDIA_ART_SIZE_PIXELS hint.
|
|
53
61
|
*/
|
|
54
|
-
@Volatile
|
|
62
|
+
@Volatile
|
|
63
|
+
var artworkSizeHintPixels: Int? = null
|
|
55
64
|
private set
|
|
56
65
|
|
|
57
66
|
init {
|
|
@@ -72,22 +81,81 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
72
81
|
}
|
|
73
82
|
|
|
74
83
|
/** Creates an offline error MediaItem. */
|
|
75
|
-
private fun createOfflineMediaItem(): MediaItem
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
player.context.getString(com.audiobrowser.R.string.
|
|
79
|
-
|
|
80
|
-
|
|
84
|
+
private fun createOfflineMediaItem(): MediaItem =
|
|
85
|
+
createErrorMediaItem(
|
|
86
|
+
mediaId = BrowserPathHelper.OFFLINE_PATH,
|
|
87
|
+
title = player.context.getString(com.audiobrowser.R.string.audio_browser_offline_error),
|
|
88
|
+
subtitle =
|
|
89
|
+
player.context.getString(com.audiobrowser.R.string.audio_browser_offline_error_subtitle),
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Builds a non-browsable, non-playable [MediaItem] used to surface an error inside an Android
|
|
94
|
+
* Auto / AAOS browse list. Rendered as a greyed-out, non-interactive tile, which is the only
|
|
95
|
+
* side-effect-free way to communicate a browse failure to legacy controllers (Media3 drops
|
|
96
|
+
* [LibraryResult.ofError] on the legacy browse bridge, leaving an empty "No items" screen).
|
|
97
|
+
*/
|
|
98
|
+
private fun createErrorMediaItem(mediaId: String, title: String, subtitle: String): MediaItem =
|
|
99
|
+
MediaItem.Builder()
|
|
100
|
+
.setMediaId(mediaId)
|
|
81
101
|
.setMediaMetadata(
|
|
82
102
|
MediaMetadata.Builder()
|
|
83
|
-
.setTitle(
|
|
84
|
-
.setSubtitle(
|
|
103
|
+
.setTitle(title)
|
|
104
|
+
.setSubtitle(subtitle)
|
|
105
|
+
// Non-browsable, non-playable. Android Auto ignores these flags and still drills into a
|
|
106
|
+
// tapped tile, but onGetChildren returns an empty list for the sentinel paths so it's a
|
|
107
|
+
// harmless "No Items" dead-end rather than an endless stack of error pages.
|
|
85
108
|
.setIsBrowsable(false)
|
|
86
109
|
.setIsPlayable(false)
|
|
87
110
|
.build()
|
|
88
111
|
)
|
|
89
112
|
.build()
|
|
90
|
-
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Builds the gate tile from a per-request chrome: while a gate is active, tabs stay visible but a
|
|
116
|
+
* gated browse/search level serves this single tile (see the gate checks in [onGetChildren] /
|
|
117
|
+
* [onGetSearchResult]). Same shape as the error tiles — non-browsable, non-playable — and
|
|
118
|
+
* deliberately NOT accompanied by a SessionError: a gate is deliberate app state, not a failure.
|
|
119
|
+
* The message renders as the tile's subtitle (newlines collapse to spaces — list rows are
|
|
120
|
+
* single-line).
|
|
121
|
+
*/
|
|
122
|
+
/**
|
|
123
|
+
* Wraps a raw external-search query string into the structured [SearchParams] the gate request
|
|
124
|
+
* carries. The car search surfaces only give a free-text query, so the other fields stay null —
|
|
125
|
+
* mirrors BrowserManager's query→SearchParams construction.
|
|
126
|
+
*/
|
|
127
|
+
private fun searchParams(query: String): SearchParams =
|
|
128
|
+
SearchParams(
|
|
129
|
+
mode = null,
|
|
130
|
+
query = query,
|
|
131
|
+
genre = null,
|
|
132
|
+
artist = null,
|
|
133
|
+
album = null,
|
|
134
|
+
title = null,
|
|
135
|
+
playlist = null,
|
|
136
|
+
reference = MediaReference.UNKNOWN,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
private fun createGateMediaItem(gate: Gate): MediaItem =
|
|
140
|
+
createErrorMediaItem(
|
|
141
|
+
mediaId = BrowserPathHelper.GATE_PATH,
|
|
142
|
+
title = gate.title,
|
|
143
|
+
subtitle = gate.message?.replace('\n', ' ') ?: "",
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Builds a generic "something went wrong" error tile for a browse failure. The true offline case
|
|
148
|
+
* is handled separately by the [networkMonitor] guard in [onGetChildren]; anything reaching the
|
|
149
|
+
* catch block is an online-but-failed request (e.g. server down, bad status), so it must NOT be
|
|
150
|
+
* labelled "no internet connection".
|
|
151
|
+
*/
|
|
152
|
+
private fun createBrowseErrorMediaItem(): MediaItem =
|
|
153
|
+
createErrorMediaItem(
|
|
154
|
+
mediaId = BrowserPathHelper.ERROR_PATH,
|
|
155
|
+
title = player.context.getString(com.audiobrowser.R.string.audio_browser_browse_error),
|
|
156
|
+
subtitle =
|
|
157
|
+
player.context.getString(com.audiobrowser.R.string.audio_browser_browse_error_subtitle),
|
|
158
|
+
)
|
|
91
159
|
|
|
92
160
|
fun updateMediaSession(
|
|
93
161
|
mediaSession: MediaSession,
|
|
@@ -113,18 +181,6 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
113
181
|
return commandManager.buildConnectionResult(session)
|
|
114
182
|
}
|
|
115
183
|
|
|
116
|
-
/** Updates the favorite state of the current track and emits onFavoriteChanged. */
|
|
117
|
-
private fun setFavorited(favorited: Boolean) {
|
|
118
|
-
val currentTrack = player.currentTrack ?: return
|
|
119
|
-
|
|
120
|
-
// Update native favorites cache (only tracks with src can be favorited)
|
|
121
|
-
currentTrack.src?.let { src -> player.browser?.browserManager?.updateFavorite(src, favorited) }
|
|
122
|
-
|
|
123
|
-
player.setActiveTrackFavorited(favorited)
|
|
124
|
-
val event = FavoriteChangedEvent(player.currentTrack ?: currentTrack, favorited)
|
|
125
|
-
player.callbacks?.onFavoriteChanged(event)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
184
|
override fun onCustomCommand(
|
|
129
185
|
session: MediaSession,
|
|
130
186
|
controller: MediaSession.ControllerInfo,
|
|
@@ -135,7 +191,7 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
135
191
|
if (command.customAction == MediaSessionCommandManager.CUSTOM_ACTION_FAVORITE) {
|
|
136
192
|
val currentFavorited = player.currentTrack?.favorited ?: false
|
|
137
193
|
Timber.d("Favorite button tapped - toggling from $currentFavorited to ${!currentFavorited}")
|
|
138
|
-
|
|
194
|
+
player.setActiveTrackFavorited(!currentFavorited)
|
|
139
195
|
return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS))
|
|
140
196
|
}
|
|
141
197
|
|
|
@@ -150,15 +206,10 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
150
206
|
controller: MediaSession.ControllerInfo,
|
|
151
207
|
rating: Rating,
|
|
152
208
|
): ListenableFuture<SessionResult> {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
// Also emit onRemoteSetRating for listeners
|
|
158
|
-
RatingFactory.media3ToBridge(rating)?.let {
|
|
159
|
-
val event = RemoteSetRatingEvent(it)
|
|
160
|
-
player.callbacks?.onRemoteSetRating(event)
|
|
161
|
-
}
|
|
209
|
+
// A heart rating from a controller (e.g. Google Assistant "I like this") toggles the
|
|
210
|
+
// now-playing favorite. setActiveTrackFavorited fires onFavoriteChanged so the consumer
|
|
211
|
+
// persists it — the same path as the notification / CarPlay heart button.
|
|
212
|
+
RatingFavorites.favoritedFor(rating)?.let { player.setActiveTrackFavorited(it) }
|
|
162
213
|
return super.onSetRating(session, controller, rating)
|
|
163
214
|
}
|
|
164
215
|
|
|
@@ -220,25 +271,55 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
220
271
|
)
|
|
221
272
|
return scope.future {
|
|
222
273
|
// Wait for browser to be registered if it's not available yet
|
|
223
|
-
val
|
|
224
|
-
player
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
274
|
+
val audioBrowser =
|
|
275
|
+
player.awaitBrowser().also { Timber.d("Browser ready, proceeding with onGetChildren") }
|
|
276
|
+
val browserManager = audioBrowser.browserManager
|
|
277
|
+
|
|
278
|
+
// While a gate is active, tabs stay visible (the root keeps serving them below) but each
|
|
279
|
+
// non-root level is resolved per request: a gated path — including re-queries of the gate
|
|
280
|
+
// tile's own sentinel path — serves the single gate tile, so drilling into it re-shows the
|
|
281
|
+
// message instead of dead-ending in "No items"; an allowed path falls through to real
|
|
282
|
+
// children. Checked before the offline guard: gated content isn't coming back with
|
|
283
|
+
// connectivity, so the gate copy is the truer message.
|
|
284
|
+
if (parentId != BrowserPathHelper.ROOT_PATH) {
|
|
285
|
+
val outcome =
|
|
286
|
+
audioBrowser.gateDecision(
|
|
287
|
+
NativeGateRequest(reason = GateReason.BROWSE, path = parentId, search = null)
|
|
288
|
+
)
|
|
289
|
+
if (outcome.gated) {
|
|
290
|
+
audioBrowser.onGate(GateEvent(GateReason.BROWSE))
|
|
291
|
+
// gateDecision guarantees non-null chrome on a gated decision (override → default →
|
|
292
|
+
// built-in).
|
|
293
|
+
return@future LibraryResult.ofItemList(
|
|
294
|
+
ImmutableList.of(createGateMediaItem(outcome.chrome!!)),
|
|
295
|
+
params,
|
|
296
|
+
)
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// The error / offline tiles are dead-ends. Some controllers (e.g. Android Auto when online)
|
|
301
|
+
// treat a non-browsable tile as tappable and subscribe to its mediaId anyway; returning the
|
|
302
|
+
// error tile again here would push an endless stack of error pages. Return nothing instead.
|
|
303
|
+
// For the offline tile, re-send the alert when still offline so a tap surfaces the
|
|
304
|
+
// explanation again — but only then, since these paths are also re-queried by
|
|
305
|
+
// notifyChildrenChanged (e.g. when connectivity returns) without any user action.
|
|
306
|
+
if (parentId == BrowserPathHelper.OFFLINE_PATH || parentId == BrowserPathHelper.ERROR_PATH) {
|
|
307
|
+
if (parentId == BrowserPathHelper.OFFLINE_PATH && !player.networkMonitor.isOnline.value) {
|
|
308
|
+
sendBrowseError(session, browser, offline = true)
|
|
309
|
+
}
|
|
310
|
+
return@future LibraryResult.ofItemList(ImmutableList.of<MediaItem>(), params)
|
|
311
|
+
}
|
|
228
312
|
|
|
229
313
|
// Show offline error when offline:
|
|
230
314
|
if (
|
|
231
315
|
!player.networkMonitor.isOnline.value && browserManager.config.androidControllerOfflineError
|
|
232
316
|
) {
|
|
233
317
|
Timber.w("Network offline - returning error message for: $parentId")
|
|
318
|
+
sendBrowseError(session, browser, offline = true)
|
|
234
319
|
return@future LibraryResult.ofItemList(ImmutableList.of(createOfflineMediaItem()), params)
|
|
235
320
|
}
|
|
236
321
|
|
|
237
322
|
try {
|
|
238
|
-
// Get context and imageLoader for SVG pre-rendering
|
|
239
|
-
val context = player.context
|
|
240
|
-
val imageLoader = player.imageLoader
|
|
241
|
-
|
|
242
323
|
val children =
|
|
243
324
|
if (parentId == BrowserPathHelper.RECENT_PATH) {
|
|
244
325
|
// TODO: implement recent media items
|
|
@@ -246,36 +327,90 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
246
327
|
} else if (parentId == BrowserPathHelper.ROOT_PATH) {
|
|
247
328
|
// Return tabs as root children (limited to 4 for automotive platform compatibility)
|
|
248
329
|
// TODO: Check what Android Auto does with empty tabs list - may need to return error?
|
|
249
|
-
val tabs = browserManager.queryTabs()
|
|
250
|
-
if (
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
330
|
+
val tabs = browserManager.queryTabs()
|
|
331
|
+
if (tabs.size > 4) {
|
|
332
|
+
Timber.w(
|
|
333
|
+
"Root has ${tabs.size} tabs; dropping ${tabs.size - 4} (Android Auto root limit)"
|
|
334
|
+
)
|
|
254
335
|
}
|
|
336
|
+
toMediaItems(tabs.take(4))
|
|
255
337
|
} else {
|
|
256
338
|
// Resolve the specific path and get its children
|
|
257
339
|
val resolvedTrack = browserManager.resolve(parentId)
|
|
258
340
|
|
|
259
341
|
// Convert children to MediaItems (url is already set to contextual URL)
|
|
260
|
-
val trackChildren =
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
} else {
|
|
267
|
-
trackChildren.map { track -> TrackFactory.toMedia3(track) }
|
|
268
|
-
}
|
|
342
|
+
val trackChildren =
|
|
343
|
+
resolvedTrack.children
|
|
344
|
+
?: throw IllegalStateException(
|
|
345
|
+
"Expected browsed ResolvedTrack to have a children array"
|
|
346
|
+
)
|
|
347
|
+
toMediaItems(trackChildren.toList())
|
|
269
348
|
}
|
|
270
349
|
|
|
271
350
|
LibraryResult.ofItemList(ImmutableList.copyOf(children.paginate(page, pageSize)), params)
|
|
272
351
|
} catch (e: Exception) {
|
|
352
|
+
// A cancelled browse (controller disconnected) is not a failure — don't render it as an
|
|
353
|
+
// error tile. awaitBrowser's TimeoutCancellationException IS a real failure, keep that.
|
|
354
|
+
if (e is CancellationException && e !is TimeoutCancellationException) throw e
|
|
273
355
|
Timber.e(e, "Error getting children for parentId: $parentId")
|
|
274
|
-
|
|
356
|
+
// Surface an error tile instead of a bare ofError(): Media3 drops the error message on the
|
|
357
|
+
// legacy browse bridge, which would otherwise leave an empty "No items" screen in Android
|
|
358
|
+
// Auto. See https://github.com/androidx/media/issues/2901
|
|
359
|
+
//
|
|
360
|
+
// Verified on a head unit (2026-06): the AA browse list NEVER renders error text — not for
|
|
361
|
+
// transient sendError, sticky non-fatal replication, or fatal replication
|
|
362
|
+
// (setLibraryErrorReplicationMode). Fatal replication does show the message on the
|
|
363
|
+
// playback screen, but presents the session as STATE_ERROR with no actions, hiding the
|
|
364
|
+
// now-playing item and transport controls — not worth it. Tiles remain the only in-browse
|
|
365
|
+
// signal we control.
|
|
366
|
+
sendBrowseError(session, browser, offline = false)
|
|
367
|
+
LibraryResult.ofItemList(ImmutableList.of(createBrowseErrorMediaItem()), params)
|
|
275
368
|
}
|
|
276
369
|
}
|
|
277
370
|
}
|
|
278
371
|
|
|
372
|
+
/**
|
|
373
|
+
* Sends a non-fatal [SessionError] to the controller whose browse failed, complementing the error
|
|
374
|
+
* tile. Media3 browsers receive it via MediaController.Listener.onError; for legacy controllers
|
|
375
|
+
* Media3 transiently attaches the error code/message to the platform session's playback state
|
|
376
|
+
* without entering STATE_ERROR.
|
|
377
|
+
*
|
|
378
|
+
* NOTE: current Android Auto renders NOTHING for this (verified on a head unit — see
|
|
379
|
+
* androidx/media#2901; the transient state is cleared microseconds after being set). It is kept
|
|
380
|
+
* because it is the correct Media3-API error signal, costs nothing, and becomes user-visible if
|
|
381
|
+
* Android Auto moves to consuming SessionError via the Media3 controller API.
|
|
382
|
+
*
|
|
383
|
+
* Dispatched to the main thread: the session and its legacy stub are application-thread bound.
|
|
384
|
+
*/
|
|
385
|
+
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
|
386
|
+
private fun sendBrowseError(
|
|
387
|
+
session: MediaLibraryService.MediaLibrarySession,
|
|
388
|
+
browser: MediaSession.ControllerInfo,
|
|
389
|
+
offline: Boolean,
|
|
390
|
+
) {
|
|
391
|
+
val message =
|
|
392
|
+
player.context.getString(
|
|
393
|
+
if (offline) com.audiobrowser.R.string.audio_browser_offline_error
|
|
394
|
+
else com.audiobrowser.R.string.audio_browser_browse_error
|
|
395
|
+
)
|
|
396
|
+
val code = if (offline) SessionError.ERROR_IO else SessionError.ERROR_UNKNOWN
|
|
397
|
+
scope.launch(Dispatchers.Main) { session.sendError(browser, SessionError(code, message)) }
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Converts tracks to MediaItems for browse delivery, routing http(s) artwork through the
|
|
402
|
+
* content:// provider so Android Auto can load it via the ArtworkContentProvider. Image-row
|
|
403
|
+
* tracks (a CarPlay-only rendering) are expanded into their items as regular grouped rows
|
|
404
|
+
* first — see [TrackFactory.expandImageRows].
|
|
405
|
+
*/
|
|
406
|
+
private fun toMediaItems(tracks: List<Track>): List<MediaItem> {
|
|
407
|
+
val registry = player.browseArtworkRegistry
|
|
408
|
+
val authority = com.audiobrowser.util.ArtworkUris.authorityFor(player.context.packageName)
|
|
409
|
+
return TrackFactory.expandImageRows(tracks).map {
|
|
410
|
+
TrackFactory.toBrowseMediaItem(it, registry, authority)
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
279
414
|
override fun onGetItem(
|
|
280
415
|
session: MediaLibraryService.MediaLibrarySession,
|
|
281
416
|
browser: MediaSession.ControllerInfo,
|
|
@@ -288,6 +423,30 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
288
423
|
return@future LibraryResult.ofItem(createOfflineMediaItem(), null)
|
|
289
424
|
}
|
|
290
425
|
|
|
426
|
+
// Return the error tile as a non-browsable item so tapping it can't re-browse into a
|
|
427
|
+
// failing path (which would push another error page onto the stack).
|
|
428
|
+
if (mediaId == BrowserPathHelper.ERROR_PATH) {
|
|
429
|
+
return@future LibraryResult.ofItem(createBrowseErrorMediaItem(), null)
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (mediaId == BrowserPathHelper.GATE_PATH) {
|
|
433
|
+
// A direct fetch of the gate tile's own sentinel (a controller re-reading the item it was
|
|
434
|
+
// served). Resolve the chrome for the gate path but do NOT emit onGate — that fires at the
|
|
435
|
+
// browse/search serve sites, not on an item lookup.
|
|
436
|
+
val outcome =
|
|
437
|
+
player
|
|
438
|
+
.awaitBrowser()
|
|
439
|
+
.gateDecision(
|
|
440
|
+
NativeGateRequest(
|
|
441
|
+
reason = GateReason.BROWSE,
|
|
442
|
+
path = BrowserPathHelper.GATE_PATH,
|
|
443
|
+
search = null,
|
|
444
|
+
)
|
|
445
|
+
)
|
|
446
|
+
if (!outcome.gated) return@future LibraryResult.ofError(SessionError.ERROR_BAD_VALUE)
|
|
447
|
+
return@future LibraryResult.ofItem(createGateMediaItem(outcome.chrome!!), null)
|
|
448
|
+
}
|
|
449
|
+
|
|
291
450
|
if (mediaId == BrowserPathHelper.ROOT_PATH || mediaId == BrowserPathHelper.RECENT_PATH) {
|
|
292
451
|
return@future LibraryResult.ofItem(
|
|
293
452
|
MediaItem.Builder()
|
|
@@ -303,11 +462,33 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
303
462
|
// Wait for browser to be registered if it's not available yet
|
|
304
463
|
val browserManager = player.awaitBrowser().browserManager
|
|
305
464
|
|
|
465
|
+
// Serve tracks from the track cache first (keyed by url and src). Besides avoiding an HTTP
|
|
466
|
+
// resolve, this keeps item identity correct for contextual mediaIds: resolve() strips
|
|
467
|
+
// __trackId and would return the *parent container's* metadata as the item.
|
|
468
|
+
val browseAuthority =
|
|
469
|
+
com.audiobrowser.util.ArtworkUris.authorityFor(player.context.packageName)
|
|
470
|
+
browserManager.getCachedTrack(mediaId)?.let { track ->
|
|
471
|
+
return@future LibraryResult.ofItem(
|
|
472
|
+
TrackFactory.toBrowseMediaItem(track, player.browseArtworkRegistry, browseAuthority),
|
|
473
|
+
null,
|
|
474
|
+
)
|
|
475
|
+
}
|
|
476
|
+
|
|
306
477
|
try {
|
|
307
478
|
val resolvedTrack = browserManager.resolve(mediaId)
|
|
308
|
-
|
|
309
|
-
|
|
479
|
+
// Through the one Track conversion, so the resolve path renders identically
|
|
480
|
+
// to the cached-track path above (list line from subtitle, favorited heart)
|
|
481
|
+
// and the item's tag is a Track, as fromMedia3 expects.
|
|
482
|
+
LibraryResult.ofItem(
|
|
483
|
+
TrackFactory.toBrowseMediaItem(
|
|
484
|
+
resolvedTrack.toTrack(),
|
|
485
|
+
player.browseArtworkRegistry,
|
|
486
|
+
browseAuthority,
|
|
487
|
+
),
|
|
488
|
+
null,
|
|
489
|
+
)
|
|
310
490
|
} catch (e: Exception) {
|
|
491
|
+
if (e is CancellationException && e !is TimeoutCancellationException) throw e
|
|
311
492
|
Timber.e(e, "Error getting item for mediaId: $mediaId")
|
|
312
493
|
LibraryResult.ofError(SessionError.ERROR_UNKNOWN)
|
|
313
494
|
}
|
|
@@ -322,8 +503,17 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
322
503
|
): ListenableFuture<LibraryResult<Void>> {
|
|
323
504
|
Timber.d("onSubscribe: ${browser.packageName}, parentId = $parentId")
|
|
324
505
|
|
|
325
|
-
parentIdSubscriptions.getOrPut(parentId) { mutableSetOf() }.add(browser)
|
|
326
|
-
|
|
506
|
+
synchronized(this) { parentIdSubscriptions.getOrPut(parentId) { mutableSetOf() }.add(browser) }
|
|
507
|
+
|
|
508
|
+
// Don't call super: Media3's default onSubscribe validates the parent by calling
|
|
509
|
+
// onGetItem(parentId), which for us is a full resolve() — an HTTP fetch whose result the
|
|
510
|
+
// legacy stub discards for Android Auto controllers. onGetChildren already surfaces browse
|
|
511
|
+
// failures. Keep the default's other behavior: notify Media3 (non-legacy) browsers so they
|
|
512
|
+
// fetch the children; legacy browsers get onLoadChildren from the framework after subscribing.
|
|
513
|
+
if (browser.controllerVersion != MediaSession.ControllerInfo.LEGACY_CONTROLLER_VERSION) {
|
|
514
|
+
session.notifyChildrenChanged(browser, parentId, Int.MAX_VALUE, params)
|
|
515
|
+
}
|
|
516
|
+
return Futures.immediateFuture(LibraryResult.ofVoid())
|
|
327
517
|
}
|
|
328
518
|
|
|
329
519
|
override fun onUnsubscribe(
|
|
@@ -333,9 +523,11 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
333
523
|
): ListenableFuture<LibraryResult<Void>> {
|
|
334
524
|
Timber.d("onUnsubscribe: ${browser.packageName}, parentId = $parentId")
|
|
335
525
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
parentIdSubscriptions
|
|
526
|
+
synchronized(this) {
|
|
527
|
+
parentIdSubscriptions[parentId]?.remove(browser)
|
|
528
|
+
if (parentIdSubscriptions[parentId]?.isEmpty() == true) {
|
|
529
|
+
parentIdSubscriptions.remove(parentId)
|
|
530
|
+
}
|
|
339
531
|
}
|
|
340
532
|
|
|
341
533
|
return super.onUnsubscribe(session, browser, parentId)
|
|
@@ -344,22 +536,38 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
344
536
|
/**
|
|
345
537
|
* Notifies all subscribed controllers to refresh their content. Called internally when network
|
|
346
538
|
* state changes to refresh all subscribed paths.
|
|
539
|
+
*
|
|
540
|
+
* Safe to call from any thread: snapshots the subscribed paths and dispatches the session calls
|
|
541
|
+
* to the main (Media3 application) thread.
|
|
347
542
|
*/
|
|
348
543
|
private fun notifySubscribedChildrenChanged() {
|
|
349
|
-
|
|
350
|
-
|
|
544
|
+
val session = mediaLibrarySession ?: return
|
|
545
|
+
val parentIds = synchronized(this) { parentIdSubscriptions.keys.toList() }
|
|
546
|
+
scope.launch(Dispatchers.Main) {
|
|
547
|
+
parentIds.forEach { parentId -> session.notifyChildrenChanged(parentId, Int.MAX_VALUE, null) }
|
|
351
548
|
}
|
|
352
549
|
}
|
|
353
550
|
|
|
354
551
|
/**
|
|
355
552
|
* Notifies external controllers that content at the given path has changed. Controllers
|
|
356
|
-
* subscribed to this path will refresh their UI.
|
|
553
|
+
* subscribed to this path will refresh their UI. Safe to call from any thread.
|
|
357
554
|
*
|
|
358
555
|
* @param path The path where content has changed
|
|
359
556
|
*/
|
|
360
557
|
fun notifyContentChanged(path: String) {
|
|
361
558
|
Timber.d("Notifying content changed for path: $path")
|
|
362
|
-
mediaLibrarySession
|
|
559
|
+
val session = mediaLibrarySession ?: return
|
|
560
|
+
scope.launch(Dispatchers.Main) { session.notifyChildrenChanged(path, Int.MAX_VALUE, null) }
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Notifies all subscribed controllers that content everywhere has changed (e.g. on a locale
|
|
565
|
+
* switch) so they re-query their children. Pairs with AudioBrowser.invalidateAllContent(), which
|
|
566
|
+
* clears the content cache first.
|
|
567
|
+
*/
|
|
568
|
+
fun invalidateAllContent() {
|
|
569
|
+
Timber.d("Invalidating all content - notifying all subscribed paths")
|
|
570
|
+
notifySubscribedChildrenChanged()
|
|
363
571
|
}
|
|
364
572
|
|
|
365
573
|
/**
|
|
@@ -367,10 +575,15 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
367
575
|
* controllers to refresh their content.
|
|
368
576
|
*/
|
|
369
577
|
fun notifyBrowserReady() {
|
|
370
|
-
Timber.d("Browser ready - notifying
|
|
578
|
+
Timber.d("Browser ready - notifying all subscribed paths")
|
|
371
579
|
notifySubscribedChildrenChanged()
|
|
372
580
|
}
|
|
373
581
|
|
|
582
|
+
/** Cancels in-flight browse/search work. Call when the owning player is destroyed. */
|
|
583
|
+
fun destroy() {
|
|
584
|
+
scope.cancel()
|
|
585
|
+
}
|
|
586
|
+
|
|
374
587
|
override fun onSearch(
|
|
375
588
|
session: MediaLibraryService.MediaLibrarySession,
|
|
376
589
|
browser: MediaSession.ControllerInfo,
|
|
@@ -379,11 +592,27 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
379
592
|
): ListenableFuture<LibraryResult<Void>> {
|
|
380
593
|
Timber.d("onSearch: ${browser.packageName}, query = $query")
|
|
381
594
|
return scope.future {
|
|
382
|
-
|
|
595
|
+
// Wait for browser registration like onGetChildren does, so a cold-start voice search
|
|
596
|
+
// doesn't fail before JS has configured the browser.
|
|
597
|
+
val audioBrowser =
|
|
598
|
+
try {
|
|
599
|
+
player.awaitBrowser()
|
|
600
|
+
} catch (e: TimeoutCancellationException) {
|
|
601
|
+
Timber.w("Timed out waiting for browser - search not available")
|
|
602
|
+
return@future LibraryResult.ofError(SessionError.ERROR_NOT_SUPPORTED)
|
|
603
|
+
}
|
|
604
|
+
val browserManager = audioBrowser.browserManager
|
|
383
605
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
606
|
+
// External-surface search is gated with the rest of the browse tree — otherwise search is
|
|
607
|
+
// a way around the gate. One "result": the gate tile (see onGetSearchResult).
|
|
608
|
+
val searchOutcome =
|
|
609
|
+
audioBrowser.gateDecision(
|
|
610
|
+
NativeGateRequest(reason = GateReason.SEARCH, path = null, search = searchParams(query))
|
|
611
|
+
)
|
|
612
|
+
if (searchOutcome.gated) {
|
|
613
|
+
audioBrowser.onGate(GateEvent(GateReason.SEARCH))
|
|
614
|
+
session.notifySearchResultChanged(browser, query, 1, params)
|
|
615
|
+
return@future LibraryResult.ofVoid()
|
|
387
616
|
}
|
|
388
617
|
|
|
389
618
|
// Check if search is configured
|
|
@@ -404,6 +633,7 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
404
633
|
|
|
405
634
|
LibraryResult.ofVoid()
|
|
406
635
|
} catch (e: Exception) {
|
|
636
|
+
if (e is CancellationException && e !is TimeoutCancellationException) throw e
|
|
407
637
|
Timber.e(e, "Error during search for query: $query")
|
|
408
638
|
LibraryResult.ofError(SessionError.ERROR_UNKNOWN)
|
|
409
639
|
}
|
|
@@ -422,21 +652,38 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
422
652
|
"onGetSearchResult: ${browser.packageName}, query = $query, page = $page, pageSize = $pageSize"
|
|
423
653
|
)
|
|
424
654
|
return scope.future {
|
|
425
|
-
val
|
|
655
|
+
val audioBrowser =
|
|
656
|
+
try {
|
|
657
|
+
player.awaitBrowser()
|
|
658
|
+
} catch (e: TimeoutCancellationException) {
|
|
659
|
+
Timber.w("Timed out waiting for browser - search not available")
|
|
660
|
+
return@future LibraryResult.ofError(SessionError.ERROR_NOT_SUPPORTED)
|
|
661
|
+
}
|
|
662
|
+
val browserManager = audioBrowser.browserManager
|
|
426
663
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
664
|
+
// Gated: the single search "result" is the gate tile (paired with onSearch's count of 1).
|
|
665
|
+
val searchOutcome =
|
|
666
|
+
audioBrowser.gateDecision(
|
|
667
|
+
NativeGateRequest(reason = GateReason.SEARCH, path = null, search = searchParams(query))
|
|
668
|
+
)
|
|
669
|
+
if (searchOutcome.gated) {
|
|
670
|
+
audioBrowser.onGate(GateEvent(GateReason.SEARCH))
|
|
671
|
+
return@future LibraryResult.ofItemList(
|
|
672
|
+
ImmutableList.of(createGateMediaItem(searchOutcome.chrome!!)),
|
|
673
|
+
params,
|
|
674
|
+
)
|
|
430
675
|
}
|
|
431
676
|
|
|
432
677
|
try {
|
|
433
678
|
// Get cached search results from BrowserManager
|
|
434
679
|
browserManager.getCachedSearchResults(query)?.let { tracks ->
|
|
435
680
|
// Convert to MediaItems
|
|
681
|
+
val searchAuthority =
|
|
682
|
+
com.audiobrowser.util.ArtworkUris.authorityFor(player.context.packageName)
|
|
436
683
|
val mediaItems =
|
|
437
684
|
tracks.map { track ->
|
|
438
685
|
Timber.d("Search result: ${track.title} (url=${track.url}, src=${track.src})")
|
|
439
|
-
TrackFactory.
|
|
686
|
+
TrackFactory.toBrowseMediaItem(track, player.browseArtworkRegistry, searchAuthority)
|
|
440
687
|
}
|
|
441
688
|
|
|
442
689
|
val paginatedItems = mediaItems.paginate(page, pageSize)
|
|
@@ -448,6 +695,7 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
448
695
|
LibraryResult.ofItemList(ImmutableList.of(), params)
|
|
449
696
|
}
|
|
450
697
|
} catch (e: Exception) {
|
|
698
|
+
if (e is CancellationException && e !is TimeoutCancellationException) throw e
|
|
451
699
|
Timber.e(e, "Error getting search results for query: $query")
|
|
452
700
|
LibraryResult.ofError(SessionError.ERROR_UNKNOWN)
|
|
453
701
|
}
|
|
@@ -462,65 +710,84 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
462
710
|
startPositionMs: Long,
|
|
463
711
|
): ListenableFuture<MediaSession.MediaItemsWithStartPosition> {
|
|
464
712
|
Timber.Forest.d(
|
|
465
|
-
"onSetMediaItems: ${controller.packageName}, count=${mediaItems.size}, mediaId=${mediaItems
|
|
713
|
+
"onSetMediaItems: ${controller.packageName}, count=${mediaItems.size}, mediaId=${mediaItems.firstOrNull()?.mediaId}, uri=${mediaItems.firstOrNull()?.localConfiguration?.uri}, title=${mediaItems.firstOrNull()?.mediaMetadata?.title}"
|
|
466
714
|
)
|
|
467
715
|
|
|
716
|
+
if (mediaItems.isEmpty()) {
|
|
717
|
+
return Futures.immediateFuture(
|
|
718
|
+
MediaSession.MediaItemsWithStartPosition(emptyList(), 0, startPositionMs)
|
|
719
|
+
)
|
|
720
|
+
}
|
|
721
|
+
|
|
468
722
|
return scope.future {
|
|
469
723
|
val audioBrowser = player.awaitBrowser()
|
|
470
724
|
|
|
471
|
-
// Helper: returns the current player state unchanged so Media3 doesn't modify playback
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
currentIndex,
|
|
478
|
-
|
|
479
|
-
)
|
|
480
|
-
}
|
|
725
|
+
// Helper: returns the current player state unchanged so Media3 doesn't modify playback.
|
|
726
|
+
// ExoPlayer is main-thread confined; this future runs on IO, so hop to Main for the reads.
|
|
727
|
+
suspend fun currentPlayerState(): MediaSession.MediaItemsWithStartPosition =
|
|
728
|
+
withContext(Dispatchers.Main) {
|
|
729
|
+
val currentItems = player.tracks.map { TrackFactory.toMedia3(it) }
|
|
730
|
+
val currentIndex = player.currentIndex ?: 0
|
|
731
|
+
MediaSession.MediaItemsWithStartPosition(currentItems, currentIndex, startPositionMs)
|
|
732
|
+
}
|
|
481
733
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
734
|
+
val browserManager = audioBrowser.browserManager
|
|
735
|
+
|
|
736
|
+
// A single tapped item resolves to the contextual url of the list it was
|
|
737
|
+
// tapped in: directly for contextual mediaIds, via the track cache for
|
|
738
|
+
// stable-id mediaIds (see BrowserManager.contextualUrlFor). A search
|
|
739
|
+
// selection is not a list tap — its queue comes from the search results
|
|
740
|
+
// (resolveMediaItemsForPlayback), never from a browsed container.
|
|
741
|
+
val singleContextualUrl =
|
|
742
|
+
mediaItems
|
|
743
|
+
.singleOrNull()
|
|
744
|
+
?.takeIf { it.requestMetadata.searchQuery == null }
|
|
745
|
+
?.let { browserManager.contextualUrlFor(it.mediaId) }
|
|
746
|
+
|
|
747
|
+
// Check if this is a single item from the current queue source
|
|
748
|
+
if (singleContextualUrl != null) {
|
|
749
|
+
val parentPath = BrowserPathHelper.stripTrackId(singleContextualUrl)
|
|
750
|
+
val trackId = BrowserPathHelper.extractTrackId(singleContextualUrl)
|
|
751
|
+
|
|
752
|
+
// Check if queue already came from this parent path - just skip to the track
|
|
753
|
+
if (trackId != null && parentPath == player.queueSourcePath) {
|
|
754
|
+
val queueTracks = withContext(Dispatchers.Main) { player.tracks }
|
|
755
|
+
val index = queueTracks.indexOfFirst { it.src == trackId }
|
|
756
|
+
if (index >= 0) {
|
|
757
|
+
Timber.d("Queue already from $parentPath, skipping to index $index")
|
|
758
|
+
val track = queueTracks[index]
|
|
759
|
+
return@future handleTrackLoad(
|
|
760
|
+
audioBrowser.configuration.handleTrackLoad,
|
|
761
|
+
track,
|
|
762
|
+
queueTracks,
|
|
763
|
+
index.toDouble(),
|
|
764
|
+
::currentPlayerState,
|
|
765
|
+
) {
|
|
766
|
+
// Return the existing queue items with the new start index
|
|
767
|
+
val existingItems = queueTracks.map { TrackFactory.toMedia3(it) }
|
|
768
|
+
MediaSession.MediaItemsWithStartPosition(existingItems, index, startPositionMs)
|
|
504
769
|
}
|
|
505
770
|
}
|
|
506
771
|
}
|
|
507
772
|
}
|
|
508
773
|
|
|
509
|
-
val browserManager = audioBrowser.browserManager
|
|
510
774
|
val result =
|
|
511
775
|
browserManager.resolveMediaItemsForPlayback(mediaItems, startIndex, startPositionMs)
|
|
512
776
|
|
|
513
777
|
val tracks = result.mediaItems.map { TrackFactory.fromMedia3(it) }.toTypedArray()
|
|
514
778
|
val selectedTrack = tracks.getOrElse(result.startIndex) { tracks.first() }
|
|
515
779
|
|
|
516
|
-
handleTrackLoad(
|
|
780
|
+
handleTrackLoad(
|
|
781
|
+
audioBrowser.configuration.handleTrackLoad,
|
|
782
|
+
selectedTrack,
|
|
783
|
+
tracks,
|
|
784
|
+
result.startIndex.toDouble(),
|
|
785
|
+
::currentPlayerState,
|
|
786
|
+
) {
|
|
517
787
|
// If this was a contextual URL expansion, track the source path (only for default behavior)
|
|
518
|
-
if (
|
|
519
|
-
val
|
|
520
|
-
|
|
521
|
-
val parentPath = BrowserPathHelper.stripTrackId(mediaId)
|
|
522
|
-
withContext(Dispatchers.Main) { player.queueSourcePath = parentPath }
|
|
523
|
-
}
|
|
788
|
+
if (singleContextualUrl != null) {
|
|
789
|
+
val parentPath = BrowserPathHelper.stripTrackId(singleContextualUrl)
|
|
790
|
+
withContext(Dispatchers.Main) { player.queueSourcePath = parentPath }
|
|
524
791
|
}
|
|
525
792
|
result
|
|
526
793
|
}
|
|
@@ -537,25 +804,42 @@ class MediaSessionCallback(private val player: Player) :
|
|
|
537
804
|
*
|
|
538
805
|
* @param mediaSession The media session
|
|
539
806
|
* @param controller The controller requesting resumption
|
|
540
|
-
* @param
|
|
807
|
+
* @param isForPlayback True if this should start playback; false if just gathering info for the
|
|
808
|
+
* boot-time resumption notification (no network; local metadata only).
|
|
541
809
|
* @see https://developer.android.com/media/media3/session/background-playback#resumption
|
|
542
810
|
*/
|
|
543
811
|
override fun onPlaybackResumption(
|
|
544
812
|
mediaSession: MediaSession,
|
|
545
813
|
controller: MediaSession.ControllerInfo,
|
|
814
|
+
isForPlayback: Boolean,
|
|
546
815
|
): ListenableFuture<MediaSession.MediaItemsWithStartPosition> {
|
|
547
816
|
Timber.d("${controller.packageName}")
|
|
548
817
|
|
|
549
818
|
return scope.future {
|
|
550
|
-
//
|
|
819
|
+
// A pure read first: restore()'s side effects (it applies repeat/shuffle/speed to the
|
|
820
|
+
// live player, emitting option-changed events to JS) belong to actual resumption only.
|
|
551
821
|
val state =
|
|
552
|
-
|
|
553
|
-
withContext(Dispatchers.Main) { player.playbackStateStore.restore() }
|
|
822
|
+
player.playbackStateStore.get()
|
|
554
823
|
?: run {
|
|
555
824
|
Timber.w("No persisted playback state found")
|
|
556
825
|
throw IllegalStateException("No playback state to resume")
|
|
557
826
|
}
|
|
558
827
|
|
|
828
|
+
// isForPlayback == false is the device-boot-time notification case: network may be
|
|
829
|
+
// unavailable and we must not start playback. Return just the locally-stored track with its
|
|
830
|
+
// already-local metadata; skip the settings restore and network queue expansion below.
|
|
831
|
+
if (!isForPlayback) {
|
|
832
|
+
Timber.d("Info-gathering resumption (boot-time); returning stored track without expansion")
|
|
833
|
+
return@future MediaSession.MediaItemsWithStartPosition(
|
|
834
|
+
ImmutableList.of(TrackFactory.toMedia3(state.track)),
|
|
835
|
+
0,
|
|
836
|
+
state.positionMs,
|
|
837
|
+
)
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// restore() sets player properties which must happen on main thread
|
|
841
|
+
withContext(Dispatchers.Main) { player.playbackStateStore.restore() }
|
|
842
|
+
|
|
559
843
|
val url = state.track.url
|
|
560
844
|
Timber.d("Resuming from url=$url, positionMs=${state.positionMs}")
|
|
561
845
|
|