react-native-audio-browser 0.1.1 → 0.2.0-next.10

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.
Files changed (1000) hide show
  1. package/AudioBrowser.podspec +1 -1
  2. package/README.md +184 -2
  3. package/android/build.gradle +17 -5
  4. package/android/gradle.properties +2 -2
  5. package/android/src/main/AndroidManifest.xml +18 -1
  6. package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +473 -158
  7. package/android/src/main/java/com/audiobrowser/AudioBrowserLifecycleModule.kt +38 -0
  8. package/android/src/main/java/com/audiobrowser/AudioBrowserPackage.kt +18 -2
  9. package/android/src/main/java/com/audiobrowser/Callbacks.kt +4 -6
  10. package/android/src/main/java/com/audiobrowser/Service.kt +67 -18
  11. package/android/src/main/java/com/audiobrowser/ServiceBinding.kt +48 -0
  12. package/android/src/main/java/com/audiobrowser/browser/ArtworkResolutionRegistry.kt +37 -0
  13. package/android/src/main/java/com/audiobrowser/browser/BrowseArtworkRegistry.kt +34 -0
  14. package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +442 -178
  15. package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +299 -0
  16. package/android/src/main/java/com/audiobrowser/browser/JsonArtwork.kt +79 -0
  17. package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +41 -4
  18. package/android/src/main/java/com/audiobrowser/browser/SectionScope.kt +42 -0
  19. package/android/src/main/java/com/audiobrowser/browser/TrackLoadHandler.kt +4 -4
  20. package/android/src/main/java/com/audiobrowser/extension/ResolvedTrackExt.kt +35 -0
  21. package/android/src/main/java/com/audiobrowser/http/HttpClient.kt +20 -3
  22. package/android/src/main/java/com/audiobrowser/http/RequestConfigBuilder.kt +109 -97
  23. package/android/src/main/java/com/audiobrowser/model/PlaybackMetadata.kt +6 -10
  24. package/android/src/main/java/com/audiobrowser/model/PlayerSetupOptions.kt +40 -8
  25. package/android/src/main/java/com/audiobrowser/model/PlayerUpdateOptions.kt +40 -46
  26. package/android/src/main/java/com/audiobrowser/player/AutomaticBufferManager.kt +4 -1
  27. package/android/src/main/java/com/audiobrowser/player/CapabilityControls.kt +172 -0
  28. package/android/src/main/java/com/audiobrowser/player/DynamicLoadControl.kt +18 -1
  29. package/android/src/main/java/com/audiobrowser/player/EqualizerController.kt +153 -0
  30. package/android/src/main/java/com/audiobrowser/player/InterceptingPlayer.kt +141 -0
  31. package/android/src/main/java/com/audiobrowser/player/MediaFactory.kt +15 -3
  32. package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +422 -134
  33. package/android/src/main/java/com/audiobrowser/player/MediaSessionCommandManager.kt +248 -404
  34. package/android/src/main/java/com/audiobrowser/player/NowPlayingUpdater.kt +347 -0
  35. package/android/src/main/java/com/audiobrowser/player/PlaybackErrorClassifier.kt +129 -0
  36. package/android/src/main/java/com/audiobrowser/player/PlaybackStateMachine.kt +85 -0
  37. package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +25 -5
  38. package/android/src/main/java/com/audiobrowser/player/PlaybackTimer.kt +56 -0
  39. package/android/src/main/java/com/audiobrowser/player/Player.kt +475 -577
  40. package/android/src/main/java/com/audiobrowser/player/PlayerCapabilitiesExt.kt +20 -0
  41. package/android/src/main/java/com/audiobrowser/player/PlayerEngineFactory.kt +130 -0
  42. package/android/src/main/java/com/audiobrowser/player/PlayerListener.kt +190 -67
  43. package/android/src/main/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicy.kt +118 -53
  44. package/android/src/main/java/com/audiobrowser/player/SleepTimer.kt +37 -3
  45. package/android/src/main/java/com/audiobrowser/player/SleepTimerManager.kt +80 -0
  46. package/android/src/main/java/com/audiobrowser/player/StuckRecoveryPolicy.kt +50 -0
  47. package/android/src/main/java/com/audiobrowser/player/TransformingDataSource.kt +85 -40
  48. package/android/src/main/java/com/audiobrowser/player/VolumeFader.kt +81 -0
  49. package/android/src/main/java/com/audiobrowser/tls/AiaCertChaser.kt +156 -0
  50. package/android/src/main/java/com/audiobrowser/tls/AiaChasingExtendedTrustManager.kt +109 -0
  51. package/android/src/main/java/com/audiobrowser/tls/AiaChasingTrustManager.kt +37 -0
  52. package/android/src/main/java/com/audiobrowser/tls/AiaTls.kt +55 -0
  53. package/android/src/main/java/com/audiobrowser/tls/CachingCertificateFetcher.kt +265 -0
  54. package/android/src/main/java/com/audiobrowser/util/ArtworkContentProvider.kt +161 -0
  55. package/android/src/main/java/com/audiobrowser/util/ArtworkUris.kt +28 -0
  56. package/android/src/main/java/com/audiobrowser/util/ArtworkVariant.kt +24 -0
  57. package/android/src/main/java/com/audiobrowser/util/BrowserPathHelper.kt +24 -0
  58. package/android/src/main/java/com/audiobrowser/util/CoilArtworkLoader.kt +49 -0
  59. package/android/src/main/java/com/audiobrowser/util/CoilArtworkLoaderHolder.kt +36 -0
  60. package/android/src/main/java/com/audiobrowser/util/CoilBitmapLoader.kt +23 -300
  61. package/android/src/main/java/com/audiobrowser/util/EqualizerManager.kt +13 -23
  62. package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +2 -2
  63. package/android/src/main/java/com/audiobrowser/util/MetadataAdapter.kt +4 -3
  64. package/android/src/main/java/com/audiobrowser/util/OutputMonitor.kt +211 -0
  65. package/android/src/main/java/com/audiobrowser/util/OutputSwitcher.kt +58 -0
  66. package/android/src/main/java/com/audiobrowser/util/PlayingStateFactory.kt +2 -1
  67. package/android/src/main/java/com/audiobrowser/util/RatingFavorites.kt +14 -0
  68. package/android/src/main/java/com/audiobrowser/util/SvgArtworkRenderer.kt +6 -111
  69. package/android/src/main/java/com/audiobrowser/util/SystemVolumeMonitor.kt +22 -8
  70. package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +112 -80
  71. package/android/src/main/res/values/strings.xml +4 -0
  72. package/android/src/test/java/com/audiobrowser/ServiceBindingTest.kt +87 -0
  73. package/android/src/test/java/com/audiobrowser/TestFixtures.kt +165 -0
  74. package/android/src/test/java/com/audiobrowser/browser/ArtworkResolutionRegistryTest.kt +46 -0
  75. package/android/src/test/java/com/audiobrowser/browser/BrowseArtworkRegistryTest.kt +39 -0
  76. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerBuildApiRequestTest.kt +114 -0
  77. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerLayerResolutionTest.kt +141 -0
  78. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +4 -0
  79. package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +177 -0
  80. package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +55 -0
  81. package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +94 -0
  82. package/android/src/test/java/com/audiobrowser/browser/SimpleRouterTest.kt +1 -2
  83. package/android/src/test/java/com/audiobrowser/http/RequestConfigBuilderTest.kt +72 -0
  84. package/android/src/test/java/com/audiobrowser/player/CapabilityControlsTest.kt +203 -0
  85. package/android/src/test/java/com/audiobrowser/player/DynamicLoadControlTest.kt +56 -0
  86. package/android/src/test/java/com/audiobrowser/player/EqualizerControllerTest.kt +216 -0
  87. package/android/src/test/java/com/audiobrowser/player/MediaSessionSlotMappingTest.kt +45 -0
  88. package/android/src/test/java/com/audiobrowser/player/NowPlayingUpdaterTest.kt +442 -0
  89. package/android/src/test/java/com/audiobrowser/player/PlaybackErrorClassifierTest.kt +190 -0
  90. package/android/src/test/java/com/audiobrowser/player/PlaybackStateMachineTest.kt +198 -0
  91. package/android/src/test/java/com/audiobrowser/player/PlaybackTimerTest.kt +137 -0
  92. package/android/src/test/java/com/audiobrowser/player/PlayerEngineFactoryTest.kt +36 -0
  93. package/android/src/test/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicyTest.kt +268 -0
  94. package/android/src/test/java/com/audiobrowser/player/SessionErrorMaskTest.kt +68 -0
  95. package/android/src/test/java/com/audiobrowser/player/StuckRecoveryPolicyTest.kt +40 -0
  96. package/android/src/test/java/com/audiobrowser/player/TransformingDataSourceTest.kt +193 -0
  97. package/android/src/test/java/com/audiobrowser/tls/AiaCertChaserTest.kt +153 -0
  98. package/android/src/test/java/com/audiobrowser/tls/AiaChasingTrustManagerTest.kt +186 -0
  99. package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherTest.kt +158 -0
  100. package/android/src/test/java/com/audiobrowser/tls/CertFixtures.kt +18 -0
  101. package/android/src/test/java/com/audiobrowser/util/ArtworkContentProviderTest.kt +163 -0
  102. package/android/src/test/java/com/audiobrowser/util/ArtworkUrisTest.kt +34 -0
  103. package/android/src/test/java/com/audiobrowser/util/BrowserPathHelperTest.kt +28 -0
  104. package/android/src/test/java/com/audiobrowser/util/CoilArtworkLoaderHolderTest.kt +53 -0
  105. package/android/src/test/java/com/audiobrowser/util/CoilArtworkLoaderTest.kt +58 -0
  106. package/android/src/test/java/com/audiobrowser/util/FakeImageLoader.kt +57 -0
  107. package/android/src/test/java/com/audiobrowser/util/PlayingStateFactoryTest.kt +40 -0
  108. package/android/src/test/java/com/audiobrowser/util/RatingFavoritesTest.kt +34 -0
  109. package/android/src/test/java/com/audiobrowser/util/TrackFactoryBrowseTest.kt +50 -0
  110. package/android/src/test/java/com/audiobrowser/util/TrackFactoryMediaIdTest.kt +63 -0
  111. package/android/src/test/java/com/audiobrowser/util/TrackFactoryRatingTest.kt +35 -0
  112. package/android/src/test/resources/certs/isrg-root-x1.pem +31 -0
  113. package/android/src/test/resources/certs/letsencrypt-r13.der +0 -0
  114. package/android/src/test/resources/certs/letsencrypt-r13.pem +29 -0
  115. package/android/src/test/resources/certs/stationplaylist-leaf.pem +34 -0
  116. package/ios/Browser/BrowserConfig.swift +41 -11
  117. package/ios/Browser/BrowserManager+URLResolution.swift +213 -93
  118. package/ios/Browser/BrowserManager.swift +303 -135
  119. package/ios/Browser/BrowserPathHelper.swift +32 -3
  120. package/ios/Browser/JsonModels.swift +287 -66
  121. package/ios/Browser/MediaResolveComposer.swift +114 -0
  122. package/ios/Browser/SearchDrillIn.swift +44 -0
  123. package/ios/Browser/SectionScope.swift +35 -0
  124. package/ios/Browser/TabBarEntries.swift +15 -0
  125. package/ios/CarPlay/CPInterfaceController+Safe.swift +126 -0
  126. package/ios/CarPlay/CarPlayArtworkResolver.swift +6 -6
  127. package/ios/CarPlay/CarPlayController.swift +739 -149
  128. package/ios/CarPlay/CarPlayImageLoader.swift +57 -8
  129. package/ios/CarPlay/CarPlayListItemFactory.swift +44 -35
  130. package/ios/CarPlay/CarPlayNowPlayingManager.swift +180 -36
  131. package/ios/CarPlay/ImageRowItem+CarPlay.swift +19 -0
  132. package/ios/CarPlay/RNABAudioBrowser.h +15 -10
  133. package/ios/CarPlay/RNABAudioBrowser.m +15 -14
  134. package/ios/CarPlay/RNABCarPlaySceneDelegate.m +2 -0
  135. package/ios/CarPlay/RNABMediaAddHandler.swift +75 -0
  136. package/ios/CarPlay/RNABMediaAffinityHandler.swift +69 -0
  137. package/ios/CarPlay/RNABMediaIntentHandler.swift +53 -43
  138. package/ios/Extension/Capability+RemoteCommand.swift +7 -9
  139. package/ios/Extension/ChapterMetadata+AVFoundation.swift +1 -1
  140. package/ios/Extension/NavigationError+Conversion.swift +8 -1
  141. package/ios/Extension/PlayerCapabilities+Favorite.swift +20 -0
  142. package/ios/Extension/RequestConfig+Copying.swift +31 -0
  143. package/ios/Extension/ResolvedTrack+Copying.swift +10 -4
  144. package/ios/Extension/TimedMetadata+AVFoundation.swift +1 -1
  145. package/ios/Extension/Track+AVPlayer.swift +4 -4
  146. package/ios/Extension/Track+Copying.swift +9 -3
  147. package/ios/Extension/TrackMetadata+AVFoundation.swift +1 -1
  148. package/ios/Extension/Variant+Artwork.swift +49 -0
  149. package/ios/HybridAudioBrowser.swift +805 -197
  150. package/ios/Model/NitroTypeStubs.swift +299 -224
  151. package/ios/Model/PlayerUpdateOptions.swift +23 -23
  152. package/ios/Model/RemoteCommand.swift +24 -6
  153. package/ios/Model/TrackPlayerError.swift +82 -18
  154. package/ios/NowPlayingInfo/NowPlayingInfoController.swift +99 -121
  155. package/ios/NowPlayingInfo/SilentAudioPrimer.swift +73 -0
  156. package/ios/Observer/PlayerItemNotificationObserver.swift +45 -5
  157. package/ios/Observer/PlayerItemPropertyObserver.swift +27 -4
  158. package/ios/Observer/PlayerTimeObserver.swift +3 -53
  159. package/ios/Option/SessionCategories.swift +34 -11
  160. package/ios/Player/AirPlayStallJudgement.swift +25 -0
  161. package/ios/Player/EndOfTrackJudgement.swift +32 -0
  162. package/ios/Player/LoadSeekCoordinator.swift +16 -1
  163. package/ios/Player/MediaIntentCriteria.swift +139 -0
  164. package/ios/Player/MediaLoader.swift +31 -11
  165. package/ios/Player/NowPlayingUpdater.swift +119 -26
  166. package/ios/Player/PersistedPlaybackState.swift +11 -0
  167. package/ios/Player/PlaybackCoordinator.swift +285 -51
  168. package/ios/Player/PlaybackCoordinatorCallbacks.swift +6 -1
  169. package/ios/Player/PlaybackEffectHandler.swift +19 -9
  170. package/ios/Player/PlaybackErrorHandler.swift +98 -14
  171. package/ios/Player/PlaybackStateMachine.swift +18 -13
  172. package/ios/Player/PlaybackStateStore.swift +27 -0
  173. package/ios/Player/PlaybackTimer.swift +61 -0
  174. package/ios/Player/PlayingStateManager.swift +3 -2
  175. package/ios/Player/QueueManager.swift +77 -64
  176. package/ios/Player/RetryManager.swift +175 -38
  177. package/ios/Player/ShuffleOrder.swift +10 -0
  178. package/ios/Player/SleepTimerHandling.swift +8 -0
  179. package/ios/Player/SleepTimerManager.swift +72 -11
  180. package/ios/Player/VolumeFader.swift +77 -0
  181. package/ios/RemoteCommand/RemoteCommandCallbacks.swift +47 -0
  182. package/ios/RemoteCommand/RemoteCommandController.swift +40 -21
  183. package/ios/Tests/AirPlayStallJudgementTests.swift +52 -0
  184. package/ios/Tests/BrowserPathHelperTests.swift +28 -0
  185. package/ios/Tests/CarPlayArtworkResolverTests.swift +39 -39
  186. package/ios/Tests/ChapterMetadataAVFoundationTests.swift +2 -2
  187. package/ios/Tests/EndOfTrackJudgementTests.swift +35 -0
  188. package/ios/Tests/JsonModelsTests.swift +58 -0
  189. package/ios/Tests/LRUCacheTests.swift +111 -0
  190. package/ios/Tests/LoadSeekCoordinatorTests.swift +40 -7
  191. package/ios/Tests/MediaIntentCriteriaTests.swift +170 -0
  192. package/ios/Tests/MediaLoaderAssetOptionsTests.swift +46 -0
  193. package/ios/Tests/MediaLoaderTests.swift +32 -20
  194. package/ios/Tests/MediaResolveTests.swift +126 -0
  195. package/ios/Tests/OnceValueTests.swift +79 -0
  196. package/ios/Tests/PlaybackCoordinatorTests.swift +787 -13
  197. package/ios/Tests/PlaybackErrorHandlerTests.swift +383 -47
  198. package/ios/Tests/PlaybackStateMachineTests.swift +33 -8
  199. package/ios/Tests/PlaybackStateStoreTests.swift +48 -0
  200. package/ios/Tests/PlaybackTimerTests.swift +55 -0
  201. package/ios/Tests/PlayerTimeObserverTests.swift +37 -0
  202. package/ios/Tests/PlayingStateManagerTests.swift +57 -0
  203. package/ios/Tests/QueueManagerTests.swift +195 -18
  204. package/ios/Tests/RemoteCommandControllerTests.swift +156 -0
  205. package/ios/Tests/RemoteCommandTests.swift +67 -0
  206. package/ios/Tests/ResolvedTrackCopyingTests.swift +15 -8
  207. package/ios/Tests/RetryManagerTests.swift +178 -0
  208. package/ios/Tests/SearchDrillInTests.swift +63 -0
  209. package/ios/Tests/SectionScopeTests.swift +82 -0
  210. package/ios/Tests/SleepTimerManagerTests.swift +107 -0
  211. package/ios/Tests/Support/ManualSleepTimerScheduler.swift +47 -0
  212. package/ios/Tests/Support/TestTypes.swift +61 -20
  213. package/ios/Tests/TabBarEntriesTests.swift +71 -0
  214. package/ios/Tests/TrackSelectorTests.swift +15 -15
  215. package/ios/TrackPlayer.swift +385 -58
  216. package/ios/TrackPlayerCallbacks.swift +5 -44
  217. package/ios/TrackSelector.swift +5 -5
  218. package/ios/Util/ArtworkImageFetcher.swift +4 -2
  219. package/ios/Util/LRUCache.swift +4 -1
  220. package/ios/Util/NetworkMonitor.swift +7 -3
  221. package/ios/Util/OnceValue.swift +34 -0
  222. package/lib/commonjs/AudioBrowser.js +0 -11
  223. package/lib/commonjs/AudioBrowser.js.map +1 -1
  224. package/lib/commonjs/CLAUDE.md +52 -0
  225. package/lib/commonjs/features/browser-config.js +227 -0
  226. package/lib/commonjs/features/browser-config.js.map +1 -0
  227. package/lib/commonjs/features/browser.js +60 -159
  228. package/lib/commonjs/features/browser.js.map +1 -1
  229. package/lib/commonjs/features/carConnection.js +42 -0
  230. package/lib/commonjs/features/carConnection.js.map +1 -0
  231. package/lib/commonjs/features/equalizer.js +1 -1
  232. package/lib/commonjs/features/errors.js +37 -5
  233. package/lib/commonjs/features/errors.js.map +1 -1
  234. package/lib/commonjs/features/favorites.js +1 -1
  235. package/lib/commonjs/features/gate.js +164 -0
  236. package/lib/commonjs/features/gate.js.map +1 -0
  237. package/lib/commonjs/features/index.js +22 -0
  238. package/lib/commonjs/features/index.js.map +1 -1
  239. package/lib/commonjs/features/metadata.js +20 -3
  240. package/lib/commonjs/features/metadata.js.map +1 -1
  241. package/lib/commonjs/features/network.js +1 -1
  242. package/lib/commonjs/features/nowPlaying.js +36 -1
  243. package/lib/commonjs/features/nowPlaying.js.map +1 -1
  244. package/lib/commonjs/features/output.js +37 -23
  245. package/lib/commonjs/features/output.js.map +1 -1
  246. package/lib/commonjs/features/playback/controls.js +9 -0
  247. package/lib/commonjs/features/playback/controls.js.map +1 -1
  248. package/lib/commonjs/features/playback/index.js +11 -0
  249. package/lib/commonjs/features/playback/index.js.map +1 -1
  250. package/lib/commonjs/features/playback/playWhenReady.js +1 -1
  251. package/lib/commonjs/features/playback/playing.js +1 -1
  252. package/lib/commonjs/features/playback/progress.js +29 -13
  253. package/lib/commonjs/features/playback/progress.js.map +1 -1
  254. package/lib/commonjs/features/playback/state.js +1 -1
  255. package/lib/commonjs/features/playback/trackPlaybackTime.js +86 -0
  256. package/lib/commonjs/features/playback/trackPlaybackTime.js.map +1 -0
  257. package/lib/commonjs/features/playback/volume.js +2 -2
  258. package/lib/commonjs/features/player/options.js +79 -29
  259. package/lib/commonjs/features/player/options.js.map +1 -1
  260. package/lib/commonjs/features/player/setup.js +256 -3
  261. package/lib/commonjs/features/player/setup.js.map +1 -1
  262. package/lib/commonjs/features/player/validateOptions.js +21 -0
  263. package/lib/commonjs/features/player/validateOptions.js.map +1 -0
  264. package/lib/commonjs/features/queue/activeTrack.js +1 -1
  265. package/lib/commonjs/features/queue/queue.js +12 -5
  266. package/lib/commonjs/features/queue/queue.js.map +1 -1
  267. package/lib/commonjs/features/queue/repeatMode.js +1 -1
  268. package/lib/commonjs/features/queue/shuffle.js +1 -1
  269. package/lib/commonjs/features/remoteControls.js +14 -104
  270. package/lib/commonjs/features/remoteControls.js.map +1 -1
  271. package/lib/commonjs/features/sleepTimer.js +22 -5
  272. package/lib/commonjs/features/sleepTimer.js.map +1 -1
  273. package/lib/commonjs/native.js +5 -0
  274. package/lib/commonjs/native.js.map +1 -1
  275. package/lib/commonjs/native.web.js +4 -1
  276. package/lib/commonjs/native.web.js.map +1 -1
  277. package/lib/commonjs/test-utils/reactNativeStub.js +65 -0
  278. package/lib/commonjs/test-utils/reactNativeStub.js.map +1 -0
  279. package/lib/commonjs/utils/LazyNativeEmitter.js +8 -8
  280. package/lib/commonjs/utils/LazyNativeEmitter.js.map +1 -1
  281. package/lib/commonjs/utils/NativeUpdatedValue.js +0 -3
  282. package/lib/commonjs/utils/NativeUpdatedValue.js.map +1 -1
  283. package/lib/commonjs/utils/artwork.js +31 -0
  284. package/lib/commonjs/utils/artwork.js.map +1 -0
  285. package/lib/commonjs/web/NativeAudioBrowser.js +302 -125
  286. package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
  287. package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js +71 -0
  288. package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js.map +1 -0
  289. package/lib/commonjs/web/TrackPlayer/PlaybackTimer.js +34 -0
  290. package/lib/commonjs/web/TrackPlayer/PlaybackTimer.js.map +1 -0
  291. package/lib/commonjs/web/TrackPlayer/Player.js +90 -26
  292. package/lib/commonjs/web/TrackPlayer/Player.js.map +1 -1
  293. package/lib/commonjs/web/TrackPlayer/PlayingStateFactory.js +21 -0
  294. package/lib/commonjs/web/TrackPlayer/PlayingStateFactory.js.map +1 -0
  295. package/lib/commonjs/web/TrackPlayer/QueueManager.js +273 -0
  296. package/lib/commonjs/web/TrackPlayer/QueueManager.js.map +1 -0
  297. package/lib/commonjs/web/TrackPlayer/QueuePlayer.js +158 -0
  298. package/lib/commonjs/web/TrackPlayer/QueuePlayer.js.map +1 -0
  299. package/lib/commonjs/web/TrackPlayer/RepeatMode.js +1 -1
  300. package/lib/commonjs/web/TrackPlayer/RepeatMode.js.map +1 -1
  301. package/lib/commonjs/web/TrackPlayer/SleepTimer.js +34 -3
  302. package/lib/commonjs/web/TrackPlayer/SleepTimer.js.map +1 -1
  303. package/lib/commonjs/web/TrackPlayer/VolumeFader.js +75 -0
  304. package/lib/commonjs/web/TrackPlayer/VolumeFader.js.map +1 -0
  305. package/lib/commonjs/web/TrackPlayer/index.js +13 -5
  306. package/lib/commonjs/web/TrackPlayer/index.js.map +1 -1
  307. package/lib/commonjs/web/browser/BrowserManager.js +176 -50
  308. package/lib/commonjs/web/browser/BrowserManager.js.map +1 -1
  309. package/lib/commonjs/web/browser/NavigationErrorManager.js +3 -1
  310. package/lib/commonjs/web/browser/NavigationErrorManager.js.map +1 -1
  311. package/lib/commonjs/web/browser/SearchManager.js +11 -9
  312. package/lib/commonjs/web/browser/SearchManager.js.map +1 -1
  313. package/lib/commonjs/web/browser/assertBrowsePageShape.js +22 -0
  314. package/lib/commonjs/web/browser/assertBrowsePageShape.js.map +1 -0
  315. package/lib/commonjs/web/browser/classifyTrackNavigation.js +41 -0
  316. package/lib/commonjs/web/browser/classifyTrackNavigation.js.map +1 -0
  317. package/lib/commonjs/web/browser/parseSearchResponse.js +20 -0
  318. package/lib/commonjs/web/browser/parseSearchResponse.js.map +1 -0
  319. package/lib/commonjs/web/http/HttpClient.js +4 -23
  320. package/lib/commonjs/web/http/HttpClient.js.map +1 -1
  321. package/lib/commonjs/web/http/RequestConfigBuilder.js +107 -58
  322. package/lib/commonjs/web/http/RequestConfigBuilder.js.map +1 -1
  323. package/lib/commonjs/web/playbackErrorKind.js +57 -0
  324. package/lib/commonjs/web/playbackErrorKind.js.map +1 -0
  325. package/lib/commonjs/web/player/MediaSessionManager.js +121 -0
  326. package/lib/commonjs/web/player/MediaSessionManager.js.map +1 -0
  327. package/lib/commonjs/web/player/NowPlayingManager.js +6 -5
  328. package/lib/commonjs/web/player/NowPlayingManager.js.map +1 -1
  329. package/lib/commonjs/web/player/OptionsManager.js +9 -17
  330. package/lib/commonjs/web/player/OptionsManager.js.map +1 -1
  331. package/lib/commonjs/web/player/RemoteCommandController.js +96 -0
  332. package/lib/commonjs/web/player/RemoteCommandController.js.map +1 -0
  333. package/lib/module/AudioBrowser.js +1 -1
  334. package/lib/module/AudioBrowser.js.map +1 -1
  335. package/lib/module/CLAUDE.md +52 -0
  336. package/lib/module/features/browser-config.js +221 -0
  337. package/lib/module/features/browser-config.js.map +1 -0
  338. package/lib/module/features/browser.js +54 -157
  339. package/lib/module/features/browser.js.map +1 -1
  340. package/lib/module/features/carConnection.js +37 -0
  341. package/lib/module/features/carConnection.js.map +1 -0
  342. package/lib/module/features/equalizer.js +1 -1
  343. package/lib/module/features/errors.js +37 -5
  344. package/lib/module/features/errors.js.map +1 -1
  345. package/lib/module/features/favorites.js +1 -1
  346. package/lib/module/features/gate.js +159 -0
  347. package/lib/module/features/gate.js.map +1 -0
  348. package/lib/module/features/index.js +2 -0
  349. package/lib/module/features/index.js.map +1 -1
  350. package/lib/module/features/metadata.js +20 -3
  351. package/lib/module/features/metadata.js.map +1 -1
  352. package/lib/module/features/network.js +1 -1
  353. package/lib/module/features/nowPlaying.js +34 -1
  354. package/lib/module/features/nowPlaying.js.map +1 -1
  355. package/lib/module/features/output.js +32 -19
  356. package/lib/module/features/output.js.map +1 -1
  357. package/lib/module/features/playback/controls.js +8 -0
  358. package/lib/module/features/playback/controls.js.map +1 -1
  359. package/lib/module/features/playback/index.js +1 -0
  360. package/lib/module/features/playback/index.js.map +1 -1
  361. package/lib/module/features/playback/playWhenReady.js +1 -1
  362. package/lib/module/features/playback/playing.js +1 -1
  363. package/lib/module/features/playback/progress.js +29 -13
  364. package/lib/module/features/playback/progress.js.map +1 -1
  365. package/lib/module/features/playback/state.js +1 -1
  366. package/lib/module/features/playback/trackPlaybackTime.js +83 -0
  367. package/lib/module/features/playback/trackPlaybackTime.js.map +1 -0
  368. package/lib/module/features/playback/volume.js +2 -2
  369. package/lib/module/features/player/options.js +79 -29
  370. package/lib/module/features/player/options.js.map +1 -1
  371. package/lib/module/features/player/setup.js +256 -3
  372. package/lib/module/features/player/setup.js.map +1 -1
  373. package/lib/module/features/player/validateOptions.js +17 -0
  374. package/lib/module/features/player/validateOptions.js.map +1 -0
  375. package/lib/module/features/queue/activeTrack.js +1 -1
  376. package/lib/module/features/queue/queue.js +12 -5
  377. package/lib/module/features/queue/queue.js.map +1 -1
  378. package/lib/module/features/queue/repeatMode.js +1 -1
  379. package/lib/module/features/queue/shuffle.js +1 -1
  380. package/lib/module/features/remoteControls.js +13 -103
  381. package/lib/module/features/remoteControls.js.map +1 -1
  382. package/lib/module/features/sleepTimer.js +22 -5
  383. package/lib/module/features/sleepTimer.js.map +1 -1
  384. package/lib/module/native.js +5 -0
  385. package/lib/module/native.js.map +1 -1
  386. package/lib/module/native.web.js +4 -1
  387. package/lib/module/native.web.js.map +1 -1
  388. package/lib/module/test-utils/reactNativeStub.js +58 -0
  389. package/lib/module/test-utils/reactNativeStub.js.map +1 -0
  390. package/lib/module/utils/LazyNativeEmitter.js +8 -8
  391. package/lib/module/utils/LazyNativeEmitter.js.map +1 -1
  392. package/lib/module/utils/NativeUpdatedValue.js +0 -3
  393. package/lib/module/utils/NativeUpdatedValue.js.map +1 -1
  394. package/lib/module/utils/artwork.js +26 -0
  395. package/lib/module/utils/artwork.js.map +1 -0
  396. package/lib/module/web/NativeAudioBrowser.js +303 -126
  397. package/lib/module/web/NativeAudioBrowser.js.map +1 -1
  398. package/lib/module/web/TrackPlayer/PlaybackStateMachine.js +67 -0
  399. package/lib/module/web/TrackPlayer/PlaybackStateMachine.js.map +1 -0
  400. package/lib/module/web/TrackPlayer/PlaybackTimer.js +29 -0
  401. package/lib/module/web/TrackPlayer/PlaybackTimer.js.map +1 -0
  402. package/lib/module/web/TrackPlayer/Player.js +90 -26
  403. package/lib/module/web/TrackPlayer/Player.js.map +1 -1
  404. package/lib/module/web/TrackPlayer/PlayingStateFactory.js +17 -0
  405. package/lib/module/web/TrackPlayer/PlayingStateFactory.js.map +1 -0
  406. package/lib/module/web/TrackPlayer/QueueManager.js +269 -0
  407. package/lib/module/web/TrackPlayer/QueueManager.js.map +1 -0
  408. package/lib/module/web/TrackPlayer/QueuePlayer.js +154 -0
  409. package/lib/module/web/TrackPlayer/QueuePlayer.js.map +1 -0
  410. package/lib/module/web/TrackPlayer/RepeatMode.js +1 -1
  411. package/lib/module/web/TrackPlayer/RepeatMode.js.map +1 -1
  412. package/lib/module/web/TrackPlayer/SleepTimer.js +34 -3
  413. package/lib/module/web/TrackPlayer/SleepTimer.js.map +1 -1
  414. package/lib/module/web/TrackPlayer/VolumeFader.js +70 -0
  415. package/lib/module/web/TrackPlayer/VolumeFader.js.map +1 -0
  416. package/lib/module/web/TrackPlayer/index.js +2 -1
  417. package/lib/module/web/TrackPlayer/index.js.map +1 -1
  418. package/lib/module/web/browser/BrowserManager.js +176 -50
  419. package/lib/module/web/browser/BrowserManager.js.map +1 -1
  420. package/lib/module/web/browser/NavigationErrorManager.js +3 -1
  421. package/lib/module/web/browser/NavigationErrorManager.js.map +1 -1
  422. package/lib/module/web/browser/SearchManager.js +11 -9
  423. package/lib/module/web/browser/SearchManager.js.map +1 -1
  424. package/lib/module/web/browser/assertBrowsePageShape.js +18 -0
  425. package/lib/module/web/browser/assertBrowsePageShape.js.map +1 -0
  426. package/lib/module/web/browser/classifyTrackNavigation.js +38 -0
  427. package/lib/module/web/browser/classifyTrackNavigation.js.map +1 -0
  428. package/lib/module/web/browser/parseSearchResponse.js +16 -0
  429. package/lib/module/web/browser/parseSearchResponse.js.map +1 -0
  430. package/lib/module/web/http/HttpClient.js +4 -23
  431. package/lib/module/web/http/HttpClient.js.map +1 -1
  432. package/lib/module/web/http/RequestConfigBuilder.js +107 -58
  433. package/lib/module/web/http/RequestConfigBuilder.js.map +1 -1
  434. package/lib/module/web/playbackErrorKind.js +52 -0
  435. package/lib/module/web/playbackErrorKind.js.map +1 -0
  436. package/lib/module/web/player/MediaSessionManager.js +116 -0
  437. package/lib/module/web/player/MediaSessionManager.js.map +1 -0
  438. package/lib/module/web/player/NowPlayingManager.js +7 -5
  439. package/lib/module/web/player/NowPlayingManager.js.map +1 -1
  440. package/lib/module/web/player/OptionsManager.js +9 -17
  441. package/lib/module/web/player/OptionsManager.js.map +1 -1
  442. package/lib/module/web/player/RemoteCommandController.js +92 -0
  443. package/lib/module/web/player/RemoteCommandController.js.map +1 -0
  444. package/lib/typescript/src/AudioBrowser.d.ts +0 -1
  445. package/lib/typescript/src/AudioBrowser.d.ts.map +1 -1
  446. package/lib/typescript/src/features/browser-config.d.ts +12 -0
  447. package/lib/typescript/src/features/browser-config.d.ts.map +1 -0
  448. package/lib/typescript/src/features/browser.d.ts +40 -1
  449. package/lib/typescript/src/features/browser.d.ts.map +1 -1
  450. package/lib/typescript/src/features/carConnection.d.ts +20 -0
  451. package/lib/typescript/src/features/carConnection.d.ts.map +1 -0
  452. package/lib/typescript/src/features/equalizer.d.ts +1 -1
  453. package/lib/typescript/src/features/errors.d.ts +61 -6
  454. package/lib/typescript/src/features/errors.d.ts.map +1 -1
  455. package/lib/typescript/src/features/favorites.d.ts +1 -1
  456. package/lib/typescript/src/features/gate.d.ts +93 -0
  457. package/lib/typescript/src/features/gate.d.ts.map +1 -0
  458. package/lib/typescript/src/features/index.d.ts +2 -0
  459. package/lib/typescript/src/features/index.d.ts.map +1 -1
  460. package/lib/typescript/src/features/metadata.d.ts +26 -7
  461. package/lib/typescript/src/features/metadata.d.ts.map +1 -1
  462. package/lib/typescript/src/features/network.d.ts +1 -1
  463. package/lib/typescript/src/features/nowPlaying.d.ts +28 -1
  464. package/lib/typescript/src/features/nowPlaying.d.ts.map +1 -1
  465. package/lib/typescript/src/features/output.d.ts +28 -18
  466. package/lib/typescript/src/features/output.d.ts.map +1 -1
  467. package/lib/typescript/src/features/playback/controls.d.ts +5 -0
  468. package/lib/typescript/src/features/playback/controls.d.ts.map +1 -1
  469. package/lib/typescript/src/features/playback/index.d.ts +1 -0
  470. package/lib/typescript/src/features/playback/index.d.ts.map +1 -1
  471. package/lib/typescript/src/features/playback/playWhenReady.d.ts +1 -1
  472. package/lib/typescript/src/features/playback/playing.d.ts +1 -1
  473. package/lib/typescript/src/features/playback/progress.d.ts +4 -1
  474. package/lib/typescript/src/features/playback/progress.d.ts.map +1 -1
  475. package/lib/typescript/src/features/playback/state.d.ts +1 -1
  476. package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts +34 -0
  477. package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts.map +1 -0
  478. package/lib/typescript/src/features/playback/volume.d.ts +2 -2
  479. package/lib/typescript/src/features/player/options.d.ts +176 -127
  480. package/lib/typescript/src/features/player/options.d.ts.map +1 -1
  481. package/lib/typescript/src/features/player/setup.d.ts +216 -167
  482. package/lib/typescript/src/features/player/setup.d.ts.map +1 -1
  483. package/lib/typescript/src/features/player/validateOptions.d.ts +9 -0
  484. package/lib/typescript/src/features/player/validateOptions.d.ts.map +1 -0
  485. package/lib/typescript/src/features/queue/activeTrack.d.ts +1 -1
  486. package/lib/typescript/src/features/queue/queue.d.ts +11 -4
  487. package/lib/typescript/src/features/queue/queue.d.ts.map +1 -1
  488. package/lib/typescript/src/features/queue/repeatMode.d.ts +1 -1
  489. package/lib/typescript/src/features/queue/shuffle.d.ts +1 -1
  490. package/lib/typescript/src/features/remoteControls.d.ts +23 -35
  491. package/lib/typescript/src/features/remoteControls.d.ts.map +1 -1
  492. package/lib/typescript/src/features/sleepTimer.d.ts +19 -4
  493. package/lib/typescript/src/features/sleepTimer.d.ts.map +1 -1
  494. package/lib/typescript/src/index.d.ts.map +1 -1
  495. package/lib/typescript/src/native.d.ts +1 -2
  496. package/lib/typescript/src/native.d.ts.map +1 -1
  497. package/lib/typescript/src/specs/audio-browser.nitro.d.ts +17 -225
  498. package/lib/typescript/src/specs/audio-browser.nitro.d.ts.map +1 -1
  499. package/lib/typescript/src/test-utils/reactNativeStub.d.ts +36 -0
  500. package/lib/typescript/src/test-utils/reactNativeStub.d.ts.map +1 -0
  501. package/lib/typescript/src/types/browser-native.d.ts +9 -3
  502. package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
  503. package/lib/typescript/src/types/browser-nodes.d.ts +145 -13
  504. package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
  505. package/lib/typescript/src/types/browser.d.ts +349 -85
  506. package/lib/typescript/src/types/browser.d.ts.map +1 -1
  507. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +8 -6
  508. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts.map +1 -1
  509. package/lib/typescript/src/utils/NativeUpdatedValue.d.ts +0 -2
  510. package/lib/typescript/src/utils/NativeUpdatedValue.d.ts.map +1 -1
  511. package/lib/typescript/src/utils/artwork.d.ts +19 -0
  512. package/lib/typescript/src/utils/artwork.d.ts.map +1 -0
  513. package/lib/typescript/src/utils/resolveAssetSource.d.ts.map +1 -1
  514. package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +4 -2
  515. package/nitrogen/generated/android/AudioBrowserOnLoad.cpp +24 -10
  516. package/nitrogen/generated/android/c++/JAndroidAudioContentType.hpp +6 -6
  517. package/nitrogen/generated/android/c++/JAndroidOptions.hpp +10 -20
  518. package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +33 -1
  519. package/nitrogen/generated/android/c++/JArtworkVariants.hpp +61 -0
  520. package/nitrogen/generated/android/c++/JBrowseResult.hpp +5 -0
  521. package/nitrogen/generated/android/c++/JCarPlayNowPlayingButton.hpp +3 -3
  522. package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +6 -0
  523. package/nitrogen/generated/android/c++/JFavoriteConfig.hpp +58 -0
  524. package/nitrogen/generated/android/c++/JFavoritesMatchMode.hpp +58 -0
  525. package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +100 -0
  526. package/nitrogen/generated/android/c++/JFormattedNavigationError.hpp +3 -2
  527. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.hpp +112 -0
  528. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___RequestConfig_std__optional_std__unordered_map_std__string__std__string__.hpp +121 -0
  529. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +123 -0
  530. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +133 -0
  531. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +121 -0
  532. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.hpp +139 -0
  533. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +6 -0
  534. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.hpp +134 -0
  535. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +8 -0
  536. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +6 -0
  537. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.hpp +131 -0
  538. package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +6 -0
  539. package/nitrogen/generated/android/c++/JFunc_void_GateEvent.hpp +79 -0
  540. package/nitrogen/generated/android/c++/JFunc_void_NowPlayingMetadata.hpp +0 -10
  541. package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +14 -9
  542. package/nitrogen/generated/android/c++/JFunc_void_Output.hpp +80 -0
  543. package/nitrogen/generated/android/c++/JFunc_void_Playback.hpp +2 -0
  544. package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +6 -0
  545. package/nitrogen/generated/android/c++/JFunc_void_PlaybackErrorEvent.hpp +2 -0
  546. package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +10 -10
  547. package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +6 -0
  548. package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +6 -0
  549. package/nitrogen/generated/android/c++/JGate.hpp +62 -0
  550. package/nitrogen/generated/android/c++/JGateDecision.hpp +64 -0
  551. package/nitrogen/generated/android/c++/{JThumbsRating.hpp → JGateEvent.hpp} +16 -15
  552. package/nitrogen/generated/android/c++/JGateReason.hpp +58 -0
  553. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +247 -223
  554. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.hpp +26 -23
  555. package/nitrogen/generated/android/c++/JIOSOptions.hpp +95 -0
  556. package/nitrogen/generated/android/c++/JImageRowItem.hpp +33 -3
  557. package/nitrogen/generated/android/c++/JMediaReference.hpp +58 -0
  558. package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +33 -1
  559. package/nitrogen/generated/android/c++/{JPartialAndroidSetupPlayerOptions.hpp → JNativeAndroidSetupOptions.hpp} +10 -10
  560. package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +61 -28
  561. package/nitrogen/generated/android/c++/JNativeGateRequest.hpp +74 -0
  562. package/nitrogen/generated/android/c++/{JPartialIOSSetupPlayerOptions.hpp → JNativeIOSSetupOptions.hpp} +10 -10
  563. package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +20 -9
  564. package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +182 -0
  565. package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +21 -24
  566. package/nitrogen/generated/android/c++/JNavigationErrorType.hpp +6 -0
  567. package/nitrogen/generated/android/c++/JNitroAndroidUpdateOptions.hpp +10 -20
  568. package/nitrogen/generated/android/c++/JNitroIOSUpdateOptions.hpp +96 -0
  569. package/nitrogen/generated/android/c++/JNowPlayingMetadata.hpp +3 -17
  570. package/nitrogen/generated/android/c++/JNowPlayingUpdate.hpp +7 -3
  571. package/nitrogen/generated/android/c++/JOptions.hpp +19 -14
  572. package/nitrogen/generated/android/c++/{JIosOutput.hpp → JOutput.hpp} +15 -15
  573. package/nitrogen/generated/android/c++/JOutputType.hpp +82 -0
  574. package/nitrogen/generated/android/c++/JPlayback.hpp +2 -0
  575. package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +6 -0
  576. package/nitrogen/generated/android/c++/JPlaybackError.hpp +18 -3
  577. package/nitrogen/generated/android/c++/JPlaybackErrorEvent.hpp +2 -0
  578. package/nitrogen/generated/android/c++/JPlaybackErrorKind.hpp +76 -0
  579. package/nitrogen/generated/android/c++/JPlaybackState.hpp +3 -3
  580. package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +11 -5
  581. package/nitrogen/generated/android/c++/{JNotificationButton.hpp → JRemoteButton.hpp} +20 -20
  582. package/nitrogen/generated/android/c++/JRemoteButtonLayout.hpp +86 -0
  583. package/nitrogen/generated/android/c++/JResolvedTrack.hpp +23 -5
  584. package/nitrogen/generated/android/c++/JRetryConfig.hpp +11 -7
  585. package/nitrogen/generated/android/c++/JSearchMode.hpp +27 -9
  586. package/nitrogen/generated/android/c++/JSearchParams.hpp +9 -3
  587. package/nitrogen/generated/android/c++/JStallReason.hpp +58 -0
  588. package/nitrogen/generated/android/c++/JTrack.hpp +23 -5
  589. package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +6 -0
  590. package/nitrogen/generated/android/c++/JTrackRequest.hpp +93 -0
  591. package/nitrogen/generated/android/c++/JTransformableRequestConfig.hpp +14 -1
  592. package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.cpp +26 -0
  593. package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.hpp +71 -0
  594. package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.cpp +26 -0
  595. package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.hpp +75 -0
  596. package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.cpp +41 -0
  597. package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.hpp +121 -0
  598. package/nitrogen/generated/android/c++/JVariant_String_ArtworkVariants.cpp +26 -0
  599. package/nitrogen/generated/android/c++/JVariant_String_ArtworkVariants.hpp +70 -0
  600. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidAudioContentType.kt +4 -4
  601. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidOptions.kt +3 -9
  602. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ArtworkRequestConfig.kt +10 -4
  603. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ArtworkVariants.kt +41 -0
  604. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayNowPlayingButton.kt +3 -3
  605. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{HeartRating.kt → FavoriteConfig.kt} +6 -6
  606. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{RatingType.kt → FavoritesMatchMode.kt} +5 -10
  607. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormatNowPlayingParams.kt +50 -0
  608. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormattedNavigationError.kt +2 -2
  609. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.kt +80 -0
  610. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___RequestConfig_std__optional_std__unordered_map_std__string__std__string__.kt +80 -0
  611. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___Track.kt +80 -0
  612. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.kt +80 -0
  613. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_std__string____Track.kt +80 -0
  614. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.kt +80 -0
  615. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.kt +80 -0
  616. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.kt → Func_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.kt} +12 -12
  617. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Func_void_RemoteSetRatingEvent.kt → Func_void_GateEvent.kt} +9 -9
  618. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Func_void_IosOutput.kt → Func_void_Output.kt} +9 -9
  619. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_bool.kt +9 -9
  620. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{ThumbsRating.kt → Gate.kt} +9 -6
  621. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{PercentageRating.kt → GateDecision.kt} +9 -6
  622. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{StarRating.kt → GateEvent.kt} +6 -6
  623. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{NotificationButton.kt → GateReason.kt} +5 -8
  624. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HybridAudioBrowserSpec.kt +104 -110
  625. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSOptions.kt +44 -0
  626. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +24 -3
  627. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaReference.kt +23 -0
  628. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaRequestConfig.kt +10 -4
  629. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{PartialAndroidSetupPlayerOptions.kt → NativeAndroidSetupOptions.kt} +5 -5
  630. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +18 -6
  631. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{RemoteSetRatingEvent.kt → NativeGateRequest.kt} +12 -6
  632. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{PartialIOSSetupPlayerOptions.kt → NativeIOSSetupOptions.kt} +5 -5
  633. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeRouteEntry.kt +4 -4
  634. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeSetupPlayerOptions.kt +66 -0
  635. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeUpdateOptions.kt +6 -6
  636. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorType.kt +3 -1
  637. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroAndroidUpdateOptions.kt +3 -9
  638. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroIOSUpdateOptions.kt +44 -0
  639. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingMetadata.kt +3 -6
  640. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingUpdate.kt +6 -3
  641. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Options.kt +3 -3
  642. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{IosOutput.kt → Output.kt} +6 -6
  643. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/OutputType.kt +31 -0
  644. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackError.kt +12 -3
  645. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackErrorKind.kt +29 -0
  646. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackState.kt +6 -6
  647. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
  648. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteButton.kt +26 -0
  649. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteButtonLayout.kt +44 -0
  650. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +12 -3
  651. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RetryConfig.kt +7 -4
  652. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchMode.kt +12 -6
  653. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchParams.kt +6 -3
  654. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StallReason.kt +23 -0
  655. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +12 -3
  656. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackRequest.kt +44 -0
  657. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TransformableRequestConfig.kt +7 -4
  658. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_FavoriteConfig.kt +53 -0
  659. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Variant_NullType_NotificationButtonLayout.kt → Variant_NullType_RemoteButtonLayout.kt} +9 -9
  660. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_ResolvedTrack_BrowseError_Promise_BrowseResult_.kt +65 -0
  661. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_String_ArtworkVariants.kt +53 -0
  662. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.cpp +139 -28
  663. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +1126 -490
  664. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +66 -45
  665. package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +178 -120
  666. package/nitrogen/generated/ios/swift/AndroidAudioContentType.swift +8 -8
  667. package/nitrogen/generated/ios/swift/AndroidOptions.swift +12 -22
  668. package/nitrogen/generated/ios/swift/ArtworkRequestConfig.swift +95 -1
  669. package/nitrogen/generated/ios/swift/ArtworkVariants.swift +34 -0
  670. package/nitrogen/generated/ios/swift/CarPlayNowPlayingButton.swift +4 -4
  671. package/nitrogen/generated/ios/swift/FavoriteConfig.swift +29 -0
  672. package/nitrogen/generated/ios/swift/FavoritesMatchMode.swift +40 -0
  673. package/nitrogen/generated/ios/swift/FormatNowPlayingParams.swift +67 -0
  674. package/nitrogen/generated/ios/swift/FormattedNavigationError.swift +17 -4
  675. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.swift +54 -0
  676. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_RequestConfig___RequestConfig_std__optional_std__unordered_map_std__string__std__string__.swift +69 -0
  677. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_RequestConfig___Track.swift +54 -0
  678. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.swift +60 -0
  679. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__optional_std__string____Track.swift +60 -0
  680. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.swift +61 -0
  681. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.swift +61 -0
  682. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.swift +77 -0
  683. package/nitrogen/generated/ios/swift/Func_void_GateDecision.swift +46 -0
  684. package/nitrogen/generated/ios/swift/{Func_void_RemoteSetRatingEvent.swift → Func_void_GateEvent.swift} +10 -10
  685. package/nitrogen/generated/ios/swift/{Func_void_IosOutput.swift → Func_void_Output.swift} +10 -10
  686. package/nitrogen/generated/ios/swift/Func_void_TransformableRequestConfig.swift +46 -0
  687. package/nitrogen/generated/ios/swift/Func_void_bool.swift +5 -5
  688. package/nitrogen/generated/ios/swift/Func_void_std__optional_NowPlayingUpdate_.swift +46 -0
  689. package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string_.swift +53 -0
  690. package/nitrogen/generated/ios/swift/{Func_void_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError___.swift → Func_void_std__shared_ptr_Promise_GateDecision__.swift} +17 -17
  691. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_TransformableRequestConfig__.swift +66 -0
  692. package/nitrogen/generated/ios/swift/Func_void_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError____.swift +81 -0
  693. package/nitrogen/generated/ios/swift/Gate.swift +47 -0
  694. package/nitrogen/generated/ios/swift/GateDecision.swift +40 -0
  695. package/nitrogen/generated/ios/swift/GateEvent.swift +29 -0
  696. package/nitrogen/generated/ios/swift/GateReason.swift +40 -0
  697. package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec.swift +21 -15
  698. package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec_cxx.swift +232 -199
  699. package/nitrogen/generated/ios/swift/IOSOptions.swift +51 -0
  700. package/nitrogen/generated/ios/swift/ImageRowItem.swift +121 -2
  701. package/nitrogen/generated/ios/swift/MediaReference.swift +40 -0
  702. package/nitrogen/generated/ios/swift/MediaRequestConfig.swift +107 -1
  703. package/nitrogen/generated/ios/swift/{PartialAndroidSetupPlayerOptions.swift → NativeAndroidSetupOptions.swift} +5 -5
  704. package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +161 -22
  705. package/nitrogen/generated/ios/swift/NativeGateRequest.swift +58 -0
  706. package/nitrogen/generated/ios/swift/{PartialIOSSetupPlayerOptions.swift → NativeIOSSetupOptions.swift} +5 -5
  707. package/nitrogen/generated/ios/swift/NativeRouteEntry.swift +19 -19
  708. package/nitrogen/generated/ios/swift/NativeSetupPlayerOptions.swift +206 -0
  709. package/nitrogen/generated/ios/swift/NativeUpdateOptions.swift +12 -25
  710. package/nitrogen/generated/ios/swift/NavigationErrorType.swift +8 -0
  711. package/nitrogen/generated/ios/swift/NitroAndroidUpdateOptions.swift +12 -41
  712. package/nitrogen/generated/ios/swift/NitroIOSUpdateOptions.swift +90 -0
  713. package/nitrogen/generated/ios/swift/NowPlayingMetadata.swift +1 -48
  714. package/nitrogen/generated/ios/swift/NowPlayingUpdate.swift +19 -1
  715. package/nitrogen/generated/ios/swift/Options.swift +10 -4
  716. package/nitrogen/generated/ios/swift/{IosOutput.swift → Output.swift} +7 -7
  717. package/nitrogen/generated/ios/swift/OutputType.swift +72 -0
  718. package/nitrogen/generated/ios/swift/PlaybackError.swift +43 -2
  719. package/nitrogen/generated/ios/swift/PlaybackErrorKind.swift +64 -0
  720. package/nitrogen/generated/ios/swift/PlaybackState.swift +4 -4
  721. package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +27 -8
  722. package/nitrogen/generated/ios/swift/{NotificationButton.swift → RemoteButton.swift} +10 -10
  723. package/nitrogen/generated/ios/swift/RemoteButtonLayout.swift +57 -0
  724. package/nitrogen/generated/ios/swift/ResolvedTrack.swift +74 -8
  725. package/nitrogen/generated/ios/swift/RetryConfig.swift +35 -4
  726. package/nitrogen/generated/ios/swift/SearchMode.swift +36 -12
  727. package/nitrogen/generated/ios/swift/SearchParams.swift +7 -2
  728. package/nitrogen/generated/ios/swift/StallReason.swift +40 -0
  729. package/nitrogen/generated/ios/swift/Track.swift +74 -8
  730. package/nitrogen/generated/ios/swift/TrackRequest.swift +106 -0
  731. package/nitrogen/generated/ios/swift/TransformableRequestConfig.swift +60 -1
  732. package/nitrogen/generated/ios/swift/Variant_Bool_FavoriteConfig.swift +18 -0
  733. package/nitrogen/generated/ios/swift/{Variant_NullType_NotificationButtonLayout.swift → Variant_NullType_RemoteButtonLayout.swift} +3 -3
  734. package/nitrogen/generated/ios/swift/Variant_ResolvedTrack_BrowseError_Promise_BrowseResult_.swift +19 -0
  735. package/nitrogen/generated/ios/swift/Variant_String_ArtworkVariants.swift +18 -0
  736. package/nitrogen/generated/shared/c++/AndroidAudioContentType.hpp +10 -10
  737. package/nitrogen/generated/shared/c++/AndroidOptions.hpp +8 -19
  738. package/nitrogen/generated/shared/c++/ArtworkRequestConfig.hpp +10 -2
  739. package/nitrogen/generated/shared/c++/ArtworkVariants.hpp +87 -0
  740. package/nitrogen/generated/shared/c++/CarPlayNowPlayingButton.hpp +6 -6
  741. package/nitrogen/generated/shared/c++/EqualizerSettings.hpp +0 -2
  742. package/nitrogen/generated/shared/c++/{StarRating.hpp → FavoriteConfig.hpp} +18 -17
  743. package/nitrogen/generated/shared/c++/FavoritesMatchMode.hpp +76 -0
  744. package/nitrogen/generated/shared/c++/FormatNowPlayingParams.hpp +110 -0
  745. package/nitrogen/generated/shared/c++/FormattedNavigationError.hpp +6 -5
  746. package/nitrogen/generated/shared/c++/{PercentageRating.hpp → Gate.hpp} +21 -16
  747. package/nitrogen/generated/shared/c++/{HeartRating.hpp → GateDecision.hpp} +23 -17
  748. package/nitrogen/generated/shared/c++/{ThumbsRating.hpp → GateEvent.hpp} +18 -17
  749. package/nitrogen/generated/shared/c++/GateReason.hpp +76 -0
  750. package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.cpp +22 -19
  751. package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.hpp +45 -36
  752. package/nitrogen/generated/shared/c++/IOSOptions.hpp +91 -0
  753. package/nitrogen/generated/shared/c++/ImageRowItem.hpp +33 -2
  754. package/nitrogen/generated/shared/c++/MediaReference.hpp +76 -0
  755. package/nitrogen/generated/shared/c++/MediaRequestConfig.hpp +10 -2
  756. package/nitrogen/generated/shared/c++/{PartialAndroidSetupPlayerOptions.hpp → NativeAndroidSetupOptions.hpp} +11 -11
  757. package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +31 -15
  758. package/nitrogen/generated/shared/c++/NativeGateRequest.hpp +97 -0
  759. package/nitrogen/generated/shared/c++/{PartialIOSSetupPlayerOptions.hpp → NativeIOSSetupOptions.hpp} +11 -11
  760. package/nitrogen/generated/shared/c++/NativeRouteEntry.hpp +5 -5
  761. package/nitrogen/generated/shared/c++/NativeSetupPlayerOptions.hpp +138 -0
  762. package/nitrogen/generated/shared/c++/NativeUpdateOptions.hpp +9 -7
  763. package/nitrogen/generated/shared/c++/NavigationErrorType.hpp +8 -0
  764. package/nitrogen/generated/shared/c++/NitroAndroidUpdateOptions.hpp +8 -19
  765. package/nitrogen/generated/shared/c++/NitroIOSUpdateOptions.hpp +92 -0
  766. package/nitrogen/generated/shared/c++/NowPlayingMetadata.hpp +3 -19
  767. package/nitrogen/generated/shared/c++/NowPlayingUpdate.hpp +6 -2
  768. package/nitrogen/generated/shared/c++/Options.hpp +8 -8
  769. package/nitrogen/generated/shared/c++/{IosOutput.hpp → Output.hpp} +18 -18
  770. package/nitrogen/generated/shared/c++/OutputType.hpp +108 -0
  771. package/nitrogen/generated/shared/c++/PlaybackError.hpp +18 -3
  772. package/nitrogen/generated/shared/c++/PlaybackErrorKind.hpp +100 -0
  773. package/nitrogen/generated/shared/c++/PlaybackState.hpp +9 -9
  774. package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +9 -6
  775. package/nitrogen/generated/shared/c++/{NotificationButton.hpp → RemoteButton.hpp} +25 -25
  776. package/nitrogen/generated/shared/c++/RemoteButtonLayout.hpp +94 -0
  777. package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +24 -5
  778. package/nitrogen/generated/shared/c++/RetryConfig.hpp +10 -6
  779. package/nitrogen/generated/shared/c++/SearchMode.hpp +39 -15
  780. package/nitrogen/generated/shared/c++/SearchParams.hpp +9 -2
  781. package/nitrogen/generated/shared/c++/StallReason.hpp +76 -0
  782. package/nitrogen/generated/shared/c++/Track.hpp +24 -5
  783. package/nitrogen/generated/shared/c++/TrackRequest.hpp +93 -0
  784. package/nitrogen/generated/shared/c++/TransformableRequestConfig.hpp +6 -2
  785. package/package.json +20 -8
  786. package/src/AudioBrowser.ts +1 -1
  787. package/src/CLAUDE.md +52 -0
  788. package/src/codegen-no-config-variant.test.ts +70 -0
  789. package/src/features/battery.test.ts +79 -0
  790. package/src/features/browser-config.test.ts +110 -0
  791. package/src/features/browser-config.ts +293 -0
  792. package/src/features/browser.test.ts +19 -0
  793. package/src/features/browser.ts +59 -202
  794. package/src/features/carConnection.ts +36 -0
  795. package/src/features/equalizer.ts +1 -1
  796. package/src/features/errors.ts +71 -5
  797. package/src/features/favorites.ts +1 -1
  798. package/src/features/gate.test.ts +72 -0
  799. package/src/features/gate.ts +170 -0
  800. package/src/features/hook-wiring.test.ts +254 -0
  801. package/src/features/index.ts +2 -0
  802. package/src/features/metadata.ts +26 -15
  803. package/src/features/network.ts +1 -1
  804. package/src/features/nowPlaying.ts +37 -1
  805. package/src/features/output.ts +35 -22
  806. package/src/features/playback/controls.ts +8 -0
  807. package/src/features/playback/index.ts +1 -0
  808. package/src/features/playback/playWhenReady.ts +1 -1
  809. package/src/features/playback/playing.ts +1 -1
  810. package/src/features/playback/progress.test.ts +169 -0
  811. package/src/features/playback/progress.ts +32 -13
  812. package/src/features/playback/state.ts +1 -1
  813. package/src/features/playback/trackPlaybackTime.test.ts +76 -0
  814. package/src/features/playback/trackPlaybackTime.ts +101 -0
  815. package/src/features/playback/volume.ts +2 -2
  816. package/src/features/player/options.test.ts +38 -0
  817. package/src/features/player/options.ts +217 -110
  818. package/src/features/player/setup.test.ts +125 -0
  819. package/src/features/player/setup.ts +400 -175
  820. package/src/features/player/validateOptions.ts +19 -0
  821. package/src/features/queue/activeTrack.ts +1 -1
  822. package/src/features/queue/queue.test.ts +36 -0
  823. package/src/features/queue/queue.ts +17 -6
  824. package/src/features/queue/repeatMode.ts +1 -1
  825. package/src/features/queue/shuffle.ts +1 -1
  826. package/src/features/remoteControls.ts +13 -115
  827. package/src/features/sleepTimer.test.ts +172 -0
  828. package/src/features/sleepTimer.ts +32 -5
  829. package/src/native.ts +5 -0
  830. package/src/native.web.ts +4 -1
  831. package/src/public-surface.test.ts +107 -0
  832. package/src/specs/audio-browser.nitro.ts +132 -42
  833. package/src/test-utils/reactNativeStub.ts +60 -0
  834. package/src/types/browser-native.ts +19 -6
  835. package/src/types/browser-nodes.ts +160 -13
  836. package/src/types/browser.ts +377 -89
  837. package/src/utils/LazyNativeEmitter.ts +9 -8
  838. package/src/utils/NativeUpdatedValue.ts +0 -2
  839. package/src/utils/artwork.ts +30 -0
  840. package/src/utils/useDebug.test.ts +182 -0
  841. package/src/utils/useNativeUpdatedValue.test.ts +103 -0
  842. package/src/web/NativeAudioBrowser.playWhenReady.test.ts +301 -0
  843. package/src/web/NativeAudioBrowser.ts +366 -159
  844. package/src/web/TrackPlayer/PlaybackStateMachine.test.ts +139 -0
  845. package/src/web/TrackPlayer/PlaybackStateMachine.ts +82 -0
  846. package/src/web/TrackPlayer/PlaybackTimer.test.ts +67 -0
  847. package/src/web/TrackPlayer/PlaybackTimer.ts +33 -0
  848. package/src/web/TrackPlayer/Player.dispatch.test.ts +229 -0
  849. package/src/web/TrackPlayer/Player.load.test.ts +86 -0
  850. package/src/web/TrackPlayer/Player.ts +113 -39
  851. package/src/web/TrackPlayer/PlayingStateFactory.test.ts +51 -0
  852. package/src/web/TrackPlayer/PlayingStateFactory.ts +24 -0
  853. package/src/web/TrackPlayer/QueueManager.test.ts +289 -0
  854. package/src/web/TrackPlayer/QueueManager.ts +302 -0
  855. package/src/web/TrackPlayer/QueuePlayer.ts +188 -0
  856. package/src/web/TrackPlayer/RepeatMode.ts +1 -1
  857. package/src/web/TrackPlayer/SleepTimer.ts +38 -3
  858. package/src/web/TrackPlayer/VolumeFader.ts +74 -0
  859. package/src/web/TrackPlayer/index.ts +2 -1
  860. package/src/web/browser/BrowserManager.ts +231 -62
  861. package/src/web/browser/NavigationErrorManager.ts +3 -1
  862. package/src/web/browser/SearchManager.ts +11 -15
  863. package/src/web/browser/__tests__/layer-resolver.test.ts +69 -0
  864. package/src/web/browser/assertBrowsePageShape.test.ts +27 -0
  865. package/src/web/browser/assertBrowsePageShape.ts +27 -0
  866. package/src/web/browser/classifyTrackNavigation.test.ts +41 -0
  867. package/src/web/browser/classifyTrackNavigation.ts +35 -0
  868. package/src/web/browser/parseSearchResponse.test.ts +25 -0
  869. package/src/web/browser/parseSearchResponse.ts +15 -0
  870. package/src/web/http/HttpClient.ts +5 -35
  871. package/src/web/http/RequestConfigBuilder.test.ts +59 -0
  872. package/src/web/http/RequestConfigBuilder.ts +120 -63
  873. package/src/web/playbackErrorKind.test.ts +55 -0
  874. package/src/web/playbackErrorKind.ts +56 -0
  875. package/src/web/player/MediaSessionManager.test.ts +220 -0
  876. package/src/web/player/MediaSessionManager.ts +151 -0
  877. package/src/web/player/NowPlayingManager.test.ts +46 -0
  878. package/src/web/player/NowPlayingManager.ts +6 -5
  879. package/src/web/player/OptionsManager.ts +12 -18
  880. package/src/web/player/RemoteCommandController.test.ts +171 -0
  881. package/src/web/player/RemoteCommandController.ts +166 -0
  882. package/android/src/main/java/com/audiobrowser/player/PlaybackProgressUpdateManager.kt +0 -59
  883. package/android/src/main/java/com/audiobrowser/util/RatingFactory.kt +0 -72
  884. package/android/src/main/java/com/audiobrowser/util/ResolvedTrackFactory.kt +0 -36
  885. package/android/src/test/java/com/audiobrowser/player/PlaybackProgressUpdateManagerTest.kt +0 -146
  886. package/ios/CarPlay/Track+CarPlay.swift +0 -63
  887. package/ios/Model/MediaURL.swift +0 -67
  888. package/ios/NowPlayingInfo/NowPlayingInfoCenter.swift +0 -9
  889. package/ios/Player/PlaybackProgressUpdateManager.swift +0 -68
  890. package/ios/Tests/PlaybackProgressUpdateManagerTests.swift +0 -166
  891. package/lib/commonjs/features/rating.js +0 -2
  892. package/lib/commonjs/features/rating.js.map +0 -1
  893. package/lib/commonjs/types/player.js +0 -2
  894. package/lib/commonjs/types/player.js.map +0 -1
  895. package/lib/commonjs/web/SimpleRouter.test.js +0 -174
  896. package/lib/commonjs/web/SimpleRouter.test.js.map +0 -1
  897. package/lib/commonjs/web/TrackPlayer/PlaylistPlayer.js +0 -293
  898. package/lib/commonjs/web/TrackPlayer/PlaylistPlayer.js.map +0 -1
  899. package/lib/module/features/rating.js +0 -2
  900. package/lib/module/features/rating.js.map +0 -1
  901. package/lib/module/types/player.js +0 -2
  902. package/lib/module/types/player.js.map +0 -1
  903. package/lib/module/web/SimpleRouter.test.js +0 -174
  904. package/lib/module/web/SimpleRouter.test.js.map +0 -1
  905. package/lib/module/web/TrackPlayer/PlaylistPlayer.js +0 -288
  906. package/lib/module/web/TrackPlayer/PlaylistPlayer.js.map +0 -1
  907. package/lib/typescript/src/features/rating.d.ts +0 -14
  908. package/lib/typescript/src/features/rating.d.ts.map +0 -1
  909. package/lib/typescript/src/native.web.d.ts +0 -3
  910. package/lib/typescript/src/native.web.d.ts.map +0 -1
  911. package/lib/typescript/src/types/player.d.ts +0 -64
  912. package/lib/typescript/src/types/player.d.ts.map +0 -1
  913. package/lib/typescript/src/web/NativeAudioBrowser.d.ts +0 -188
  914. package/lib/typescript/src/web/NativeAudioBrowser.d.ts.map +0 -1
  915. package/lib/typescript/src/web/SimpleRouter.d.ts +0 -40
  916. package/lib/typescript/src/web/SimpleRouter.d.ts.map +0 -1
  917. package/lib/typescript/src/web/SimpleRouter.test.d.ts +0 -2
  918. package/lib/typescript/src/web/SimpleRouter.test.d.ts.map +0 -1
  919. package/lib/typescript/src/web/TrackPlayer/Event.d.ts +0 -11
  920. package/lib/typescript/src/web/TrackPlayer/Event.d.ts.map +0 -1
  921. package/lib/typescript/src/web/TrackPlayer/Player.d.ts +0 -59
  922. package/lib/typescript/src/web/TrackPlayer/Player.d.ts.map +0 -1
  923. package/lib/typescript/src/web/TrackPlayer/PlaylistPlayer.d.ts +0 -39
  924. package/lib/typescript/src/web/TrackPlayer/PlaylistPlayer.d.ts.map +0 -1
  925. package/lib/typescript/src/web/TrackPlayer/RepeatMode.d.ts +0 -6
  926. package/lib/typescript/src/web/TrackPlayer/RepeatMode.d.ts.map +0 -1
  927. package/lib/typescript/src/web/TrackPlayer/SetupNotCalledError.d.ts +0 -4
  928. package/lib/typescript/src/web/TrackPlayer/SetupNotCalledError.d.ts.map +0 -1
  929. package/lib/typescript/src/web/TrackPlayer/SleepTimer.d.ts +0 -34
  930. package/lib/typescript/src/web/TrackPlayer/SleepTimer.d.ts.map +0 -1
  931. package/lib/typescript/src/web/TrackPlayer/State.d.ts +0 -13
  932. package/lib/typescript/src/web/TrackPlayer/State.d.ts.map +0 -1
  933. package/lib/typescript/src/web/TrackPlayer/index.d.ts +0 -5
  934. package/lib/typescript/src/web/TrackPlayer/index.d.ts.map +0 -1
  935. package/lib/typescript/src/web/browser/BrowserManager.d.ts +0 -154
  936. package/lib/typescript/src/web/browser/BrowserManager.d.ts.map +0 -1
  937. package/lib/typescript/src/web/browser/FavoriteManager.d.ts +0 -42
  938. package/lib/typescript/src/web/browser/FavoriteManager.d.ts.map +0 -1
  939. package/lib/typescript/src/web/browser/NavigationErrorManager.d.ts +0 -40
  940. package/lib/typescript/src/web/browser/NavigationErrorManager.d.ts.map +0 -1
  941. package/lib/typescript/src/web/browser/SearchManager.d.ts +0 -22
  942. package/lib/typescript/src/web/browser/SearchManager.d.ts.map +0 -1
  943. package/lib/typescript/src/web/http/HttpClient.d.ts +0 -25
  944. package/lib/typescript/src/web/http/HttpClient.d.ts.map +0 -1
  945. package/lib/typescript/src/web/http/RequestConfigBuilder.d.ts +0 -98
  946. package/lib/typescript/src/web/http/RequestConfigBuilder.d.ts.map +0 -1
  947. package/lib/typescript/src/web/player/NowPlayingManager.d.ts +0 -34
  948. package/lib/typescript/src/web/player/NowPlayingManager.d.ts.map +0 -1
  949. package/lib/typescript/src/web/player/OptionsManager.d.ts +0 -32
  950. package/lib/typescript/src/web/player/OptionsManager.d.ts.map +0 -1
  951. package/lib/typescript/src/web/util/BrowserPathHelper.d.ts +0 -69
  952. package/lib/typescript/src/web/util/BrowserPathHelper.d.ts.map +0 -1
  953. package/lib/typescript/src/web/util/shuffle.d.ts +0 -8
  954. package/lib/typescript/src/web/util/shuffle.d.ts.map +0 -1
  955. package/nitrogen/generated/android/c++/JAndroidUpdateOptions.hpp +0 -86
  956. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.hpp +0 -147
  957. package/nitrogen/generated/android/c++/JFunc_void_IosOutput.hpp +0 -80
  958. package/nitrogen/generated/android/c++/JFunc_void_RemoteSetRatingEvent.hpp +0 -87
  959. package/nitrogen/generated/android/c++/JHeartRating.hpp +0 -57
  960. package/nitrogen/generated/android/c++/JIosOutputType.hpp +0 -85
  961. package/nitrogen/generated/android/c++/JNotificationButtonLayout.hpp +0 -94
  962. package/nitrogen/generated/android/c++/JPartialSetupPlayerOptions.hpp +0 -96
  963. package/nitrogen/generated/android/c++/JPercentageRating.hpp +0 -57
  964. package/nitrogen/generated/android/c++/JRatingType.hpp +0 -73
  965. package/nitrogen/generated/android/c++/JRemoteSetRatingEvent.hpp +0 -66
  966. package/nitrogen/generated/android/c++/JStarRating.hpp +0 -57
  967. package/nitrogen/generated/android/c++/JUpdateOptions.hpp +0 -105
  968. package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.cpp +0 -34
  969. package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.hpp +0 -105
  970. package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.cpp +0 -26
  971. package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.hpp +0 -75
  972. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidUpdateOptions.kt +0 -50
  973. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IosOutputType.kt +0 -32
  974. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButtonLayout.kt +0 -50
  975. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialSetupPlayerOptions.kt +0 -47
  976. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/UpdateOptions.kt +0 -53
  977. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.kt +0 -77
  978. package/nitrogen/generated/ios/swift/AndroidUpdateOptions.swift +0 -119
  979. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.swift +0 -68
  980. package/nitrogen/generated/ios/swift/HeartRating.swift +0 -29
  981. package/nitrogen/generated/ios/swift/IosOutputType.swift +0 -76
  982. package/nitrogen/generated/ios/swift/NotificationButtonLayout.swift +0 -92
  983. package/nitrogen/generated/ios/swift/PartialSetupPlayerOptions.swift +0 -101
  984. package/nitrogen/generated/ios/swift/PercentageRating.swift +0 -29
  985. package/nitrogen/generated/ios/swift/RatingType.swift +0 -60
  986. package/nitrogen/generated/ios/swift/RemoteSetRatingEvent.swift +0 -58
  987. package/nitrogen/generated/ios/swift/StarRating.swift +0 -29
  988. package/nitrogen/generated/ios/swift/ThumbsRating.swift +0 -29
  989. package/nitrogen/generated/ios/swift/UpdateOptions.swift +0 -143
  990. package/nitrogen/generated/ios/swift/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.swift +0 -20
  991. package/nitrogen/generated/shared/c++/AndroidUpdateOptions.hpp +0 -109
  992. package/nitrogen/generated/shared/c++/IosOutputType.hpp +0 -112
  993. package/nitrogen/generated/shared/c++/NotificationButtonLayout.hpp +0 -102
  994. package/nitrogen/generated/shared/c++/PartialSetupPlayerOptions.hpp +0 -104
  995. package/nitrogen/generated/shared/c++/RatingType.hpp +0 -96
  996. package/nitrogen/generated/shared/c++/RemoteSetRatingEvent.hpp +0 -94
  997. package/nitrogen/generated/shared/c++/UpdateOptions.hpp +0 -111
  998. package/src/features/rating.ts +0 -17
  999. package/src/types/player.ts +0 -69
  1000. package/src/web/TrackPlayer/PlaylistPlayer.ts +0 -346
