react-native-audio-browser 0.2.0-next.3 → 0.2.0-next.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -22
- package/android/build.gradle +35 -12
- package/android/gradle.properties +2 -2
- package/android/src/main/AndroidManifest.xml +3 -1
- package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +541 -278
- package/android/src/main/java/com/audiobrowser/AudioBrowserLifecycleModule.kt +38 -0
- package/android/src/main/java/com/audiobrowser/AudioBrowserPackage.kt +18 -2
- package/android/src/main/java/com/audiobrowser/ServiceBinding.kt +52 -0
- package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +315 -213
- package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +27 -9
- package/android/src/main/java/com/audiobrowser/browser/InertStyleDiagnostic.kt +288 -0
- package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +97 -58
- package/android/src/main/java/com/audiobrowser/browser/SectionScope.kt +70 -29
- package/android/src/main/java/com/audiobrowser/browser/StyleResolver.kt +60 -0
- package/android/src/main/java/com/audiobrowser/extension/ResolvedTrackExt.kt +20 -7
- package/android/src/main/java/com/audiobrowser/extension/TappedTrack.kt +20 -0
- package/android/src/main/java/com/audiobrowser/extension/TrackIdentity.kt +15 -0
- package/android/src/main/java/com/audiobrowser/http/HttpClient.kt +20 -3
- package/android/src/main/java/com/audiobrowser/model/IcyTitle.kt +24 -0
- package/android/src/main/java/com/audiobrowser/model/PlaybackMetadata.kt +10 -6
- package/android/src/main/java/com/audiobrowser/model/PlayerUpdateOptions.kt +12 -12
- package/android/src/main/java/com/audiobrowser/player/CapabilityControls.kt +111 -58
- package/android/src/main/java/com/audiobrowser/player/CrossOriginHeaderStripper.kt +77 -0
- package/android/src/main/java/com/audiobrowser/player/MediaFactory.kt +28 -10
- package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +509 -230
- package/android/src/main/java/com/audiobrowser/player/MediaSessionCommandManager.kt +218 -252
- package/android/src/main/java/com/audiobrowser/player/NowPlayingUpdater.kt +21 -25
- package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +113 -78
- package/android/src/main/java/com/audiobrowser/player/Player.kt +81 -38
- package/android/src/main/java/com/audiobrowser/player/PlayerCapabilitiesExt.kt +2 -15
- package/android/src/main/java/com/audiobrowser/player/PlayerListener.kt +1 -1
- package/android/src/main/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicy.kt +2 -1
- package/android/src/main/java/com/audiobrowser/player/ShuffleOrderLedBy.kt +30 -0
- package/android/src/main/java/com/audiobrowser/tls/AiaCertChaser.kt +67 -11
- package/android/src/main/java/com/audiobrowser/tls/AiaChasingExtendedTrustManager.kt +168 -0
- package/android/src/main/java/com/audiobrowser/tls/AiaChasingTrustManager.kt +58 -14
- package/android/src/main/java/com/audiobrowser/tls/AiaTls.kt +35 -7
- package/android/src/main/java/com/audiobrowser/tls/CachingCertificateFetcher.kt +278 -59
- package/android/src/main/java/com/audiobrowser/util/ArtworkVariant.kt +7 -9
- package/android/src/main/java/com/audiobrowser/util/BrowserPathHelper.kt +62 -40
- package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +28 -23
- package/android/src/main/java/com/audiobrowser/util/StyleWire.kt +110 -0
- package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +56 -52
- package/android/src/main/res/values/strings.xml +25 -5
- package/android/src/test/java/com/audiobrowser/ServiceBindingTest.kt +100 -0
- package/android/src/test/java/com/audiobrowser/TestFixtures.kt +119 -33
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerFavoritesTest.kt +153 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerLayerResolutionTest.kt +15 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +346 -8
- package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +40 -2
- package/android/src/test/java/com/audiobrowser/browser/InertStyleDiagnosticTest.kt +301 -0
- package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +3 -2
- package/android/src/test/java/com/audiobrowser/browser/JsonStyleTest.kt +168 -0
- package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +128 -55
- package/android/src/test/java/com/audiobrowser/browser/StyleResolverTest.kt +160 -0
- package/android/src/test/java/com/audiobrowser/extension/TappedTrackTest.kt +43 -0
- package/android/src/test/java/com/audiobrowser/extension/TrackIdentityTest.kt +41 -0
- package/android/src/test/java/com/audiobrowser/model/IcyTitleTest.kt +49 -0
- package/android/src/test/java/com/audiobrowser/player/BrowseTilesTest.kt +385 -0
- package/android/src/test/java/com/audiobrowser/player/CapabilityControlsTest.kt +101 -58
- package/android/src/test/java/com/audiobrowser/player/CrossOriginHeaderStripperTest.kt +94 -0
- package/android/src/test/java/com/audiobrowser/player/MediaSessionSlotMappingTest.kt +45 -0
- package/android/src/test/java/com/audiobrowser/player/NowPlayingUpdaterTest.kt +42 -2
- package/android/src/test/java/com/audiobrowser/player/PlaybackErrorClassifierTest.kt +3 -4
- package/android/src/test/java/com/audiobrowser/player/PlaybackStateStoreTrackJsonTest.kt +55 -0
- package/android/src/test/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicyTest.kt +3 -3
- package/android/src/test/java/com/audiobrowser/player/ShuffleOrderLedByTest.kt +79 -0
- package/android/src/test/java/com/audiobrowser/tls/AiaCertChaserTest.kt +197 -7
- package/android/src/test/java/com/audiobrowser/tls/AiaChasingTrustManagerTest.kt +325 -4
- package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherCallSiteTest.kt +322 -0
- package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherTest.kt +83 -0
- package/android/src/test/java/com/audiobrowser/util/BrowserPathHelperTest.kt +55 -16
- package/android/src/test/java/com/audiobrowser/util/MediaExtrasBuilderTest.kt +162 -0
- package/android/src/test/java/com/audiobrowser/util/TrackFactoryMediaIdTest.kt +7 -7
- package/ios/AVPlayerEngine.swift +330 -0
- package/ios/AVPlayerEngineCallbacks.swift +15 -0
- package/ios/Browser/BrowseGate.swift +58 -0
- package/ios/Browser/BrowserConfig.swift +117 -78
- package/ios/Browser/BrowserManager.swift +209 -603
- package/ios/Browser/BrowserPathHelper.swift +50 -46
- package/ios/Browser/InertStyleDiagnostic.swift +296 -0
- package/ios/Browser/JsonModels.swift +264 -106
- package/ios/Browser/NavigationErrorState.swift +41 -0
- package/ios/Browser/PageResolver.swift +227 -0
- package/ios/Browser/RequestLayer.swift +90 -0
- package/ios/Browser/{BrowserManager+URLResolution.swift → RequestPipeline.swift} +193 -121
- package/ios/Browser/SearchDrillIn.swift +7 -7
- package/ios/Browser/SectionScope.swift +58 -24
- package/ios/Browser/StyleResolver.swift +58 -0
- package/ios/Browser/TabBarEntries.swift +9 -3
- package/ios/Browser/TrackIdTemplate.swift +37 -0
- package/ios/CarPlay/CPInterfaceController+Safe.swift +100 -43
- package/ios/CarPlay/CarPlayArtworkResolver.swift +36 -83
- package/ios/CarPlay/CarPlayController.swift +42 -1296
- package/ios/CarPlay/CarPlayImageLoader.swift +78 -97
- package/ios/CarPlay/CarPlayListItemFactory.swift +303 -92
- package/ios/CarPlay/CarPlayNowPlayingManager.swift +129 -136
- package/ios/CarPlay/CarPlaySession+Navigator.swift +114 -0
- package/ios/CarPlay/CarPlaySession+PageLoader.swift +92 -0
- package/ios/CarPlay/CarPlaySession+Refresher.swift +43 -0
- package/ios/CarPlay/CarPlaySession+TabBar.swift +193 -0
- package/ios/CarPlay/CarPlaySession.swift +209 -0
- package/ios/CarPlay/CarPlayTemplates.swift +63 -0
- package/ios/CarPlay/HybridAudioBrowser+IntentFavorite.swift +20 -0
- package/ios/{Player → CarPlay}/MediaIntentCriteria.swift +17 -9
- package/ios/CarPlay/MediaIntentPlayback.swift +74 -0
- package/ios/CarPlay/RNABMediaAddHandler.swift +8 -24
- package/ios/CarPlay/RNABMediaAffinityHandler.swift +7 -23
- package/ios/CarPlay/RNABMediaIntentHandler.swift +18 -19
- package/ios/CarPlay/SectionPresentation.swift +77 -0
- package/ios/CarPlay/TopTemplateReplacer.swift +96 -0
- package/ios/Extension/Capability+RemoteCommand.swift +1 -1
- package/ios/Extension/NavigationError+Conversion.swift +14 -4
- package/ios/Extension/PlayerCapabilities+Favorite.swift +1 -15
- package/ios/Extension/ResolvedTrack+Copying.swift +13 -15
- package/ios/Extension/Section+Copying.swift +29 -0
- package/ios/Extension/String+IcyCharset.swift +21 -0
- package/ios/Extension/TimedMetadata+AVFoundation.swift +6 -4
- package/ios/Extension/Track+Copying.swift +8 -12
- package/ios/Extension/Track+Identity.swift +18 -0
- package/ios/Extension/UIApplication+ActiveScene.swift +27 -0
- package/ios/Extension/UIImage+Adaptive.swift +12 -0
- package/ios/Extension/URLError+Connectivity.swift +15 -0
- package/ios/Http/HttpClient.swift +66 -142
- package/ios/HybridAudioBrowser+Browser.swift +153 -0
- package/ios/HybridAudioBrowser+Options.swift +144 -0
- package/ios/HybridAudioBrowser+Player.swift +397 -0
- package/ios/HybridAudioBrowser+PlayerCallbacks.swift +189 -0
- package/ios/HybridAudioBrowser+Stubs.swift +46 -0
- package/ios/HybridAudioBrowser.swift +153 -1610
- package/ios/Model/NitroTypeStubs.swift +146 -24
- package/ios/Model/PlayerUpdateOptions.swift +8 -1
- package/ios/Model/RemoteCommand.swift +18 -0
- package/ios/Model/TrackPlayerError.swift +2 -2
- package/ios/NowPlayingInfo/NowPlayingInfoController.swift +18 -53
- package/ios/Observer/ItemObserver.swift +90 -0
- package/ios/Observer/PlayerObserver.swift +59 -0
- package/ios/Option/SessionCategories.swift +42 -92
- package/ios/Player/AudioSessionController.swift +189 -0
- package/ios/Player/DeferredSeek.swift +70 -0
- package/ios/Player/ErrorStatus.swift +27 -0
- package/ios/Player/MediaLoader.swift +62 -35
- package/ios/Player/NowPlayingUpdater.swift +197 -50
- package/ios/Player/PlaybackFailure.swift +125 -0
- package/ios/Player/PlaybackPersistence.swift +73 -0
- package/ios/Player/PlaybackTimer.swift +8 -2
- package/ios/Player/Player.swift +1078 -0
- package/ios/Player/{PlaybackCoordinatorCallbacks.swift → PlayerCallbacks.swift} +3 -4
- package/ios/Player/PlayerEngine.swift +87 -0
- package/ios/Player/PlayerStatusTypes.swift +2 -6
- package/ios/Player/QueueManager.swift +93 -67
- package/ios/Player/RetryLoop.swift +261 -0
- package/ios/Player/ShuffleOrder.swift +33 -0
- package/ios/Player/SleepTimerManager.swift +1 -1
- package/ios/RemoteCommand/RemoteCommandCallbacks.swift +46 -0
- package/ios/RemoteCommand/RemoteCommandController.swift +87 -331
- package/ios/Tests/BrowserPathHelperTests.swift +56 -15
- package/ios/Tests/CarPlayArtworkResolverTests.swift +60 -373
- package/ios/Tests/DeferredSeekTests.swift +70 -0
- package/ios/Tests/EmitterTests.swift +29 -0
- package/ios/Tests/GenerationMemoTests.swift +121 -0
- package/ios/Tests/InertStyleDiagnosticTests.swift +209 -0
- package/ios/Tests/JsonModelsTests.swift +164 -1
- package/ios/Tests/LRUCacheTests.swift +110 -0
- package/ios/Tests/MediaIntentCriteriaTests.swift +2 -2
- package/ios/Tests/MediaLoaderTests.swift +12 -48
- package/ios/Tests/ObserverTests.swift +88 -0
- package/ios/Tests/PlaybackErrorTests.swift +76 -0
- package/ios/Tests/PlaybackFailureTests.swift +189 -0
- package/ios/Tests/PlaybackPersistenceTests.swift +93 -0
- package/ios/Tests/PlayerPolicyTests.swift +420 -0
- package/ios/Tests/{PlaybackCoordinatorTests.swift → PlayerTests.swift} +300 -248
- package/ios/Tests/PlayingStateTests.swift +42 -0
- package/ios/Tests/QueueManagerTests.swift +196 -115
- package/ios/Tests/ReadyValueTests.swift +73 -0
- package/ios/Tests/RemoteCommandControllerTests.swift +152 -0
- package/ios/Tests/RemoteCommandTests.swift +65 -0
- package/ios/Tests/RequestLayerTests.swift +112 -0
- package/ios/Tests/ResolvedTrackCopyingTests.swift +39 -35
- package/ios/Tests/RetryLoopTests.swift +270 -0
- package/ios/Tests/SearchDrillInTests.swift +16 -16
- package/ios/Tests/SectionPresentationTests.swift +98 -0
- package/ios/Tests/SectionScopeTests.swift +87 -55
- package/ios/Tests/StyleResolverTests.swift +132 -0
- package/ios/Tests/Support/TestTypes.swift +108 -104
- package/ios/Tests/TabBarEntriesTests.swift +19 -19
- package/ios/Tests/TimedMetadataAVFoundationTests.swift +42 -0
- package/ios/Tests/TopTemplateReplacerTests.swift +172 -0
- package/ios/Tests/TrackIdTemplateTests.swift +67 -0
- package/ios/Tests/TrackIdentityTests.swift +20 -0
- package/ios/Tests/TrackSelectorTests.swift +168 -33
- package/ios/Tests/URLErrorConnectivityTests.swift +20 -0
- package/ios/TrackSelector.swift +46 -31
- package/ios/Util/ArtworkImageFetcher.swift +58 -1
- package/ios/Util/Emitter.swift +42 -0
- package/ios/Util/GenerationMemo.swift +36 -0
- package/ios/Util/LRUCache.swift +23 -159
- package/ios/Util/NetworkMonitor.swift +43 -26
- package/ios/Util/ReadyValue.swift +56 -0
- package/ios/Util/SFSymbolRenderer.swift +59 -31
- package/ios/Util/SVGProcessor.swift +9 -12
- package/lib/commonjs/AudioBrowser.js +8 -8
- package/lib/commonjs/AudioBrowser.js.map +1 -1
- package/lib/commonjs/CLAUDE.md +52 -0
- package/lib/commonjs/features/browser-config.js +12 -8
- package/lib/commonjs/features/browser-config.js.map +1 -1
- package/lib/commonjs/features/browser.js +11 -3
- package/lib/commonjs/features/browser.js.map +1 -1
- package/lib/commonjs/features/carConnection.js +1 -1
- package/lib/commonjs/features/equalizer.js +1 -1
- package/lib/commonjs/features/errors.js +3 -3
- package/lib/commonjs/features/favorites.js +14 -11
- package/lib/commonjs/features/favorites.js.map +1 -1
- package/lib/commonjs/features/gate.js +16 -1
- package/lib/commonjs/features/gate.js.map +1 -1
- package/lib/commonjs/features/metadata.js +20 -3
- package/lib/commonjs/features/metadata.js.map +1 -1
- package/lib/commonjs/features/network.js +1 -1
- package/lib/commonjs/features/nowPlaying.js +1 -1
- package/lib/commonjs/features/output.js +1 -1
- package/lib/commonjs/features/playback/controls.js +4 -2
- package/lib/commonjs/features/playback/controls.js.map +1 -1
- package/lib/commonjs/features/playback/playWhenReady.js +1 -1
- package/lib/commonjs/features/playback/playing.js +1 -1
- package/lib/commonjs/features/playback/progress.js +3 -2
- package/lib/commonjs/features/playback/progress.js.map +1 -1
- package/lib/commonjs/features/playback/rate.js +8 -1
- package/lib/commonjs/features/playback/rate.js.map +1 -1
- package/lib/commonjs/features/playback/state.js +3 -4
- package/lib/commonjs/features/playback/state.js.map +1 -1
- package/lib/commonjs/features/playback/trackPlaybackTime.js +0 -6
- package/lib/commonjs/features/playback/trackPlaybackTime.js.map +1 -1
- package/lib/commonjs/features/playback/volume.js +1 -1
- package/lib/commonjs/features/player/options.js +48 -34
- package/lib/commonjs/features/player/options.js.map +1 -1
- package/lib/commonjs/features/player/setup.js +18 -9
- package/lib/commonjs/features/player/setup.js.map +1 -1
- package/lib/commonjs/features/player/validateOptions.js +23 -0
- package/lib/commonjs/features/player/validateOptions.js.map +1 -0
- package/lib/commonjs/features/queue/activeTrack.js +15 -4
- package/lib/commonjs/features/queue/activeTrack.js.map +1 -1
- package/lib/commonjs/features/queue/queue.js +13 -6
- package/lib/commonjs/features/queue/queue.js.map +1 -1
- package/lib/commonjs/features/queue/repeatMode.js +1 -1
- package/lib/commonjs/features/queue/shuffle.js +1 -1
- package/lib/commonjs/features/remoteControls.js +13 -92
- package/lib/commonjs/features/remoteControls.js.map +1 -1
- package/lib/commonjs/features/sleepTimer.js +13 -1
- package/lib/commonjs/features/sleepTimer.js.map +1 -1
- package/lib/commonjs/test-utils/reactNativeStub.js +65 -0
- package/lib/commonjs/test-utils/reactNativeStub.js.map +1 -0
- package/lib/commonjs/utils/LazyNativeEmitter.js +28 -14
- package/lib/commonjs/utils/LazyNativeEmitter.js.map +1 -1
- package/lib/commonjs/utils/NativeUpdatedValue.js +31 -13
- package/lib/commonjs/utils/NativeUpdatedValue.js.map +1 -1
- package/lib/commonjs/utils/getTrackIdentity.js +24 -0
- package/lib/commonjs/utils/getTrackIdentity.js.map +1 -0
- package/lib/commonjs/utils/useNativeValueRefreshedBy.js +33 -0
- package/lib/commonjs/utils/useNativeValueRefreshedBy.js.map +1 -0
- package/lib/commonjs/web/NativeAudioBrowser.js +201 -76
- package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/LoadAttempt.js +37 -0
- package/lib/commonjs/web/TrackPlayer/LoadAttempt.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js +18 -2
- package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/Player.js +254 -39
- package/lib/commonjs/web/TrackPlayer/Player.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/PlayingStateFactory.js +1 -1
- package/lib/commonjs/web/TrackPlayer/QueueManager.js +14 -0
- package/lib/commonjs/web/TrackPlayer/QueueManager.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/QueuePlayer.js +33 -12
- package/lib/commonjs/web/TrackPlayer/QueuePlayer.js.map +1 -1
- package/lib/commonjs/web/browser/BrowserManager.js +175 -100
- package/lib/commonjs/web/browser/BrowserManager.js.map +1 -1
- package/lib/commonjs/web/browser/FavoriteManager.js +30 -21
- package/lib/commonjs/web/browser/FavoriteManager.js.map +1 -1
- package/lib/commonjs/web/browser/NavigationErrorManager.js +3 -1
- package/lib/commonjs/web/browser/NavigationErrorManager.js.map +1 -1
- package/lib/commonjs/web/browser/SearchManager.js +18 -23
- package/lib/commonjs/web/browser/SearchManager.js.map +1 -1
- package/lib/commonjs/web/browser/assertBrowsePageShape.js +2 -2
- package/lib/commonjs/web/browser/assertBrowsePageShape.js.map +1 -1
- package/lib/commonjs/web/browser/classifyTrackNavigation.js +9 -9
- package/lib/commonjs/web/browser/classifyTrackNavigation.js.map +1 -1
- package/lib/commonjs/web/browser/sections.js +89 -0
- package/lib/commonjs/web/browser/sections.js.map +1 -0
- package/lib/commonjs/web/http/RequestConfigBuilder.js +110 -27
- package/lib/commonjs/web/http/RequestConfigBuilder.js.map +1 -1
- package/lib/commonjs/web/http/followMediaRedirect.js +219 -0
- package/lib/commonjs/web/http/followMediaRedirect.js.map +1 -0
- package/lib/commonjs/web/player/NowPlayingManager.js +4 -3
- package/lib/commonjs/web/player/NowPlayingManager.js.map +1 -1
- package/lib/commonjs/web/util/BrowserPathHelper.js +62 -11
- package/lib/commonjs/web/util/BrowserPathHelper.js.map +1 -1
- package/lib/module/AudioBrowser.js +2 -1
- package/lib/module/AudioBrowser.js.map +1 -1
- package/lib/module/CLAUDE.md +52 -0
- package/lib/module/features/browser-config.js +12 -8
- package/lib/module/features/browser-config.js.map +1 -1
- package/lib/module/features/browser.js +11 -3
- package/lib/module/features/browser.js.map +1 -1
- package/lib/module/features/carConnection.js +1 -1
- package/lib/module/features/equalizer.js +1 -1
- package/lib/module/features/errors.js +3 -3
- package/lib/module/features/favorites.js +14 -11
- package/lib/module/features/favorites.js.map +1 -1
- package/lib/module/features/gate.js +16 -1
- package/lib/module/features/gate.js.map +1 -1
- package/lib/module/features/metadata.js +20 -3
- package/lib/module/features/metadata.js.map +1 -1
- package/lib/module/features/network.js +1 -1
- package/lib/module/features/nowPlaying.js +1 -1
- package/lib/module/features/output.js +1 -1
- package/lib/module/features/playback/controls.js +4 -2
- package/lib/module/features/playback/controls.js.map +1 -1
- package/lib/module/features/playback/playWhenReady.js +1 -1
- package/lib/module/features/playback/playing.js +1 -1
- package/lib/module/features/playback/progress.js +3 -2
- package/lib/module/features/playback/progress.js.map +1 -1
- package/lib/module/features/playback/rate.js +8 -1
- package/lib/module/features/playback/rate.js.map +1 -1
- package/lib/module/features/playback/state.js +3 -4
- package/lib/module/features/playback/state.js.map +1 -1
- package/lib/module/features/playback/trackPlaybackTime.js +0 -5
- package/lib/module/features/playback/trackPlaybackTime.js.map +1 -1
- package/lib/module/features/playback/volume.js +1 -1
- package/lib/module/features/player/options.js +47 -32
- package/lib/module/features/player/options.js.map +1 -1
- package/lib/module/features/player/setup.js +17 -8
- package/lib/module/features/player/setup.js.map +1 -1
- package/lib/module/features/player/validateOptions.js +19 -0
- package/lib/module/features/player/validateOptions.js.map +1 -0
- package/lib/module/features/queue/activeTrack.js +15 -4
- package/lib/module/features/queue/activeTrack.js.map +1 -1
- package/lib/module/features/queue/queue.js +13 -6
- package/lib/module/features/queue/queue.js.map +1 -1
- package/lib/module/features/queue/repeatMode.js +1 -1
- package/lib/module/features/queue/shuffle.js +1 -1
- package/lib/module/features/remoteControls.js +13 -92
- package/lib/module/features/remoteControls.js.map +1 -1
- package/lib/module/features/sleepTimer.js +13 -1
- package/lib/module/features/sleepTimer.js.map +1 -1
- package/lib/module/test-utils/reactNativeStub.js +58 -0
- package/lib/module/test-utils/reactNativeStub.js.map +1 -0
- package/lib/module/utils/LazyNativeEmitter.js +28 -14
- package/lib/module/utils/LazyNativeEmitter.js.map +1 -1
- package/lib/module/utils/NativeUpdatedValue.js +31 -13
- package/lib/module/utils/NativeUpdatedValue.js.map +1 -1
- package/lib/module/utils/getTrackIdentity.js +20 -0
- package/lib/module/utils/getTrackIdentity.js.map +1 -0
- package/lib/module/utils/useNativeValueRefreshedBy.js +29 -0
- package/lib/module/utils/useNativeValueRefreshedBy.js.map +1 -0
- package/lib/module/web/NativeAudioBrowser.js +201 -76
- package/lib/module/web/NativeAudioBrowser.js.map +1 -1
- package/lib/module/web/TrackPlayer/LoadAttempt.js +32 -0
- package/lib/module/web/TrackPlayer/LoadAttempt.js.map +1 -0
- package/lib/module/web/TrackPlayer/PlaybackStateMachine.js +18 -2
- package/lib/module/web/TrackPlayer/PlaybackStateMachine.js.map +1 -1
- package/lib/module/web/TrackPlayer/Player.js +254 -39
- package/lib/module/web/TrackPlayer/Player.js.map +1 -1
- package/lib/module/web/TrackPlayer/PlayingStateFactory.js +1 -1
- package/lib/module/web/TrackPlayer/QueueManager.js +14 -0
- package/lib/module/web/TrackPlayer/QueueManager.js.map +1 -1
- package/lib/module/web/TrackPlayer/QueuePlayer.js +33 -12
- package/lib/module/web/TrackPlayer/QueuePlayer.js.map +1 -1
- package/lib/module/web/browser/BrowserManager.js +175 -100
- package/lib/module/web/browser/BrowserManager.js.map +1 -1
- package/lib/module/web/browser/FavoriteManager.js +31 -21
- package/lib/module/web/browser/FavoriteManager.js.map +1 -1
- package/lib/module/web/browser/NavigationErrorManager.js +3 -1
- package/lib/module/web/browser/NavigationErrorManager.js.map +1 -1
- package/lib/module/web/browser/SearchManager.js +18 -23
- package/lib/module/web/browser/SearchManager.js.map +1 -1
- package/lib/module/web/browser/assertBrowsePageShape.js +2 -2
- package/lib/module/web/browser/assertBrowsePageShape.js.map +1 -1
- package/lib/module/web/browser/classifyTrackNavigation.js +9 -9
- package/lib/module/web/browser/classifyTrackNavigation.js.map +1 -1
- package/lib/module/web/browser/sections.js +83 -0
- package/lib/module/web/browser/sections.js.map +1 -0
- package/lib/module/web/http/RequestConfigBuilder.js +110 -27
- package/lib/module/web/http/RequestConfigBuilder.js.map +1 -1
- package/lib/module/web/http/followMediaRedirect.js +215 -0
- package/lib/module/web/http/followMediaRedirect.js.map +1 -0
- package/lib/module/web/player/NowPlayingManager.js +4 -3
- package/lib/module/web/player/NowPlayingManager.js.map +1 -1
- package/lib/module/web/util/BrowserPathHelper.js +62 -11
- package/lib/module/web/util/BrowserPathHelper.js.map +1 -1
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/AudioBrowser.d.ts +1 -1
- package/lib/typescript/src/AudioBrowser.d.ts.map +1 -1
- package/lib/typescript/src/features/browser-config.d.ts.map +1 -1
- package/lib/typescript/src/features/browser.d.ts +10 -2
- package/lib/typescript/src/features/browser.d.ts.map +1 -1
- package/lib/typescript/src/features/carConnection.d.ts +1 -1
- package/lib/typescript/src/features/equalizer.d.ts +1 -1
- package/lib/typescript/src/features/errors.d.ts +3 -3
- package/lib/typescript/src/features/favorites.d.ts +14 -11
- package/lib/typescript/src/features/favorites.d.ts.map +1 -1
- package/lib/typescript/src/features/gate.d.ts +18 -2
- package/lib/typescript/src/features/gate.d.ts.map +1 -1
- package/lib/typescript/src/features/metadata.d.ts +20 -3
- package/lib/typescript/src/features/metadata.d.ts.map +1 -1
- package/lib/typescript/src/features/network.d.ts +1 -1
- package/lib/typescript/src/features/nowPlaying.d.ts +1 -1
- package/lib/typescript/src/features/output.d.ts +1 -1
- package/lib/typescript/src/features/playback/controls.d.ts +4 -2
- package/lib/typescript/src/features/playback/controls.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/playWhenReady.d.ts +1 -1
- package/lib/typescript/src/features/playback/playing.d.ts +1 -1
- package/lib/typescript/src/features/playback/progress.d.ts +1 -1
- package/lib/typescript/src/features/playback/progress.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/rate.d.ts +8 -1
- package/lib/typescript/src/features/playback/rate.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/state.d.ts +3 -4
- package/lib/typescript/src/features/playback/state.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts +1 -1
- package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/volume.d.ts +1 -1
- package/lib/typescript/src/features/player/options.d.ts +108 -56
- package/lib/typescript/src/features/player/options.d.ts.map +1 -1
- package/lib/typescript/src/features/player/setup.d.ts +14 -4
- package/lib/typescript/src/features/player/setup.d.ts.map +1 -1
- package/lib/typescript/src/features/player/validateOptions.d.ts +2 -0
- package/lib/typescript/src/features/player/validateOptions.d.ts.map +1 -0
- package/lib/typescript/src/features/queue/activeTrack.d.ts +9 -2
- package/lib/typescript/src/features/queue/activeTrack.d.ts.map +1 -1
- package/lib/typescript/src/features/queue/queue.d.ts +7 -4
- package/lib/typescript/src/features/queue/queue.d.ts.map +1 -1
- package/lib/typescript/src/features/queue/repeatMode.d.ts +1 -1
- package/lib/typescript/src/features/queue/shuffle.d.ts +1 -1
- package/lib/typescript/src/features/remoteControls.d.ts +23 -22
- package/lib/typescript/src/features/remoteControls.d.ts.map +1 -1
- package/lib/typescript/src/features/sleepTimer.d.ts +1 -1
- package/lib/typescript/src/features/sleepTimer.d.ts.map +1 -1
- package/lib/typescript/src/test-utils/reactNativeStub.d.ts +36 -0
- package/lib/typescript/src/test-utils/reactNativeStub.d.ts.map +1 -0
- package/lib/typescript/src/types/browser-native.d.ts +3 -2
- package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
- package/lib/typescript/src/types/browser-nodes.d.ts +387 -126
- package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
- package/lib/typescript/src/types/browser.d.ts +93 -61
- package/lib/typescript/src/types/browser.d.ts.map +1 -1
- package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +19 -16
- package/lib/typescript/src/utils/LazyNativeEmitter.d.ts.map +1 -1
- package/lib/typescript/src/utils/NativeUpdatedValue.d.ts +24 -19
- package/lib/typescript/src/utils/NativeUpdatedValue.d.ts.map +1 -1
- package/lib/typescript/src/utils/getTrackIdentity.d.ts +18 -0
- package/lib/typescript/src/utils/getTrackIdentity.d.ts.map +1 -0
- package/lib/typescript/src/utils/resolveAssetSource.d.ts +1 -2
- package/lib/typescript/src/utils/resolveAssetSource.d.ts.map +1 -1
- package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts +21 -0
- package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts.map +1 -0
- package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +1 -2
- package/nitrogen/generated/android/AudioBrowserOnLoad.cpp +4 -2
- package/nitrogen/generated/android/c++/JAndroidAudioContentType.hpp +2 -2
- package/nitrogen/generated/android/c++/JAndroidAudioOffloadSettings.hpp +2 -2
- package/nitrogen/generated/android/c++/JAndroidOptions.hpp +12 -12
- package/nitrogen/generated/android/c++/JAndroidPlayerWakeMode.hpp +2 -2
- package/nitrogen/generated/android/c++/JAppKilledPlaybackBehavior.hpp +2 -2
- package/nitrogen/generated/android/c++/JArtworkRendering.hpp +58 -0
- package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +10 -5
- package/nitrogen/generated/android/c++/JArtworkVariants.hpp +2 -2
- package/nitrogen/generated/android/c++/JBatteryOptimizationStatus.hpp +2 -2
- package/nitrogen/generated/android/c++/JBatteryOptimizationStatusChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JBatteryWarningPendingChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JBrowseError.hpp +2 -2
- package/nitrogen/generated/android/c++/JBrowseResult.hpp +19 -7
- package/nitrogen/generated/android/c++/JBrowserSourceCallbackParam.hpp +2 -2
- package/nitrogen/generated/android/c++/JCarPlayNowPlayingButton.hpp +2 -2
- package/nitrogen/generated/android/c++/JCarPlayPlayingIndicatorLocation.hpp +58 -0
- package/nitrogen/generated/android/c++/JCarPlaySiriListButtonPosition.hpp +2 -2
- package/nitrogen/generated/android/c++/JCardImage.hpp +58 -0
- package/nitrogen/generated/android/c++/JChapterMetadata.hpp +2 -2
- package/nitrogen/generated/android/c++/JEqualizerSettings.hpp +10 -10
- package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +10 -5
- package/nitrogen/generated/android/c++/JFormatNavigationErrorParams.hpp +11 -5
- package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +10 -5
- package/nitrogen/generated/android/c++/JFormattedNavigationError.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___RequestConfig_std__optional_std__unordered_map_std__string__std__string__.hpp +9 -9
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +10 -5
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.hpp +4 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +10 -5
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +10 -5
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____RequestConfig_std__optional_std__unordered_map_std__string__std__string__.hpp +9 -9
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +10 -5
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +18 -12
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +10 -4
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__string__.hpp +102 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.hpp +18 -6
- package/nitrogen/generated/android/c++/JFunc_void.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_BatteryOptimizationStatusChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_BatteryWarningPendingChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_EqualizerSettings.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +10 -5
- package/nitrogen/generated/android/c++/JFunc_void_GateEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_NavigationErrorEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_NowPlayingMetadata.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +9 -12
- package/nitrogen/generated/android/c++/JFunc_void_Output.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_Playback.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +10 -5
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackErrorEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackPlayWhenReadyChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackProgressUpdatedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackQueueEndedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_PlayingState.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_RemoteJumpBackwardEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_RemoteJumpForwardEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_RemotePlayIdEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_RemotePlaySearchEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_RemoteSeekEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_RemoteSkipEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_RepeatModeChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_TimedMetadata.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_TrackMetadata.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_double.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_FormattedNavigationError_.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +17 -5
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +2 -2
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_ChapterMetadata_.hpp +16 -16
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +24 -18
- package/nitrogen/generated/android/c++/JGate.hpp +2 -2
- package/nitrogen/generated/android/c++/JGateDecision.hpp +2 -2
- package/nitrogen/generated/android/c++/JGateEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JGateReason.hpp +2 -2
- package/nitrogen/generated/android/c++/JGridTile.hpp +64 -0
- package/nitrogen/generated/android/c++/JHttpMethod.hpp +2 -2
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +77 -53
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.hpp +3 -3
- package/nitrogen/generated/android/c++/JIOSCategory.hpp +2 -2
- package/nitrogen/generated/android/c++/JIOSCategoryMode.hpp +2 -2
- package/nitrogen/generated/android/c++/JIOSCategoryOptions.hpp +2 -2
- package/nitrogen/generated/android/c++/JIOSCategoryPolicy.hpp +2 -2
- package/nitrogen/generated/android/c++/JIOSOptions.hpp +17 -11
- package/nitrogen/generated/android/c++/JImageContext.hpp +2 -2
- package/nitrogen/generated/android/c++/JImageQueryParams.hpp +2 -2
- package/nitrogen/generated/android/c++/JImageShape.hpp +58 -0
- package/nitrogen/generated/android/c++/JImageSource.hpp +2 -2
- package/nitrogen/generated/android/c++/JMediaReference.hpp +2 -2
- package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +10 -5
- package/nitrogen/generated/android/c++/JMediaTransformParams.hpp +2 -2
- package/nitrogen/generated/android/c++/JNativeAndroidSetupOptions.hpp +2 -2
- package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +48 -21
- package/nitrogen/generated/android/c++/JNativeGateRequest.hpp +2 -2
- package/nitrogen/generated/android/c++/JNativeIOSSetupOptions.hpp +10 -10
- package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +16 -4
- package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +17 -14
- package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +9 -12
- package/nitrogen/generated/android/c++/JNavigationError.hpp +2 -2
- package/nitrogen/generated/android/c++/JNavigationErrorEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JNavigationErrorKind.hpp +58 -0
- package/nitrogen/generated/android/c++/JNavigationErrorType.hpp +2 -2
- package/nitrogen/generated/android/c++/JNitroAndroidUpdateOptions.hpp +12 -12
- package/nitrogen/generated/android/c++/JNitroIOSUpdateOptions.hpp +17 -11
- package/nitrogen/generated/android/c++/JNowPlayingMetadata.hpp +2 -2
- package/nitrogen/generated/android/c++/JNowPlayingUpdate.hpp +2 -2
- package/nitrogen/generated/android/c++/JOptions.hpp +9 -12
- package/nitrogen/generated/android/c++/JOutput.hpp +2 -2
- package/nitrogen/generated/android/c++/JOutputType.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlayback.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +10 -5
- package/nitrogen/generated/android/c++/JPlaybackError.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlaybackErrorEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlaybackErrorKind.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlaybackPlayWhenReadyChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlaybackProgressUpdatedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlaybackQueueEndedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlaybackState.hpp +2 -2
- package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +7 -13
- package/nitrogen/generated/android/c++/JPlayingState.hpp +2 -2
- package/nitrogen/generated/android/c++/JProgress.hpp +2 -2
- package/nitrogen/generated/android/c++/{JNotificationButton.hpp → JRemoteButton.hpp} +19 -19
- package/nitrogen/generated/android/c++/JRemoteButtonLayout.hpp +86 -0
- package/nitrogen/generated/android/c++/JRemoteJumpBackwardEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JRemoteJumpForwardEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JRemotePlayIdEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JRemotePlaySearchEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JRemoteSeekEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JRemoteSkipEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JRepeatMode.hpp +2 -2
- package/nitrogen/generated/android/c++/JRepeatModeChangedEvent.hpp +2 -2
- package/nitrogen/generated/android/c++/JRequestConfig.hpp +2 -2
- package/nitrogen/generated/android/c++/JResolvedTrack.hpp +67 -59
- package/nitrogen/generated/android/c++/JRetryConfig.hpp +2 -2
- package/nitrogen/generated/android/c++/JSearchMode.hpp +2 -2
- package/nitrogen/generated/android/c++/JSearchParams.hpp +2 -2
- package/nitrogen/generated/android/c++/JSection.hpp +116 -0
- package/nitrogen/generated/android/c++/JSectionStyle.hpp +96 -0
- package/nitrogen/generated/android/c++/JSleepTimer.hpp +4 -4
- package/nitrogen/generated/android/c++/JSleepTimerEndOfTrack.hpp +2 -2
- package/nitrogen/generated/android/c++/JSleepTimerTime.hpp +2 -2
- package/nitrogen/generated/android/c++/JStallReason.hpp +2 -2
- package/nitrogen/generated/android/c++/JStyleDisplay.hpp +58 -0
- package/nitrogen/generated/android/c++/JTimedMetadata.hpp +2 -2
- package/nitrogen/generated/android/c++/JTrack.hpp +27 -48
- package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +18 -12
- package/nitrogen/generated/android/c++/JTrackMetadata.hpp +2 -2
- package/nitrogen/generated/android/c++/JTrackRequest.hpp +2 -2
- package/nitrogen/generated/android/c++/JTrackStyle.hpp +47 -19
- package/nitrogen/generated/android/c++/JTransformableRequestConfig.hpp +2 -2
- package/nitrogen/generated/android/c++/JVariant_Boolean_AndroidAudioOffloadSettings.hpp +3 -3
- package/nitrogen/generated/android/c++/JVariant_Boolean_RetryConfig.hpp +3 -3
- package/nitrogen/generated/android/c++/JVariant_NullType_Double.hpp +3 -3
- package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.hpp +75 -0
- package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.hpp +20 -8
- package/nitrogen/generated/android/c++/JVariant_String_ArtworkVariants.hpp +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidAudioOffloadSettings.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidOptions.kt +20 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoritesMatchMode.kt → ArtworkRendering.kt} +5 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ArtworkRequestConfig.kt +37 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ArtworkVariants.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryOptimizationStatusChangedEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryWarningPendingChangedEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowseError.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowseResult.kt +16 -7
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowserSourceCallbackParam.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayPlayingIndicatorLocation.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CardImage.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ChapterMetadata.kt +19 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/EqualizerSettings.kt +27 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FavoriteChangedEvent.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormatNavigationErrorParams.kt +25 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormatNowPlayingParams.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormattedNavigationError.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___RequestConfig_std__optional_std__unordered_map_std__string__std__string__.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___Track.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_std__string____Track.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____RequestConfig_std__optional_std__unordered_map_std__string__std__string__.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__string__.kt +78 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_BatteryOptimizationStatusChangedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_BatteryWarningPendingChangedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_EqualizerSettings.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_FavoriteChangedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_GateEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_NavigationErrorEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_NowPlayingMetadata.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_Options.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_Output.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_Playback.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackActiveTrackChangedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackErrorEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackPlayWhenReadyChangedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackProgressUpdatedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackQueueEndedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlayingState.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteJumpBackwardEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteJumpForwardEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemotePlayIdEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemotePlaySearchEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSeekEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSkipEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RepeatModeChangedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_TimedMetadata.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_TrackMetadata.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_bool.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_double.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_FormattedNavigationError_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_ResolvedTrack_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__string.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__vector_ChapterMetadata_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__vector_Track_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Gate.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/GateDecision.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/GateEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/GridTile.kt +25 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HybridAudioBrowserSpec.kt +3 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSOptions.kt +25 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageContext.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageQueryParams.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageShape.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageSource.kt +19 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaRequestConfig.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaTransformParams.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeAndroidSetupOptions.kt +31 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +51 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeGateRequest.kt +17 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeIOSSetupOptions.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeRouteEntry.kt +27 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeSetupPlayerOptions.kt +29 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeUpdateOptions.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationError.kt +19 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorKind.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroAndroidUpdateOptions.kt +20 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroIOSUpdateOptions.kt +25 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingMetadata.kt +29 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingUpdate.kt +17 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Options.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Output.kt +17 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Playback.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackActiveTrackChangedEvent.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackError.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackErrorEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackPlayWhenReadyChangedEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackProgressUpdatedEvent.kt +19 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackQueueEndedEvent.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +37 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayingState.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Progress.kt +17 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{NotificationButton.kt → RemoteButton.kt} +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteButtonLayout.kt +61 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteJumpBackwardEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteJumpForwardEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemotePlayIdEvent.kt +15 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemotePlaySearchEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSeekEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSkipEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RepeatModeChangedEvent.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RequestConfig.kt +27 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +67 -15
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RetryConfig.kt +17 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchParams.kt +27 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Section.kt +66 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SectionStyle.kt +86 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimer.kt +18 -8
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimerEndOfTrack.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimerTime.kt +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StyleDisplay.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TimedMetadata.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +55 -12
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackLoadEvent.kt +17 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackMetadata.kt +43 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackRequest.kt +17 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackStyle.kt +58 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TransformableRequestConfig.kt +31 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_AndroidAudioOffloadSettings.kt +16 -7
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_RetryConfig.kt +16 -7
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_NullType_Double.kt +16 -7
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Variant_NullType_NotificationButtonLayout.kt → Variant_NullType_RemoteButtonLayout.kt} +24 -15
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_ResolvedTrack_BrowseError_Promise_BrowseResult_.kt +18 -8
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_String_ArtworkVariants.kt +16 -7
- package/nitrogen/generated/ios/AudioBrowser+autolinking.rb +2 -0
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.cpp +38 -29
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +779 -665
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +34 -16
- package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +36 -18
- package/nitrogen/generated/ios/swift/AndroidOptions.swift +12 -12
- package/nitrogen/generated/ios/swift/ArtworkRendering.swift +40 -0
- package/nitrogen/generated/ios/swift/BrowseResult.swift +12 -0
- package/nitrogen/generated/ios/swift/CarPlayPlayingIndicatorLocation.swift +40 -0
- package/nitrogen/generated/ios/swift/CardImage.swift +40 -0
- package/nitrogen/generated/ios/swift/FormatNavigationErrorParams.swift +7 -2
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__string__.swift +54 -0
- package/nitrogen/generated/ios/swift/GridTile.swift +48 -0
- package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec_cxx.swift +2 -2
- package/nitrogen/generated/ios/swift/IOSOptions.swift +7 -2
- package/nitrogen/generated/ios/swift/ImageShape.swift +40 -0
- package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +52 -5
- package/nitrogen/generated/ios/swift/NavigationErrorKind.swift +40 -0
- package/nitrogen/generated/ios/swift/NitroAndroidUpdateOptions.swift +12 -12
- package/nitrogen/generated/ios/swift/NitroIOSUpdateOptions.swift +12 -1
- package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +8 -27
- package/nitrogen/generated/ios/swift/{NotificationButton.swift → RemoteButton.swift} +6 -6
- package/nitrogen/generated/ios/swift/RemoteButtonLayout.swift +57 -0
- package/nitrogen/generated/ios/swift/ResolvedTrack.swift +62 -73
- package/nitrogen/generated/ios/swift/Section.swift +82 -0
- package/nitrogen/generated/ios/swift/SectionStyle.swift +133 -0
- package/nitrogen/generated/ios/swift/SleepTimer.swift +13 -0
- package/nitrogen/generated/ios/swift/StyleDisplay.swift +40 -0
- package/nitrogen/generated/ios/swift/Track.swift +28 -63
- package/nitrogen/generated/ios/swift/TrackStyle.swift +86 -22
- package/nitrogen/generated/ios/swift/Variant_Bool_AndroidAudioOffloadSettings.swift +12 -0
- package/nitrogen/generated/ios/swift/Variant_Bool_RetryConfig.swift +12 -0
- package/nitrogen/generated/ios/swift/Variant_NullType_Double.swift +12 -0
- package/nitrogen/generated/ios/swift/Variant_NullType_RemoteButtonLayout.swift +30 -0
- package/nitrogen/generated/ios/swift/Variant_ResolvedTrack_BrowseError_Promise_BrowseResult_.swift +13 -0
- package/nitrogen/generated/ios/swift/Variant_String_ArtworkVariants.swift +12 -0
- package/nitrogen/generated/shared/c++/AndroidOptions.hpp +8 -8
- package/nitrogen/generated/shared/c++/{FavoritesMatchMode.hpp → ArtworkRendering.hpp} +17 -17
- package/nitrogen/generated/shared/c++/CarPlayPlayingIndicatorLocation.hpp +76 -0
- package/nitrogen/generated/shared/c++/CardImage.hpp +76 -0
- package/nitrogen/generated/shared/c++/FormatNavigationErrorParams.hpp +9 -2
- package/nitrogen/generated/shared/c++/GridTile.hpp +84 -0
- package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/IOSOptions.hpp +9 -2
- package/nitrogen/generated/shared/c++/ImageShape.hpp +76 -0
- package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +10 -6
- package/nitrogen/generated/shared/c++/NavigationErrorKind.hpp +76 -0
- package/nitrogen/generated/shared/c++/NitroAndroidUpdateOptions.hpp +8 -8
- package/nitrogen/generated/shared/c++/NitroIOSUpdateOptions.hpp +9 -2
- package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +6 -9
- package/nitrogen/generated/shared/c++/{NotificationButton.hpp → RemoteButton.hpp} +19 -19
- package/nitrogen/generated/shared/c++/RemoteButtonLayout.hpp +94 -0
- package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +33 -37
- package/nitrogen/generated/shared/c++/Section.hpp +102 -0
- package/nitrogen/generated/shared/c++/SectionStyle.hpp +126 -0
- package/nitrogen/generated/shared/c++/StyleDisplay.hpp +76 -0
- package/nitrogen/generated/shared/c++/Track.hpp +18 -30
- package/nitrogen/generated/shared/c++/TrackStyle.hpp +73 -34
- package/package.json +24 -11
- package/src/AudioBrowser.ts +2 -1
- package/src/CLAUDE.md +52 -0
- package/src/features/battery.test.ts +79 -0
- package/src/features/browser-config.test.ts +21 -6
- package/src/features/browser-config.ts +12 -8
- package/src/features/browser.test.ts +1 -1
- package/src/features/browser.ts +11 -3
- package/src/features/carConnection.ts +1 -1
- package/src/features/equalizer.ts +1 -1
- package/src/features/errors.ts +3 -3
- package/src/features/favorites.ts +14 -11
- package/src/features/gate.ts +16 -1
- package/src/features/hook-wiring.test.ts +302 -0
- package/src/features/metadata.ts +20 -3
- package/src/features/network.ts +1 -1
- package/src/features/nowPlaying.ts +1 -1
- package/src/features/output.ts +1 -1
- package/src/features/playback/controls.ts +4 -2
- package/src/features/playback/playWhenReady.ts +1 -1
- package/src/features/playback/playing.ts +1 -1
- package/src/features/playback/progress.test.ts +169 -0
- package/src/features/playback/progress.ts +3 -2
- package/src/features/playback/rate.ts +8 -1
- package/src/features/playback/state.ts +3 -4
- package/src/features/playback/trackPlaybackTime.test.ts +16 -6
- package/src/features/playback/trackPlaybackTime.ts +1 -6
- package/src/features/playback/volume.ts +1 -1
- package/src/features/player/options.ts +126 -76
- package/src/features/player/setup.test.ts +24 -7
- package/src/features/player/setup.ts +22 -10
- package/src/features/player/validateOptions.ts +21 -0
- package/src/features/queue/activeTrack.ts +15 -4
- package/src/features/queue/queue.ts +13 -6
- package/src/features/queue/repeatMode.ts +1 -1
- package/src/features/queue/shuffle.ts +1 -1
- package/src/features/remoteControls.ts +13 -92
- package/src/features/sleepTimer.test.ts +172 -0
- package/src/features/sleepTimer.ts +9 -1
- package/src/nitro-stub-drift.test.ts +277 -0
- package/src/public-surface.test.ts +147 -0
- package/src/specs/audio-browser.nitro.ts +5 -4
- package/src/style-resolution.test.ts +210 -0
- package/src/test-utils/reactNativeStub.ts +60 -0
- package/src/types/browser-native.ts +7 -3
- package/src/types/browser-nodes.ts +403 -134
- package/src/types/browser.ts +97 -63
- package/src/utils/LazyNativeEmitter.ts +28 -15
- package/src/utils/NativeUpdatedValue.ts +29 -13
- package/src/utils/getTrackIdentity.ts +20 -0
- package/src/utils/useDebug.test.ts +182 -0
- package/src/utils/useNativeUpdatedValue.test.ts +103 -0
- package/src/utils/useNativeValueRefreshedBy.ts +38 -0
- package/src/web/NativeAudioBrowser.playWhenReady.test.ts +232 -2
- package/src/web/NativeAudioBrowser.ts +240 -83
- package/src/web/TrackPlayer/LoadAttempt.ts +29 -0
- package/src/web/TrackPlayer/PlaybackStateMachine.test.ts +60 -13
- package/src/web/TrackPlayer/PlaybackStateMachine.ts +22 -6
- package/src/web/TrackPlayer/Player.dispatch.test.ts +5 -3
- package/src/web/TrackPlayer/Player.load.test.ts +137 -1
- package/src/web/TrackPlayer/Player.ts +284 -37
- package/src/web/TrackPlayer/PlayingStateFactory.test.ts +1 -1
- package/src/web/TrackPlayer/PlayingStateFactory.ts +1 -1
- package/src/web/TrackPlayer/QueueManager.test.ts +29 -0
- package/src/web/TrackPlayer/QueueManager.ts +14 -0
- package/src/web/TrackPlayer/QueuePlayer.ts +33 -14
- package/src/web/__tests__/lifecycle.test.ts +345 -0
- package/src/web/__tests__/lifecycleHarness.ts +351 -0
- package/src/web/__tests__/loadEdgeCases.test.ts +246 -0
- package/src/web/__tests__/loadSupersession.test.ts +175 -0
- package/src/web/__tests__/retry.test.ts +169 -0
- package/src/web/browser/BrowserManager.ts +209 -111
- package/src/web/browser/FavoriteManager.test.ts +84 -0
- package/src/web/browser/FavoriteManager.ts +28 -23
- package/src/web/browser/NavigationErrorManager.ts +3 -1
- package/src/web/browser/SearchManager.test.ts +75 -0
- package/src/web/browser/SearchManager.ts +25 -28
- package/src/web/browser/__tests__/artwork-resolution.test.ts +117 -0
- package/src/web/browser/__tests__/layer-resolver.test.ts +35 -0
- package/src/web/browser/__tests__/search-artwork.test.ts +46 -0
- package/src/web/browser/__tests__/search-navigation.test.ts +76 -0
- package/src/web/browser/assertBrowsePageShape.test.ts +1 -1
- package/src/web/browser/assertBrowsePageShape.ts +5 -3
- package/src/web/browser/classifyTrackNavigation.test.ts +10 -8
- package/src/web/browser/classifyTrackNavigation.ts +9 -9
- package/src/web/browser/parseSearchResponse.test.ts +8 -2
- package/src/web/browser/sections.test.ts +91 -0
- package/src/web/browser/sections.ts +72 -0
- package/src/web/http/RequestConfigBuilder.test.ts +241 -1
- package/src/web/http/RequestConfigBuilder.ts +140 -33
- package/src/web/http/followMediaRedirect.test.ts +289 -0
- package/src/web/http/followMediaRedirect.ts +253 -0
- package/src/web/player/NowPlayingManager.ts +4 -3
- package/src/web/util/BrowserPathHelper.test.ts +68 -0
- package/src/web/util/BrowserPathHelper.ts +70 -13
- package/website/guide/android-auto.md +114 -0
- package/website/guide/android-certificates.md +409 -0
- package/website/guide/artwork.md +255 -0
- package/website/guide/audio-output.md +135 -0
- package/website/guide/automotive.md +86 -0
- package/website/guide/basic-usage.md +151 -0
- package/website/guide/battery.md +115 -0
- package/website/guide/browser.md +587 -0
- package/website/guide/carplay.md +650 -0
- package/website/guide/configuration.md +173 -0
- package/website/guide/equalizer.md +231 -0
- package/website/guide/errors.md +310 -0
- package/website/guide/favorites.md +154 -0
- package/website/guide/gate.md +143 -0
- package/website/guide/getting-started.md +46 -0
- package/website/guide/hooks.md +238 -0
- package/website/guide/live-streams.md +125 -0
- package/website/guide/metadata.md +239 -0
- package/website/guide/migrating-from-track-player.md +244 -0
- package/website/guide/native-callback-fetch.md +127 -0
- package/website/guide/network.md +86 -0
- package/website/guide/now-playing.md +175 -0
- package/website/guide/playback.md +328 -0
- package/website/guide/queue.md +300 -0
- package/website/guide/remote-controls.md +256 -0
- package/website/guide/search.md +255 -0
- package/website/guide/sleep-timer.md +268 -0
- package/website/guide/track.md +247 -0
- package/ios/Bridge.h +0 -8
- package/ios/Browser/MediaResolveComposer.swift +0 -114
- package/ios/CarPlay/ImageRowItem+CarPlay.swift +0 -19
- package/ios/Model/MediaURL.swift +0 -67
- package/ios/NowPlayingInfo/MediaItemProperty.swift +0 -78
- package/ios/NowPlayingInfo/NowPlayingInfoKeyValue.swift +0 -6
- package/ios/NowPlayingInfo/NowPlayingInfoProperty.swift +0 -220
- package/ios/Observer/PlayerItemNotificationObserver.swift +0 -119
- package/ios/Observer/PlayerItemPropertyObserver.swift +0 -133
- package/ios/Observer/PlayerStateObserver.swift +0 -50
- package/ios/Observer/PlayerTimeObserver.swift +0 -55
- package/ios/Option/PitchAlgorithms.swift +0 -17
- package/ios/Option/TimeEventFrequency.swift +0 -18
- package/ios/Player/LoadSeekCoordinator.swift +0 -99
- package/ios/Player/MediaLoaderDelegate.swift +0 -11
- package/ios/Player/PlaybackCoordinator.swift +0 -754
- package/ios/Player/PlaybackEffectHandler.swift +0 -54
- package/ios/Player/PlaybackErrorHandler.swift +0 -175
- package/ios/Player/PlaybackStateStore.swift +0 -27
- package/ios/Player/PlayingStateManager.swift +0 -33
- package/ios/Player/RetryManager.swift +0 -322
- package/ios/Player/SeekCompletionHandler.swift +0 -3
- package/ios/Player/SleepTimerHandling.swift +0 -15
- package/ios/Support/RNTrackPlayer-Bridging-Header.h +0 -7
- package/ios/Tests/LoadSeekCoordinatorTests.swift +0 -325
- package/ios/Tests/MediaResolveTests.swift +0 -126
- package/ios/Tests/OnceValueTests.swift +0 -79
- package/ios/Tests/PlaybackErrorHandlerTests.swift +0 -547
- package/ios/Tests/PlaybackStateStoreTests.swift +0 -48
- package/ios/Tests/PlayingStateManagerTests.swift +0 -57
- package/ios/Tests/RetryManagerTests.swift +0 -89
- package/ios/TrackPlayer.swift +0 -1014
- package/ios/TrackPlayerCallbacks.swift +0 -86
- package/ios/Util/MetadataAdapter.swift +0 -131
- package/ios/Util/OnceValue.swift +0 -104
- package/nitrogen/generated/android/c++/JFavoriteConfig.hpp +0 -58
- package/nitrogen/generated/android/c++/JFavoritesMatchMode.hpp +0 -58
- package/nitrogen/generated/android/c++/JImageRowItem.hpp +0 -105
- package/nitrogen/generated/android/c++/JNotificationButtonLayout.hpp +0 -94
- package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.cpp +0 -26
- package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.hpp +0 -71
- package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.cpp +0 -26
- package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.hpp +0 -75
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FavoriteConfig.kt +0 -38
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +0 -68
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButtonLayout.kt +0 -50
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_FavoriteConfig.kt +0 -53
- package/nitrogen/generated/ios/swift/FavoriteConfig.swift +0 -29
- package/nitrogen/generated/ios/swift/FavoritesMatchMode.swift +0 -40
- package/nitrogen/generated/ios/swift/ImageRowItem.swift +0 -195
- package/nitrogen/generated/ios/swift/NotificationButtonLayout.swift +0 -92
- package/nitrogen/generated/ios/swift/Variant_Bool_FavoriteConfig.swift +0 -18
- package/nitrogen/generated/ios/swift/Variant_NullType_NotificationButtonLayout.swift +0 -18
- package/nitrogen/generated/shared/c++/FavoriteConfig.hpp +0 -84
- package/nitrogen/generated/shared/c++/ImageRowItem.hpp +0 -129
- package/nitrogen/generated/shared/c++/NotificationButtonLayout.hpp +0 -102
|
@@ -2,46 +2,43 @@
|
|
|
2
2
|
import Foundation
|
|
3
3
|
import Testing
|
|
4
4
|
|
|
5
|
-
/// Helper to build a
|
|
5
|
+
/// Helper to build a player with mocks for testing.
|
|
6
6
|
@MainActor
|
|
7
7
|
private func makeCoordinator() -> (
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
callbacks:
|
|
11
|
-
sleepTimer:
|
|
8
|
+
player: Player,
|
|
9
|
+
engine: MockPlayerEngine,
|
|
10
|
+
callbacks: MockPlayerCallbacks,
|
|
11
|
+
sleepTimer: SleepTimerManager,
|
|
12
12
|
) {
|
|
13
|
-
let
|
|
14
|
-
let
|
|
15
|
-
let
|
|
16
|
-
let
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
coordinator.effectHandler = effectHandler
|
|
20
|
-
coordinator.callbacks = callbacks
|
|
21
|
-
return (coordinator, effectHandler, callbacks, sleepTimer)
|
|
13
|
+
let sleepTimer = SleepTimerManager(scheduler: ManualSleepTimerScheduler())
|
|
14
|
+
let engine = MockPlayerEngine()
|
|
15
|
+
let player = makePlayer(engine: engine, retries: false, sleepTimer: sleepTimer)
|
|
16
|
+
let callbacks = MockPlayerCallbacks()
|
|
17
|
+
player.callbacks = callbacks
|
|
18
|
+
return (player, engine, callbacks, sleepTimer)
|
|
22
19
|
}
|
|
23
20
|
|
|
24
|
-
/// Helper to load a track into the
|
|
21
|
+
/// Helper to load a track into the player's queue so it has a currentTrack.
|
|
25
22
|
@MainActor
|
|
26
23
|
private func loadTrack(
|
|
27
|
-
_
|
|
24
|
+
_ player: Player,
|
|
28
25
|
id: String = "t1",
|
|
29
26
|
src: String? = "https://example.com/audio.mp3",
|
|
30
27
|
title: String = "Test Track",
|
|
31
28
|
) {
|
|
32
29
|
let track = Track(id: id, src: src, title: title)
|
|
33
|
-
|
|
30
|
+
player.setQueue([track])
|
|
34
31
|
}
|
|
35
32
|
|
|
36
33
|
// MARK: - Transition + Side Effects
|
|
37
34
|
|
|
38
|
-
@Suite("
|
|
35
|
+
@Suite("Player - transition + side effects")
|
|
39
36
|
struct TransitionTests {
|
|
40
37
|
@Test @MainActor
|
|
41
38
|
func toReady_startsPlayback_whenPlayWhenReady() {
|
|
42
39
|
let (c, eh, _, _) = makeCoordinator()
|
|
43
40
|
loadTrack(c)
|
|
44
|
-
c.
|
|
41
|
+
c.setPlayWhenReady(true)
|
|
45
42
|
eh.startPlaybackCallCount = 0 // reset from playWhenReady setter
|
|
46
43
|
|
|
47
44
|
c.transition(.bufferingSufficient)
|
|
@@ -77,19 +74,19 @@ struct TransitionTests {
|
|
|
77
74
|
c.transition(.errorOccurred(.playbackFailed))
|
|
78
75
|
|
|
79
76
|
#expect(c.state == .error)
|
|
80
|
-
#expect(c.
|
|
77
|
+
#expect(c.errorStatus.error == .playbackFailed)
|
|
81
78
|
}
|
|
82
79
|
|
|
83
80
|
@Test @MainActor
|
|
84
81
|
func leavingError_clearsPlaybackError() {
|
|
85
82
|
let (c, _, _, _) = makeCoordinator()
|
|
86
83
|
c.transition(.errorOccurred(.playbackFailed))
|
|
87
|
-
#expect(c.
|
|
84
|
+
#expect(c.errorStatus.error == .playbackFailed)
|
|
88
85
|
|
|
89
86
|
c.transition(.trackLoading)
|
|
90
87
|
|
|
91
88
|
#expect(c.state == .loading)
|
|
92
|
-
#expect(c.
|
|
89
|
+
#expect(c.errorStatus.error == nil)
|
|
93
90
|
}
|
|
94
91
|
|
|
95
92
|
@Test @MainActor
|
|
@@ -103,7 +100,7 @@ struct TransitionTests {
|
|
|
103
100
|
|
|
104
101
|
// State stays .error but error is updated
|
|
105
102
|
#expect(c.state == .error)
|
|
106
|
-
#expect(c.
|
|
103
|
+
#expect(c.errorStatus.error == .notConnectedToInternet)
|
|
107
104
|
#expect(cb.playbackChanges.count == 1)
|
|
108
105
|
#expect(cb.errorEvents.count == 1)
|
|
109
106
|
}
|
|
@@ -114,29 +111,21 @@ struct TransitionTests {
|
|
|
114
111
|
/// Advisory errors from the retry loop: attached to the current non-terminal
|
|
115
112
|
/// state via `playerDidChangePlayback`, never a state transition and never a
|
|
116
113
|
/// `playerDidError`.
|
|
117
|
-
/// Builds a
|
|
118
|
-
/// pretend the (instant) retry succeeded, so only the advisory path runs.
|
|
119
|
-
/// The effect handler is returned solely to keep the weak reference alive.
|
|
114
|
+
/// Builds a player whose retries reload at once, so the advisory path is what shows.
|
|
120
115
|
@MainActor
|
|
121
116
|
private func makeRetrying() -> (
|
|
122
|
-
|
|
123
|
-
|
|
117
|
+
Player, RetryLoop, MockPlayerCallbacks,
|
|
118
|
+
MockPlayerEngine,
|
|
124
119
|
) {
|
|
125
|
-
let retryHandler =
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
let
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
)
|
|
132
|
-
let effectHandler = MockPlaybackEffectHandler()
|
|
133
|
-
coordinator.effectHandler = effectHandler
|
|
134
|
-
let callbacks = MockPlaybackCoordinatorCallbacks()
|
|
135
|
-
coordinator.callbacks = callbacks
|
|
136
|
-
return (coordinator, retryHandler, callbacks, effectHandler)
|
|
120
|
+
let retryHandler = makeRetryLoop()
|
|
121
|
+
let engine = MockPlayerEngine()
|
|
122
|
+
let player = makePlayer(engine: engine, retry: retryHandler)
|
|
123
|
+
let callbacks = MockPlayerCallbacks()
|
|
124
|
+
player.callbacks = callbacks
|
|
125
|
+
return (player, retryHandler, callbacks, engine)
|
|
137
126
|
}
|
|
138
127
|
|
|
139
|
-
@Suite("
|
|
128
|
+
@Suite("Player - retrying errors")
|
|
140
129
|
struct RetryingErrorTests {
|
|
141
130
|
@Test @MainActor
|
|
142
131
|
func retryingError_attachesToCurrentState() async {
|
|
@@ -144,16 +133,16 @@ struct RetryingErrorTests {
|
|
|
144
133
|
c.transition(.trackLoading)
|
|
145
134
|
cb.playbackChanges.removeAll()
|
|
146
135
|
|
|
147
|
-
c.
|
|
136
|
+
c.retry.handleError(URLError(.cannotConnectToHost), context: .mediaLoad)
|
|
148
137
|
|
|
149
138
|
#expect(c.state == .loading)
|
|
150
|
-
#expect(c.
|
|
139
|
+
#expect(c.errorStatus.error == .hostUnreachable)
|
|
151
140
|
#expect(cb.playbackChanges.count == 1)
|
|
152
141
|
#expect(cb.playbackChanges.last?.state == .loading)
|
|
153
142
|
#expect(cb.playbackChanges.last?.error?.retrying == true)
|
|
154
143
|
// Advisory, not terminal: the error event is reserved for .error.
|
|
155
144
|
#expect(cb.errorEvents.isEmpty)
|
|
156
|
-
await c.
|
|
145
|
+
await c.retry.pendingTask?.value
|
|
157
146
|
}
|
|
158
147
|
|
|
159
148
|
/// Every failed attempt re-reports through `handleError`; identical repeats
|
|
@@ -164,10 +153,10 @@ struct RetryingErrorTests {
|
|
|
164
153
|
c.transition(.trackLoading)
|
|
165
154
|
cb.playbackChanges.removeAll()
|
|
166
155
|
|
|
167
|
-
c.
|
|
168
|
-
await c.
|
|
169
|
-
c.
|
|
170
|
-
await c.
|
|
156
|
+
c.retry.handleError(URLError(.cannotConnectToHost), context: .mediaLoad)
|
|
157
|
+
await c.retry.pendingTask?.value
|
|
158
|
+
c.retry.handleError(URLError(.cannotConnectToHost), context: .mediaLoad)
|
|
159
|
+
await c.retry.pendingTask?.value
|
|
171
160
|
|
|
172
161
|
#expect(cb.playbackChanges.count == 1)
|
|
173
162
|
}
|
|
@@ -180,11 +169,11 @@ struct RetryingErrorTests {
|
|
|
180
169
|
c.transition(.avPlayerPlaying)
|
|
181
170
|
cb.playbackChanges.removeAll()
|
|
182
171
|
|
|
183
|
-
c.
|
|
172
|
+
c.retry.handleError(URLError(.cannotConnectToHost), context: .playback)
|
|
184
173
|
|
|
185
|
-
#expect(c.
|
|
174
|
+
#expect(c.errorStatus.error == nil)
|
|
186
175
|
#expect(cb.playbackChanges.isEmpty)
|
|
187
|
-
await c.
|
|
176
|
+
await c.retry.pendingTask?.value
|
|
188
177
|
}
|
|
189
178
|
|
|
190
179
|
/// Reaching .ready proves the retry recovered: the advisory error must not
|
|
@@ -193,13 +182,13 @@ struct RetryingErrorTests {
|
|
|
193
182
|
func recovery_clearsTheRetryingError() async {
|
|
194
183
|
let (c, _, cb, _) = makeRetrying()
|
|
195
184
|
c.transition(.trackLoading)
|
|
196
|
-
c.
|
|
197
|
-
await c.
|
|
185
|
+
c.retry.handleError(URLError(.cannotConnectToHost), context: .mediaLoad)
|
|
186
|
+
await c.retry.pendingTask?.value
|
|
198
187
|
|
|
199
188
|
c.transition(.loadSeekCompleted)
|
|
200
189
|
|
|
201
190
|
#expect(c.state == .ready)
|
|
202
|
-
#expect(c.
|
|
191
|
+
#expect(c.errorStatus.error == nil)
|
|
203
192
|
#expect(cb.playbackChanges.last?.error == nil)
|
|
204
193
|
}
|
|
205
194
|
|
|
@@ -209,12 +198,12 @@ struct RetryingErrorTests {
|
|
|
209
198
|
func exhaustion_hardensIntoTerminalError() async {
|
|
210
199
|
let (c, retryHandler, cb, _) = makeRetrying()
|
|
211
200
|
c.transition(.trackLoading)
|
|
212
|
-
c.
|
|
213
|
-
await c.
|
|
201
|
+
c.retry.handleError(URLError(.cannotConnectToHost), context: .mediaLoad)
|
|
202
|
+
await c.retry.pendingTask?.value
|
|
214
203
|
|
|
215
|
-
retryHandler.
|
|
216
|
-
c.
|
|
217
|
-
await c.
|
|
204
|
+
retryHandler.shouldRetry = { false }
|
|
205
|
+
c.retry.handleError(URLError(.cannotConnectToHost), context: .mediaLoad)
|
|
206
|
+
await c.retry.pendingTask?.value
|
|
218
207
|
|
|
219
208
|
#expect(c.state == .error)
|
|
220
209
|
#expect(cb.playbackChanges.last?.state == .error)
|
|
@@ -225,7 +214,7 @@ struct RetryingErrorTests {
|
|
|
225
214
|
|
|
226
215
|
// MARK: - emitStateChange
|
|
227
216
|
|
|
228
|
-
@Suite("
|
|
217
|
+
@Suite("Player - emitStateChange")
|
|
229
218
|
struct EmitStateChangeTests {
|
|
230
219
|
@Test @MainActor
|
|
231
220
|
func alwaysEmits_playerDidChangePlayback() {
|
|
@@ -275,7 +264,7 @@ struct EmitStateChangeTests {
|
|
|
275
264
|
|
|
276
265
|
// MARK: - Observer Guards
|
|
277
266
|
|
|
278
|
-
@Suite("
|
|
267
|
+
@Suite("Player - observer guards")
|
|
279
268
|
struct ObserverGuardTests {
|
|
280
269
|
@Test @MainActor
|
|
281
270
|
func timeControlStatus_paused_nearTrackEnd_ignored() {
|
|
@@ -312,7 +301,7 @@ struct ObserverGuardTests {
|
|
|
312
301
|
eh.hasLoadedAsset = true
|
|
313
302
|
eh.currentTime = 10
|
|
314
303
|
eh.duration = 100
|
|
315
|
-
c.
|
|
304
|
+
c.setPlayWhenReady(false)
|
|
316
305
|
|
|
317
306
|
c.avPlayerDidChangeTimeControlStatus(.paused)
|
|
318
307
|
|
|
@@ -326,7 +315,7 @@ struct ObserverGuardTests {
|
|
|
326
315
|
eh.hasLoadedAsset = true
|
|
327
316
|
eh.currentTime = 10
|
|
328
317
|
eh.duration = 100
|
|
329
|
-
c.
|
|
318
|
+
c.setPlayWhenReady(true)
|
|
330
319
|
|
|
331
320
|
c.avPlayerDidChangeTimeControlStatus(.paused)
|
|
332
321
|
|
|
@@ -414,28 +403,39 @@ struct ObserverGuardTests {
|
|
|
414
403
|
|
|
415
404
|
// MARK: - playWhenReady
|
|
416
405
|
|
|
417
|
-
@Suite("
|
|
406
|
+
@Suite("Player - playWhenReady")
|
|
418
407
|
struct PlayWhenReadyTests {
|
|
419
408
|
@Test @MainActor
|
|
420
409
|
func true_fromError_triggersReload() {
|
|
421
410
|
let (c, eh, _, _) = makeCoordinator()
|
|
411
|
+
loadTrack(c)
|
|
412
|
+
eh.emit(.itemPrepared(likelyToKeepUp: false))
|
|
422
413
|
c.transition(.errorOccurred(.playbackFailed))
|
|
414
|
+
eh.resumePosition = 42
|
|
415
|
+
let resolvesBefore = eh.resolveAndLoadCalls.count
|
|
423
416
|
|
|
424
|
-
c.
|
|
417
|
+
c.setPlayWhenReady(true)
|
|
425
418
|
|
|
426
|
-
|
|
427
|
-
#expect(eh.
|
|
419
|
+
// A restart from .error is a new Load on a new AVPlayer, resuming where it failed.
|
|
420
|
+
#expect(eh.recreateCount == 1)
|
|
421
|
+
#expect(eh.resolveAndLoadCalls.count == resolvesBefore + 1)
|
|
422
|
+
#expect(c.state == .loading)
|
|
423
|
+
#expect(c.deferredSeek.target == 42)
|
|
428
424
|
}
|
|
429
425
|
|
|
430
426
|
@Test @MainActor
|
|
431
427
|
func true_fromStopped_triggersReload() {
|
|
432
428
|
let (c, eh, _, _) = makeCoordinator()
|
|
429
|
+
loadTrack(c)
|
|
433
430
|
c.transition(.stopped)
|
|
431
|
+
eh.resumePosition = 42
|
|
432
|
+
let resolvesBefore = eh.resolveAndLoadCalls.count
|
|
434
433
|
|
|
435
|
-
c.
|
|
434
|
+
c.setPlayWhenReady(true)
|
|
436
435
|
|
|
437
|
-
#expect(eh.
|
|
438
|
-
#expect(eh.
|
|
436
|
+
#expect(eh.recreateCount == 0)
|
|
437
|
+
#expect(eh.resolveAndLoadCalls.count == resolvesBefore + 1)
|
|
438
|
+
#expect(c.deferredSeek.target == nil) // a stop restarts from the start
|
|
439
439
|
}
|
|
440
440
|
|
|
441
441
|
@Test @MainActor
|
|
@@ -443,7 +443,7 @@ struct PlayWhenReadyTests {
|
|
|
443
443
|
let (c, eh, _, _) = makeCoordinator()
|
|
444
444
|
c.transition(.bufferingSufficient) // .ready state
|
|
445
445
|
|
|
446
|
-
c.
|
|
446
|
+
c.setPlayWhenReady(true)
|
|
447
447
|
|
|
448
448
|
#expect(eh.startPlaybackCallCount >= 1)
|
|
449
449
|
}
|
|
@@ -452,10 +452,10 @@ struct PlayWhenReadyTests {
|
|
|
452
452
|
func false_notLoading_pausesPlayback() {
|
|
453
453
|
let (c, eh, _, _) = makeCoordinator()
|
|
454
454
|
c.transition(.avPlayerPlaying)
|
|
455
|
-
c.
|
|
455
|
+
c.setPlayWhenReady(true)
|
|
456
456
|
eh.pausePlaybackCallCount = 0
|
|
457
457
|
|
|
458
|
-
c.
|
|
458
|
+
c.setPlayWhenReady(false)
|
|
459
459
|
|
|
460
460
|
#expect(eh.pausePlaybackCallCount == 1)
|
|
461
461
|
}
|
|
@@ -467,7 +467,7 @@ struct PlayWhenReadyTests {
|
|
|
467
467
|
eh.startPlaybackCallCount = 0
|
|
468
468
|
eh.pausePlaybackCallCount = 0
|
|
469
469
|
|
|
470
|
-
c.
|
|
470
|
+
c.setPlayWhenReady(true)
|
|
471
471
|
|
|
472
472
|
// During loading, should NOT call start/pause
|
|
473
473
|
#expect(eh.startPlaybackCallCount == 0)
|
|
@@ -478,7 +478,7 @@ struct PlayWhenReadyTests {
|
|
|
478
478
|
func emitsCallback_onChange() {
|
|
479
479
|
let (c, _, cb, _) = makeCoordinator()
|
|
480
480
|
|
|
481
|
-
c.
|
|
481
|
+
c.setPlayWhenReady(true)
|
|
482
482
|
|
|
483
483
|
#expect(cb.playWhenReadyChanges.count == 1)
|
|
484
484
|
#expect(cb.playWhenReadyChanges.first == true)
|
|
@@ -487,7 +487,7 @@ struct PlayWhenReadyTests {
|
|
|
487
487
|
|
|
488
488
|
// MARK: - Skip availability (next/previous greying)
|
|
489
489
|
|
|
490
|
-
@Suite("
|
|
490
|
+
@Suite("Player - skip availability")
|
|
491
491
|
struct SkipAvailabilityCoordinatorTests {
|
|
492
492
|
private static func multiTrack() -> [Track] {
|
|
493
493
|
[
|
|
@@ -541,25 +541,25 @@ struct SkipAvailabilityCoordinatorTests {
|
|
|
541
541
|
|
|
542
542
|
// MARK: - handleCurrentTrackChanged
|
|
543
543
|
|
|
544
|
-
@Suite("
|
|
544
|
+
@Suite("Player - handleCurrentTrackChanged")
|
|
545
545
|
struct HandleCurrentTrackChangedTests {
|
|
546
546
|
@Test @MainActor
|
|
547
547
|
func clearsError_beforeTransition() {
|
|
548
548
|
let (c, eh, _, _) = makeCoordinator()
|
|
549
549
|
eh.hasLoadedAsset = true
|
|
550
550
|
c.transition(.errorOccurred(.playbackFailed))
|
|
551
|
-
#expect(c.
|
|
551
|
+
#expect(c.errorStatus.error != nil)
|
|
552
552
|
|
|
553
553
|
loadTrack(c)
|
|
554
554
|
|
|
555
555
|
// After loading a track, the error should be cleared
|
|
556
|
-
#expect(c.
|
|
556
|
+
#expect(c.errorStatus.error == nil)
|
|
557
557
|
}
|
|
558
558
|
|
|
559
559
|
@Test @MainActor
|
|
560
560
|
func preservesPlayWhenReady_acrossLoading() {
|
|
561
561
|
let (c, _, _, _) = makeCoordinator()
|
|
562
|
-
c.
|
|
562
|
+
c.setPlayWhenReady(true)
|
|
563
563
|
|
|
564
564
|
loadTrack(c)
|
|
565
565
|
|
|
@@ -575,7 +575,7 @@ struct HandleCurrentTrackChangedTests {
|
|
|
575
575
|
c.setQueue([track])
|
|
576
576
|
|
|
577
577
|
#expect(c.state == .error)
|
|
578
|
-
#expect(c.
|
|
578
|
+
#expect(c.errorStatus.error == .invalidSourceUrl("nil"))
|
|
579
579
|
#expect(cb.errorEvents.count >= 1)
|
|
580
580
|
}
|
|
581
581
|
|
|
@@ -595,19 +595,19 @@ struct HandleCurrentTrackChangedTests {
|
|
|
595
595
|
|
|
596
596
|
// MARK: - handleTrackDidPlayToEndTime
|
|
597
597
|
|
|
598
|
-
@Suite("
|
|
598
|
+
@Suite("Player - handleTrackDidPlayToEndTime")
|
|
599
599
|
struct HandleTrackDidPlayToEndTimeTests {
|
|
600
600
|
@Test @MainActor
|
|
601
601
|
func repeatTrack_replays() {
|
|
602
602
|
let (c, eh, _, _) = makeCoordinator()
|
|
603
|
-
|
|
603
|
+
startPlaying(c, eh)
|
|
604
604
|
c.repeatMode = .track
|
|
605
|
-
|
|
605
|
+
eh.startPlaybackCallCount = 0
|
|
606
606
|
|
|
607
607
|
c.handleTrackDidPlayToEndTime()
|
|
608
608
|
|
|
609
|
-
|
|
610
|
-
#expect(eh.
|
|
609
|
+
#expect(eh.seekCalls == [0])
|
|
610
|
+
#expect(eh.startPlaybackCallCount == 1)
|
|
611
611
|
}
|
|
612
612
|
|
|
613
613
|
/// The end-of-track sleep timer pauses (clears intent) just before this
|
|
@@ -620,19 +620,18 @@ struct HandleTrackDidPlayToEndTimeTests {
|
|
|
620
620
|
let (c, eh, cb, _) = makeCoordinator()
|
|
621
621
|
loadTrack(c)
|
|
622
622
|
c.repeatMode = .track
|
|
623
|
-
c.
|
|
623
|
+
c.setPlayWhenReady(false)
|
|
624
624
|
|
|
625
625
|
c.handleTrackDidPlayToEndTime()
|
|
626
626
|
|
|
627
627
|
#expect(cb.queueEndedEvents.isEmpty)
|
|
628
|
-
#expect(eh.
|
|
628
|
+
#expect(eh.seekCalls.isEmpty)
|
|
629
629
|
#expect(c.state == .ended)
|
|
630
630
|
}
|
|
631
631
|
|
|
632
632
|
@Test @MainActor
|
|
633
633
|
func lastTrack_noRepeat_transitionsToEnded() {
|
|
634
634
|
let (c, eh, cb, _) = makeCoordinator()
|
|
635
|
-
_ = eh // retain weak effectHandler
|
|
636
635
|
loadTrack(c)
|
|
637
636
|
c.repeatMode = .off
|
|
638
637
|
|
|
@@ -666,7 +665,7 @@ struct HandleTrackDidPlayToEndTimeTests {
|
|
|
666
665
|
/// `playWhenReady` must not stay true. Keeping it inverted the play/pause
|
|
667
666
|
/// toggle, held the audio session forever, armed interruption auto-resume into
|
|
668
667
|
/// silence, and made play-from-ended a silent no-op.
|
|
669
|
-
@Suite("
|
|
668
|
+
@Suite("Player - natural end drops play intent")
|
|
670
669
|
struct NaturalEndPlayIntentTests {
|
|
671
670
|
@Test @MainActor
|
|
672
671
|
func naturalEnd_clearsPlayWhenReady() {
|
|
@@ -697,11 +696,13 @@ struct NaturalEndPlayIntentTests {
|
|
|
697
696
|
let (c, eh, _, _) = makeCoordinator()
|
|
698
697
|
startPlaying(c, eh)
|
|
699
698
|
c.handleTrackDidPlayToEndTime()
|
|
700
|
-
eh.
|
|
699
|
+
eh.resumePosition = 300
|
|
700
|
+
let resolvesBefore = eh.resolveAndLoadCalls.count
|
|
701
701
|
|
|
702
702
|
c.play()
|
|
703
703
|
|
|
704
|
-
#expect(eh.
|
|
704
|
+
#expect(eh.resolveAndLoadCalls.count == resolvesBefore + 1)
|
|
705
|
+
#expect(c.deferredSeek.target == nil)
|
|
705
706
|
}
|
|
706
707
|
|
|
707
708
|
/// The cleared intent opens the call-site `!playWhenReady` gate, so a stray
|
|
@@ -724,13 +725,13 @@ struct NaturalEndPlayIntentTests {
|
|
|
724
725
|
let (c, eh, _, _) = makeCoordinator()
|
|
725
726
|
startPlaying(c, eh)
|
|
726
727
|
c.handleTrackDidPlayToEndTime()
|
|
727
|
-
eh.
|
|
728
|
+
let resolvesBefore = eh.resolveAndLoadCalls.count
|
|
728
729
|
|
|
729
730
|
c.handleInterruptionBegan()
|
|
730
731
|
c.handleInterruptionEnded(shouldResume: true)
|
|
731
732
|
|
|
732
733
|
#expect(c.playWhenReady == false) // nothing was playing — never resume
|
|
733
|
-
#expect(eh.
|
|
734
|
+
#expect(eh.resolveAndLoadCalls.count == resolvesBefore)
|
|
734
735
|
}
|
|
735
736
|
}
|
|
736
737
|
|
|
@@ -740,153 +741,69 @@ struct NaturalEndPlayIntentTests {
|
|
|
740
741
|
/// window/attempt counters must refill (mirrors Android's healthy-playback
|
|
741
742
|
/// refill) — otherwise a long-lived stream permanently loses retry after its
|
|
742
743
|
/// first recovered blip.
|
|
743
|
-
@Suite("
|
|
744
|
+
@Suite("Player - healthy playback resets retry budget")
|
|
744
745
|
struct HealthyPlaybackRetryResetTests {
|
|
746
|
+
/// A player whose retry loop has already executed one retry, so a reset shows.
|
|
747
|
+
@MainActor
|
|
748
|
+
private func makeAfterOneRetry(delay: TimeInterval = 0) async -> (Player, RetryLoop, MockPlayerEngine) {
|
|
749
|
+
let retry = makeRetryLoop(delay: delay)
|
|
750
|
+
let engine = MockPlayerEngine()
|
|
751
|
+
let player = makePlayer(engine: engine, retry: retry)
|
|
752
|
+
if delay == 0 {
|
|
753
|
+
retry.handleError(URLError(.timedOut), context: .playback)
|
|
754
|
+
await retry.pendingTask?.value
|
|
755
|
+
}
|
|
756
|
+
return (player, retry, engine)
|
|
757
|
+
}
|
|
758
|
+
|
|
745
759
|
@Test @MainActor
|
|
746
760
|
func sustainedPlayback_resetsRetryBudget() async {
|
|
747
|
-
let
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
errorHandler: errorHandler, sleepTimerManager: MockSleepTimerHandling(),
|
|
751
|
-
)
|
|
752
|
-
let effectHandler = MockPlaybackEffectHandler()
|
|
753
|
-
coordinator.effectHandler = effectHandler
|
|
754
|
-
coordinator.healthyPlaybackDuration = 0.01
|
|
761
|
+
let (player, retry, _) = await makeAfterOneRetry()
|
|
762
|
+
#expect(retry.attempts == 1)
|
|
763
|
+
player.healthyPlaybackDuration = 0.01
|
|
755
764
|
|
|
756
|
-
|
|
757
|
-
await
|
|
765
|
+
player.transition(.avPlayerPlaying)
|
|
766
|
+
await player.healthyPlaybackTask?.value
|
|
758
767
|
|
|
759
|
-
#expect(
|
|
768
|
+
#expect(retry.attempts == 0)
|
|
760
769
|
}
|
|
761
770
|
|
|
762
|
-
///
|
|
771
|
+
/// reset() cancels a pending retry — firing the refill mid-episode
|
|
763
772
|
/// would kill an in-flight reconnect silently (stuck .playing forever).
|
|
764
773
|
@Test @MainActor
|
|
765
774
|
func refill_skipsWhileRetryIsPending() async {
|
|
766
|
-
let
|
|
767
|
-
|
|
768
|
-
retryHandler.attemptRetryDelayNs = 1_000_000_000
|
|
769
|
-
let errorHandler = PlaybackErrorHandler(retryHandler: retryHandler)
|
|
770
|
-
let coordinator = PlaybackCoordinator(
|
|
771
|
-
errorHandler: errorHandler, sleepTimerManager: MockSleepTimerHandling(),
|
|
772
|
-
)
|
|
773
|
-
let effectHandler = MockPlaybackEffectHandler()
|
|
774
|
-
coordinator.effectHandler = effectHandler
|
|
775
|
-
coordinator.healthyPlaybackDuration = 0.01
|
|
775
|
+
let (player, retry, _) = await makeAfterOneRetry(delay: 1)
|
|
776
|
+
player.healthyPlaybackDuration = 0.01
|
|
776
777
|
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
await
|
|
778
|
+
player.transition(.avPlayerPlaying)
|
|
779
|
+
retry.handleError(URLError(.timedOut), context: .playback)
|
|
780
|
+
await player.healthyPlaybackTask?.value
|
|
780
781
|
|
|
781
|
-
#expect(
|
|
782
|
-
|
|
782
|
+
#expect(retry.pendingTask != nil)
|
|
783
|
+
retry.cancel()
|
|
783
784
|
}
|
|
784
785
|
|
|
785
786
|
@Test @MainActor
|
|
786
787
|
func playbackInterruptedBeforeThreshold_doesNotReset() async {
|
|
787
|
-
let
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
errorHandler: errorHandler, sleepTimerManager: MockSleepTimerHandling(),
|
|
791
|
-
)
|
|
792
|
-
let effectHandler = MockPlaybackEffectHandler()
|
|
793
|
-
coordinator.effectHandler = effectHandler
|
|
794
|
-
effectHandler.hasLoadedAsset = true
|
|
795
|
-
coordinator.healthyPlaybackDuration = 0.5
|
|
788
|
+
let (player, retry, engine) = await makeAfterOneRetry()
|
|
789
|
+
engine.hasLoadedAsset = true
|
|
790
|
+
player.healthyPlaybackDuration = 0.5
|
|
796
791
|
|
|
797
|
-
|
|
798
|
-
let refill =
|
|
799
|
-
|
|
792
|
+
player.transition(.avPlayerPlaying)
|
|
793
|
+
let refill = player.healthyPlaybackTask
|
|
794
|
+
player.transition(.avPlayerWaiting) // stalls before the threshold
|
|
800
795
|
|
|
801
796
|
// Leaving .playing cancels the refill; awaiting the cancelled task is the
|
|
802
797
|
// deterministic way to reach the point where it would have fired.
|
|
803
798
|
await refill?.value
|
|
804
799
|
|
|
805
|
-
#expect(
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
@Suite("PlaybackCoordinator - now playing state")
|
|
810
|
-
struct PlaybackCoordinatorNowPlayingStateTests {
|
|
811
|
-
@Test @MainActor
|
|
812
|
-
func change_updatesNowPlayingState_evenDuringLoading() {
|
|
813
|
-
let (c, eh, _, _) = makeCoordinator()
|
|
814
|
-
c.transition(.trackLoading) // mid track-load; start/pause is deferred
|
|
815
|
-
eh.updateNowPlayingStateCalls.removeAll()
|
|
816
|
-
|
|
817
|
-
c.playWhenReady = true
|
|
818
|
-
|
|
819
|
-
// The lock-screen / CarPlay play-pause button reflects the user's play
|
|
820
|
-
// *intent* immediately, even while the new item is still loading — otherwise
|
|
821
|
-
// it stays stuck showing "paused" until a later state transition repairs it.
|
|
822
|
-
#expect(eh.updateNowPlayingStateCalls.last == true)
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
@Test @MainActor
|
|
826
|
-
func staysPlaying_whenBufferRunsDry() {
|
|
827
|
-
let (c, eh, _, _) = makeCoordinator()
|
|
828
|
-
c.playWhenReady = true
|
|
829
|
-
c.transition(.avPlayerPlaying)
|
|
830
|
-
eh.updateNowPlayingStateCalls.removeAll()
|
|
831
|
-
|
|
832
|
-
c.transition(.avPlayerWaiting) // buffer ran dry → .buffering
|
|
833
|
-
|
|
834
|
-
// A buffer underrun doesn't change play intent, so the button stays "playing"
|
|
835
|
-
// (the system shows buffering) — it must NOT flip to paused like a user pause.
|
|
836
|
-
#expect(eh.updateNowPlayingStateCalls.last == true)
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
@Test @MainActor
|
|
840
|
-
func fallsBackToPaused_onError() {
|
|
841
|
-
let (c, eh, _, _) = makeCoordinator()
|
|
842
|
-
c.playWhenReady = true
|
|
843
|
-
c.transition(.trackLoading) // active + intent → playing
|
|
844
|
-
eh.updateNowPlayingStateCalls.removeAll()
|
|
845
|
-
|
|
846
|
-
c.transition(.errorOccurred(.playbackFailed))
|
|
847
|
-
|
|
848
|
-
// On a terminal error the button must fall back to paused — never stick on
|
|
849
|
-
// "playing" — even though playWhenReady is still true.
|
|
850
|
-
#expect(eh.updateNowPlayingStateCalls.last == false)
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
@Test @MainActor
|
|
854
|
-
func change_doesNotStampNowPlayingState_fromTerminalState() {
|
|
855
|
-
let (c, eh, _, _) = makeCoordinator()
|
|
856
|
-
c.transition(.errorOccurred(.playbackFailed)) // terminal, not playbackActive
|
|
857
|
-
eh.updateNowPlayingStateCalls.removeAll()
|
|
858
|
-
|
|
859
|
-
c.playWhenReady = true
|
|
860
|
-
|
|
861
|
-
// Must NOT stamp .playing from a terminal state: the reload may fail and no
|
|
862
|
-
// active transition would repair a premature "playing", leaving a phantom
|
|
863
|
-
// playing button. The reload's own .loading/.ready transition stamps it.
|
|
864
|
-
#expect(eh.updateNowPlayingStateCalls.isEmpty)
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
@Test @MainActor
|
|
868
|
-
func selectingNewTrack_whileStopped_showsPlayingInNowPlaying() {
|
|
869
|
-
let (c, eh, _, _) = makeCoordinator()
|
|
870
|
-
let tracks = [
|
|
871
|
-
Track(id: "t1", src: "https://example.com/1.mp3", title: "Track 1"),
|
|
872
|
-
Track(id: "t2", src: "https://example.com/2.mp3", title: "Track 2"),
|
|
873
|
-
]
|
|
874
|
-
c.setQueue(tracks) // loads t1 (playWhenReady defaults to false)
|
|
875
|
-
c.transition(.stopped) // user had paused/stopped
|
|
876
|
-
eh.updateNowPlayingStateCalls.removeAll()
|
|
877
|
-
|
|
878
|
-
// User selects another track, intending to play it.
|
|
879
|
-
try? c.skipTo(1, playWhenReady: true)
|
|
880
|
-
|
|
881
|
-
// Audio will play, so the now-playing button must end up "playing" — not the
|
|
882
|
-
// stale "paused" captured before playWhenReady flipped true during loading.
|
|
883
|
-
#expect(eh.updateNowPlayingStateCalls.last == true)
|
|
800
|
+
#expect(retry.attempts == 1)
|
|
884
801
|
}
|
|
885
802
|
}
|
|
886
803
|
|
|
887
804
|
// MARK: - Sleep Timer Fade
|
|
888
805
|
|
|
889
|
-
@Suite("
|
|
806
|
+
@Suite("Player - sleep timer fade")
|
|
890
807
|
struct SleepTimerFadeTests {
|
|
891
808
|
@Test @MainActor
|
|
892
809
|
func fadeStart_capturesPreFadeVolume() {
|
|
@@ -903,7 +820,7 @@ struct SleepTimerFadeTests {
|
|
|
903
820
|
func completion_pausesThenRestoresPreFadeVolume() {
|
|
904
821
|
let (c, eh, _, st) = makeCoordinator()
|
|
905
822
|
loadTrack(c)
|
|
906
|
-
c.
|
|
823
|
+
c.setPlayWhenReady(true)
|
|
907
824
|
c.transition(.bufferingSufficient) // leave .loading so pause reaches the player
|
|
908
825
|
eh.pausePlaybackCallCount = 0
|
|
909
826
|
|
|
@@ -922,7 +839,7 @@ struct SleepTimerFadeTests {
|
|
|
922
839
|
func completion_withoutFade_justPauses() {
|
|
923
840
|
let (c, eh, _, st) = makeCoordinator()
|
|
924
841
|
loadTrack(c)
|
|
925
|
-
c.
|
|
842
|
+
c.setPlayWhenReady(true)
|
|
926
843
|
eh.volume = 0.8
|
|
927
844
|
|
|
928
845
|
st.onComplete?()
|
|
@@ -949,38 +866,41 @@ struct SleepTimerFadeTests {
|
|
|
949
866
|
func pauseDuringFade_clearsSleepTimer() {
|
|
950
867
|
let (c, _, _, st) = makeCoordinator()
|
|
951
868
|
loadTrack(c)
|
|
952
|
-
c.
|
|
869
|
+
c.setPlayWhenReady(true)
|
|
870
|
+
st.set(seconds: 60, fadeDuration: 10)
|
|
953
871
|
|
|
954
872
|
st.onFadeStart?(10)
|
|
955
873
|
c.pause()
|
|
956
874
|
|
|
957
|
-
#expect(st.
|
|
875
|
+
#expect(st.get() == nil)
|
|
958
876
|
}
|
|
959
877
|
|
|
960
878
|
@Test @MainActor
|
|
961
879
|
func pauseWithoutFade_leavesSleepTimerAlone() {
|
|
962
880
|
let (c, _, _, st) = makeCoordinator()
|
|
963
881
|
loadTrack(c)
|
|
964
|
-
c.
|
|
882
|
+
c.setPlayWhenReady(true)
|
|
883
|
+
st.set(seconds: 60, fadeDuration: 10)
|
|
965
884
|
|
|
966
885
|
c.pause()
|
|
967
886
|
|
|
968
|
-
#expect(st.
|
|
887
|
+
#expect(st.get() != nil)
|
|
969
888
|
}
|
|
970
889
|
}
|
|
971
890
|
|
|
972
891
|
// MARK: - Audio Session Interruptions
|
|
973
892
|
|
|
974
|
-
/// Helper to drive the
|
|
893
|
+
/// Helper to drive the player into an actively-playing state.
|
|
975
894
|
@MainActor
|
|
976
|
-
private func startPlaying(_ c:
|
|
895
|
+
private func startPlaying(_ c: Player, _ eh: MockPlayerEngine) {
|
|
977
896
|
loadTrack(c)
|
|
978
897
|
eh.hasLoadedAsset = true
|
|
979
|
-
|
|
898
|
+
eh.hasItem = true
|
|
899
|
+
c.setPlayWhenReady(true)
|
|
980
900
|
c.transition(.avPlayerPlaying)
|
|
981
901
|
}
|
|
982
902
|
|
|
983
|
-
@Suite("
|
|
903
|
+
@Suite("Player - audio session interruptions")
|
|
984
904
|
struct InterruptionTests {
|
|
985
905
|
@Test @MainActor
|
|
986
906
|
func began_whilePlaying_pauses() {
|
|
@@ -1090,13 +1010,14 @@ struct InterruptionTests {
|
|
|
1090
1010
|
let (c, eh, _, _) = makeCoordinator()
|
|
1091
1011
|
startPlaying(c, eh)
|
|
1092
1012
|
c.handleInterruptionBegan()
|
|
1013
|
+
let resolvesBefore = eh.resolveAndLoadCalls.count
|
|
1093
1014
|
|
|
1094
1015
|
c.stop()
|
|
1095
1016
|
c.handleInterruptionEnded(shouldResume: true)
|
|
1096
1017
|
|
|
1097
1018
|
#expect(c.state == .stopped)
|
|
1098
1019
|
#expect(c.playWhenReady == false)
|
|
1099
|
-
#expect(eh.
|
|
1020
|
+
#expect(eh.resolveAndLoadCalls.count == resolvesBefore)
|
|
1100
1021
|
}
|
|
1101
1022
|
|
|
1102
1023
|
/// A user who plays then pauses during the interruption has taken ownership
|
|
@@ -1119,7 +1040,7 @@ struct InterruptionTests {
|
|
|
1119
1040
|
let (c, eh, _, _) = makeCoordinator()
|
|
1120
1041
|
startPlaying(c, eh)
|
|
1121
1042
|
// Pause before the interruption (e.g. user already paused).
|
|
1122
|
-
c.
|
|
1043
|
+
c.setPlayWhenReady(false)
|
|
1123
1044
|
c.avPlayerDidChangeTimeControlStatus(.paused)
|
|
1124
1045
|
#expect(c.state == .paused)
|
|
1125
1046
|
|
|
@@ -1132,10 +1053,9 @@ struct InterruptionTests {
|
|
|
1132
1053
|
|
|
1133
1054
|
// MARK: - Skip availability freshness
|
|
1134
1055
|
|
|
1135
|
-
///
|
|
1136
|
-
/// shuffle order
|
|
1137
|
-
|
|
1138
|
-
@Suite("PlaybackCoordinator - skip availability after mutations")
|
|
1056
|
+
/// A mutation pushes next/previous availability once, after currentIndex and the
|
|
1057
|
+
/// shuffle order have settled; an earlier push leaves the lock-screen buttons wrong.
|
|
1058
|
+
@Suite("Player - skip availability after mutations")
|
|
1139
1059
|
struct MutationSkipAvailabilityTests {
|
|
1140
1060
|
@Test @MainActor
|
|
1141
1061
|
func move_pushesPostMutationAvailability() throws {
|
|
@@ -1149,6 +1069,7 @@ struct MutationSkipAvailabilityTests {
|
|
|
1149
1069
|
try c.move(fromIndex: 0, toIndex: 1)
|
|
1150
1070
|
|
|
1151
1071
|
// Current track is now last: nothing to skip to.
|
|
1072
|
+
#expect(eh.updateSkipAvailabilityCalls.count == 1)
|
|
1152
1073
|
#expect(eh.updateSkipAvailabilityCalls.last?.canNext == false)
|
|
1153
1074
|
}
|
|
1154
1075
|
|
|
@@ -1167,49 +1088,180 @@ struct MutationSkipAvailabilityTests {
|
|
|
1167
1088
|
try c.remove(0)
|
|
1168
1089
|
|
|
1169
1090
|
// Current settled at index 1 of 2: previous available, next not.
|
|
1091
|
+
#expect(eh.updateSkipAvailabilityCalls.count == 1)
|
|
1170
1092
|
#expect(eh.updateSkipAvailabilityCalls.last?.canNext == false)
|
|
1171
1093
|
#expect(eh.updateSkipAvailabilityCalls.last?.canPrevious == true)
|
|
1172
1094
|
}
|
|
1173
1095
|
}
|
|
1174
1096
|
|
|
1097
|
+
// MARK: - Publishing
|
|
1098
|
+
|
|
1099
|
+
@Suite("Player - publishing")
|
|
1100
|
+
struct PublishingTests {
|
|
1101
|
+
/// The order JS has always seen: the intent, then the playing state, then the playback. A
|
|
1102
|
+
/// natural end clears the intent on the way in; each change still goes out once.
|
|
1103
|
+
@Test @MainActor
|
|
1104
|
+
func endingPublishesTheIntentThenThePlayingStateThenThePlayback() {
|
|
1105
|
+
let (c, _, cb, _) = makeCoordinator()
|
|
1106
|
+
c.setPlayWhenReady(true)
|
|
1107
|
+
c.transition(.avPlayerPlaying)
|
|
1108
|
+
cb.publishOrder.removeAll()
|
|
1109
|
+
|
|
1110
|
+
c.transition(.trackEndedNaturally)
|
|
1111
|
+
|
|
1112
|
+
#expect(cb.publishOrder == ["playWhenReady", "playingState", "playback"])
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
@Test @MainActor
|
|
1116
|
+
func aTransitionPublishesThePlayingStateBeforeThePlayback() {
|
|
1117
|
+
let (c, _, cb, _) = makeCoordinator()
|
|
1118
|
+
c.setPlayWhenReady(true)
|
|
1119
|
+
cb.publishOrder.removeAll()
|
|
1120
|
+
|
|
1121
|
+
c.transition(.avPlayerPlaying)
|
|
1122
|
+
|
|
1123
|
+
#expect(cb.publishOrder == ["playingState", "playback"])
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
@Test @MainActor
|
|
1127
|
+
func aRepeatedTerminalErrorIsReportedAgain() {
|
|
1128
|
+
let (c, _, cb, _) = makeCoordinator()
|
|
1129
|
+
c.transition(.errorOccurred(.playbackFailed))
|
|
1130
|
+
c.transition(.errorOccurred(.playbackFailed))
|
|
1131
|
+
|
|
1132
|
+
#expect(cb.errorEvents.count == 2)
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// MARK: - Load
|
|
1137
|
+
|
|
1138
|
+
@Suite("Player - Load")
|
|
1139
|
+
struct LoadTests {
|
|
1140
|
+
@MainActor
|
|
1141
|
+
private func track(_ id: String) -> Track {
|
|
1142
|
+
Track(id: id, src: "https://example.com/\(id).mp3", title: id)
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
@Test @MainActor
|
|
1146
|
+
func aNewTrackStartsAnUnprovenLoad() {
|
|
1147
|
+
let (c, _, _, _) = makeCoordinator()
|
|
1148
|
+
c.setQueue([track("a"), track("b")])
|
|
1149
|
+
let first = c.load
|
|
1150
|
+
c.audioDidStart()
|
|
1151
|
+
#expect(c.load?.hasPlayed == true)
|
|
1152
|
+
|
|
1153
|
+
c.next()
|
|
1154
|
+
|
|
1155
|
+
#expect(c.load != nil && c.load?.id != first?.id)
|
|
1156
|
+
#expect(c.load?.hasPlayed == false)
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
/// The healthy-playback refill resets the retry budgets mid-play; the load, and with it the
|
|
1160
|
+
/// recovery budget, must survive it.
|
|
1161
|
+
@Test @MainActor
|
|
1162
|
+
func aRetryResetKeepsTheLoad() {
|
|
1163
|
+
let (c, _, _, _) = makeCoordinator()
|
|
1164
|
+
c.setQueue([track("a")])
|
|
1165
|
+
c.audioDidStart()
|
|
1166
|
+
let load = c.load
|
|
1167
|
+
|
|
1168
|
+
c.retry.reset()
|
|
1169
|
+
|
|
1170
|
+
#expect(c.load == load)
|
|
1171
|
+
#expect(c.load?.hasPlayed == true)
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
@Test @MainActor
|
|
1175
|
+
func theNowPlayingPrimeRunsOncePerLoad() {
|
|
1176
|
+
let (c, _, _, _) = makeCoordinator()
|
|
1177
|
+
c.setQueue([track("a")])
|
|
1178
|
+
#expect(c.claimNowPlayingPrime())
|
|
1179
|
+
#expect(!c.claimNowPlayingPrime())
|
|
1180
|
+
|
|
1181
|
+
c.beginLoad()
|
|
1182
|
+
|
|
1183
|
+
#expect(c.claimNowPlayingPrime())
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
// MARK: - Queue publication
|
|
1188
|
+
|
|
1189
|
+
@Suite("Player - queue publication")
|
|
1190
|
+
struct QueuePublicationTests {
|
|
1191
|
+
@MainActor
|
|
1192
|
+
private func threeTracks() -> [Track] {
|
|
1193
|
+
["a", "b", "c"].map { Track(id: $0, src: "https://example.com/\($0).mp3", title: $0) }
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
@Test @MainActor
|
|
1197
|
+
func setQueue_publishesTheQueueBeforeTheActiveTrack() {
|
|
1198
|
+
let (c, _, cb, _) = makeCoordinator()
|
|
1199
|
+
c.setQueue(threeTracks())
|
|
1200
|
+
#expect(cb.queueChanges.map { $0.map(\.id) } == [["a", "b", "c"]])
|
|
1201
|
+
#expect(cb.queueAndTrackOrder == ["queue", "activeTrack"])
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
@Test @MainActor
|
|
1205
|
+
func move_publishesTheSettledQueueOnce() throws {
|
|
1206
|
+
let (c, _, cb, _) = makeCoordinator()
|
|
1207
|
+
c.setQueue(threeTracks())
|
|
1208
|
+
cb.queueChanges.removeAll()
|
|
1209
|
+
try c.move(fromIndex: 0, toIndex: 2)
|
|
1210
|
+
#expect(cb.queueChanges.map { $0.map(\.id) } == [["b", "c", "a"]])
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
@Test @MainActor
|
|
1214
|
+
func clear_publishesAnEmptyQueue() {
|
|
1215
|
+
let (c, _, cb, _) = makeCoordinator()
|
|
1216
|
+
c.setQueue(threeTracks())
|
|
1217
|
+
cb.queueChanges.removeAll()
|
|
1218
|
+
c.clear()
|
|
1219
|
+
#expect(cb.queueChanges.map(\.count) == [0])
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
@Test @MainActor
|
|
1223
|
+
func navigation_publishesNoQueue() throws {
|
|
1224
|
+
let (c, _, cb, _) = makeCoordinator()
|
|
1225
|
+
c.setQueue(threeTracks())
|
|
1226
|
+
cb.queueChanges.removeAll()
|
|
1227
|
+
c.next()
|
|
1228
|
+
c.previous()
|
|
1229
|
+
try c.skipTo(2)
|
|
1230
|
+
#expect(cb.queueChanges.isEmpty)
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1175
1234
|
// MARK: - Stop cancels pending retry
|
|
1176
1235
|
|
|
1177
|
-
@Suite("
|
|
1236
|
+
@Suite("Player - stop cancels pending retry")
|
|
1178
1237
|
struct StopCancelsRetryTests {
|
|
1179
1238
|
/// A retry surviving stop() gives up later (intent dropped) and surfaced
|
|
1180
1239
|
/// .errorOccurred over the deliberate stop — the UI showed an error seconds
|
|
1181
1240
|
/// after the user stopped.
|
|
1182
1241
|
@Test @MainActor
|
|
1183
1242
|
func stop_cancelsPendingRetry_andStaysSilent() async {
|
|
1184
|
-
let
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
let coordinator = PlaybackCoordinator(
|
|
1190
|
-
errorHandler: errorHandler, sleepTimerManager: MockSleepTimerHandling(),
|
|
1191
|
-
)
|
|
1192
|
-
let effectHandler = MockPlaybackEffectHandler()
|
|
1193
|
-
let callbacks = MockPlaybackCoordinatorCallbacks()
|
|
1194
|
-
coordinator.effectHandler = effectHandler
|
|
1195
|
-
coordinator.callbacks = callbacks
|
|
1243
|
+
let errorHandler = makeRetryLoop(delay: 0.05)
|
|
1244
|
+
let engine = MockPlayerEngine()
|
|
1245
|
+
let player = makePlayer(engine: engine, retry: errorHandler)
|
|
1246
|
+
let callbacks = MockPlayerCallbacks()
|
|
1247
|
+
player.callbacks = callbacks
|
|
1196
1248
|
|
|
1197
1249
|
errorHandler.handleError(URLError(.timedOut), context: .playback)
|
|
1198
|
-
let task = errorHandler.
|
|
1250
|
+
let task = errorHandler.pendingTask
|
|
1199
1251
|
#expect(task != nil)
|
|
1200
1252
|
|
|
1201
|
-
|
|
1202
|
-
#expect(errorHandler.
|
|
1253
|
+
player.stop()
|
|
1254
|
+
#expect(errorHandler.pendingTask == nil)
|
|
1203
1255
|
|
|
1204
1256
|
await task?.value
|
|
1205
|
-
#expect(
|
|
1257
|
+
#expect(player.state == .stopped)
|
|
1206
1258
|
#expect(callbacks.errorEvents.isEmpty)
|
|
1207
1259
|
}
|
|
1208
1260
|
}
|
|
1209
1261
|
|
|
1210
1262
|
// MARK: - Audio session release (#60)
|
|
1211
1263
|
|
|
1212
|
-
@Suite("
|
|
1264
|
+
@Suite("Player - audio session release")
|
|
1213
1265
|
struct SessionReleaseTests {
|
|
1214
1266
|
@Test @MainActor
|
|
1215
1267
|
func deliberatePause_requestsRelease() {
|