react-native-audio-browser 0.2.0-next.2 → 0.2.0-next.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (660) hide show
  1. package/README.md +35 -21
  2. package/android/build.gradle +35 -12
  3. package/android/gradle.properties +2 -2
  4. package/android/src/main/AndroidManifest.xml +3 -1
  5. package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +389 -164
  6. package/android/src/main/java/com/audiobrowser/AudioBrowserLifecycleModule.kt +38 -0
  7. package/android/src/main/java/com/audiobrowser/AudioBrowserPackage.kt +18 -2
  8. package/android/src/main/java/com/audiobrowser/ServiceBinding.kt +48 -0
  9. package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +315 -213
  10. package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +24 -5
  11. package/android/src/main/java/com/audiobrowser/browser/InertStyleDiagnostic.kt +267 -0
  12. package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +97 -58
  13. package/android/src/main/java/com/audiobrowser/browser/SectionScope.kt +70 -29
  14. package/android/src/main/java/com/audiobrowser/browser/StyleResolver.kt +60 -0
  15. package/android/src/main/java/com/audiobrowser/extension/ResolvedTrackExt.kt +20 -7
  16. package/android/src/main/java/com/audiobrowser/extension/TappedTrack.kt +20 -0
  17. package/android/src/main/java/com/audiobrowser/extension/TrackIdentity.kt +15 -0
  18. package/android/src/main/java/com/audiobrowser/http/HttpClient.kt +20 -3
  19. package/android/src/main/java/com/audiobrowser/model/IcyTitle.kt +24 -0
  20. package/android/src/main/java/com/audiobrowser/model/PlaybackMetadata.kt +10 -6
  21. package/android/src/main/java/com/audiobrowser/model/PlayerUpdateOptions.kt +12 -12
  22. package/android/src/main/java/com/audiobrowser/player/CapabilityControls.kt +111 -58
  23. package/android/src/main/java/com/audiobrowser/player/CrossOriginHeaderStripper.kt +77 -0
  24. package/android/src/main/java/com/audiobrowser/player/MediaFactory.kt +28 -10
  25. package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +509 -230
  26. package/android/src/main/java/com/audiobrowser/player/MediaSessionCommandManager.kt +218 -252
  27. package/android/src/main/java/com/audiobrowser/player/NowPlayingUpdater.kt +21 -25
  28. package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +113 -78
  29. package/android/src/main/java/com/audiobrowser/player/Player.kt +81 -38
  30. package/android/src/main/java/com/audiobrowser/player/PlayerCapabilitiesExt.kt +2 -15
  31. package/android/src/main/java/com/audiobrowser/player/PlayerListener.kt +1 -1
  32. package/android/src/main/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicy.kt +2 -1
  33. package/android/src/main/java/com/audiobrowser/player/ShuffleOrderLedBy.kt +30 -0
  34. package/android/src/main/java/com/audiobrowser/tls/AiaCertChaser.kt +67 -11
  35. package/android/src/main/java/com/audiobrowser/tls/AiaChasingExtendedTrustManager.kt +168 -0
  36. package/android/src/main/java/com/audiobrowser/tls/AiaChasingTrustManager.kt +58 -14
  37. package/android/src/main/java/com/audiobrowser/tls/AiaTls.kt +35 -7
  38. package/android/src/main/java/com/audiobrowser/tls/CachingCertificateFetcher.kt +278 -59
  39. package/android/src/main/java/com/audiobrowser/util/ArtworkVariant.kt +7 -9
  40. package/android/src/main/java/com/audiobrowser/util/BrowserPathHelper.kt +56 -40
  41. package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +28 -23
  42. package/android/src/main/java/com/audiobrowser/util/StyleWire.kt +108 -0
  43. package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +56 -52
  44. package/android/src/main/res/values/strings.xml +25 -5
  45. package/android/src/test/java/com/audiobrowser/ServiceBindingTest.kt +87 -0
  46. package/android/src/test/java/com/audiobrowser/TestFixtures.kt +119 -33
  47. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerFavoritesTest.kt +153 -0
  48. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerLayerResolutionTest.kt +15 -0
  49. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +346 -8
  50. package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +38 -0
  51. package/android/src/test/java/com/audiobrowser/browser/InertStyleDiagnosticTest.kt +277 -0
  52. package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +3 -2
  53. package/android/src/test/java/com/audiobrowser/browser/JsonStyleTest.kt +147 -0
  54. package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +128 -55
  55. package/android/src/test/java/com/audiobrowser/browser/StyleResolverTest.kt +154 -0
  56. package/android/src/test/java/com/audiobrowser/extension/TappedTrackTest.kt +43 -0
  57. package/android/src/test/java/com/audiobrowser/extension/TrackIdentityTest.kt +41 -0
  58. package/android/src/test/java/com/audiobrowser/model/IcyTitleTest.kt +49 -0
  59. package/android/src/test/java/com/audiobrowser/player/BrowseTilesTest.kt +385 -0
  60. package/android/src/test/java/com/audiobrowser/player/CapabilityControlsTest.kt +101 -58
  61. package/android/src/test/java/com/audiobrowser/player/CrossOriginHeaderStripperTest.kt +94 -0
  62. package/android/src/test/java/com/audiobrowser/player/MediaSessionSlotMappingTest.kt +45 -0
  63. package/android/src/test/java/com/audiobrowser/player/NowPlayingUpdaterTest.kt +42 -2
  64. package/android/src/test/java/com/audiobrowser/player/PlaybackErrorClassifierTest.kt +3 -4
  65. package/android/src/test/java/com/audiobrowser/player/PlaybackStateStoreTrackJsonTest.kt +55 -0
  66. package/android/src/test/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicyTest.kt +3 -3
  67. package/android/src/test/java/com/audiobrowser/player/ShuffleOrderLedByTest.kt +79 -0
  68. package/android/src/test/java/com/audiobrowser/tls/AiaCertChaserTest.kt +197 -7
  69. package/android/src/test/java/com/audiobrowser/tls/AiaChasingTrustManagerTest.kt +325 -4
  70. package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherCallSiteTest.kt +322 -0
  71. package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherTest.kt +83 -0
  72. package/android/src/test/java/com/audiobrowser/util/BrowserPathHelperTest.kt +41 -16
  73. package/android/src/test/java/com/audiobrowser/util/MediaExtrasBuilderTest.kt +162 -0
  74. package/android/src/test/java/com/audiobrowser/util/TrackFactoryMediaIdTest.kt +7 -7
  75. package/ios/Browser/BrowserConfig.swift +102 -5
  76. package/ios/Browser/BrowserManager+URLResolution.swift +18 -14
  77. package/ios/Browser/BrowserManager.swift +230 -205
  78. package/ios/Browser/BrowserPathHelper.swift +44 -44
  79. package/ios/Browser/InertStyleDiagnostic.swift +279 -0
  80. package/ios/Browser/JsonModels.swift +264 -106
  81. package/ios/Browser/SearchDrillIn.swift +7 -7
  82. package/ios/Browser/SectionPresentation.swift +64 -0
  83. package/ios/Browser/SectionScope.swift +58 -24
  84. package/ios/Browser/StyleResolver.swift +58 -0
  85. package/ios/Browser/TabBarEntries.swift +9 -3
  86. package/ios/Browser/TrackIdTemplate.swift +37 -0
  87. package/ios/CarPlay/CarPlayArtworkResolver.swift +8 -7
  88. package/ios/CarPlay/CarPlayController.swift +227 -85
  89. package/ios/CarPlay/CarPlayImageLoader.swift +42 -20
  90. package/ios/CarPlay/CarPlayListItemFactory.swift +289 -84
  91. package/ios/CarPlay/CarPlayNowPlayingManager.swift +15 -12
  92. package/ios/CarPlay/RNABMediaAddHandler.swift +6 -6
  93. package/ios/CarPlay/RNABMediaAffinityHandler.swift +2 -2
  94. package/ios/CarPlay/RNABMediaIntentHandler.swift +16 -16
  95. package/ios/Extension/Capability+RemoteCommand.swift +1 -1
  96. package/ios/Extension/PlayerCapabilities+Favorite.swift +1 -15
  97. package/ios/Extension/ResolvedTrack+Copying.swift +13 -15
  98. package/ios/Extension/Section+Copying.swift +29 -0
  99. package/ios/Extension/String+IcyCharset.swift +21 -0
  100. package/ios/Extension/TimedMetadata+AVFoundation.swift +6 -4
  101. package/ios/Extension/Track+Copying.swift +8 -12
  102. package/ios/Extension/Track+Identity.swift +18 -0
  103. package/ios/Extension/UIApplication+ActiveScene.swift +27 -0
  104. package/ios/Http/HttpClient.swift +8 -2
  105. package/ios/HybridAudioBrowser.swift +253 -100
  106. package/ios/Model/NitroTypeStubs.swift +125 -23
  107. package/ios/Model/PlayerUpdateOptions.swift +7 -0
  108. package/ios/Model/RemoteCommand.swift +18 -0
  109. package/ios/Model/TrackPlayerError.swift +2 -2
  110. package/ios/Option/SessionCategories.swift +3 -2
  111. package/ios/Player/MediaIntentCriteria.swift +17 -9
  112. package/ios/Player/MediaLoader.swift +33 -9
  113. package/ios/Player/NowPlayingUpdater.swift +54 -6
  114. package/ios/Player/PlaybackCoordinator.swift +13 -6
  115. package/ios/Player/PlaybackErrorHandler.swift +4 -4
  116. package/ios/Player/PlaybackTimer.swift +8 -2
  117. package/ios/Player/QueueManager.swift +46 -13
  118. package/ios/Player/RetryManager.swift +80 -18
  119. package/ios/Player/SeekCompletionHandler.swift +3 -1
  120. package/ios/Player/ShuffleOrder.swift +33 -0
  121. package/ios/Player/SleepTimerHandling.swift +13 -0
  122. package/ios/RemoteCommand/RemoteCommandCallbacks.swift +47 -0
  123. package/ios/RemoteCommand/RemoteCommandController.swift +62 -24
  124. package/ios/Tests/BrowserPathHelperTests.swift +50 -20
  125. package/ios/Tests/CarPlayArtworkResolverTests.swift +24 -41
  126. package/ios/Tests/InertStyleDiagnosticTests.swift +200 -0
  127. package/ios/Tests/JsonModelsTests.swift +150 -1
  128. package/ios/Tests/LRUCacheTests.swift +111 -0
  129. package/ios/Tests/LoadSeekCoordinatorTests.swift +3 -1
  130. package/ios/Tests/MediaIntentCriteriaTests.swift +2 -2
  131. package/ios/Tests/PlaybackCoordinatorTests.swift +1 -1
  132. package/ios/Tests/PlaybackErrorHandlerTests.swift +3 -1
  133. package/ios/Tests/PlaybackStateStoreTests.swift +4 -3
  134. package/ios/Tests/PlayerTimeObserverTests.swift +37 -0
  135. package/ios/Tests/QueueManagerTests.swift +122 -10
  136. package/ios/Tests/RemoteCommandControllerTests.swift +172 -0
  137. package/ios/Tests/RemoteCommandTests.swift +67 -0
  138. package/ios/Tests/ResolvedTrackCopyingTests.swift +39 -35
  139. package/ios/Tests/RetryManagerTests.swift +89 -0
  140. package/ios/Tests/SearchDrillInTests.swift +16 -16
  141. package/ios/Tests/SectionPresentationTests.swift +90 -0
  142. package/ios/Tests/SectionScopeTests.swift +87 -55
  143. package/ios/Tests/StyleResolverTests.swift +127 -0
  144. package/ios/Tests/Support/TestTypes.swift +8 -1
  145. package/ios/Tests/TabBarEntriesTests.swift +19 -19
  146. package/ios/Tests/TimedMetadataAVFoundationTests.swift +42 -0
  147. package/ios/Tests/TrackIdTemplateTests.swift +67 -0
  148. package/ios/Tests/TrackIdentityTests.swift +20 -0
  149. package/ios/Tests/TrackSelectorTests.swift +168 -33
  150. package/ios/TrackPlayer.swift +63 -35
  151. package/ios/TrackPlayerCallbacks.swift +5 -38
  152. package/ios/TrackSelector.swift +45 -30
  153. package/ios/Util/ArtworkImageFetcher.swift +16 -1
  154. package/ios/Util/LRUCache.swift +4 -1
  155. package/ios/Util/NetworkMonitor.swift +43 -26
  156. package/ios/Util/SFSymbolRenderer.swift +24 -2
  157. package/ios/Util/SVGProcessor.swift +9 -2
  158. package/lib/commonjs/AudioBrowser.js +8 -8
  159. package/lib/commonjs/AudioBrowser.js.map +1 -1
  160. package/lib/commonjs/CLAUDE.md +52 -0
  161. package/lib/commonjs/features/browser-config.js +12 -8
  162. package/lib/commonjs/features/browser-config.js.map +1 -1
  163. package/lib/commonjs/features/browser.js +11 -3
  164. package/lib/commonjs/features/browser.js.map +1 -1
  165. package/lib/commonjs/features/carConnection.js +1 -1
  166. package/lib/commonjs/features/equalizer.js +1 -1
  167. package/lib/commonjs/features/errors.js +3 -3
  168. package/lib/commonjs/features/favorites.js +14 -11
  169. package/lib/commonjs/features/favorites.js.map +1 -1
  170. package/lib/commonjs/features/gate.js +16 -1
  171. package/lib/commonjs/features/gate.js.map +1 -1
  172. package/lib/commonjs/features/metadata.js +20 -3
  173. package/lib/commonjs/features/metadata.js.map +1 -1
  174. package/lib/commonjs/features/network.js +1 -1
  175. package/lib/commonjs/features/nowPlaying.js +1 -1
  176. package/lib/commonjs/features/output.js +1 -1
  177. package/lib/commonjs/features/playback/controls.js +4 -2
  178. package/lib/commonjs/features/playback/controls.js.map +1 -1
  179. package/lib/commonjs/features/playback/playWhenReady.js +1 -1
  180. package/lib/commonjs/features/playback/playing.js +1 -1
  181. package/lib/commonjs/features/playback/progress.js +3 -2
  182. package/lib/commonjs/features/playback/progress.js.map +1 -1
  183. package/lib/commonjs/features/playback/rate.js +8 -1
  184. package/lib/commonjs/features/playback/rate.js.map +1 -1
  185. package/lib/commonjs/features/playback/state.js +3 -4
  186. package/lib/commonjs/features/playback/state.js.map +1 -1
  187. package/lib/commonjs/features/playback/trackPlaybackTime.js +0 -6
  188. package/lib/commonjs/features/playback/trackPlaybackTime.js.map +1 -1
  189. package/lib/commonjs/features/playback/volume.js +1 -1
  190. package/lib/commonjs/features/player/options.js +48 -34
  191. package/lib/commonjs/features/player/options.js.map +1 -1
  192. package/lib/commonjs/features/player/setup.js +18 -9
  193. package/lib/commonjs/features/player/setup.js.map +1 -1
  194. package/lib/commonjs/features/player/validateOptions.js +23 -0
  195. package/lib/commonjs/features/player/validateOptions.js.map +1 -0
  196. package/lib/commonjs/features/queue/activeTrack.js +15 -4
  197. package/lib/commonjs/features/queue/activeTrack.js.map +1 -1
  198. package/lib/commonjs/features/queue/queue.js +13 -6
  199. package/lib/commonjs/features/queue/queue.js.map +1 -1
  200. package/lib/commonjs/features/queue/repeatMode.js +1 -1
  201. package/lib/commonjs/features/queue/shuffle.js +1 -1
  202. package/lib/commonjs/features/remoteControls.js +13 -92
  203. package/lib/commonjs/features/remoteControls.js.map +1 -1
  204. package/lib/commonjs/features/sleepTimer.js +13 -1
  205. package/lib/commonjs/features/sleepTimer.js.map +1 -1
  206. package/lib/commonjs/test-utils/reactNativeStub.js +65 -0
  207. package/lib/commonjs/test-utils/reactNativeStub.js.map +1 -0
  208. package/lib/commonjs/utils/LazyNativeEmitter.js +28 -14
  209. package/lib/commonjs/utils/LazyNativeEmitter.js.map +1 -1
  210. package/lib/commonjs/utils/NativeUpdatedValue.js +31 -13
  211. package/lib/commonjs/utils/NativeUpdatedValue.js.map +1 -1
  212. package/lib/commonjs/utils/getTrackIdentity.js +24 -0
  213. package/lib/commonjs/utils/getTrackIdentity.js.map +1 -0
  214. package/lib/commonjs/utils/useNativeValueRefreshedBy.js +33 -0
  215. package/lib/commonjs/utils/useNativeValueRefreshedBy.js.map +1 -0
  216. package/lib/commonjs/web/NativeAudioBrowser.js +200 -75
  217. package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
  218. package/lib/commonjs/web/TrackPlayer/LoadAttempt.js +37 -0
  219. package/lib/commonjs/web/TrackPlayer/LoadAttempt.js.map +1 -0
  220. package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js +18 -2
  221. package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js.map +1 -1
  222. package/lib/commonjs/web/TrackPlayer/Player.js +254 -39
  223. package/lib/commonjs/web/TrackPlayer/Player.js.map +1 -1
  224. package/lib/commonjs/web/TrackPlayer/QueueManager.js +14 -0
  225. package/lib/commonjs/web/TrackPlayer/QueueManager.js.map +1 -1
  226. package/lib/commonjs/web/TrackPlayer/QueuePlayer.js +33 -12
  227. package/lib/commonjs/web/TrackPlayer/QueuePlayer.js.map +1 -1
  228. package/lib/commonjs/web/browser/BrowserManager.js +175 -100
  229. package/lib/commonjs/web/browser/BrowserManager.js.map +1 -1
  230. package/lib/commonjs/web/browser/FavoriteManager.js +30 -21
  231. package/lib/commonjs/web/browser/FavoriteManager.js.map +1 -1
  232. package/lib/commonjs/web/browser/SearchManager.js +18 -23
  233. package/lib/commonjs/web/browser/SearchManager.js.map +1 -1
  234. package/lib/commonjs/web/browser/assertBrowsePageShape.js +2 -2
  235. package/lib/commonjs/web/browser/assertBrowsePageShape.js.map +1 -1
  236. package/lib/commonjs/web/browser/classifyTrackNavigation.js +9 -9
  237. package/lib/commonjs/web/browser/classifyTrackNavigation.js.map +1 -1
  238. package/lib/commonjs/web/browser/sections.js +89 -0
  239. package/lib/commonjs/web/browser/sections.js.map +1 -0
  240. package/lib/commonjs/web/http/RequestConfigBuilder.js +110 -27
  241. package/lib/commonjs/web/http/RequestConfigBuilder.js.map +1 -1
  242. package/lib/commonjs/web/http/followMediaRedirect.js +219 -0
  243. package/lib/commonjs/web/http/followMediaRedirect.js.map +1 -0
  244. package/lib/commonjs/web/player/NowPlayingManager.js +4 -3
  245. package/lib/commonjs/web/player/NowPlayingManager.js.map +1 -1
  246. package/lib/commonjs/web/util/BrowserPathHelper.js +56 -11
  247. package/lib/commonjs/web/util/BrowserPathHelper.js.map +1 -1
  248. package/lib/module/AudioBrowser.js +2 -1
  249. package/lib/module/AudioBrowser.js.map +1 -1
  250. package/lib/module/CLAUDE.md +52 -0
  251. package/lib/module/features/browser-config.js +12 -8
  252. package/lib/module/features/browser-config.js.map +1 -1
  253. package/lib/module/features/browser.js +11 -3
  254. package/lib/module/features/browser.js.map +1 -1
  255. package/lib/module/features/carConnection.js +1 -1
  256. package/lib/module/features/equalizer.js +1 -1
  257. package/lib/module/features/errors.js +3 -3
  258. package/lib/module/features/favorites.js +14 -11
  259. package/lib/module/features/favorites.js.map +1 -1
  260. package/lib/module/features/gate.js +16 -1
  261. package/lib/module/features/gate.js.map +1 -1
  262. package/lib/module/features/metadata.js +20 -3
  263. package/lib/module/features/metadata.js.map +1 -1
  264. package/lib/module/features/network.js +1 -1
  265. package/lib/module/features/nowPlaying.js +1 -1
  266. package/lib/module/features/output.js +1 -1
  267. package/lib/module/features/playback/controls.js +4 -2
  268. package/lib/module/features/playback/controls.js.map +1 -1
  269. package/lib/module/features/playback/playWhenReady.js +1 -1
  270. package/lib/module/features/playback/playing.js +1 -1
  271. package/lib/module/features/playback/progress.js +3 -2
  272. package/lib/module/features/playback/progress.js.map +1 -1
  273. package/lib/module/features/playback/rate.js +8 -1
  274. package/lib/module/features/playback/rate.js.map +1 -1
  275. package/lib/module/features/playback/state.js +3 -4
  276. package/lib/module/features/playback/state.js.map +1 -1
  277. package/lib/module/features/playback/trackPlaybackTime.js +0 -5
  278. package/lib/module/features/playback/trackPlaybackTime.js.map +1 -1
  279. package/lib/module/features/playback/volume.js +1 -1
  280. package/lib/module/features/player/options.js +47 -32
  281. package/lib/module/features/player/options.js.map +1 -1
  282. package/lib/module/features/player/setup.js +17 -8
  283. package/lib/module/features/player/setup.js.map +1 -1
  284. package/lib/module/features/player/validateOptions.js +19 -0
  285. package/lib/module/features/player/validateOptions.js.map +1 -0
  286. package/lib/module/features/queue/activeTrack.js +15 -4
  287. package/lib/module/features/queue/activeTrack.js.map +1 -1
  288. package/lib/module/features/queue/queue.js +13 -6
  289. package/lib/module/features/queue/queue.js.map +1 -1
  290. package/lib/module/features/queue/repeatMode.js +1 -1
  291. package/lib/module/features/queue/shuffle.js +1 -1
  292. package/lib/module/features/remoteControls.js +13 -92
  293. package/lib/module/features/remoteControls.js.map +1 -1
  294. package/lib/module/features/sleepTimer.js +13 -1
  295. package/lib/module/features/sleepTimer.js.map +1 -1
  296. package/lib/module/test-utils/reactNativeStub.js +58 -0
  297. package/lib/module/test-utils/reactNativeStub.js.map +1 -0
  298. package/lib/module/utils/LazyNativeEmitter.js +28 -14
  299. package/lib/module/utils/LazyNativeEmitter.js.map +1 -1
  300. package/lib/module/utils/NativeUpdatedValue.js +31 -13
  301. package/lib/module/utils/NativeUpdatedValue.js.map +1 -1
  302. package/lib/module/utils/getTrackIdentity.js +20 -0
  303. package/lib/module/utils/getTrackIdentity.js.map +1 -0
  304. package/lib/module/utils/useNativeValueRefreshedBy.js +29 -0
  305. package/lib/module/utils/useNativeValueRefreshedBy.js.map +1 -0
  306. package/lib/module/web/NativeAudioBrowser.js +200 -75
  307. package/lib/module/web/NativeAudioBrowser.js.map +1 -1
  308. package/lib/module/web/TrackPlayer/LoadAttempt.js +32 -0
  309. package/lib/module/web/TrackPlayer/LoadAttempt.js.map +1 -0
  310. package/lib/module/web/TrackPlayer/PlaybackStateMachine.js +18 -2
  311. package/lib/module/web/TrackPlayer/PlaybackStateMachine.js.map +1 -1
  312. package/lib/module/web/TrackPlayer/Player.js +254 -39
  313. package/lib/module/web/TrackPlayer/Player.js.map +1 -1
  314. package/lib/module/web/TrackPlayer/QueueManager.js +14 -0
  315. package/lib/module/web/TrackPlayer/QueueManager.js.map +1 -1
  316. package/lib/module/web/TrackPlayer/QueuePlayer.js +33 -12
  317. package/lib/module/web/TrackPlayer/QueuePlayer.js.map +1 -1
  318. package/lib/module/web/browser/BrowserManager.js +175 -100
  319. package/lib/module/web/browser/BrowserManager.js.map +1 -1
  320. package/lib/module/web/browser/FavoriteManager.js +31 -21
  321. package/lib/module/web/browser/FavoriteManager.js.map +1 -1
  322. package/lib/module/web/browser/SearchManager.js +18 -23
  323. package/lib/module/web/browser/SearchManager.js.map +1 -1
  324. package/lib/module/web/browser/assertBrowsePageShape.js +2 -2
  325. package/lib/module/web/browser/assertBrowsePageShape.js.map +1 -1
  326. package/lib/module/web/browser/classifyTrackNavigation.js +9 -9
  327. package/lib/module/web/browser/classifyTrackNavigation.js.map +1 -1
  328. package/lib/module/web/browser/sections.js +83 -0
  329. package/lib/module/web/browser/sections.js.map +1 -0
  330. package/lib/module/web/http/RequestConfigBuilder.js +110 -27
  331. package/lib/module/web/http/RequestConfigBuilder.js.map +1 -1
  332. package/lib/module/web/http/followMediaRedirect.js +215 -0
  333. package/lib/module/web/http/followMediaRedirect.js.map +1 -0
  334. package/lib/module/web/player/NowPlayingManager.js +4 -3
  335. package/lib/module/web/player/NowPlayingManager.js.map +1 -1
  336. package/lib/module/web/util/BrowserPathHelper.js +56 -11
  337. package/lib/module/web/util/BrowserPathHelper.js.map +1 -1
  338. package/lib/typescript/package.json +1 -0
  339. package/lib/typescript/src/AudioBrowser.d.ts +1 -1
  340. package/lib/typescript/src/AudioBrowser.d.ts.map +1 -1
  341. package/lib/typescript/src/features/browser-config.d.ts.map +1 -1
  342. package/lib/typescript/src/features/browser.d.ts +10 -2
  343. package/lib/typescript/src/features/browser.d.ts.map +1 -1
  344. package/lib/typescript/src/features/carConnection.d.ts +1 -1
  345. package/lib/typescript/src/features/equalizer.d.ts +1 -1
  346. package/lib/typescript/src/features/errors.d.ts +3 -3
  347. package/lib/typescript/src/features/favorites.d.ts +14 -11
  348. package/lib/typescript/src/features/favorites.d.ts.map +1 -1
  349. package/lib/typescript/src/features/gate.d.ts +18 -2
  350. package/lib/typescript/src/features/gate.d.ts.map +1 -1
  351. package/lib/typescript/src/features/metadata.d.ts +20 -3
  352. package/lib/typescript/src/features/metadata.d.ts.map +1 -1
  353. package/lib/typescript/src/features/network.d.ts +1 -1
  354. package/lib/typescript/src/features/nowPlaying.d.ts +1 -1
  355. package/lib/typescript/src/features/output.d.ts +1 -1
  356. package/lib/typescript/src/features/playback/controls.d.ts +4 -2
  357. package/lib/typescript/src/features/playback/controls.d.ts.map +1 -1
  358. package/lib/typescript/src/features/playback/playWhenReady.d.ts +1 -1
  359. package/lib/typescript/src/features/playback/playing.d.ts +1 -1
  360. package/lib/typescript/src/features/playback/progress.d.ts +1 -1
  361. package/lib/typescript/src/features/playback/progress.d.ts.map +1 -1
  362. package/lib/typescript/src/features/playback/rate.d.ts +8 -1
  363. package/lib/typescript/src/features/playback/rate.d.ts.map +1 -1
  364. package/lib/typescript/src/features/playback/state.d.ts +3 -4
  365. package/lib/typescript/src/features/playback/state.d.ts.map +1 -1
  366. package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts +1 -1
  367. package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts.map +1 -1
  368. package/lib/typescript/src/features/playback/volume.d.ts +1 -1
  369. package/lib/typescript/src/features/player/options.d.ts +108 -56
  370. package/lib/typescript/src/features/player/options.d.ts.map +1 -1
  371. package/lib/typescript/src/features/player/setup.d.ts +14 -4
  372. package/lib/typescript/src/features/player/setup.d.ts.map +1 -1
  373. package/lib/typescript/src/features/player/validateOptions.d.ts +2 -0
  374. package/lib/typescript/src/features/player/validateOptions.d.ts.map +1 -0
  375. package/lib/typescript/src/features/queue/activeTrack.d.ts +9 -2
  376. package/lib/typescript/src/features/queue/activeTrack.d.ts.map +1 -1
  377. package/lib/typescript/src/features/queue/queue.d.ts +7 -4
  378. package/lib/typescript/src/features/queue/queue.d.ts.map +1 -1
  379. package/lib/typescript/src/features/queue/repeatMode.d.ts +1 -1
  380. package/lib/typescript/src/features/queue/shuffle.d.ts +1 -1
  381. package/lib/typescript/src/features/remoteControls.d.ts +23 -22
  382. package/lib/typescript/src/features/remoteControls.d.ts.map +1 -1
  383. package/lib/typescript/src/features/sleepTimer.d.ts +1 -1
  384. package/lib/typescript/src/features/sleepTimer.d.ts.map +1 -1
  385. package/lib/typescript/src/test-utils/reactNativeStub.d.ts +36 -0
  386. package/lib/typescript/src/test-utils/reactNativeStub.d.ts.map +1 -0
  387. package/lib/typescript/src/types/browser-native.d.ts +3 -2
  388. package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
  389. package/lib/typescript/src/types/browser-nodes.d.ts +380 -126
  390. package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
  391. package/lib/typescript/src/types/browser.d.ts +82 -57
  392. package/lib/typescript/src/types/browser.d.ts.map +1 -1
  393. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +19 -16
  394. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts.map +1 -1
  395. package/lib/typescript/src/utils/NativeUpdatedValue.d.ts +24 -19
  396. package/lib/typescript/src/utils/NativeUpdatedValue.d.ts.map +1 -1
  397. package/lib/typescript/src/utils/getTrackIdentity.d.ts +18 -0
  398. package/lib/typescript/src/utils/getTrackIdentity.d.ts.map +1 -0
  399. package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts +21 -0
  400. package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts.map +1 -0
  401. package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +1 -2
  402. package/nitrogen/generated/android/AudioBrowserOnLoad.cpp +2 -0
  403. package/nitrogen/generated/android/c++/JAndroidOptions.hpp +10 -10
  404. package/nitrogen/generated/android/c++/{JFavoritesMatchMode.hpp → JArtworkRendering.hpp} +15 -15
  405. package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +8 -3
  406. package/nitrogen/generated/android/c++/JBrowseResult.hpp +16 -4
  407. package/nitrogen/generated/android/c++/JCarPlayPlayingIndicatorLocation.hpp +58 -0
  408. package/nitrogen/generated/android/c++/JCardImage.hpp +58 -0
  409. package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +8 -3
  410. package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +8 -3
  411. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +8 -3
  412. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +8 -3
  413. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +8 -3
  414. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +8 -3
  415. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +8 -2
  416. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +8 -2
  417. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__string__.hpp +102 -0
  418. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.hpp +16 -4
  419. package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +8 -3
  420. package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +7 -10
  421. package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +8 -3
  422. package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +15 -3
  423. package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +8 -2
  424. package/nitrogen/generated/android/c++/JGridTile.hpp +61 -0
  425. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +45 -25
  426. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.hpp +1 -1
  427. package/nitrogen/generated/android/c++/JIOSOptions.hpp +9 -3
  428. package/nitrogen/generated/android/c++/JImageShape.hpp +58 -0
  429. package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +8 -3
  430. package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +36 -11
  431. package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +14 -2
  432. package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +15 -12
  433. package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +7 -10
  434. package/nitrogen/generated/android/c++/JNitroAndroidUpdateOptions.hpp +10 -10
  435. package/nitrogen/generated/android/c++/JNitroIOSUpdateOptions.hpp +9 -3
  436. package/nitrogen/generated/android/c++/JOptions.hpp +7 -10
  437. package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +8 -3
  438. package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +5 -11
  439. package/nitrogen/generated/android/c++/{JNotificationButton.hpp → JRemoteButton.hpp} +19 -19
  440. package/nitrogen/generated/android/c++/JRemoteButtonLayout.hpp +86 -0
  441. package/nitrogen/generated/android/c++/JResolvedTrack.hpp +57 -49
  442. package/nitrogen/generated/android/c++/JSection.hpp +116 -0
  443. package/nitrogen/generated/android/c++/JSectionStyle.hpp +96 -0
  444. package/nitrogen/generated/android/c++/JStyleDisplay.hpp +58 -0
  445. package/nitrogen/generated/android/c++/JTrack.hpp +25 -46
  446. package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +8 -2
  447. package/nitrogen/generated/android/c++/JTrackStyle.hpp +46 -18
  448. package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.cpp +26 -0
  449. package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.hpp +75 -0
  450. package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.hpp +16 -4
  451. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidOptions.kt +3 -3
  452. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoritesMatchMode.kt → ArtworkRendering.kt} +5 -5
  453. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayPlayingIndicatorLocation.kt +23 -0
  454. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CardImage.kt +23 -0
  455. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__string__.kt +80 -0
  456. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/GridTile.kt +24 -0
  457. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HybridAudioBrowserSpec.kt +1 -1
  458. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSOptions.kt +6 -3
  459. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageShape.kt +23 -0
  460. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +8 -5
  461. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroAndroidUpdateOptions.kt +3 -3
  462. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroIOSUpdateOptions.kt +6 -3
  463. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
  464. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{NotificationButton.kt → RemoteButton.kt} +3 -3
  465. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteButtonLayout.kt +44 -0
  466. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +12 -15
  467. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoriteConfig.kt → Section.kt} +15 -6
  468. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SectionStyle.kt +59 -0
  469. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StyleDisplay.kt +23 -0
  470. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +6 -12
  471. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackStyle.kt +35 -5
  472. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Variant_NullType_NotificationButtonLayout.kt → Variant_NullType_RemoteButtonLayout.kt} +9 -9
  473. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.cpp +9 -0
  474. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +244 -133
  475. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +31 -16
  476. package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +33 -18
  477. package/nitrogen/generated/ios/swift/AndroidOptions.swift +12 -12
  478. package/nitrogen/generated/ios/swift/ArtworkRendering.swift +40 -0
  479. package/nitrogen/generated/ios/swift/CarPlayPlayingIndicatorLocation.swift +40 -0
  480. package/nitrogen/generated/ios/swift/CardImage.swift +40 -0
  481. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__string__.swift +54 -0
  482. package/nitrogen/generated/ios/swift/GridTile.swift +44 -0
  483. package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec.swift +1 -1
  484. package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec_cxx.swift +2 -2
  485. package/nitrogen/generated/ios/swift/IOSOptions.swift +7 -2
  486. package/nitrogen/generated/ios/swift/ImageShape.swift +40 -0
  487. package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +52 -5
  488. package/nitrogen/generated/ios/swift/NitroAndroidUpdateOptions.swift +12 -12
  489. package/nitrogen/generated/ios/swift/NitroIOSUpdateOptions.swift +12 -1
  490. package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +8 -27
  491. package/nitrogen/generated/ios/swift/{NotificationButton.swift → RemoteButton.swift} +6 -6
  492. package/nitrogen/generated/ios/swift/RemoteButtonLayout.swift +57 -0
  493. package/nitrogen/generated/ios/swift/ResolvedTrack.swift +62 -73
  494. package/nitrogen/generated/ios/swift/Section.swift +82 -0
  495. package/nitrogen/generated/ios/swift/SectionStyle.swift +133 -0
  496. package/nitrogen/generated/ios/swift/StyleDisplay.swift +40 -0
  497. package/nitrogen/generated/ios/swift/Track.swift +28 -63
  498. package/nitrogen/generated/ios/swift/TrackStyle.swift +86 -22
  499. package/nitrogen/generated/ios/swift/{Variant_NullType_NotificationButtonLayout.swift → Variant_NullType_RemoteButtonLayout.swift} +3 -3
  500. package/nitrogen/generated/shared/c++/AndroidOptions.hpp +8 -8
  501. package/nitrogen/generated/shared/c++/{FavoritesMatchMode.hpp → ArtworkRendering.hpp} +17 -17
  502. package/nitrogen/generated/shared/c++/CarPlayPlayingIndicatorLocation.hpp +76 -0
  503. package/nitrogen/generated/shared/c++/CardImage.hpp +76 -0
  504. package/nitrogen/generated/shared/c++/GridTile.hpp +80 -0
  505. package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.cpp +1 -1
  506. package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.hpp +1 -1
  507. package/nitrogen/generated/shared/c++/IOSOptions.hpp +9 -2
  508. package/nitrogen/generated/shared/c++/ImageShape.hpp +76 -0
  509. package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +10 -6
  510. package/nitrogen/generated/shared/c++/NitroAndroidUpdateOptions.hpp +8 -8
  511. package/nitrogen/generated/shared/c++/NitroIOSUpdateOptions.hpp +9 -2
  512. package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +6 -9
  513. package/nitrogen/generated/shared/c++/{NotificationButton.hpp → RemoteButton.hpp} +19 -19
  514. package/nitrogen/generated/shared/c++/RemoteButtonLayout.hpp +94 -0
  515. package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +33 -37
  516. package/nitrogen/generated/shared/c++/Section.hpp +102 -0
  517. package/nitrogen/generated/shared/c++/SectionStyle.hpp +126 -0
  518. package/nitrogen/generated/shared/c++/StyleDisplay.hpp +76 -0
  519. package/nitrogen/generated/shared/c++/Track.hpp +18 -30
  520. package/nitrogen/generated/shared/c++/TrackStyle.hpp +73 -34
  521. package/package.json +24 -11
  522. package/src/AudioBrowser.ts +2 -1
  523. package/src/CLAUDE.md +52 -0
  524. package/src/features/battery.test.ts +79 -0
  525. package/src/features/browser-config.test.ts +21 -6
  526. package/src/features/browser-config.ts +12 -8
  527. package/src/features/browser.test.ts +1 -1
  528. package/src/features/browser.ts +11 -3
  529. package/src/features/carConnection.ts +1 -1
  530. package/src/features/equalizer.ts +1 -1
  531. package/src/features/errors.ts +3 -3
  532. package/src/features/favorites.ts +14 -11
  533. package/src/features/gate.ts +16 -1
  534. package/src/features/hook-wiring.test.ts +302 -0
  535. package/src/features/metadata.ts +20 -3
  536. package/src/features/network.ts +1 -1
  537. package/src/features/nowPlaying.ts +1 -1
  538. package/src/features/output.ts +1 -1
  539. package/src/features/playback/controls.ts +4 -2
  540. package/src/features/playback/playWhenReady.ts +1 -1
  541. package/src/features/playback/playing.ts +1 -1
  542. package/src/features/playback/progress.test.ts +169 -0
  543. package/src/features/playback/progress.ts +3 -2
  544. package/src/features/playback/rate.ts +8 -1
  545. package/src/features/playback/state.ts +3 -4
  546. package/src/features/playback/trackPlaybackTime.test.ts +16 -6
  547. package/src/features/playback/trackPlaybackTime.ts +1 -6
  548. package/src/features/playback/volume.ts +1 -1
  549. package/src/features/player/options.ts +126 -76
  550. package/src/features/player/setup.test.ts +24 -7
  551. package/src/features/player/setup.ts +22 -10
  552. package/src/features/player/validateOptions.ts +21 -0
  553. package/src/features/queue/activeTrack.ts +15 -4
  554. package/src/features/queue/queue.ts +13 -6
  555. package/src/features/queue/repeatMode.ts +1 -1
  556. package/src/features/queue/shuffle.ts +1 -1
  557. package/src/features/remoteControls.ts +13 -92
  558. package/src/features/sleepTimer.test.ts +172 -0
  559. package/src/features/sleepTimer.ts +9 -1
  560. package/src/nitro-stub-drift.test.ts +277 -0
  561. package/src/public-surface.test.ts +147 -0
  562. package/src/specs/audio-browser.nitro.ts +5 -4
  563. package/src/style-resolution.test.ts +210 -0
  564. package/src/test-utils/reactNativeStub.ts +60 -0
  565. package/src/types/browser-native.ts +7 -3
  566. package/src/types/browser-nodes.ts +396 -134
  567. package/src/types/browser.ts +85 -59
  568. package/src/utils/LazyNativeEmitter.ts +28 -15
  569. package/src/utils/NativeUpdatedValue.ts +29 -13
  570. package/src/utils/getTrackIdentity.ts +20 -0
  571. package/src/utils/useDebug.test.ts +182 -0
  572. package/src/utils/useNativeUpdatedValue.test.ts +103 -0
  573. package/src/utils/useNativeValueRefreshedBy.ts +38 -0
  574. package/src/web/NativeAudioBrowser.playWhenReady.test.ts +232 -2
  575. package/src/web/NativeAudioBrowser.ts +239 -82
  576. package/src/web/TrackPlayer/LoadAttempt.ts +29 -0
  577. package/src/web/TrackPlayer/PlaybackStateMachine.test.ts +60 -13
  578. package/src/web/TrackPlayer/PlaybackStateMachine.ts +22 -6
  579. package/src/web/TrackPlayer/Player.dispatch.test.ts +5 -3
  580. package/src/web/TrackPlayer/Player.load.test.ts +137 -1
  581. package/src/web/TrackPlayer/Player.ts +284 -37
  582. package/src/web/TrackPlayer/QueueManager.test.ts +29 -0
  583. package/src/web/TrackPlayer/QueueManager.ts +14 -0
  584. package/src/web/TrackPlayer/QueuePlayer.ts +33 -14
  585. package/src/web/__tests__/lifecycle.test.ts +345 -0
  586. package/src/web/__tests__/lifecycleHarness.ts +351 -0
  587. package/src/web/__tests__/loadEdgeCases.test.ts +246 -0
  588. package/src/web/__tests__/loadSupersession.test.ts +175 -0
  589. package/src/web/__tests__/retry.test.ts +169 -0
  590. package/src/web/browser/BrowserManager.ts +209 -111
  591. package/src/web/browser/FavoriteManager.test.ts +84 -0
  592. package/src/web/browser/FavoriteManager.ts +28 -23
  593. package/src/web/browser/SearchManager.test.ts +75 -0
  594. package/src/web/browser/SearchManager.ts +25 -28
  595. package/src/web/browser/__tests__/artwork-resolution.test.ts +117 -0
  596. package/src/web/browser/__tests__/layer-resolver.test.ts +35 -0
  597. package/src/web/browser/__tests__/search-artwork.test.ts +46 -0
  598. package/src/web/browser/__tests__/search-navigation.test.ts +76 -0
  599. package/src/web/browser/assertBrowsePageShape.test.ts +1 -1
  600. package/src/web/browser/assertBrowsePageShape.ts +5 -3
  601. package/src/web/browser/classifyTrackNavigation.test.ts +10 -8
  602. package/src/web/browser/classifyTrackNavigation.ts +9 -9
  603. package/src/web/browser/parseSearchResponse.test.ts +8 -2
  604. package/src/web/browser/sections.test.ts +91 -0
  605. package/src/web/browser/sections.ts +72 -0
  606. package/src/web/http/RequestConfigBuilder.test.ts +241 -1
  607. package/src/web/http/RequestConfigBuilder.ts +140 -33
  608. package/src/web/http/followMediaRedirect.test.ts +289 -0
  609. package/src/web/http/followMediaRedirect.ts +253 -0
  610. package/src/web/player/NowPlayingManager.ts +4 -3
  611. package/src/web/util/BrowserPathHelper.test.ts +52 -0
  612. package/src/web/util/BrowserPathHelper.ts +61 -13
  613. package/website/guide/android-auto.md +114 -0
  614. package/website/guide/android-certificates.md +409 -0
  615. package/website/guide/artwork.md +255 -0
  616. package/website/guide/audio-output.md +135 -0
  617. package/website/guide/automotive.md +86 -0
  618. package/website/guide/basic-usage.md +151 -0
  619. package/website/guide/battery.md +115 -0
  620. package/website/guide/browser.md +581 -0
  621. package/website/guide/carplay.md +620 -0
  622. package/website/guide/configuration.md +173 -0
  623. package/website/guide/equalizer.md +231 -0
  624. package/website/guide/errors.md +310 -0
  625. package/website/guide/favorites.md +154 -0
  626. package/website/guide/gate.md +143 -0
  627. package/website/guide/getting-started.md +46 -0
  628. package/website/guide/hooks.md +238 -0
  629. package/website/guide/live-streams.md +125 -0
  630. package/website/guide/metadata.md +239 -0
  631. package/website/guide/migrating-from-track-player.md +244 -0
  632. package/website/guide/native-callback-fetch.md +127 -0
  633. package/website/guide/network.md +86 -0
  634. package/website/guide/now-playing.md +175 -0
  635. package/website/guide/playback.md +328 -0
  636. package/website/guide/queue.md +300 -0
  637. package/website/guide/remote-controls.md +256 -0
  638. package/website/guide/search.md +255 -0
  639. package/website/guide/sleep-timer.md +268 -0
  640. package/website/guide/track.md +247 -0
  641. package/ios/CarPlay/ImageRowItem+CarPlay.swift +0 -19
  642. package/ios/Model/MediaURL.swift +0 -67
  643. package/nitrogen/generated/android/c++/JFavoriteConfig.hpp +0 -58
  644. package/nitrogen/generated/android/c++/JImageRowItem.hpp +0 -105
  645. package/nitrogen/generated/android/c++/JNotificationButtonLayout.hpp +0 -94
  646. package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.cpp +0 -26
  647. package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.hpp +0 -71
  648. package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.cpp +0 -26
  649. package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.hpp +0 -75
  650. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +0 -68
  651. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButtonLayout.kt +0 -50
  652. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_FavoriteConfig.kt +0 -53
  653. package/nitrogen/generated/ios/swift/FavoriteConfig.swift +0 -29
  654. package/nitrogen/generated/ios/swift/FavoritesMatchMode.swift +0 -40
  655. package/nitrogen/generated/ios/swift/ImageRowItem.swift +0 -195
  656. package/nitrogen/generated/ios/swift/NotificationButtonLayout.swift +0 -92
  657. package/nitrogen/generated/ios/swift/Variant_Bool_FavoriteConfig.swift +0 -18
  658. package/nitrogen/generated/shared/c++/FavoriteConfig.hpp +0 -84
  659. package/nitrogen/generated/shared/c++/ImageRowItem.hpp +0 -129
  660. package/nitrogen/generated/shared/c++/NotificationButtonLayout.hpp +0 -102
