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,5 +1,7 @@
|
|
|
1
1
|
package com.audiobrowser.browser
|
|
2
2
|
|
|
3
|
+
import com.audiobrowser.util.artworkOf
|
|
4
|
+
|
|
3
5
|
import android.util.LruCache
|
|
4
6
|
import androidx.media3.common.MediaItem
|
|
5
7
|
import androidx.media3.session.MediaSession
|
|
@@ -9,8 +11,10 @@ import com.audiobrowser.util.BrowserPathHelper
|
|
|
9
11
|
import com.audiobrowser.util.TrackFactory
|
|
10
12
|
import com.margelo.nitro.audiobrowser.ArtworkRequestConfig
|
|
11
13
|
import com.margelo.nitro.audiobrowser.BrowserSourceCallbackParam
|
|
14
|
+
import com.margelo.nitro.audiobrowser.FavoritesMatchMode
|
|
15
|
+
import com.margelo.nitro.audiobrowser.Func_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____
|
|
12
16
|
import com.margelo.nitro.audiobrowser.ImageContext
|
|
13
|
-
import com.margelo.nitro.audiobrowser.
|
|
17
|
+
import com.margelo.nitro.audiobrowser.MediaReference
|
|
14
18
|
import com.margelo.nitro.audiobrowser.MediaRequestConfig
|
|
15
19
|
import com.margelo.nitro.audiobrowser.NativeRouteEntry
|
|
16
20
|
import com.margelo.nitro.audiobrowser.RequestConfig
|
|
@@ -46,6 +50,7 @@ class BrowserManager {
|
|
|
46
50
|
private var onPathChanged: ((String) -> Unit)? = null
|
|
47
51
|
private var onContentChanged: ((ResolvedTrack?) -> Unit)? = null
|
|
48
52
|
private var onTabsChanged: ((Array<Track>) -> Unit)? = null
|
|
53
|
+
private var onArtworkRegistriesCleared: (() -> Unit)? = null
|
|
49
54
|
|
|
50
55
|
private var path: String = "/"
|
|
51
56
|
set(value) {
|
|
@@ -86,28 +91,64 @@ class BrowserManager {
|
|
|
86
91
|
// Invalidated via invalidateContentCache() when content changes
|
|
87
92
|
private val contentCache = LruCache<String, ResolvedTrack>(20)
|
|
88
93
|
|
|
89
|
-
// Cache for search results
|
|
90
|
-
|
|
91
|
-
private var
|
|
94
|
+
// Cache for the most recent search - the query string and its results stored as one pair, so a
|
|
95
|
+
// concurrent reader never sees one query matched with another query's results.
|
|
96
|
+
@Volatile private var lastSearch: Pair<String, Array<Track>>? = null
|
|
92
97
|
|
|
93
98
|
// Set of favorited track identifiers (src)
|
|
94
99
|
private var favoriteIds = setOf<String>()
|
|
95
100
|
|
|
101
|
+
// Favorite match mode, propagated from the player's `favorite` capability.
|
|
102
|
+
// null = favoriting disabled (no row hearts). Set via setFavoriteMatch.
|
|
103
|
+
private var favoriteMatch: FavoritesMatchMode? = null
|
|
104
|
+
|
|
96
105
|
// Navigation tracking to prevent race conditions
|
|
97
106
|
@Volatile private var currentNavigationId = 0
|
|
98
107
|
|
|
99
108
|
/**
|
|
100
109
|
* Browser configuration containing routes, search, tabs, and request settings. This can be
|
|
101
110
|
* updated dynamically when the configuration changes.
|
|
111
|
+
*
|
|
112
|
+
* Setting a new config bumps [layerGeneration] so the cached request/browse resolver layers are
|
|
113
|
+
* re-resolved on the next request (the resolvers may close over config-derived state).
|
|
102
114
|
*/
|
|
103
115
|
var config: BrowserConfig = BrowserConfig()
|
|
116
|
+
set(value) {
|
|
117
|
+
field = value
|
|
118
|
+
layerGeneration += 1
|
|
119
|
+
// Registered artwork resolutions pin configs (and their JS callback handles)
|
|
120
|
+
// from the previous configuration — never resolve through them again.
|
|
121
|
+
artworkResolutions.clear()
|
|
122
|
+
onArtworkRegistriesCleared?.invoke()
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Resolver-layer caching. The request/browse layers may be resolver thunks
|
|
126
|
+
// (config.requestResolver / config.browseResolver) resolved once per *content generation*:
|
|
127
|
+
// re-resolved when content is invalidated (clearContentCache, from invalidateAllContent) or when
|
|
128
|
+
// a new config is set, cached, and merged per request.
|
|
129
|
+
private var layerGeneration = 0
|
|
130
|
+
private var resolvedLayerGeneration = -1
|
|
131
|
+
private var resolvedRequestLayer: TransformableRequestConfig? = null
|
|
132
|
+
private var resolvedBrowseLayer: TransformableRequestConfig? = null
|
|
133
|
+
|
|
134
|
+
/** Test-only accessors for the resolver-layer cache state (see ensureLayersResolved). */
|
|
135
|
+
internal val layerGenerationForTest: Int
|
|
136
|
+
get() = layerGeneration
|
|
137
|
+
|
|
138
|
+
internal val resolvedLayerGenerationForTest: Int
|
|
139
|
+
get() = resolvedLayerGeneration
|
|
140
|
+
|
|
141
|
+
internal val resolvedRequestLayerForTest: TransformableRequestConfig?
|
|
142
|
+
get() = resolvedRequestLayer
|
|
143
|
+
|
|
144
|
+
internal val resolvedBrowseLayerForTest: TransformableRequestConfig?
|
|
145
|
+
get() = resolvedBrowseLayer
|
|
104
146
|
|
|
105
147
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* The ImageContext parameter provides size hints for CDN URL generation.
|
|
148
|
+
* Maps produced artwork URIs back to (Track, artwork-config kind) so display-time bitmap loading
|
|
149
|
+
* can re-resolve Track-first. See [ArtworkResolutionRegistry].
|
|
109
150
|
*/
|
|
110
|
-
|
|
151
|
+
val artworkResolutions = ArtworkResolutionRegistry()
|
|
111
152
|
|
|
112
153
|
/**
|
|
113
154
|
* Sets the favorited track identifiers. Tracks will have their favorited field hydrated based on
|
|
@@ -118,6 +159,14 @@ class BrowserManager {
|
|
|
118
159
|
Timber.d("Set ${favoriteIds.size} favorite IDs")
|
|
119
160
|
}
|
|
120
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Sets the favorite match mode (propagated from the `favorite` capability). null disables
|
|
164
|
+
* row-heart hydration.
|
|
165
|
+
*/
|
|
166
|
+
fun setFavoriteMatch(match: FavoritesMatchMode?) {
|
|
167
|
+
favoriteMatch = match
|
|
168
|
+
}
|
|
169
|
+
|
|
121
170
|
/**
|
|
122
171
|
* Updates the favorite state for a single track identifier. Called when the heart button is
|
|
123
172
|
* tapped in media controllers.
|
|
@@ -133,40 +182,30 @@ class BrowserManager {
|
|
|
133
182
|
}
|
|
134
183
|
|
|
135
184
|
/**
|
|
136
|
-
* Hydrates the favorited field on a track based on the favoriteIds set.
|
|
137
|
-
*
|
|
138
|
-
* favorited.
|
|
185
|
+
* Hydrates the favorited field on a track based on the favoriteIds set. No-op unless favoriting
|
|
186
|
+
* is enabled (the `favorite` capability). Only playable (src-bearing) tracks are favoritable; the
|
|
187
|
+
* flag is set to true OR false so non-favorited tracks still show an (empty) heart. Doesn't
|
|
188
|
+
* overwrite API-provided values.
|
|
139
189
|
*/
|
|
140
190
|
private fun hydrateFavorite(track: Track): Track {
|
|
191
|
+
val match = favoriteMatch ?: return track
|
|
141
192
|
// Don't overwrite API-provided favorites
|
|
142
193
|
if (track.favorited != null) return track
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
return
|
|
149
|
-
url = track.url,
|
|
150
|
-
src = track.src,
|
|
151
|
-
artwork = track.artwork,
|
|
152
|
-
artworkSource = track.artworkSource,
|
|
153
|
-
artworkCarPlayTinted = track.artworkCarPlayTinted,
|
|
154
|
-
title = track.title,
|
|
155
|
-
subtitle = track.subtitle,
|
|
156
|
-
artist = track.artist,
|
|
157
|
-
album = track.album,
|
|
158
|
-
description = track.description,
|
|
159
|
-
genre = track.genre,
|
|
160
|
-
duration = track.duration,
|
|
161
|
-
style = track.style,
|
|
162
|
-
childrenStyle = track.childrenStyle,
|
|
163
|
-
favorited = true,
|
|
164
|
-
groupTitle = track.groupTitle,
|
|
165
|
-
live = track.live,
|
|
166
|
-
imageRow = track.imageRow,
|
|
167
|
-
)
|
|
194
|
+
// Only playable tracks are favoritable
|
|
195
|
+
val src = track.src ?: return track
|
|
196
|
+
|
|
197
|
+
val isFavorited = isFavorite(src, match)
|
|
198
|
+
|
|
199
|
+
return track.copy(favorited = isFavorited)
|
|
168
200
|
}
|
|
169
201
|
|
|
202
|
+
/** Whether [src] is favorited under the given match mode. */
|
|
203
|
+
private fun isFavorite(src: String, match: FavoritesMatchMode): Boolean =
|
|
204
|
+
when (match) {
|
|
205
|
+
FavoritesMatchMode.EXACT -> favoriteIds.contains(src)
|
|
206
|
+
FavoritesMatchMode.PARTIAL -> favoriteIds.any { BrowserPathHelper.containsSegment(src, it) }
|
|
207
|
+
}
|
|
208
|
+
|
|
170
209
|
/** Hydrates favorites on all children of a ResolvedTrack. */
|
|
171
210
|
private fun hydrateChildren(resolvedTrack: ResolvedTrack): ResolvedTrack {
|
|
172
211
|
val children = resolvedTrack.children ?: return resolvedTrack
|
|
@@ -174,20 +213,29 @@ class BrowserManager {
|
|
|
174
213
|
return resolvedTrack.copy(children = hydratedChildren)
|
|
175
214
|
}
|
|
176
215
|
|
|
177
|
-
/** Cache a track by
|
|
216
|
+
/** Cache a track by id, url, and src for O(1) lookup from any mediaId form. */
|
|
178
217
|
private fun cacheTrack(track: Track) {
|
|
218
|
+
track.id?.takeUnless { it.isBlank() }?.let { trackCache.put(it, track) }
|
|
179
219
|
track.url?.let { trackCache.put(it, track) }
|
|
180
220
|
track.src?.let { trackCache.put(it, track) }
|
|
181
221
|
}
|
|
182
222
|
|
|
183
223
|
private fun cacheChildren(resolvedTrack: ResolvedTrack) {
|
|
184
|
-
resolvedTrack.children?.forEach { track ->
|
|
224
|
+
resolvedTrack.children?.forEach { track ->
|
|
225
|
+
cacheTrack(track)
|
|
226
|
+
// Image-row items are playable surfaces of their own: cache them (with
|
|
227
|
+
// their stamped contextual urls) so an id-keyed mediaId from an
|
|
228
|
+
// expanded Android Auto tile can find its way back to queue expansion.
|
|
229
|
+
track.imageRow?.forEach { item ->
|
|
230
|
+
cacheTrack(with(TrackFactory) { item.toTrack(groupTitle = track.title) })
|
|
231
|
+
}
|
|
232
|
+
}
|
|
185
233
|
}
|
|
186
234
|
|
|
187
235
|
/**
|
|
188
|
-
* Get a cached Track by mediaId (url or src), or null if not cached. Used by Media3
|
|
189
|
-
* MediaItem shells with full track metadata. Re-hydrates favorites in case
|
|
190
|
-
* called after caching.
|
|
236
|
+
* Get a cached Track by mediaId (stable id, url, or src), or null if not cached. Used by Media3
|
|
237
|
+
* to rehydrate MediaItem shells with full track metadata. Re-hydrates favorites in case
|
|
238
|
+
* setFavoriteStates was called after caching.
|
|
191
239
|
*/
|
|
192
240
|
fun getCachedTrack(mediaId: String): Track? {
|
|
193
241
|
// Try direct lookup first (matches url or src)
|
|
@@ -212,27 +260,76 @@ class BrowserManager {
|
|
|
212
260
|
}
|
|
213
261
|
|
|
214
262
|
/**
|
|
215
|
-
* Resolves
|
|
216
|
-
*
|
|
263
|
+
* Resolves a tapped mediaId to the contextual url to expand a queue from, or null when there is
|
|
264
|
+
* none. A contextual mediaId is its own; a stable-id mediaId (see TrackFactory.buildMediaItem)
|
|
265
|
+
* resolves through the track cache to the contextual url of the container it was most recently
|
|
266
|
+
* browsed in — a legacy car controller round-trips only the mediaId, so the cache is what
|
|
267
|
+
* remembers which list the row came from.
|
|
268
|
+
*/
|
|
269
|
+
fun contextualUrlFor(mediaId: String): String? {
|
|
270
|
+
if (BrowserPathHelper.isContextual(mediaId)) return mediaId
|
|
271
|
+
return getCachedTrack(mediaId)?.url?.takeIf { BrowserPathHelper.isContextual(it) }
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Resolves a single Media3 MediaItem to a Track. Prefers the track cache (keyed by id, url, and
|
|
276
|
+
* src).
|
|
277
|
+
*
|
|
278
|
+
* A cache miss is legitimately reachable: a controller can replay a mediaId this process never
|
|
279
|
+
* browsed — e.g. a search-result track after process death. When the mediaId is a playable URL,
|
|
280
|
+
* or the item's requestMetadata carries the playable uri (stamped by TrackFactory for stable-id
|
|
281
|
+
* mediaIds, and round-tripped by Media3 controllers), fall back to a minimal track built from the
|
|
282
|
+
* item's own metadata instead of failing playback.
|
|
217
283
|
*
|
|
218
|
-
* @
|
|
219
|
-
* @return List of Track objects
|
|
284
|
+
* @throws IllegalStateException if the mediaId is not cached and no playable URL is available
|
|
220
285
|
*/
|
|
221
|
-
fun
|
|
222
|
-
|
|
223
|
-
Timber.d("=== Resolving from cache: mediaId='$mediaId' ===")
|
|
286
|
+
private fun resolveMediaItemToTrack(mediaItem: MediaItem): Track {
|
|
287
|
+
val mediaId = mediaItem.mediaId
|
|
224
288
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
289
|
+
getCachedTrack(mediaId)?.let { cachedTrack ->
|
|
290
|
+
Timber.d("Resolved mediaId='$mediaId' from cache: '${cachedTrack.title}'")
|
|
291
|
+
return cachedTrack
|
|
292
|
+
}
|
|
229
293
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
294
|
+
val fallbackSrc =
|
|
295
|
+
if (mediaId.startsWith("http://") || mediaId.startsWith("https://")) {
|
|
296
|
+
mediaId
|
|
297
|
+
} else {
|
|
298
|
+
mediaItem.requestMetadata.mediaUri?.toString()
|
|
299
|
+
}
|
|
300
|
+
if (fallbackSrc != null) {
|
|
301
|
+
Timber.w("Cache MISS for mediaId='$mediaId' - building minimal track from media item")
|
|
302
|
+
val metadata = mediaItem.mediaMetadata
|
|
303
|
+
return hydrateFavorite(
|
|
304
|
+
Track(
|
|
305
|
+
// A mediaId distinct from the playable uri is the track's stable id —
|
|
306
|
+
// keep it so the item's identity (car now-playing row match) survives.
|
|
307
|
+
id = mediaId.takeIf { it != fallbackSrc },
|
|
308
|
+
url = null,
|
|
309
|
+
src = fallbackSrc,
|
|
310
|
+
artwork = artworkOf(metadata.artworkUri?.toString()),
|
|
311
|
+
artworkSource = null,
|
|
312
|
+
request = null,
|
|
313
|
+
artworkCarPlayTinted = null,
|
|
314
|
+
title = metadata.title?.toString() ?: mediaId,
|
|
315
|
+
subtitle = metadata.artist?.toString(),
|
|
316
|
+
artist = null,
|
|
317
|
+
albumUrl = null,
|
|
318
|
+
album = metadata.albumTitle?.toString(),
|
|
319
|
+
description = metadata.description?.toString(),
|
|
320
|
+
genre = metadata.genre?.toString(),
|
|
321
|
+
duration = null,
|
|
322
|
+
style = null,
|
|
323
|
+
childrenStyle = null,
|
|
324
|
+
favorited = null,
|
|
325
|
+
groupTitle = null,
|
|
326
|
+
live = null,
|
|
327
|
+
imageRow = null,
|
|
328
|
+
)
|
|
234
329
|
)
|
|
235
330
|
}
|
|
331
|
+
|
|
332
|
+
throw IllegalStateException("MediaItem not found in cache: $mediaId")
|
|
236
333
|
}
|
|
237
334
|
|
|
238
335
|
/**
|
|
@@ -249,7 +346,7 @@ class BrowserManager {
|
|
|
249
346
|
* @param startIndex Index of the item to start playing
|
|
250
347
|
* @param startPositionMs Position within the start item to begin playback
|
|
251
348
|
* @return MediaSession.MediaItemsWithStartPosition ready for Media3
|
|
252
|
-
* @throws IllegalStateException if
|
|
349
|
+
* @throws IllegalStateException if a mediaId is neither cached nor a playable URL
|
|
253
350
|
*/
|
|
254
351
|
suspend fun resolveMediaItemsForPlayback(
|
|
255
352
|
mediaItems: List<MediaItem>,
|
|
@@ -270,10 +367,13 @@ class BrowserManager {
|
|
|
270
367
|
val searchTracks = searchResults.children
|
|
271
368
|
|
|
272
369
|
if (searchTracks != null && searchTracks.isNotEmpty()) {
|
|
273
|
-
// Find the selected track in search results
|
|
370
|
+
// Find the selected track in search results (mediaId is the stable id
|
|
371
|
+
// when the track has one, else url/src — see TrackFactory)
|
|
274
372
|
val mediaId = mediaItem.mediaId
|
|
275
373
|
val selectedIndex =
|
|
276
|
-
searchTracks.indexOfFirst { track ->
|
|
374
|
+
searchTracks.indexOfFirst { track ->
|
|
375
|
+
track.id == mediaId || track.url == mediaId || track.src == mediaId
|
|
376
|
+
}
|
|
277
377
|
|
|
278
378
|
if (selectedIndex >= 0) {
|
|
279
379
|
Timber.d(
|
|
@@ -297,11 +397,14 @@ class BrowserManager {
|
|
|
297
397
|
}
|
|
298
398
|
|
|
299
399
|
val mediaId = mediaItems[0].mediaId
|
|
400
|
+
// A failed search match falls through to plain resolution, never to browse
|
|
401
|
+
// expansion — the user asked for that one result, not a browsed list.
|
|
402
|
+
val contextualUrl = if (searchQuery == null) contextualUrlFor(mediaId) else null
|
|
300
403
|
|
|
301
|
-
if (
|
|
302
|
-
Timber.d("Attempting queue expansion for mediaId='$mediaId'")
|
|
404
|
+
if (contextualUrl != null) {
|
|
405
|
+
Timber.d("Attempting queue expansion for mediaId='$mediaId' via '$contextualUrl'")
|
|
303
406
|
|
|
304
|
-
val expanded = expandQueueFromContextualUrl(
|
|
407
|
+
val expanded = expandQueueFromContextualUrl(contextualUrl)
|
|
305
408
|
|
|
306
409
|
if (expanded != null) {
|
|
307
410
|
val (tracks, selectedIndex) = expanded
|
|
@@ -318,12 +421,11 @@ class BrowserManager {
|
|
|
318
421
|
}
|
|
319
422
|
}
|
|
320
423
|
|
|
321
|
-
// No expansion - resolve from cache
|
|
322
|
-
val
|
|
323
|
-
val cachedTracks = resolveMediaIdsFromCache(mediaIds)
|
|
424
|
+
// No expansion - resolve from cache (with a minimal-track fallback for replayed mediaIds)
|
|
425
|
+
val resolvedTracks = mediaItems.map { resolveMediaItemToTrack(it) }
|
|
324
426
|
|
|
325
427
|
// Convert to Media3 MediaItems
|
|
326
|
-
val resolvedMediaItems =
|
|
428
|
+
val resolvedMediaItems = resolvedTracks.map { track -> TrackFactory.toMedia3(track) }
|
|
327
429
|
|
|
328
430
|
return MediaSession.MediaItemsWithStartPosition(resolvedMediaItems, startIndex, startPositionMs)
|
|
329
431
|
}
|
|
@@ -355,6 +457,11 @@ class BrowserManager {
|
|
|
355
457
|
if (useCache) {
|
|
356
458
|
contentCache.get(normalizedPath)?.let { cached ->
|
|
357
459
|
Timber.d("Content cache HIT for path='$normalizedPath'")
|
|
460
|
+
// Re-key the track cache even on a hit: an id-keyed lookup (stable-id
|
|
461
|
+
// mediaId → contextual url, see contextualUrlFor) must reflect the
|
|
462
|
+
// most recently *browsed* container, which a cached re-display
|
|
463
|
+
// otherwise wouldn't re-register.
|
|
464
|
+
cacheChildren(cached)
|
|
358
465
|
// Re-hydrate favorites in case they changed since caching
|
|
359
466
|
return hydrateChildren(cached)
|
|
360
467
|
}
|
|
@@ -387,35 +494,37 @@ class BrowserManager {
|
|
|
387
494
|
Timber.d("Invalidated content cache for path='$path'")
|
|
388
495
|
}
|
|
389
496
|
|
|
390
|
-
/** Clears all cached content.
|
|
497
|
+
/** Clears all cached content. */
|
|
391
498
|
fun clearContentCache() {
|
|
392
499
|
contentCache.evictAll()
|
|
500
|
+
// Bump the layer generation so request/browse resolver thunks are re-resolved on the next
|
|
501
|
+
// request (invalidateAllContent → clearContentCache is the documented re-resolve trigger).
|
|
502
|
+
layerGeneration += 1
|
|
503
|
+
// Invalidated content's artwork resolutions go with it (same staleness rule as the
|
|
504
|
+
// config setter).
|
|
505
|
+
artworkResolutions.clear()
|
|
506
|
+
onArtworkRegistriesCleared?.invoke()
|
|
393
507
|
Timber.d("Cleared all content cache")
|
|
394
508
|
}
|
|
395
509
|
|
|
396
510
|
private suspend fun resolveUncached(path: String): ResolvedTrack {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
511
|
+
// Match an explicit route (or the '*' default). With no match, fall back to
|
|
512
|
+
// the implicit default: fetch the path via the request + browse config.
|
|
513
|
+
val match = config.routes?.let { findBestRouteMatch(path, it) }
|
|
514
|
+
|
|
515
|
+
val resolvedTrack: ResolvedTrack
|
|
516
|
+
val effectiveArtworkConfig: ArtworkRequestConfig?
|
|
517
|
+
if (match != null) {
|
|
518
|
+
val (routeEntry, routeParams) = match
|
|
519
|
+
Timber.d("Matched route: ${routeEntry.path} with params: $routeParams")
|
|
520
|
+
resolvedTrack = resolveRouteEntry(routeEntry, path, routeParams)
|
|
521
|
+
effectiveArtworkConfig = routeEntry.artwork ?: config.artwork
|
|
522
|
+
} else {
|
|
523
|
+
Timber.d("No route matched for path: $path — using implicit default")
|
|
524
|
+
resolvedTrack = executeApiRequest(null, path, mapOf("path" to path))
|
|
525
|
+
effectiveArtworkConfig = config.artwork
|
|
401
526
|
}
|
|
402
527
|
|
|
403
|
-
// Find best matching route
|
|
404
|
-
val (routeEntry, routeParams) =
|
|
405
|
-
findBestRouteMatch(path, routes)
|
|
406
|
-
?: run {
|
|
407
|
-
Timber.e("No route matched for path: $path")
|
|
408
|
-
throw ContentNotFoundException(path)
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
Timber.d("Matched route: ${routeEntry.path} with params: $routeParams")
|
|
412
|
-
|
|
413
|
-
// Resolve the track from the route
|
|
414
|
-
val resolvedTrack = resolveRouteEntry(routeEntry, path, routeParams)
|
|
415
|
-
|
|
416
|
-
// Get effective artwork config: per-route overrides global
|
|
417
|
-
val effectiveArtworkConfig = routeEntry.artwork ?: config.artwork
|
|
418
|
-
|
|
419
528
|
// Transform children: generate contextual URLs and transform artwork URLs
|
|
420
529
|
val transformedChildren =
|
|
421
530
|
resolvedTrack.children?.let { children ->
|
|
@@ -423,8 +532,11 @@ class BrowserManager {
|
|
|
423
532
|
children
|
|
424
533
|
.mapIndexed { index, track ->
|
|
425
534
|
async {
|
|
426
|
-
// Validate that track has stable identifier
|
|
427
|
-
|
|
535
|
+
// Validate that track has stable identifier. A track carrying an
|
|
536
|
+
// imageRow is exempt: a url-less row is a pure preview — never
|
|
537
|
+
// selected, navigated to, or cached (its items carry their own
|
|
538
|
+
// identity; on Android Auto it expands into them).
|
|
539
|
+
if (track.imageRow.isNullOrEmpty()) validateTrack(track, "Child track")
|
|
428
540
|
|
|
429
541
|
var transformedTrack = track
|
|
430
542
|
|
|
@@ -446,22 +558,35 @@ class BrowserManager {
|
|
|
446
558
|
)
|
|
447
559
|
}
|
|
448
560
|
|
|
449
|
-
//
|
|
450
|
-
//
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
val browseContext = ImageContext(null, null)
|
|
561
|
+
// Playable image-row items get contextual URLs like any list
|
|
562
|
+
// row, so a tile tap expands into its section's queue instead
|
|
563
|
+
// of a queue of one (ADR 0006).
|
|
564
|
+
transformedTrack.imageRow?.let { items ->
|
|
454
565
|
transformedTrack =
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
566
|
+
transformedTrack.copy(
|
|
567
|
+
imageRow =
|
|
568
|
+
items
|
|
569
|
+
.map { item ->
|
|
570
|
+
if (item.url == null && item.src != null) {
|
|
571
|
+
item.copy(url = BrowserPathHelper.build(path, item.src))
|
|
572
|
+
} else {
|
|
573
|
+
item
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
.toTypedArray()
|
|
462
577
|
)
|
|
463
578
|
}
|
|
464
579
|
|
|
580
|
+
// Transform artwork URL. At browse-time there is no display size info.
|
|
581
|
+
transformedTrack =
|
|
582
|
+
transformArtworkUrl(
|
|
583
|
+
transformedTrack,
|
|
584
|
+
effectiveArtworkConfig,
|
|
585
|
+
path,
|
|
586
|
+
index,
|
|
587
|
+
ImageContext(null, null),
|
|
588
|
+
)
|
|
589
|
+
|
|
465
590
|
transformedTrack
|
|
466
591
|
}
|
|
467
592
|
}
|
|
@@ -478,7 +603,7 @@ class BrowserManager {
|
|
|
478
603
|
}
|
|
479
604
|
|
|
480
605
|
/**
|
|
481
|
-
* Transforms a track's artwork
|
|
606
|
+
* Transforms a track's artwork via [resolveArtworkUrl]. Populates artworkSource with the
|
|
482
607
|
* transformed ImageSource, keeping artwork unchanged. Handles all edge cases: undefined returns,
|
|
483
608
|
* errors, missing artwork.
|
|
484
609
|
*
|
|
@@ -487,7 +612,6 @@ class BrowserManager {
|
|
|
487
612
|
private suspend fun transformArtworkUrl(
|
|
488
613
|
track: Track,
|
|
489
614
|
artworkConfig: ArtworkRequestConfig?,
|
|
490
|
-
resolver: suspend (Track, ArtworkRequestConfig?, ImageContext?) -> ImageSource?,
|
|
491
615
|
path: String,
|
|
492
616
|
index: Int,
|
|
493
617
|
imageContext: ImageContext? = null,
|
|
@@ -498,7 +622,7 @@ class BrowserManager {
|
|
|
498
622
|
}
|
|
499
623
|
|
|
500
624
|
return try {
|
|
501
|
-
val imageSource =
|
|
625
|
+
val imageSource = resolveArtworkUrl(track, artworkConfig, imageContext)
|
|
502
626
|
|
|
503
627
|
when {
|
|
504
628
|
// resolve returned null → no artwork source
|
|
@@ -511,6 +635,15 @@ class BrowserManager {
|
|
|
511
635
|
// resolve returned ImageSource → set artworkSource
|
|
512
636
|
else -> {
|
|
513
637
|
Timber.d("[$path] Child[$index] '${track.title}': artworkSource set: ${imageSource.uri}")
|
|
638
|
+
// Remember how this URI was produced so display-time loading (which only
|
|
639
|
+
// gets a URI from Media3) can re-resolve Track-first with a size hint.
|
|
640
|
+
// Register the per-route config only when it isn't the global fallback,
|
|
641
|
+
// so display-time resolution reads the *current* config.artwork.
|
|
642
|
+
artworkResolutions.register(
|
|
643
|
+
imageSource.uri,
|
|
644
|
+
track,
|
|
645
|
+
artworkConfig?.takeIf { it !== config.artwork },
|
|
646
|
+
)
|
|
514
647
|
track.copy(artworkSource = imageSource)
|
|
515
648
|
}
|
|
516
649
|
}
|
|
@@ -549,8 +682,20 @@ class BrowserManager {
|
|
|
549
682
|
return null
|
|
550
683
|
}
|
|
551
684
|
|
|
685
|
+
// Queue scope is the tapped section, not the whole page (ADR 0006). An
|
|
686
|
+
// id that no longer appears on the page aborts the expansion — the
|
|
687
|
+
// caller falls back to the stored single track; silently queueing the
|
|
688
|
+
// changed list would resume the wrong station.
|
|
689
|
+
val sectionTracks =
|
|
690
|
+
when (val section = SectionScope.section(children.toList(), trackId)) {
|
|
691
|
+
is SectionScope.Section.ImageRow ->
|
|
692
|
+
with(TrackFactory) { section.items.map { it.toTrack(groupTitle = null) } }
|
|
693
|
+
is SectionScope.Section.Run -> section.tracks
|
|
694
|
+
null -> return null
|
|
695
|
+
}
|
|
696
|
+
|
|
552
697
|
// Filter to only playable tracks (tracks with src)
|
|
553
|
-
val playableTracks =
|
|
698
|
+
val playableTracks = sectionTracks.filter { track -> track.src != null }
|
|
554
699
|
|
|
555
700
|
if (playableTracks.isEmpty()) {
|
|
556
701
|
Timber.w("Parent has no playable tracks, cannot expand queue")
|
|
@@ -642,8 +787,9 @@ class BrowserManager {
|
|
|
642
787
|
* @return Array of Track results, or null if not found
|
|
643
788
|
*/
|
|
644
789
|
fun getCachedSearchResults(query: String): Array<Track>? {
|
|
645
|
-
|
|
646
|
-
|
|
790
|
+
val (cachedQuery, cachedResults) = lastSearch ?: return null
|
|
791
|
+
if (query != cachedQuery) return null
|
|
792
|
+
return cachedResults.map { hydrateFavorite(it) }.toTypedArray()
|
|
647
793
|
}
|
|
648
794
|
|
|
649
795
|
/**
|
|
@@ -662,6 +808,7 @@ class BrowserManager {
|
|
|
662
808
|
album = null,
|
|
663
809
|
title = null,
|
|
664
810
|
playlist = null,
|
|
811
|
+
reference = MediaReference.UNKNOWN,
|
|
665
812
|
)
|
|
666
813
|
)
|
|
667
814
|
}
|
|
@@ -686,10 +833,11 @@ class BrowserManager {
|
|
|
686
833
|
|
|
687
834
|
// Check if result is browsable-only (container/route) vs playable
|
|
688
835
|
// If it's browsable but also playable (has src or playable=true), treat it as playable
|
|
836
|
+
val firstResultUrl = firstResult.url
|
|
689
837
|
val tracksToFilter =
|
|
690
|
-
if (firstResult.src == null) {
|
|
691
|
-
Timber.d("First search result is browsable-only, resolving: $
|
|
692
|
-
val resolvedTrack = resolve(
|
|
838
|
+
if (firstResult.src == null && firstResultUrl != null) {
|
|
839
|
+
Timber.d("First search result is browsable-only, resolving: $firstResultUrl")
|
|
840
|
+
val resolvedTrack = resolve(firstResultUrl)
|
|
693
841
|
resolvedTrack.children
|
|
694
842
|
?.filter { it.src != null }
|
|
695
843
|
?.takeIf { it.isNotEmpty() }
|
|
@@ -717,6 +865,7 @@ class BrowserManager {
|
|
|
717
865
|
album = null,
|
|
718
866
|
title = null,
|
|
719
867
|
playlist = null,
|
|
868
|
+
reference = MediaReference.UNKNOWN,
|
|
720
869
|
)
|
|
721
870
|
)
|
|
722
871
|
}
|
|
@@ -735,20 +884,34 @@ class BrowserManager {
|
|
|
735
884
|
val searchPath = BrowserPathHelper.createSearchPath(params.query)
|
|
736
885
|
|
|
737
886
|
try {
|
|
738
|
-
// Execute search
|
|
739
|
-
|
|
887
|
+
// Execute search. Drop results without a stable identifier (url or src): search results come
|
|
888
|
+
// from server/JS data that doesn't pass through validateTrack like browse children do, and
|
|
889
|
+
// downstream conversion (TrackFactory.toMedia3) and browsable-result resolution require one.
|
|
890
|
+
val searchResults =
|
|
891
|
+
resolveSearch(params)
|
|
892
|
+
.filter { track ->
|
|
893
|
+
val valid = track.url != null || track.src != null
|
|
894
|
+
if (!valid) {
|
|
895
|
+
Timber.w("Dropping search result without url or src: '${track.title}'")
|
|
896
|
+
}
|
|
897
|
+
valid
|
|
898
|
+
}
|
|
899
|
+
.toTypedArray()
|
|
740
900
|
|
|
741
901
|
// Create ResolvedTrack
|
|
742
902
|
val searchResolvedTrack =
|
|
743
903
|
ResolvedTrack(
|
|
904
|
+
id = null,
|
|
744
905
|
url = searchPath,
|
|
745
906
|
title = "Search: ${params.query}",
|
|
746
907
|
children = searchResults,
|
|
747
908
|
carPlaySiriListButton = null,
|
|
748
909
|
artwork = null,
|
|
749
910
|
artworkSource = null,
|
|
911
|
+
request = null,
|
|
750
912
|
artworkCarPlayTinted = null,
|
|
751
913
|
artist = null,
|
|
914
|
+
albumUrl = null,
|
|
752
915
|
description = null,
|
|
753
916
|
subtitle = null,
|
|
754
917
|
album = null,
|
|
@@ -764,8 +927,7 @@ class BrowserManager {
|
|
|
764
927
|
)
|
|
765
928
|
|
|
766
929
|
// Cache search results for getCachedSearchResults()
|
|
767
|
-
|
|
768
|
-
lastSearchResults = searchResults
|
|
930
|
+
lastSearch = params.query to searchResults
|
|
769
931
|
|
|
770
932
|
// Cache individual tracks for Media3 lookups
|
|
771
933
|
cacheChildren(searchResolvedTrack)
|
|
@@ -780,14 +942,17 @@ class BrowserManager {
|
|
|
780
942
|
// Return empty search result on error
|
|
781
943
|
val emptySearchResult =
|
|
782
944
|
ResolvedTrack(
|
|
945
|
+
id = null,
|
|
783
946
|
url = searchPath,
|
|
784
947
|
title = "Search: ${params.query}",
|
|
785
948
|
children = emptyArray(),
|
|
786
949
|
carPlaySiriListButton = null,
|
|
787
950
|
artwork = null,
|
|
788
951
|
artworkSource = null,
|
|
952
|
+
request = null,
|
|
789
953
|
artworkCarPlayTinted = null,
|
|
790
954
|
artist = null,
|
|
955
|
+
albumUrl = null,
|
|
791
956
|
description = null,
|
|
792
957
|
subtitle = null,
|
|
793
958
|
album = null,
|
|
@@ -848,6 +1013,15 @@ class BrowserManager {
|
|
|
848
1013
|
onTabsChanged = callback
|
|
849
1014
|
}
|
|
850
1015
|
|
|
1016
|
+
/**
|
|
1017
|
+
* Set callback invoked whenever both [artworkResolutions] and the browse-artwork registry are
|
|
1018
|
+
* cleared (config swap or content invalidation). The caller should clear any parallel
|
|
1019
|
+
* [com.audiobrowser.browser.BrowseArtworkRegistry] instance it owns.
|
|
1020
|
+
*/
|
|
1021
|
+
fun setOnArtworkRegistriesCleared(callback: () -> Unit) {
|
|
1022
|
+
onArtworkRegistriesCleared = callback
|
|
1023
|
+
}
|
|
1024
|
+
|
|
851
1025
|
/**
|
|
852
1026
|
* Query navigation tabs from the configured tabs source. This is an async operation that resolves
|
|
853
1027
|
* the tabs configuration.
|
|
@@ -925,15 +1099,25 @@ class BrowserManager {
|
|
|
925
1099
|
entry.browseCallback?.let { callback ->
|
|
926
1100
|
Timber.d("Resolving route via callback")
|
|
927
1101
|
val param = BrowserSourceCallbackParam(path, routeParams)
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1102
|
+
// BrowserSourceCallback may return a BrowseResult synchronously or via a
|
|
1103
|
+
// Promise. Nitro flattens (ResolvedTrack | BrowseError) | Promise<BrowseResult>
|
|
1104
|
+
// into a 3-arm variant: sync track, sync error, or a Promise resolving to a
|
|
1105
|
+
// BrowseResult (which is itself a ResolvedTrack | BrowseError variant).
|
|
1106
|
+
return callback
|
|
1107
|
+
.invoke(param)
|
|
1108
|
+
.await()
|
|
1109
|
+
.match(
|
|
1110
|
+
first = { resolvedTrack -> resolvedTrack },
|
|
1111
|
+
second = { browseError -> throw CallbackException(browseError.error) },
|
|
1112
|
+
third = { promise ->
|
|
1113
|
+
promise
|
|
1114
|
+
.await()
|
|
1115
|
+
.match(
|
|
1116
|
+
first = { resolvedTrack -> resolvedTrack },
|
|
1117
|
+
second = { browseError -> throw CallbackException(browseError.error) },
|
|
1118
|
+
)
|
|
1119
|
+
},
|
|
1120
|
+
)
|
|
937
1121
|
}
|
|
938
1122
|
|
|
939
1123
|
entry.browseConfig?.let { apiConfig ->
|
|
@@ -999,34 +1183,119 @@ class BrowserManager {
|
|
|
999
1183
|
}
|
|
1000
1184
|
|
|
1001
1185
|
/**
|
|
1002
|
-
*
|
|
1003
|
-
*
|
|
1186
|
+
* Resolves a single request/browse layer. When a resolver thunk is present it is invoked and its
|
|
1187
|
+
* result awaited. The resolver is Promise-only (the TS layer normalizes a sync-or-async thunk via
|
|
1188
|
+
* Promise.resolve), so its native shape is `Promise<Promise<TransformableRequestConfig>>` — a
|
|
1189
|
+
* double await. When there is no resolver the static layer config is returned as-is.
|
|
1190
|
+
*/
|
|
1191
|
+
private suspend fun resolveLayer(
|
|
1192
|
+
staticConfig: TransformableRequestConfig?,
|
|
1193
|
+
resolver: Func_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____?,
|
|
1194
|
+
): TransformableRequestConfig? {
|
|
1195
|
+
if (resolver == null) return staticConfig
|
|
1196
|
+
// Promise-only resolver (the TS layer wraps a sync-or-async thunk in
|
|
1197
|
+
// Promise.resolve) → double await: the bridge promise, then the JS promise.
|
|
1198
|
+
return resolver.invoke().await().await()
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
/**
|
|
1202
|
+
* Ensures the request/browse resolver layers are resolved for the current [layerGeneration],
|
|
1203
|
+
* caching the result. Re-resolves when the generation changes (config set or content
|
|
1204
|
+
* invalidation). Uses a simple generation guard with no in-flight cache: a benign idempotent
|
|
1205
|
+
* double-resolve under concurrent first-requests is acceptable, and on a thrown resolver nothing
|
|
1206
|
+
* is cached so the next request retries naturally.
|
|
1207
|
+
*/
|
|
1208
|
+
internal suspend fun ensureLayersResolved() {
|
|
1209
|
+
if (resolvedLayerGeneration == layerGeneration) return
|
|
1210
|
+
val generation = layerGeneration
|
|
1211
|
+
val req = resolveLayer(config.request, config.requestResolver)
|
|
1212
|
+
val brw = resolveLayer(config.browse, config.browseResolver)
|
|
1213
|
+
// A newer generation started while we were awaiting — drop this stale result.
|
|
1214
|
+
if (generation != layerGeneration) return
|
|
1215
|
+
resolvedRequestLayer = req
|
|
1216
|
+
resolvedBrowseLayer = brw
|
|
1217
|
+
resolvedLayerGeneration = generation
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* Ensures the request layer is resolved for the current generation and returns it (the resolver
|
|
1222
|
+
* result when a [BrowserConfig.requestResolver] is configured, else the static
|
|
1223
|
+
* [BrowserConfig.request]).
|
|
1224
|
+
*
|
|
1225
|
+
* Consumers outside the browse path (media URL building, artwork) must obtain the request layer
|
|
1226
|
+
* through this accessor rather than reading the static `config.request`, so a resolver-only
|
|
1227
|
+
* consumer still gets a baseUrl/headers/transform for media, artwork, and now-playing artwork.
|
|
1228
|
+
*/
|
|
1229
|
+
internal suspend fun resolvedRequestConfig(): TransformableRequestConfig? {
|
|
1230
|
+
ensureLayersResolved()
|
|
1231
|
+
return resolvedRequestLayer
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
/**
|
|
1235
|
+
* Builds the HTTP request for an API-backed path by layering request (shared) → kind
|
|
1236
|
+
* (browse/search) → route configs. Each layer's transform receives the previous layer's output; a
|
|
1237
|
+
* layer with no transform merges its static fields.
|
|
1238
|
+
*
|
|
1239
|
+
* `initialQuery` seeds query params onto the BASE the kind layer receives (e.g. search q/mode/…):
|
|
1240
|
+
* a layer with a transform "wins completely" and is handed only the base, so params placed on a
|
|
1241
|
+
* layer's own static query would be dropped before the transform runs. The same goes for `path`:
|
|
1242
|
+
* it is carried from the base through every layer (only a transform may change it), so a kind
|
|
1243
|
+
* whose config supplies the path (search) must seed it via the `path` parameter. Mirrors iOS
|
|
1244
|
+
* `buildApiRequest`.
|
|
1245
|
+
*
|
|
1246
|
+
* @throws ContentNotFoundException when no layer supplies a baseUrl — there is nothing to fetch,
|
|
1247
|
+
* so the path is genuinely "not found" rather than a network error (mirrors iOS's `guard let
|
|
1248
|
+
* baseUrl`).
|
|
1249
|
+
*/
|
|
1250
|
+
internal suspend fun buildApiRequest(
|
|
1251
|
+
kindConfig: TransformableRequestConfig?,
|
|
1252
|
+
routeConfig: TransformableRequestConfig?,
|
|
1253
|
+
path: String?,
|
|
1254
|
+
params: Map<String, String>,
|
|
1255
|
+
initialQuery: Map<String, String>? = null,
|
|
1256
|
+
): HttpClient.HttpRequest {
|
|
1257
|
+
// Resolve the request/browse resolver thunks once per content generation (cached).
|
|
1258
|
+
ensureLayersResolved()
|
|
1259
|
+
|
|
1260
|
+
var merged =
|
|
1261
|
+
RequestConfig(
|
|
1262
|
+
method = null,
|
|
1263
|
+
path = path,
|
|
1264
|
+
baseUrl = null,
|
|
1265
|
+
headers = null,
|
|
1266
|
+
query = null,
|
|
1267
|
+
body = null,
|
|
1268
|
+
contentType = null,
|
|
1269
|
+
userAgent = null,
|
|
1270
|
+
)
|
|
1271
|
+
resolvedRequestLayer?.let { merged = RequestConfigBuilder.mergeConfig(merged, it, params) }
|
|
1272
|
+
if (!initialQuery.isNullOrEmpty()) {
|
|
1273
|
+
merged = merged.copy(query = (merged.query ?: emptyMap()) + initialQuery)
|
|
1274
|
+
}
|
|
1275
|
+
kindConfig?.let { merged = RequestConfigBuilder.mergeConfig(merged, it, params) }
|
|
1276
|
+
routeConfig?.let { merged = RequestConfigBuilder.mergeConfig(merged, it, params) }
|
|
1277
|
+
|
|
1278
|
+
if (merged.baseUrl.isNullOrBlank()) {
|
|
1279
|
+
throw ContentNotFoundException(path ?: "")
|
|
1280
|
+
}
|
|
1281
|
+
return RequestConfigBuilder.buildHttpRequest(merged)
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
/**
|
|
1285
|
+
* Execute an API request for browser content. Request building (layering + transforms + baseUrl
|
|
1286
|
+
* guard) lives in [buildApiRequest]; this adds the browse-specific response shape (a
|
|
1287
|
+
* ResolvedTrack page object).
|
|
1004
1288
|
*/
|
|
1005
1289
|
private suspend fun executeApiRequest(
|
|
1006
|
-
apiConfig: TransformableRequestConfig
|
|
1290
|
+
apiConfig: TransformableRequestConfig?,
|
|
1007
1291
|
path: String,
|
|
1008
1292
|
routeParams: Map<String, String>,
|
|
1009
1293
|
): ResolvedTrack {
|
|
1010
1294
|
return withContext(Dispatchers.IO) {
|
|
1011
|
-
//
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
}
|
|
1016
|
-
?: RequestConfig(
|
|
1017
|
-
path = path,
|
|
1018
|
-
method = null,
|
|
1019
|
-
baseUrl = null,
|
|
1020
|
-
headers = null,
|
|
1021
|
-
query = null,
|
|
1022
|
-
body = null,
|
|
1023
|
-
contentType = null,
|
|
1024
|
-
userAgent = null,
|
|
1025
|
-
)
|
|
1026
|
-
val mergedConfig = RequestConfigBuilder.mergeConfig(baseConfig, apiConfig, routeParams)
|
|
1027
|
-
|
|
1028
|
-
// 2. Build and execute HTTP request
|
|
1029
|
-
val httpRequest = RequestConfigBuilder.buildHttpRequest(mergedConfig)
|
|
1295
|
+
// request (shared) → browse (kind) → route. apiConfig is null for the
|
|
1296
|
+
// implicit default (an unmatched browse path → fetch via request + browse + path).
|
|
1297
|
+
ensureLayersResolved()
|
|
1298
|
+
val httpRequest = buildApiRequest(resolvedBrowseLayer, apiConfig, path, routeParams)
|
|
1030
1299
|
val response = httpClient.request(httpRequest)
|
|
1031
1300
|
|
|
1032
1301
|
response.fold(
|
|
@@ -1066,24 +1335,10 @@ class BrowserManager {
|
|
|
1066
1335
|
): Array<Track> {
|
|
1067
1336
|
return withContext(Dispatchers.IO) {
|
|
1068
1337
|
try {
|
|
1069
|
-
// 1. Start with base config
|
|
1070
|
-
val baseConfig =
|
|
1071
|
-
config.request?.let { RequestConfigBuilder.toRequestConfig(it) }
|
|
1072
|
-
?: RequestConfig(
|
|
1073
|
-
method = null,
|
|
1074
|
-
path = null,
|
|
1075
|
-
baseUrl = null,
|
|
1076
|
-
headers = null,
|
|
1077
|
-
query = null,
|
|
1078
|
-
body = null,
|
|
1079
|
-
contentType = null,
|
|
1080
|
-
userAgent = null,
|
|
1081
|
-
)
|
|
1082
|
-
|
|
1083
|
-
// 2. Build query parameters from SearchParams
|
|
1084
1338
|
val searchQueryParams = buildMap {
|
|
1085
1339
|
put("q", params.query)
|
|
1086
1340
|
params.mode?.let { put("mode", it.toString().lowercase()) }
|
|
1341
|
+
if (params.reference == MediaReference.MY) put("reference", "my")
|
|
1087
1342
|
params.genre?.let { put("genre", it) }
|
|
1088
1343
|
params.artist?.let { put("artist", it) }
|
|
1089
1344
|
params.album?.let { put("album", it) }
|
|
@@ -1091,31 +1346,26 @@ class BrowserManager {
|
|
|
1091
1346
|
params.playlist?.let { put("playlist", it) }
|
|
1092
1347
|
}
|
|
1093
1348
|
|
|
1094
|
-
//
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1349
|
+
// request (shared) → search (kind); no browse layer and no route — search
|
|
1350
|
+
// is its own kind. The search params seed the base (see buildApiRequest
|
|
1351
|
+
// docs), and so does the search config's path: a layer's static path
|
|
1352
|
+
// never applies (the path is carried from the base), so the caller
|
|
1353
|
+
// seeds it — mirrors the web stub's fetchSearchResults.
|
|
1354
|
+
val httpRequest =
|
|
1355
|
+
buildApiRequest(
|
|
1356
|
+
kindConfig = apiConfig,
|
|
1357
|
+
routeConfig = null,
|
|
1099
1358
|
path = apiConfig.path,
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
query = (apiConfig.query ?: emptyMap()) + searchQueryParams,
|
|
1103
|
-
body = apiConfig.body,
|
|
1104
|
-
contentType = apiConfig.contentType,
|
|
1105
|
-
userAgent = apiConfig.userAgent,
|
|
1359
|
+
params = emptyMap(),
|
|
1360
|
+
initialQuery = searchQueryParams,
|
|
1106
1361
|
)
|
|
1107
|
-
|
|
1108
|
-
// 3. Merge configs and apply transform if provided
|
|
1109
|
-
var mergedConfig = RequestConfigBuilder.mergeConfig(baseConfig, searchConfig, emptyMap())
|
|
1110
|
-
|
|
1111
|
-
// 4. Build and execute HTTP request
|
|
1112
|
-
val httpRequest = RequestConfigBuilder.buildHttpRequest(mergedConfig)
|
|
1113
1362
|
val response = httpClient.request(httpRequest)
|
|
1114
1363
|
|
|
1115
1364
|
response.fold(
|
|
1116
1365
|
onSuccess = { httpResponse ->
|
|
1117
1366
|
if (httpResponse.isSuccessful) {
|
|
1118
|
-
//
|
|
1367
|
+
// The search endpoint returns a bare Track array (unlike browse,
|
|
1368
|
+
// which returns a page object). iOS parses it the same way.
|
|
1119
1369
|
val jsonTracks = json.decodeFromString<List<JsonTrack>>(httpResponse.body)
|
|
1120
1370
|
jsonTracks.map { it.toNitro() }.toTypedArray()
|
|
1121
1371
|
} else {
|
|
@@ -1156,8 +1406,23 @@ class CallbackException(message: String) : Exception(message)
|
|
|
1156
1406
|
*/
|
|
1157
1407
|
data class BrowserConfig(
|
|
1158
1408
|
val request: TransformableRequestConfig? = null,
|
|
1409
|
+
// Resolver thunk for the shared request layer. When set, it is resolved once per content
|
|
1410
|
+
// generation (re-resolved after invalidateAllContent), cached, and merged per request — instead
|
|
1411
|
+
// of carrying a static `request`. `request` and `requestResolver` are mutually exclusive in
|
|
1412
|
+
// practice (the consumer sets one or the other), but both are merged if present.
|
|
1413
|
+
val requestResolver:
|
|
1414
|
+
Func_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____? =
|
|
1415
|
+
null,
|
|
1416
|
+
val browse: TransformableRequestConfig? = null,
|
|
1417
|
+
// Resolver thunk for the browse layer. See `requestResolver`.
|
|
1418
|
+
val browseResolver:
|
|
1419
|
+
Func_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____? =
|
|
1420
|
+
null,
|
|
1159
1421
|
val media: MediaRequestConfig? = null,
|
|
1160
1422
|
val artwork: ArtworkRequestConfig? = null,
|
|
1423
|
+
// Now-playing-only artwork configuration (lock screen / notification / Android Auto now-playing).
|
|
1424
|
+
// A distinct kind from `artwork`; the now-playing path falls back to `artwork` when this is null.
|
|
1425
|
+
val nowPlayingArtwork: ArtworkRequestConfig? = null,
|
|
1161
1426
|
// Routes as array with flattened entries (includes __tabs__, __search__, and __default__ special
|
|
1162
1427
|
// routes)
|
|
1163
1428
|
val routes: Array<NativeRouteEntry>? = null,
|