@@ -0,0 +1,172 @@
1
+ package com.audiobrowser.player
2
+
3
+ import com.margelo.nitro.audiobrowser.PlayerCapabilities
4
+ import com.margelo.nitro.audiobrowser.RemoteButton
5
+ import com.margelo.nitro.audiobrowser.RemoteButtonLayout
6
+
7
+ /**
8
+ * The pure decision core for Capabilities: one rule for whether a Capability is enabled
9
+ * ([isEnabled]) and one derivation of the button layout ([deriveButtonSlots]).
10
+ * MediaSessionCommandManager's Media3 assemblies all consume these decisions — previously each
11
+ * re-implemented them, and the copies had drifted.
12
+ */
13
+
14
+ /**
15
+ * A control that a Capability gates. Mirrors the [PlayerCapabilities] flags Android acts on —
16
+ * `shuffleMode`, `repeatMode` and `playbackRate` exist on the struct but only drive CarPlay, so
17
+ * they have no entry here.
18
+ */
19
+ enum class Capability {
20
+ PLAY_PAUSE,
21
+ STOP,
22
+ SEEK_TO,
23
+ SKIP_TO_NEXT,
24
+ SKIP_TO_PREVIOUS,
25
+ JUMP_FORWARD,
26
+ JUMP_BACKWARD,
27
+ FAVORITE,
28
+ }
29
+
30
+ /**
31
+ * Whether a Capability is enabled. Everything is enabled by default and only an explicit `false`
32
+ * disables — except FAVORITE, which is opt-in, and PLAY_PAUSE, which is one control on every
33
+ * surface and only goes away when both halves are disabled.
34
+ */
35
+ fun PlayerCapabilities.isEnabled(capability: Capability): Boolean =
36
+ when (capability) {
37
+ Capability.PLAY_PAUSE -> !(play == false && pause == false)
38
+ Capability.STOP -> stop != false
39
+ Capability.SEEK_TO -> seekTo != false
40
+ Capability.SKIP_TO_NEXT -> skipToNext != false
41
+ Capability.SKIP_TO_PREVIOUS -> skipToPrevious != false
42
+ Capability.JUMP_FORWARD -> jumpForward != false
43
+ Capability.JUMP_BACKWARD -> jumpBackward != false
44
+ Capability.FAVORITE -> favoriteEnabled
45
+ }
46
+
47
+ /**
48
+ * The three positions Android actually offers, mapped to `CommandButton.SLOT_*` at Media3 assembly
49
+ * time. There is no secondary pair: every system surface flattens the layout to back, forward and
50
+ * overflow, so a fourth or fifth position would have nowhere to render.
51
+ *
52
+ * Media3 does define SLOT_BACK_SECONDARY and SLOT_FORWARD_SECONDARY, but `DisplayConstraints`
53
+ * defaults both to **0 buttons** — only a controller that opts in with `setMaxButtonsForSlot` shows
54
+ * them, which no system surface does.
55
+ */
56
+ enum class ButtonSlot {
57
+ BACK,
58
+ FORWARD,
59
+ OVERFLOW,
60
+ }
61
+
62
+ data class SlottedButton(val button: RemoteButton, val slot: ButtonSlot)
63
+
64
+ /** The Capability gating a button. */
65
+ private val RemoteButton.capability: Capability
66
+ get() =
67
+ when (this) {
68
+ RemoteButton.SKIP_TO_PREVIOUS -> Capability.SKIP_TO_PREVIOUS
69
+ RemoteButton.SKIP_TO_NEXT -> Capability.SKIP_TO_NEXT
70
+ RemoteButton.JUMP_BACKWARD -> Capability.JUMP_BACKWARD
71
+ RemoteButton.JUMP_FORWARD -> Capability.JUMP_FORWARD
72
+ RemoteButton.FAVORITE -> Capability.FAVORITE
73
+ }
74
+
75
+ /** Whether [button]'s gating Capability allows it. */
76
+ fun PlayerCapabilities.allows(button: RemoteButton): Boolean = isEnabled(button.capability)
77
+
78
+ /**
79
+ * Whether two layouts describe the same arrangement.
80
+ *
81
+ * [RemoteButtonLayout] is a generated data class whose `overflow` is an `Array`, and Kotlin
82
+ * data-class equality compares arrays by *reference*. Plain `==` therefore reports "changed" for
83
+ * two identical layouts whenever overflow is set, because every options update carries a fresh
84
+ * array across the bridge — which would republish the layout to Android Auto on every unrelated
85
+ * `updateOptions` call.
86
+ */
87
+ internal fun RemoteButtonLayout?.sameAs(other: RemoteButtonLayout?): Boolean =
88
+ if (this == null || other == null) {
89
+ this == null && other == null
90
+ } else {
91
+ back == other.back && forward == other.forward && overflow.contentEquals(other.overflow)
92
+ }
93
+
94
+ /**
95
+ * The single derivation of the button layout.
96
+ *
97
+ * The two parameters answer different questions, and only one of them is authoritative:
98
+ * - [capabilities] — *may* this button exist? Admission.
99
+ * - [layout] — *where* does it go? Arrangement.
100
+ *
101
+ * **A layout can rearrange buttons but never add one.** Every entry is filtered through [allows]
102
+ * regardless of its position, so naming a button whose Capability is disabled does nothing —
103
+ * listing `FAVORITE` while `capabilities.favorite` is off leaves it off. This is the usual
104
+ * surprise, because JUMP_FORWARD and JUMP_BACKWARD default to disabled: a layout full of jump
105
+ * buttons silently produces none until those capabilities are turned on.
106
+ *
107
+ * With no [layout], [capabilities] does both jobs — it decides membership *and* infers positions:
108
+ * skip takes the primary positions, jump falls back into a primary position when its skip is
109
+ * disabled and otherwise sits in overflow, favorite in overflow.
110
+ *
111
+ * With a [layout], each field maps to its position — `back` to BACK, `forward` to FORWARD, every
112
+ * `overflow` entry to OVERFLOW in order — and disabled entries drop out. A dropped entry leaves its
113
+ * position empty rather than promoting anything into it: turning off one capability must not
114
+ * silently rearrange the row.
115
+ *
116
+ * A [layout] is all-or-nothing: every field is required, so it fully describes the arrangement and
117
+ * nothing is merged with the capability defaults. The bridge could not support a per-field merge
118
+ * anyway — Nitro maps both an omitted and a null enum field to Kotlin `null`, so native cannot tell
119
+ * "leave this empty" from "derive this one".
120
+ *
121
+ * [capabilities] has a second job outside this function: it also drives the player and session
122
+ * commands, which govern what a Bluetooth remote or headset can trigger. That is why placement is
123
+ * purely cosmetic here — a button left out of the layout disappears from every screen while still
124
+ * responding to a headset.
125
+ *
126
+ * @param capabilities What the player is allowed to do. Gates every button, in both modes.
127
+ * @param layout Explicit placement, or null to infer placement from [capabilities].
128
+ */
129
+ fun deriveButtonSlots(
130
+ capabilities: PlayerCapabilities,
131
+ layout: RemoteButtonLayout?,
132
+ ): List<SlottedButton> {
133
+ if (layout != null) {
134
+ return buildList {
135
+ layout.back?.let { add(SlottedButton(it, ButtonSlot.BACK)) }
136
+ layout.forward?.let { add(SlottedButton(it, ButtonSlot.FORWARD)) }
137
+ layout.overflow.forEach { add(SlottedButton(it, ButtonSlot.OVERFLOW)) }
138
+ }
139
+ .filter { capabilities.allows(it.button) }
140
+ }
141
+
142
+ return buildList {
143
+ val skipPrevious = capabilities.isEnabled(Capability.SKIP_TO_PREVIOUS)
144
+ val skipNext = capabilities.isEnabled(Capability.SKIP_TO_NEXT)
145
+ val jumpBackward = capabilities.isEnabled(Capability.JUMP_BACKWARD)
146
+ val jumpForward = capabilities.isEnabled(Capability.JUMP_FORWARD)
147
+
148
+ // Primary positions: skip, with jump falling back when its skip is disabled.
149
+ if (skipPrevious) {
150
+ add(SlottedButton(RemoteButton.SKIP_TO_PREVIOUS, ButtonSlot.BACK))
151
+ } else if (jumpBackward) {
152
+ add(SlottedButton(RemoteButton.JUMP_BACKWARD, ButtonSlot.BACK))
153
+ }
154
+ if (skipNext) {
155
+ add(SlottedButton(RemoteButton.SKIP_TO_NEXT, ButtonSlot.FORWARD))
156
+ } else if (jumpForward) {
157
+ add(SlottedButton(RemoteButton.JUMP_FORWARD, ButtonSlot.FORWARD))
158
+ }
159
+
160
+ // Jump moves to overflow when skip holds the primary position.
161
+ if (skipPrevious && jumpBackward) {
162
+ add(SlottedButton(RemoteButton.JUMP_BACKWARD, ButtonSlot.OVERFLOW))
163
+ }
164
+ if (skipNext && jumpForward) {
165
+ add(SlottedButton(RemoteButton.JUMP_FORWARD, ButtonSlot.OVERFLOW))
166
+ }
167
+
168
+ if (capabilities.isEnabled(Capability.FAVORITE)) {
169
+ add(SlottedButton(RemoteButton.FAVORITE, ButtonSlot.OVERFLOW))
170
+ }
171
+ }
172
+ }
@@ -3,6 +3,7 @@ package com.audiobrowser.player
3
3
  import androidx.media3.common.C