@@ -1,8 +1,11 @@
1
- import type { FavoriteConfig } from '../../types'
2
- import type { CarPlayNowPlayingButton } from '../../types/browser'
1
+ import type {
2
+ CarPlayNowPlayingButton,
3
+ CarPlayPlayingIndicatorLocation
4
+ } from '../../types/browser'
3
5
  import { nativeBrowser } from '../../native'
4
6
  import { NativeUpdatedValue } from '../../utils/NativeUpdatedValue'
5
7
  import { useNativeUpdatedValue } from '../../utils/useNativeUpdatedValue'
8
+ import { validateIOSUpdateOptions } from './validateOptions'
6
9
 
7
10
  // MARK: - Types
8
11
 
@@ -70,34 +73,26 @@ export interface PlayerCapabilities {
70
73
  *
71
74
  * Turns on the favorite/like heart across all surfaces:
72
75
  * - iOS: Control Center + CarPlay now-playing.
73
- * - Android: notification button slot + Android Auto now-playing, and an
76
+ * - Android: a place in the {@link RemoteButtonLayout} — the notification,
77
+ * Android Auto and the Android 13+ system media controls — and an
74
78
  * (empty or filled) heart on playable browse rows.
75
79
  *
76
- * `match` controls how the ids from `setFavorites` are
77
- * compared against a track's `src` to decide its `favorited` state
78
- * (see `FavoritesMatchMode`); `true` is shorthand for `'exact'`.
79
- *
80
- * - `false` / omitted: favoriting off everywhere.
81
- * - `true`: on, with `'exact'` id matching.
82
- * - `{ match }`: on, with the given match mode.
80
+ * The ids passed to `setFavorites` are matched exactly against a track's
81
+ * *identity* — its `id` when set, falling back to `src`. Store favorites as
82
+ * the same stable identifier you put in `Track.id` (or as the full `src`
83
+ * for tracks without an id).
83
84
  *
84
85
  * @example
85
86
  * ```ts
86
- * // 'exact': a favorite id must equal the track's src.
87
- * favorite: { match: 'exact' }
88
- * setFavorites(['https://cdn.example.com/audio/track-42.mp3'])
89
- * // → favorited when src === 'https://cdn.example.com/audio/track-42.mp3'
90
- *
91
- * // 'partial': a favorite id matches when it is a full path segment of src.
92
- * favorite: { match: 'partial' }
87
+ * favorite: true
93
88
  * setFavorites(['track-42'])
94
- * // → favorited when src is '/library/track-42' or '/stream/track-42?hq=1',
95
- * // but NOT '/library/track-420'
89
+ * // → favorited when track.id === 'track-42'
90
+ * // (or, for id-less tracks, when track.src === 'track-42')
96
91
  * ```
97
92
  *
98
93
  * @default false
99
94
  */
100
- favorite?: boolean | FavoriteConfig
95
+ favorite?: boolean
101
96
  /**
102
97
  * Enable shuffle mode toggle.
103
98
  * @default true
@@ -117,10 +112,11 @@ export interface PlayerCapabilities {
117
112
  }
118
113
 
119
114
  /**
120
- * Buttons that can be assigned to Android notification button slots.
121
- * These represent the interactive buttons users can tap in the notification.
115
+ * Buttons that can be placed in the Android button layout — the interactive
116
+ * controls a listener taps in the notification, on the Android Auto Now Playing
117
+ * screen, and in the Android 13+ system media controls.
122
118
  */
123
- export type NotificationButton =
119
+ export type RemoteButton =
124
120
  | 'skip-to-previous'
125
121
  | 'skip-to-next'
126
122
  | 'jump-backward'
@@ -128,43 +124,71 @@ export type NotificationButton =
128
124
  | 'favorite'
129
125
 
130
126
  /**
131
- * Configuration for notification button layout on Android.
132
- * Allows explicit control over which buttons appear in which slots.
127
+ * Where each button sits on Android.
128
+ *
129
+ * Android offers exactly three positions, and play/pause always occupies the
130
+ * centre — you cannot move it, and you cannot put two buttons on the same side
131
+ * of it:
132
+ *
133
+ * ```
134
+ * back │ ▶ play/pause │ forward overflow ⋯
135
+ * ```
136
+ *
137
+ * - **`back`** — the single position left of play/pause
138
+ * - **`forward`** — the single position right of play/pause
139
+ * - **`overflow`** — everything else, in priority order
140
+ *
141
+ * **A layout describes the whole arrangement.** All three fields are required —
142
+ * there is no per-field merge with the capability defaults, so what you write is
143
+ * exactly what renders. Use `undefined` for an empty position and `[]` for no
144
+ * overflow. To go back to the derived defaults, omit `remoteButtonLayout`
145
+ * entirely (or set it to `null`); that is the only switch.
133
146
  *
134
- * Slot behavior:
135
- * - **Omit a slot**: Derive from capabilities (smart default)
136
- * - **Set to null**: Explicitly empty slot
137
- * - **Set to button**: Show that button in that slot
147
+ * **Overflow order is priority, not coordinates.** Each surface renders as many
148
+ * buttons as it has room for, taking them from the front — a phone
149
+ * notification, the Android 13+ system media controls, and a car head unit all
150
+ * have different budgets. A head unit with a spare slot may promote the first
151
+ * overflow entry onto the main row, and a long list gets truncated by whichever
152
+ * surface is showing it. Put what matters most first.
153
+ *
154
+ * Placement never changes what a control *can* do: a button left out entirely
155
+ * still responds to a Bluetooth remote or headset, as long as its
156
+ * {@link PlayerCapabilities} entry is enabled.
138
157
  *
139
158
  * @example
140
159
  * ```typescript
141
- * // Podcast-style: jump buttons as primary
142
- * notificationButtons: {
160
+ * // Podcast-style: jump either side of play/pause
161
+ * remoteButtonLayout: {
143
162
  * back: 'jump-backward',
144
163
  * forward: 'jump-forward',
145
- * overflow: ['favorite']
164
+ * overflow: ['skip-to-previous', 'skip-to-next', 'favorite']
146
165
  * }
147
166
  *
148
- * // Music-style: skip as primary, jump as secondary
149
- * notificationButtons: {
167
+ * // Music-style: skip either side of play/pause
168
+ * remoteButtonLayout: {
150
169
  * back: 'skip-to-previous',
151
170
  * forward: 'skip-to-next',
152
- * backSecondary: 'jump-backward',
153
- * forwardSecondary: 'jump-forward'
171
+ * overflow: ['favorite']
172
+ * }
173
+ *
174
+ * // Live radio: forward only, nothing to the left
175
+ * remoteButtonLayout: {
176
+ * back: undefined,
177
+ * forward: 'skip-to-next',
178
+ * overflow: []
154
179
  * }
155
180
  * ```
156
181
  */
157
- export type NotificationButtonLayout = {
158
- /** Primary back position (SLOT_BACK) - typically previous track or jump backward */
159
- back?: NotificationButton | null
160
- /** Primary forward position (SLOT_FORWARD) - typically next track or jump forward */
161
- forward?: NotificationButton | null
162
- /** Secondary back position (SLOT_BACK_SECONDARY) */
163
- backSecondary?: NotificationButton | null
164
- /** Secondary forward position (SLOT_FORWARD_SECONDARY) */
165
- forwardSecondary?: NotificationButton | null
166
- /** Additional buttons in overflow area (SLOT_OVERFLOW) */
167
- overflow?: NotificationButton[]
182
+ export type RemoteButtonLayout = {
183
+ /** The single position left of play/pause. `undefined` leaves it empty. */
184
+ back: RemoteButton | undefined
185
+ /** The single position right of play/pause. `undefined` leaves it empty. */
186
+ forward: RemoteButton | undefined
187
+ /**
188
+ * Everything else, most important first — surfaces promote and truncate from
189
+ * the front. `[]` for none.
190
+ */
191
+ overflow: RemoteButton[]
168
192
  }
169
193
 
170
194
  /**
@@ -204,12 +228,22 @@ export interface Options {
204
228
 
205
229
  /**
206
230
  * Jump forward interval in seconds when using jump forward controls.
231
+ *
232
+ * On Android, an interval of exactly 5, 10, 15 or 30 seconds gets an icon
233
+ * showing that number; any other interval gets an icon without one. Other
234
+ * values are perfectly valid — the interval also sets the seek distance.
235
+ *
207
236
  * @default 15
208
237
  */
209
238
  forwardJumpInterval: number
210
239
 
211
240
  /**
212
241
  * Jump backward interval in seconds when using jump backward controls.
242
+ *
243
+ * On Android, an interval of exactly 5, 10, 15 or 30 seconds gets an icon
244
+ * showing that number; any other interval gets an icon without one. Other
245
+ * values are perfectly valid — the interval also sets the seek distance.
246
+ *
213
247
  * @default 15
214
248
  */
215
249
  backwardJumpInterval: number
@@ -254,6 +288,13 @@ export interface IOSOptions {
254
288
  * @default []
255
289
  */
256
290
  carPlayNowPlayingButtons: CarPlayNowPlayingButton[]
291
+
292
+ /**
293
+ * Where the now-playing indicator draws on CarPlay list rows.
294
+ * See {@link CarPlayPlayingIndicatorLocation}.
295
+ * @default 'leading'
296
+ */
297
+ carPlayPlayingIndicatorLocation: CarPlayPlayingIndicatorLocation
257
298
  }
258
299
 
259
300
  export interface AndroidOptions {
@@ -273,14 +314,14 @@ export interface AndroidOptions {
273
314
  skipSilence: boolean
274
315
 
275
316
  /**
276
- * Slot-based button layout for Android notifications.
277
- * Provides explicit control over which buttons appear in which positions.
317
+ * Ordered button layout, applied to the notification, Android Auto, and the
318
+ * Android 13+ system media controls. See {@link RemoteButtonLayout}.
278
319
  *
279
- * When not specified, button layout is derived from capabilities.
320
+ * When not specified, the layout is derived from capabilities.
280
321
  *
281
322
  * @platform android
282
323
  */
283
- notificationButtons: NotificationButtonLayout | null
324
+ remoteButtonLayout: RemoteButtonLayout | null
284
325
  }
285
326
 
286
327
  export interface AndroidUpdateOptions {
@@ -300,14 +341,14 @@ export interface AndroidUpdateOptions {
300
341
  skipSilence?: boolean
301
342
 
302
343
  /**
303
- * Slot-based button layout for Android notifications.
304
- * Provides explicit control over which buttons appear in which positions.
344
+ * Ordered button layout, applied to the notification, Android Auto, and the
345
+ * Android 13+ system media controls. See {@link RemoteButtonLayout}.
305
346
  *
306
- * When not specified, button layout is derived from capabilities.
347
+ * When not specified, the layout is derived from capabilities.
307
348
  *
308
349
  * @platform android
309
350
  */
310
- notificationButtons?: NotificationButtonLayout | null
351
+ remoteButtonLayout?: RemoteButtonLayout | null
311
352
  }
312
353
 
313
354
  /**
@@ -317,7 +358,7 @@ export interface AndroidUpdateOptions {
317
358
  export interface NitroAndroidUpdateOptions {
318
359
  appKilledPlaybackBehavior?: AppKilledPlaybackBehavior
319
360
  skipSilence?: boolean
320
- notificationButtons?: NotificationButtonLayout | null
361
+ remoteButtonLayout?: RemoteButtonLayout | null
321
362
  }
322
363
 
323
364
  /**
@@ -350,6 +391,13 @@ export interface IOSUpdateOptions {
350
391
  * @default []
351
392
  */
352
393
  carPlayNowPlayingButtons?: CarPlayNowPlayingButton[]
394
+
395
+ /**
396
+ * Where the now-playing indicator draws on CarPlay list rows.
397
+ * See {@link CarPlayPlayingIndicatorLocation}.
398
+ * @default 'leading'
399
+ */
400
+ carPlayPlayingIndicatorLocation?: CarPlayPlayingIndicatorLocation
353
401
  }
354
402
 
355
403
  /**
@@ -360,6 +408,7 @@ export interface NitroIOSUpdateOptions {
360
408
  playbackRates?: number[]
361
409
  carPlayUpNextButton?: boolean
362
410
  carPlayNowPlayingButtons?: CarPlayNowPlayingButton[]
411
+ carPlayPlayingIndicatorLocation?: CarPlayPlayingIndicatorLocation
363
412
  }
364
413
 
365
414
  /**
@@ -394,12 +443,22 @@ export interface UpdateOptions {
394
443
 
395
444
  /**
396
445
  * Jump forward interval in seconds when using jump forward controls.
446
+ *
447
+ * On Android, an interval of exactly 5, 10, 15 or 30 seconds gets an icon
448
+ * showing that number; any other interval gets an icon without one. Other
449
+ * values are perfectly valid — the interval also sets the seek distance.
450
+ *
397
451
  * @default 15
398
452
  */
399
453
  forwardJumpInterval?: number
400
454
 
401
455
  /**
402
456
  * Jump backward interval in seconds when using jump backward controls.
457
+ *
458
+ * On Android, an interval of exactly 5, 10, 15 or 30 seconds gets an icon
459
+ * showing that number; any other interval gets an icon without one. Other
460
+ * values are perfectly valid — the interval also sets the seek distance.
461
+ *
403
462
  * @default 15
404
463
  */
405
464
  backwardJumpInterval?: number
@@ -442,12 +501,22 @@ export interface NativeUpdateOptions {
442
501
 
443
502
  /**
444
503
  * Jump forward interval in seconds when using jump forward controls.
504
+ *
505
+ * On Android, an interval of exactly 5, 10, 15 or 30 seconds gets an icon
506
+ * showing that number; any other interval gets an icon without one. Other
507
+ * values are perfectly valid — the interval also sets the seek distance.
508
+ *
445
509
  * @default 15
446
510
  */
447
511
  forwardJumpInterval?: number
448
512
 
449
513
  /**
450
514
  * Jump backward interval in seconds when using jump backward controls.
515
+ *
516
+ * On Android, an interval of exactly 5, 10, 15 or 30 seconds gets an icon
517
+ * showing that number; any other interval gets an icon without one. Other
518
+ * values are perfectly valid — the interval also sets the seek distance.
519
+ *
451
520
  * @default 15
452
521
  */
453
522
  backwardJumpInterval?: number
@@ -464,25 +533,6 @@ export interface NativeUpdateOptions {
464
533
 
465
534
  // MARK: - Functions
466
535
 
467
- const MAX_CARPLAY_NOW_PLAYING_BUTTONS = 5
468
-
469
- /**
470
- * Warns when more CarPlay now-playing buttons are configured than CarPlay renders.
471
- * Shared by {@link updateOptions} and `setupPlayer` (both can carry `ios` options).
472
- *
473
- * @internal Validation helper, not public API — `stripInternal` removes it from
474
- * the published types and typedoc hides it from the docs.
475
- */
476
- export function validateIOSUpdateOptions(ios?: IOSUpdateOptions): void {
477
- const buttons = ios?.carPlayNowPlayingButtons
478
- if (buttons && buttons.length > MAX_CARPLAY_NOW_PLAYING_BUTTONS) {
479
- console.warn(
480
- `[react-native-audio-browser] ${buttons.length} CarPlay now-playing ` +
481
- `buttons configured; CarPlay shows at most ${MAX_CARPLAY_NOW_PLAYING_BUTTONS}.`
482
- )
483
- }
484
- }
485
-
486
536
  /**
487
537
  * Updates the configuration for the components.
488
538
  * Pass only the properties you want to change - all properties are optional.
@@ -527,7 +577,7 @@ export function getOptions(): Options {
527
577
  /**
528
578
  * Subscribes to player options changes.
529
579
  * @param callback - Called when the player options change
530
- * @returns Cleanup function to unsubscribe
580
+ * @returns An emitter — subscribe with `addListener(callback)`, which returns a cleanup function
531
581
  */
532
582
  export const onOptionsChanged = NativeUpdatedValue.emitterize<Options>(
533
583
  (cb) => (nativeBrowser.onOptionsChanged = cb)
@@ -52,7 +52,11 @@ describe('setupPlayer wire regrouping', () => {
52
52
  minBuffer: 50_000,
53
53
  wakeMode: 'network',
54
54
  skipSilence: true,
55
- notificationButtons: { overflow: ['favorite'] }
55
+ remoteButtonLayout: {
56
+ back: 'jump-backward',
57
+ forward: 'jump-forward',
58
+ overflow: ['favorite']
59
+ }
56
60
  }
57
61
  })
58
62
 
@@ -61,19 +65,32 @@ describe('setupPlayer wire regrouping', () => {
61
65
  expect(sent.options).toEqual({
62
66
  android: {
63
67
  skipSilence: true,
64
- notificationButtons: { overflow: ['favorite'] }
68
+ remoteButtonLayout: {
69
+ back: 'jump-backward',
70
+ forward: 'jump-forward',
71
+ overflow: ['favorite']
72
+ }
65
73
  }
66
74
  })
67
75
  })
68
76
 
69
- it('moves ios playbackRates into the runtime options', async () => {
77
+ it('moves ios runtime fields into the runtime options', async () => {
70
78
  await setupPlayer({
71
- ios: { category: 'playback', playbackRates: [0.5, 1, 2] }
79
+ ios: {
80
+ category: 'playback',
81
+ playbackRates: [0.5, 1, 2],
82
+ carPlayPlayingIndicatorLocation: 'trailing'
83
+ }
72
84
  })
73
85
 
74
86
  const sent = payload()
75
87
  expect(sent.ios).toEqual({ category: 'playback' })
76
- expect(sent.options).toEqual({ ios: { playbackRates: [0.5, 1, 2] } })
88
+ expect(sent.options).toEqual({
89
+ ios: {
90
+ playbackRates: [0.5, 1, 2],
91
+ carPlayPlayingIndicatorLocation: 'trailing'
92
+ }
93
+ })
77
94
  })
78
95
 
79
96
  it('omits a platform bag that only carried runtime fields', async () => {
@@ -85,12 +102,12 @@ describe('setupPlayer wire regrouping', () => {
85
102
  it('forwards meaningful nulls (progress disabled, empty button layout)', async () => {
86
103
  await setupPlayer({
87
104
  progressUpdateEventInterval: null,
88
- android: { notificationButtons: null }
105
+ android: { remoteButtonLayout: null }
89
106
  })
90
107
 
91
108
  expect(payload().options).toEqual({
92
109
  progressUpdateEventInterval: null,
93
- android: { notificationButtons: null }
110
+ android: { remoteButtonLayout: null }
94
111
  })
95
112
  })
96
113
 
@@ -11,7 +11,7 @@ import type {
11
11
  UpdateOptions
12
12
  } from './options'
13
13
  import { nativeBrowser } from '../../native'
14
- import { validateIOSUpdateOptions } from './options'
14
+ import { validateIOSUpdateOptions } from './validateOptions'
15
15
 
16
16
  /**
17
17
  * Parameters passed to the {@link FormatNowPlayingCallback}.
@@ -25,7 +25,10 @@ import { validateIOSUpdateOptions } from './options'
25
25
  export type FormatNowPlayingParams = {
26
26
  /** The currently playing track. */
27
27
  track: Track
28
- /** Timed metadata (ICY / ID3 "now playing song") received during playback, if any. */
28
+ /**
29
+ * Timed metadata (ICY / ID3 "now playing song") received during playback, if any.
30
+ * Always `undefined` on web — see `onTimedMetadata` for why.
31
+ */
29
32
  timedMetadata?: TimedMetadata
30
33
  /** The play/pause intent — `false` while paused. Stays `true` through buffers, so the song line won't flicker. */
31
34
  playWhenReady: boolean
@@ -326,7 +329,7 @@ export type AndroidPlayerWakeMode = 'none' | 'local' | 'network'
326
329
 
327
330
  /**
328
331
  * Android setup options: the engine-construction fields plus the Android runtime options
329
- * ({@link AndroidUpdateOptions} — `notificationButtons`, `skipSilence`, …), all expressible at
332
+ * ({@link AndroidUpdateOptions} — `remoteButtonLayout`, `skipSilence`, …), all expressible at
330
333
  * launch. The consumer never has to know which is which; `setupPlayer` routes each field to
331
334
  * where it's applied.
332
335
  */
@@ -496,7 +499,7 @@ export interface NativeSetupPlayerOptions extends Pick<
496
499
 
497
500
  /**
498
501
  * Player options to apply atomically with setup. They're stored before the player is
499
- * constructed, so e.g. Android's media session derives its notification buttons from
502
+ * constructed, so e.g. Android's media session derives its remote button layout from
500
503
  * `capabilities` the moment the service connects — no window with default controls.
501
504
  * Normalized from the flat fields on {@link SetupPlayerOptions}.
502
505
  */
@@ -658,7 +661,7 @@ function wrapNowPlayingFormatter(
658
661
 
659
662
  /**
660
663
  * The object's entries whose values aren't `undefined`. `null` stays: it's meaningful on some
661
- * fields (`progressUpdateEventInterval: null` disables progress events, `notificationButtons:
664
+ * fields (`progressUpdateEventInterval: null` disables progress events, `remoteButtonLayout:
662
665
  * null` empties the layout), so only `undefined` means "not provided".
663
666
  */
664
667
  function definedFields<T extends object>(obj: T): Partial<T> {
@@ -682,7 +685,7 @@ function nonEmpty<K extends string, T extends object>(
682
685
  /**
683
686
  * Initializes the player with the specified options — the full launch description in one
684
687
  * declarative, atomic call. Runtime options (`capabilities`, jump intervals,
685
- * `notificationButtons`, …) and the initial `playWhenReady` / `repeatMode` are applied
688
+ * `remoteButtonLayout`, …) and the initial `playWhenReady` / `repeatMode` are applied
686
689
  * natively as part of setup itself, so there is no setup-then-command ordering for consumers
687
690
  * to know about, and no window where the player exists without its options.
688
691
  *
@@ -699,7 +702,14 @@ function nonEmpty<K extends string, T extends object>(
699
702
  * playWhenReady: true,
700
703
  * repeatMode: 'queue',
701
704
  * capabilities: { favorite: true },
702
- * android: { audioContentType: 'music', notificationButtons: { overflow: ['favorite'] } },
705
+ * android: {
706
+ * audioContentType: 'music',
707
+ * remoteButtonLayout: {
708
+ * back: 'jump-backward',
709
+ * forward: 'jump-forward',
710
+ * overflow: ['favorite']
711
+ * }
712
+ * },
703
713
  * ios: { category: 'playback' }
704
714
  * })
705
715
  * ```
@@ -724,19 +734,21 @@ export async function setupPlayer(
724
734
  const {
725
735
  appKilledPlaybackBehavior,
726
736
  skipSilence,
727
- notificationButtons,
737
+ remoteButtonLayout,
728
738
  ...androidSetup
729
739
  } = android
730
740
  const {
731
741
  playbackRates,
732
742
  carPlayUpNextButton,
733
743
  carPlayNowPlayingButtons,
744
+ carPlayPlayingIndicatorLocation,
734
745
  ...iosSetup
735
746
  } = ios
736
747
  const iosUpdate = definedFields({
737
748
  playbackRates,
738
749
  carPlayUpNextButton,
739
- carPlayNowPlayingButtons
750
+ carPlayNowPlayingButtons,
751
+ carPlayPlayingIndicatorLocation
740
752
  })
741
753
  validateIOSUpdateOptions(iosUpdate)
742
754
 
@@ -750,7 +762,7 @@ export async function setupPlayer(
750
762
  definedFields({
751
763
  appKilledPlaybackBehavior,
752
764
  skipSilence,
753
- notificationButtons
765
+ remoteButtonLayout
754
766
  })
755
767
  ),
756
768
  ...nonEmpty('ios', iosUpdate)
@@ -0,0 +1,21 @@
1
+ import type { IOSUpdateOptions } from './options'
2
+
3
+ const MAX_CARPLAY_NOW_PLAYING_BUTTONS = 5
4
+
5
+ /**
6
+ * Warns when more CarPlay now-playing buttons are configured than CarPlay renders.
7
+ * Shared by `updateOptions` and `setupPlayer` (both can carry `ios` options).
8
+ * Kept out of `options.ts`, which the barrel re-exports — see
9
+ * public-surface.test.ts.
10
+ *
11
+ * @internal
12
+ */
13
+ export function validateIOSUpdateOptions(ios?: IOSUpdateOptions): void {
14
+ const buttons = ios?.carPlayNowPlayingButtons
15
+ if (buttons && buttons.length > MAX_CARPLAY_NOW_PLAYING_BUTTONS) {
16
+ console.warn(
17
+ `[react-native-audio-browser] ${buttons.length} CarPlay now-playing ` +
18
+ `buttons configured; CarPlay shows at most ${MAX_CARPLAY_NOW_PLAYING_BUTTONS}.`
19
+ )
20
+ }
21
+ }
@@ -1,7 +1,8 @@
1
1
  import type { Track } from '../../types'
2
2
  import { nativeBrowser } from '../../native'
3
3
  import { NativeUpdatedValue } from '../../utils/NativeUpdatedValue'
4
- import { useNativeUpdatedValue } from '../../utils/useNativeUpdatedValue'
4
+ import { useNativeValueRefreshedBy } from '../../utils/useNativeValueRefreshedBy'
5
+ import { onFavoriteChanged } from '../favorites'
5
6
 
6
7
  /**
7
8
  * Event data for when the active track changes.
@@ -40,8 +41,14 @@ export function getActiveTrackIndex(): number | undefined {
40
41
 
41
42
  /**
42
43
  * Subscribes to active track change events.
44
+ *
45
+ * Fires on **transitions only** — selection, queue advance, skip. In-place
46
+ * metadata mutations of the active track (a favorite toggle) emit
47
+ * {@link onFavoriteChanged} instead; {@link useActiveTrack} subscribes to
48
+ * both, so UI bound through the hook still re-renders on a heart toggle.
49
+ *
43
50
  * @param callback - Called when the active track changes
44
- * @returns Cleanup function to unsubscribe
51
+ * @returns An emitter — subscribe with `addListener(callback)`, which returns a cleanup function
45
52
  */
46
53
  export const onActiveTrackChanged =
47
54
  NativeUpdatedValue.emitterize<PlaybackActiveTrackChangedEvent>(
@@ -50,10 +57,14 @@ export const onActiveTrackChanged =
50
57
 
51
58
  // MARK: - Hooks
52
59
 
60
+ // Module-level so the hook's subscription identity is stable across renders.
61
+ const activeTrackInvalidators = [onActiveTrackChanged, onFavoriteChanged]
62
+
53
63
  /**
54
- * Hook that returns the current active track and updates when it changes.
64
+ * Hook that returns the current active track, updating on transitions AND on
65
+ * in-place mutations of the active track (favorite toggles).
55
66
  * @returns The current active track or undefined
56
67
  */
57
68
  export function useActiveTrack(): Track | undefined {
58
- return useNativeUpdatedValue(getActiveTrack, onActiveTrackChanged, 'track')
69
+ return useNativeValueRefreshedBy(getActiveTrack, activeTrackInvalidators)
59
70
  }
@@ -1,7 +1,8 @@
1
1
  import type { Track } from '../../types'
2
2
  import { nativeBrowser } from '../../native'
3
3
  import { NativeUpdatedValue } from '../../utils/NativeUpdatedValue'
4
- import { useNativeUpdatedValue } from '../../utils/useNativeUpdatedValue'
4
+ import { useNativeValueRefreshedBy } from '../../utils/useNativeValueRefreshedBy'
5
+ import { onFavoriteChanged } from '../favorites'
5
6
 
6
7
  // MARK: - Types
7
8
 
@@ -156,7 +157,7 @@ export function getQueue(): Track[] {
156
157
  /**
157
158
  * Subscribes to playback queue ended events.
158
159
  * @param callback - Called when playback has paused due to reaching the end of the queue
159
- * @returns Cleanup function to unsubscribe
160
+ * @returns An emitter — subscribe with `addListener(callback)`, which returns a cleanup function
160
161
  */
161
162
  export const onQueueEnded =
162
163
  NativeUpdatedValue.emitterize<PlaybackQueueEndedEvent>(
@@ -165,9 +166,11 @@ export const onQueueEnded =
165
166
 
166
167
  /**
167
168
  * Subscribes to queue change events.
168
- * Called when tracks are added, removed, reordered, or when track metadata changes.
169
+ * Called when tracks are added, removed, or reordered. An in-place mutation of
170
+ * a queued track's metadata (a favorite toggle) emits `onFavoriteChanged`
171
+ * instead; {@link useQueue} subscribes to both.
169
172
  * @param callback - Called with the updated queue
170
- * @returns Cleanup function to unsubscribe
173
+ * @returns An emitter — subscribe with `addListener(callback)`, which returns a cleanup function
171
174
  */
172
175
  export const onQueueChanged = NativeUpdatedValue.emitterize<Track[]>(
173
176
  (cb) => (nativeBrowser.onPlaybackQueueChanged = cb)
@@ -175,10 +178,14 @@ export const onQueueChanged = NativeUpdatedValue.emitterize<Track[]>(
175
178
 
176
179
  // MARK: - Hooks
177
180
 
181
+ // Module-level so the hook's subscription identity is stable across renders.
182
+ const queueInvalidators = [onQueueChanged, onFavoriteChanged]
183
+
178
184
  /**
179
- * Hook that returns the current queue and updates when it changes.
185
+ * Hook that returns the current queue, updating on queue changes AND on
186
+ * in-place mutations of queued tracks (favorite toggles).
180
187
  * @returns The current queue
181
188
  */
182
189
  export function useQueue(): Track[] {
183
- return useNativeUpdatedValue(getQueue, onQueueChanged)
190
+ return useNativeValueRefreshedBy(getQueue, queueInvalidators)
184
191
  }
@@ -40,7 +40,7 @@ export interface RepeatModeChangedEvent {
40
40
  /**
41
41
  * Subscribes to repeat mode changes.
42
42
  * @param callback - Called when repeat mode changes
43
- * @returns Cleanup function to unsubscribe
43
+ * @returns An emitter — subscribe with `addListener(callback)`, which returns a cleanup function
44
44
  */
45
45
  export const onRepeatModeChanged =
46
46
  NativeUpdatedValue.emitterize<RepeatModeChangedEvent>(
@@ -32,7 +32,7 @@ export function toggleShuffle(): void {
32
32
  /**
33
33
  * Subscribes to shuffle mode changes.
34
34
  * @param callback - Called when shuffle mode changes
35
- * @returns Cleanup function to unsubscribe
35
+ * @returns An emitter — subscribe with `addListener(callback)`, which returns a cleanup function
36
36
  */
37
37
  export const onShuffleChanged = NativeUpdatedValue.emitterize<boolean>(
38
38
  (cb) => (nativeBrowser.onPlaybackShuffleModeChanged = cb)