4
4
  import androidx.media3.exoplayer.DefaultLoadControl
5
5
  import androidx.media3.exoplayer.LoadControl
6
+ import androidx.media3.exoplayer.analytics.PlayerId
6
7
  import androidx.media3.exoplayer.source.TrackGroupArray
7
8
  import androidx.media3.exoplayer.trackselection.ExoTrackSelection
8
9
  import androidx.media3.exoplayer.upstream.Allocator
@@ -47,6 +48,15 @@ class DynamicLoadControl(initialConfig: BufferConfig = BufferConfig()) : LoadCon
47
48
  @Volatile private var prepareStartTimeMs: Long = 0
48
49
  @Volatile private var playbackStarted: Boolean = false
49
50
 
51
+ // ExoPlayer's own rebuffering signal (buffer depletion mid-playback, as opposed to an initial
52
+ // connect, a seek, or a track transition). Mirrored from LoadControl.Parameters so consumers
53
+ // (e.g. the now-playing "Buffering…" subtitle) can tell a rebuffer apart from an initial connect.
54
+ @Volatile private var rebuffering: Boolean = false
55
+
56
+ /** Whether playback is currently rebuffering due to buffer depletion (not initial start/seek). */
57
+ val isRebuffering: Boolean
58
+ get() = rebuffering
59
+
50
60
  // Mutable buffer thresholds - can be updated at runtime
51
61
  @Volatile private var minBufferUs: Long = initialConfig.minBufferMs * 1000L
52
62
 
@@ -97,17 +107,23 @@ class DynamicLoadControl(initialConfig: BufferConfig = BufferConfig()) : LoadCon
97
107
  updateBufferConfig(BufferConfig())
98
108
  }
99
109
 
100
- override fun getAllocator(): Allocator = allocator
110
+ // media3 1.10 added a PlayerId parameter for multi-player allocator sharing. This LoadControl is
111
+ // only ever attached to a single ExoPlayer, so we return the same allocator regardless of player.
112
+ override fun getAllocator(playerId: PlayerId): Allocator = allocator
101
113
 
102
114
  override fun getBackBufferDurationUs(): Long = backBufferUs
103
115
 
104
116
  override fun retainBackBufferFromKeyframe(): Boolean = false
105
117
 
106
118
  override fun shouldContinueLoading(parameters: LoadControl.Parameters): Boolean {
119
+ // Refreshed on every load-control poll (all playback states) so the flag clears once a
120
+ // rebuffer recovers, not just while buffering.
121
+ rebuffering = parameters.rebuffering
107
122
  return parameters.bufferedDurationUs < maxBufferUs
108
123
  }
109
124
 
110
125
  override fun shouldStartPlayback(parameters: LoadControl.Parameters): Boolean {
126
+ rebuffering = parameters.rebuffering
111
127
  val bufferedDurationUs = parameters.bufferedDurationUs
112
128
  val targetUs =
113
129
  adjustForPlaybackSpeed(
@@ -141,6 +157,7 @@ class DynamicLoadControl(initialConfig: BufferConfig = BufferConfig()) : LoadCon
141
157
  allocator.reset()
142
158
  prepareStartTimeMs = System.currentTimeMillis()
143
159
  playbackStarted = false
160
+ rebuffering = false
144
161
  }
145
162
 
146
163
  override fun onTracksSelected(
@@ -0,0 +1,153 @@
1
+ package com.audiobrowser.player
2
+
3
+ import androidx.media3.common.C
4
+ import com.audiobrowser.util.EqualizerManager
5
+ import com.margelo.nitro.audiobrowser.EqualizerSettings
6
+ import timber.log.Timber
7
+
8
+ /** The equalizer operations [EqualizerController] drives, so tests can stand in for the effect. */
9
+ internal interface EqualizerEffect {
10
+ val audioSessionId: Int
11
+
12
+ fun getSettings(): EqualizerSettings?
13
+
14
+ fun setOnSettingsChanged(callback: (EqualizerSettings) -> Unit)
15
+
16
+ fun setEnabled(enabled: Boolean)
17
+
18
+ fun setPreset(presetName: String)
19
+
20
+ fun setLevels(levels: DoubleArray)
21
+
22
+ fun release()
23
+ }
24
+
25
+ /**
26
+ * Owns the equalizer's lifecycle across audio sessions. Android's Equalizer effect binds to a
27
+ * single audioSessionId, so there are stretches with no effect at all: startup has no session until
28
+ * the first audio output, and a session change (new ExoPlayer instance) needs a fresh one. Callers
29
+ * see none of that — settings requested during a gap land on whichever effect comes next, and every
30
+ * new effect announces itself through [onSettingsChanged].
31
+ */
32
+ internal class EqualizerController(
33
+ private val onSettingsChanged: (EqualizerSettings) -> Unit,
34
+ private val createEffect: (Int) -> EqualizerEffect = { EqualizerManager(it) },
35
+ ) {
36
+
37
+ private var effect: EqualizerEffect? = null
38
+
39
+ // Settings to apply to the next effect: what the caller asked for during a gap, or what the
40
+ // outgoing effect held across a session change. A preset and custom levels are exclusive — the
41
+ // last one asked for wins, matching how the two setters behave on a live effect.
42
+ private var pendingPreset: String? = null
43
+ private var pendingLevels: DoubleArray? = null
44
+ private var pendingEnabled: Boolean? = null
45
+
46
+ /** Initializes for [audioSessionId]; deferred when the session is still unset. */
47
+ fun initialize(audioSessionId: Int) {
48
+ if (audioSessionId == C.AUDIO_SESSION_ID_UNSET) {
49
+ Timber.d("Skipping equalizer init - no audio session yet, will init on first playback")
50
+ return
51
+ }
52
+ install(audioSessionId)
53
+ }
54
+
55
+ /**
56
+ * Reacts to an audio session change: a no-op for the same session, otherwise a fresh effect that
57
+ * picks up the outgoing one's settings.
58
+ */
59
+ fun onAudioSessionChanged(newAudioSessionId: Int) {
60
+ val old = effect
61
+ if (old != null && old.audioSessionId == newAudioSessionId) return
62
+
63
+ old?.let {
64
+ it.getSettings()?.let(::remember)
65
+ it.release()
66
+ effect = null
67
+ }
68
+ install(newAudioSessionId)
69
+ }
70
+
71
+ fun release() {
72
+ effect?.release()
73
+ effect = null
74
+ }
75
+
76
+ fun getSettings(): EqualizerSettings? = effect?.getSettings()
77
+
78
+ fun setEnabled(enabled: Boolean) {
79
+ val effect = effect
80
+ if (effect == null) {
81
+ pendingEnabled = enabled
82
+ return
83
+ }
84
+ effect.setEnabled(enabled)
85
+ }
86
+
87
+ fun setPreset(preset: String) {
88
+ val effect = effect
89
+ if (effect == null) {
90
+ rememberPreset(preset)
91
+ return
92
+ }
93
+ effect.setPreset(preset)
94
+ }
95
+
96
+ fun setLevels(levels: DoubleArray) {
97
+ val effect = effect
98
+ if (effect == null) {
99
+ rememberLevels(levels)
100
+ return
101
+ }
102
+ effect.setLevels(levels)
103
+ }
104
+
105
+ /**
106
+ * Creates the effect for [audioSessionId] and hands it the pending settings before wiring the
107
+ * callback, so the restore stays silent and the caller gets one event describing the result. A
108
+ * failed create keeps the pending settings for the next attempt.
109
+ */
110
+ private fun install(audioSessionId: Int) {
111
+ val created =
112
+ try {
113
+ createEffect(audioSessionId)
114
+ } catch (e: Exception) {
115
+ Timber.e(e, "Failed to initialize equalizer")
116
+ return
117
+ }
118
+ effect = created
119
+ Timber.d("Equalizer initialized with session ID: $audioSessionId")
120
+
121
+ pendingPreset?.let(created::setPreset)
122
+ pendingLevels?.let(created::setLevels)
123
+ pendingEnabled?.let(created::setEnabled)
124
+ pendingPreset = null
125
+ pendingLevels = null
126
+ pendingEnabled = null
127
+
128
+ created.setOnSettingsChanged(onSettingsChanged)
129
+ // Announce unconditionally. The caller reads the settings once at startup, which is exactly
130
+ // when there may be no effect yet, and nothing else would tell it the equalizer now exists.
131
+ created.getSettings()?.let(onSettingsChanged)
132
+ }
133
+
134
+ private fun remember(settings: EqualizerSettings) {
135
+ val preset = settings.activePreset
136
+ if (preset != null) {
137
+ rememberPreset(preset)
138
+ } else {
139
+ rememberLevels(settings.bandLevels)
140
+ }
141
+ pendingEnabled = settings.enabled
142
+ }
143
+
144
+ private fun rememberPreset(preset: String) {
145
+ pendingPreset = preset
146
+ pendingLevels = null
147
+ }
148
+
149
+ private fun rememberLevels(levels: DoubleArray) {
150
+ pendingLevels = levels
151
+ pendingPreset = null
152
+ }
153
+ }
@@ -0,0 +1,141 @@
1
+ package com.audiobrowser.player
2
+
3
+ import androidx.media3.common.ForwardingPlayer
4
+ import androidx.media3.common.Player as MediaPlayer
5
+ import com.audiobrowser.Callbacks
6
+ import com.audiobrowser.model.PlayerUpdateOptions
7
+ import com.margelo.nitro.audiobrowser.RemoteJumpBackwardEvent
8
+ import com.margelo.nitro.audiobrowser.RemoteJumpForwardEvent
9
+ import com.margelo.nitro.audiobrowser.RemoteSeekEvent
10
+
11
+ /**
12
+ * The session-error masking rules, pure so their truth table is testable: with
13
+ * `keepSessionAliveOnError`, a terminal load error (ExoPlayer idle + error present) is reported to
14
+ * the platform session as paused-but-ready instead of STATE_NONE — Android Auto reads STATE_NONE as
15
+ * "nothing playing" and tears down the now-playing screen, losing the next/previous buttons.
16
+ */
17
+ internal object SessionErrorMask {
18
+ fun playbackState(state: Int, hasError: Boolean, keepAlive: Boolean): Int =
19
+ if (keepAlive && state == MediaPlayer.STATE_IDLE && hasError) MediaPlayer.STATE_READY else state
20
+
21
+ fun playWhenReady(raw: Boolean, state: Int, hasError: Boolean, keepAlive: Boolean): Boolean =
22
+ if (keepAlive && state == MediaPlayer.STATE_IDLE && hasError) false else raw
23
+ }
24
+
25
+ /**
26
+ * The Remote-command seam: intercepts transport controls arriving from External surfaces (lock
27
+ * screen, notification, Bluetooth, Android Auto — all via the MediaSession) and offers each to the
28
+ * app's `handleRemote*` callback first; a callback returning true consumes the command, anything
29
+ * else falls through to the default behavior. Also masks a terminal playback error from the
30
+ * platform session (see [SessionErrorMask]) so the session stays alive and skippable; the error
31
+ * still surfaces via `onPlaybackError` and `playbackState`.
32
+ */
33
+ internal class InterceptingPlayer(
34
+ player: MediaPlayer,
35
+ private val callbacksProvider: () -> Callbacks?,
36
+ private val optionsProvider: () -> PlayerUpdateOptions,
37
+ private val keepSessionAliveOnError: Boolean,
38
+ ) : ForwardingPlayer(player) {
39
+
40
+ // Hide playback errors from the platform session. Media3 builds the legacy PlaybackStateCompat
41
+ // from player.getPlayerError() (-> STATE_ERROR), which Android Auto and the notification render
42
+ // as a disruptive error. The error still surfaces via the onPlaybackError JS callback and
43
+ // `playbackState`, so a now-playing formatter can render it; playback context is preserved.
44
+ override fun getPlayerError(): androidx.media3.common.PlaybackException? = null
45
+
46
+ // Both masks read the real underlying error (super.getPlayerError()) so they're race-free with
47
+ // state-change listeners.
48
+ override fun getPlaybackState(): Int =
49
+ SessionErrorMask.playbackState(
50
+ super.getPlaybackState(),
51
+ hasError = super.getPlayerError() != null,
52
+ keepAlive = keepSessionAliveOnError,
53
+ )
54
+
55
+ override fun getPlayWhenReady(): Boolean =
56
+ SessionErrorMask.playWhenReady(
57
+ super.getPlayWhenReady(),
58
+ super.getPlaybackState(),
59
+ hasError = super.getPlayerError() != null,
60
+ keepAlive = keepSessionAliveOnError,
61
+ )
62
+
63
+ /**
64
+ * A terminal error leaves ExoPlayer idle; the default transport controls (super.play() /
65
+ * super.seekToNext()) then flip playWhenReady or move the queue index but never restart a stopped
66
+ * player. prepare() recovers it (and early-returns when not idle, so it's a no-op during normal
67
+ * playback) — so next/previous/play resume on the selected station from the masked error state
68
+ * instead of doing nothing.
69
+ */
70
+ private fun recoverFromErrorIfNeeded() {
71
+ if (keepSessionAliveOnError && super.getPlayerError() != null) {
72
+ // Through the forwarding chain (no override exists), reaching the wrapped player.
73
+ prepare()
74
+ }
75
+ }
76
+
77
+ /**
78
+ * One definition of the dispatch: offer the command to the app's handler; true consumes it,
79
+ * anything else runs the default (and, for the resuming commands, the idle-error recovery).
80
+ */
81
+ private inline fun intercept(
82
+ handler: (Callbacks) -> Boolean,
83
+ recover: Boolean = false,
84
+ fallback: () -> Unit,
85
+ ) {
86
+ if (callbacksProvider()?.let(handler) == true) return
87
+ fallback()
88
+ if (recover) recoverFromErrorIfNeeded()
89
+ }
90
+
91
+ override fun play() = intercept({ it.handleRemotePlay() }, recover = true) { super.play() }
92
+
93
+ override fun pause() = intercept({ it.handleRemotePause() }) { super.pause() }
94
+
95
+ // Media3 controllers may drive transport via setPlayWhenReady instead of play()/pause()
96
+ // (the documented ForwardingPlayer hazard); route it through the same interception so the
97
+ // remote handlers and the idle-error recovery aren't bypassed.
98
+ override fun setPlayWhenReady(playWhenReady: Boolean) = if (playWhenReady) play() else pause()
99
+
100
+ override fun stop() = intercept({ it.handleRemoteStop() }) { super.stop() }
101
+
102
+ override fun seekToNext() =
103
+ intercept({ it.handleRemoteNext() }, recover = true) { super.seekToNext() }
104
+
105
+ override fun seekToNextMediaItem() =
106
+ intercept({ it.handleRemoteNext() }, recover = true) { super.seekToNextMediaItem() }
107
+
108
+ override fun seekToPrevious() =
109
+ intercept({ it.handleRemotePrevious() }, recover = true) { super.seekToPrevious() }
110
+
111
+ override fun seekToPreviousMediaItem() =
112
+ intercept({ it.handleRemotePrevious() }, recover = true) { super.seekToPreviousMediaItem() }
113
+
114
+ override fun seekForward() =
115
+ intercept({
116
+ it.handleRemoteJumpForward(
117
+ RemoteJumpForwardEvent(interval = optionsProvider().forwardJumpInterval)
118
+ )
119
+ }) {
120
+ super.seekForward()
121
+ }
122
+
123
+ override fun seekBack() =
124
+ intercept({
125
+ it.handleRemoteJumpBackward(
126
+ RemoteJumpBackwardEvent(interval = optionsProvider().backwardJumpInterval)
127
+ )
128
+ }) {
129
+ super.seekBack()
130
+ }
131
+
132
+ override fun seekTo(mediaItemIndex: Int, positionMs: Long) =
133
+ intercept({ it.handleRemoteSeek(RemoteSeekEvent(position = positionMs.toDouble() / 1000.0)) }) {
134
+ super.seekTo(mediaItemIndex, positionMs)
135
+ }
136
+
137
+ override fun seekTo(positionMs: Long) =
138
+ intercept({ it.handleRemoteSeek(RemoteSeekEvent(position = positionMs.toDouble() / 1000.0)) }) {
139
+ super.seekTo(positionMs)
140
+ }
141
+ }
@@ -15,7 +15,7 @@ import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy
15
15
  import androidx.media3.extractor.DefaultExtractorsFactory
16
16
  import com.audiobrowser.model.RetryPolicy
17
17
  import com.margelo.nitro.audiobrowser.MediaRequestConfig
18
- import timber.log.Timber
18
+ import java.io.IOException
19
19
 
20
20
  class MediaFactory(
21
21
  private val context: Context,
@@ -23,7 +23,8 @@ class MediaFactory(
23
23
  private val retryPolicy: RetryPolicy,
24
24
  private val shouldRetry: () -> Boolean,
25
25
  private val isOnline: () -> Boolean = { true },
26
- private val onRetryPending: ((isNetworkError: Boolean) -> Unit)? = null,
26
+ private val hasPlayed: () -> Boolean = { false },
27
+ private val onRetryPending: ((exception: IOException, isNetworkError: Boolean) -> Unit)? = null,
27
28
  private val transferListener: TransferListener? = null,
28
29
  private val getRequestConfig: (originalUrl: String) -> MediaRequestConfig?,
29
30
  ) : MediaSource.Factory {
@@ -45,16 +46,20 @@ class MediaFactory(
45
46
  RetryLoadErrorHandlingPolicy(
46
47
  maxRetries = null,
47
48
  maxRetryDurationMs = retryPolicy.maxRetryDurationMs,
49
+ firstConnectMaxRetryDurationMs = retryPolicy.firstConnectMaxRetryDurationMs,
48
50
  shouldRetry = shouldRetry,
49
51
  isOnline = isOnline,
52
+ hasPlayed = hasPlayed,
50
53
  onRetryPending = onRetryPending,
51
54
  )
52
55
  is RetryPolicy.Limited ->
53
56
  RetryLoadErrorHandlingPolicy(
54
57
  maxRetries = retryPolicy.maxRetries,
55
58
  maxRetryDurationMs = retryPolicy.maxRetryDurationMs,
59
+ firstConnectMaxRetryDurationMs = retryPolicy.firstConnectMaxRetryDurationMs,
56
60
  shouldRetry = shouldRetry,
57
61
  isOnline = isOnline,
62
+ hasPlayed = hasPlayed,
58
63
  onRetryPending = onRetryPending,
59
64
  )
60
65
  }
@@ -92,7 +97,14 @@ class MediaFactory(
92
97
  // JS thread to resolve.
93
98
  val httpFactory =
94
99
  DefaultHttpDataSource.Factory().apply {
95
- setUserAgent(DEFAULT_USER_AGENT)
100
+ // Deliberately NOT setUserAgent(): DefaultHttpDataSource applies the factory
101
+ // user-agent as a FINAL setRequestProperty("User-Agent", …) that runs after —
102
+ // and overrides — the per-request DataSpec headers. That would clobber the
103
+ // User-Agent TransformingDataSource sets per request (the whole point of the
104
+ // per-request userAgent override). Supplying the same value as a default
105
+ // request property keeps the default for un-overridden requests while letting
106
+ // the per-request DataSpec header win.
107
+ setDefaultRequestProperties(mapOf("User-Agent" to DEFAULT_USER_AGENT))
96
108
  setAllowCrossProtocolRedirects(true)
97
109
  // Connect transfer listener for bandwidth measurement
98
110
  transferListener?.let { setTransferListener(it) }