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

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
@@ -0,0 +1,328 @@
1
+ ---
2
+ description: 'Control the active track — play, pause, stop, seek, playback state, progress, rate, and volume — the toolkit for building your own player UI.'
3
+ ---
4
+
5
+ # Playback
6
+
7
+ This guide covers **controlling the active track** — transport (play / pause /
8
+ stop), seeking, playback state, progress, rate, and volume. It's the toolkit for
9
+ building your own player UI.
10
+
11
+ Playback acts on whatever the **active track** is. _Which_ track that is — and
12
+ moving between tracks with next/previous — belongs to the [queue](/guide/basic-usage#the-queue);
13
+ this page is about playing the one that's already active. The system surfaces
14
+ (lock screen, notification, car) are covered in [Now Playing](/guide/now-playing).
15
+
16
+ > All functions here are synchronous and safe to call before a track is loaded —
17
+ > they're no-ops or update intent rather than throwing.
18
+
19
+ The UI snippets below import `useState` from `react`, `Text` / `Button` /
20
+ `Switch` from `react-native`, and `Slider` from
21
+ `@react-native-community/slider`; those import lines are omitted for brevity.
22
+ Everything else comes from `react-native-audio-browser`.
23
+
24
+ ## Transport controls
25
+
26
+ ```ts
27
+ import { play, pause, togglePlayback, stop } from 'react-native-audio-browser'
28
+
29
+ play() // play or resume the active track
30
+ pause() // pause, keeping position
31
+ togglePlayback() // flip between play and pause
32
+ stop() // stop and reset position to the start
33
+ ```
34
+
35
+ `stop` keeps the track loaded — `play()` afterwards starts it again from the
36
+ beginning. (For live streams there's no position to reset, so it just stops.)
37
+ That's different from `reset`, which stops playback **and clears the queue**:
38
+
39
+ ```ts
40
+ import { reset } from 'react-native-audio-browser'
41
+
42
+ reset() // tear down: stop + empty the queue
43
+ ```
44
+
45
+ | | Position | Track stays loaded | Queue |
46
+ | --------- | -------------- | ------------------ | ------- |
47
+ | `pause()` | kept | yes | kept |
48
+ | `stop()` | reset to start | yes | kept |
49
+ | `reset()` | — | no | cleared |
50
+
51
+ ## Seeking
52
+
53
+ Seek within the active track by an absolute position or a relative offset, both
54
+ in **seconds**:
55
+
56
+ ```ts
57
+ import { seekTo, seekBy } from 'react-native-audio-browser'
58
+
59
+ seekTo(90) // jump to 1:30
60
+ seekBy(30) // skip ahead 30s
61
+ seekBy(-15) // back 15s
62
+ ```
63
+
64
+ For live streams, jump back to the live edge (a no-op for non-live tracks):
65
+
66
+ ```ts
67
+ import { seekToLiveEdge } from 'react-native-audio-browser'
68
+
69
+ seekToLiveEdge()
70
+ ```
71
+
72
+ Moving between tracks (next / previous / skip) is part of the
73
+ [queue](/guide/basic-usage#the-queue), not seeking.
74
+
75
+ ## Playback state
76
+
77
+ `usePlayback` returns the current `{ state, error }`. The `state` is one of:
78
+
79
+ | State | Meaning |
80
+ | ------------- | ---------------------------------------------- |
81
+ | `'none'` | Idle — no track loaded (initial state). |
82
+ | `'loading'` | Loading the item before playback can begin. |
83
+ | `'ready'` | Track loaded and ready, currently paused. |
84
+ | `'playing'` | Currently playing. |
85
+ | `'buffering'` | Loading more data before it can continue. |
86
+ | `'paused'` | Paused. |
87
+ | `'stopped'` | Stopped. |
88
+ | `'ended'` | Reached the end of the queue. |
89
+ | `'error'` | Playback failed — see [Errors](/guide/errors). |
90
+
91
+ ```tsx
92
+ import { usePlayback, retry } from 'react-native-audio-browser'
93
+
94
+ function PlayerStatus() {
95
+ const { state } = usePlayback() // `error` is also here — see Errors
96
+
97
+ if (state === 'error') {
98
+ return <Button title="Retry" onPress={() => retry()} />
99
+ }
100
+ return <Text>{state}</Text>
101
+ }
102
+ ```
103
+
104
+ `retry()` only does something while the state is `'error'`; it re-attempts the
105
+ current item. See [Errors](/guide/errors) for the error shape and handling.
106
+
107
+ ### Just playing or buffering?
108
+
109
+ For a play/pause button, drive it off `usePlayingState` — not
110
+ `state === 'playing'` — so it isn't thrown off by the `loading`/`buffering`
111
+ states. It gives you two booleans and re-renders only when they flip:
112
+
113
+ ```tsx
114
+ import { usePlayingState, togglePlayback } from 'react-native-audio-browser'
115
+
116
+ function PlayPauseButton() {
117
+ const { playing, buffering } = usePlayingState()
118
+
119
+ return (
120
+ <Button
121
+ title={buffering ? 'Loading…' : playing ? 'Pause' : 'Play'}
122
+ onPress={() => togglePlayback()}
123
+ />
124
+ )
125
+ }
126
+ ```
127
+
128
+ ### Play-when-ready
129
+
130
+ `playWhenReady` is the **intent** to play, separate from whether audio is
131
+ actually coming out yet (it may still be loading or buffering). Setting it is
132
+ equivalent to calling `play()` / `pause()`:
133
+
134
+ ```tsx
135
+ import { setPlayWhenReady, usePlayWhenReady } from 'react-native-audio-browser'
136
+
137
+ setPlayWhenReady(true) // same as play()
138
+
139
+ function PlayToggle() {
140
+ const wantsToPlay = usePlayWhenReady()
141
+ return (
142
+ <Switch
143
+ value={wantsToPlay}
144
+ onValueChange={(next) => setPlayWhenReady(next)}
145
+ />
146
+ )
147
+ }
148
+ ```
149
+
150
+ Use `usePlayWhenReady` when your control should reflect the user's _intent_
151
+ immediately (the toggle flips the instant they tap, even while buffering); use
152
+ `usePlayingState` when it should reflect whether sound is actually playing.
153
+
154
+ ## Progress
155
+
156
+ Progress is `{ position, duration, buffered }`, all in seconds. There are two
157
+ hooks, and the difference matters:
158
+
159
+ - **`usePolledProgress(intervalMs?)`** — polls on a timer (default 1000 **ms**).
160
+ Works out of the box, and automatically pauses while the app is backgrounded.
161
+ **Start here.**
162
+ - **`useProgress()`** — driven by native progress events. These are
163
+ **disabled by default** (`progressUpdateEventInterval` is `null`), so this
164
+ hook won't update until you turn them on (see below).
165
+
166
+ > **Mind the units.** `usePolledProgress` takes its interval in
167
+ > **milliseconds**; `progressUpdateEventInterval` (below) is in **seconds**.
168
+
169
+ ```tsx
170
+ import { usePolledProgress, seekTo } from 'react-native-audio-browser'
171
+
172
+ function Scrubber() {
173
+ const { position, duration } = usePolledProgress()
174
+
175
+ return (
176
+ <Slider
177
+ minimumValue={0}
178
+ maximumValue={duration || 1}
179
+ value={position}
180
+ // Seek when the user releases the thumb.
181
+ onSlidingComplete={(seconds) => seekTo(seconds)}
182
+ />
183
+ )
184
+ }
185
+ ```
186
+
187
+ To use the event-based `useProgress` instead, enable progress events once at
188
+ setup by setting how often they fire (in seconds):
189
+
190
+ ```ts
191
+ import { setupPlayer } from 'react-native-audio-browser'
192
+
193
+ await setupPlayer({ progressUpdateEventInterval: 0.5 })
194
+ // or later: updateOptions({ progressUpdateEventInterval: 0.5 })
195
+ ```
196
+
197
+ Outside React, `getProgress()` returns a one-off snapshot of the current
198
+ position/duration/buffered — it's a plain getter and is **never** gated, so it
199
+ works even with progress events off. Only the `onProgressUpdated` event (and
200
+ therefore `useProgress`) depends on `progressUpdateEventInterval`.
201
+
202
+ ## Playback rate
203
+
204
+ Rate is a multiplier: `1` is normal, `0.5` half speed, `2` double. Handy for
205
+ podcasts and audiobooks:
206
+
207
+ ```ts
208
+ import { getRate, setRate } from 'react-native-audio-browser'
209
+
210
+ setRate(1.5) // 1.5× speed
211
+ getRate() // → current rate
212
+ ```
213
+
214
+ Rate is a speed multiplier, not a transport control: it's independent of
215
+ play/pause, and setting it while paused doesn't start playback. Pass a value
216
+ greater than zero — the platforms disagree on what a non-positive rate does
217
+ (iOS ignores it, Android throws, web stalls the audio element), so treat it as
218
+ unsupported rather than as a way to pause.
219
+
220
+ There's no reactive hook for rate (it only changes when you set it), so a
221
+ control that displays the current speed just holds it in local state:
222
+
223
+ ```tsx
224
+ function SpeedControl() {
225
+ const [rate, setRateState] = useState(() => getRate())
226
+ const cycle = () => {
227
+ const next = rate >= 2 ? 0.5 : rate + 0.5
228
+ setRate(next) // tell the player
229
+ setRateState(next) // update the label
230
+ }
231
+ return <Button title={`${rate.toFixed(1)}×`} onPress={cycle} />
232
+ }
233
+ ```
234
+
235
+ ## Volume
236
+
237
+ There are two distinct volumes:
238
+
239
+ - **Player volume** — this player's own level, `0`–`1`. Use it for in-app
240
+ controls, ducking, or fades.
241
+ - **System volume** — the device's media volume, `0`–`1`.
242
+
243
+ Player volume has no reactive hook (it only changes when you set it), so a
244
+ controlled `<Slider>` holds the value in local state — seed it from `getVolume()`
245
+ and write through to `setVolume`:
246
+
247
+ ```tsx
248
+ import { getVolume, setVolume } from 'react-native-audio-browser'
249
+
250
+ function VolumeSlider() {
251
+ const [volume, setVolumeState] = useState(() => getVolume())
252
+ return (
253
+ <Slider
254
+ minimumValue={0}
255
+ maximumValue={1}
256
+ value={volume}
257
+ onValueChange={(next) => {
258
+ setVolume(next) // apply to the player
259
+ setVolumeState(next) // keep the slider in sync
260
+ }}
261
+ />
262
+ )
263
+ }
264
+ ```
265
+
266
+ System volume _does_ have a hook, since the hardware buttons can change it
267
+ behind your back:
268
+
269
+ ```tsx
270
+ import { useSystemVolume } from 'react-native-audio-browser'
271
+
272
+ function SystemVolumeLabel() {
273
+ const volume = useSystemVolume() // re-renders on hardware volume keys
274
+ return <Text>{Math.round(volume * 100)}%</Text>
275
+ }
276
+ ```
277
+
278
+ `setSystemVolume` is a **no-op on iOS** — Apple provides no public API to set
279
+ the system volume (use the player volume there instead). Reading it and
280
+ `useSystemVolume` work on both platforms.
281
+
282
+ ## Measuring listening time
283
+
284
+ `trackPlaybackTime` calls you back every N seconds of **actual playback** — the
285
+ clock advances only while the state is `'playing'` and freezes on
286
+ pause/buffering/stop, so paused time never inflates the count. It's built for
287
+ "still listening" analytics pings:
288
+
289
+ ```ts
290
+ import { trackPlaybackTime } from 'react-native-audio-browser'
291
+
292
+ // Fire every 30 seconds of real listening. `sendHeartbeat` is your own
293
+ // analytics call. The callback also gets `sinceLast` (seconds since the
294
+ // previous fire) if you'd rather report deltas than the running total.
295
+ const cancel = trackPlaybackTime(({ total, sinceLast, track }) => {
296
+ sendHeartbeat({ seconds: total, trackId: track?.id })
297
+ }, 30)
298
+
299
+ // later:
300
+ cancel()
301
+ ```
302
+
303
+ `period` must be `>= 1` (it throws otherwise). The clock is cumulative across
304
+ the whole session and
305
+ counts _all_ play time, not per-track — `total` keeps climbing through track
306
+ changes. To measure per track, cancel and re-subscribe whenever the
307
+ [active track changes](/guide/now-playing). It's a coarse, ~1-second-resolution
308
+ signal, not a precise timer.
309
+
310
+ ## API summary
311
+
312
+ | API | Purpose |
313
+ | ----------------------------------------------- | ----------------------------------------------------------------------- |
314
+ | `play()` / `pause()` / `togglePlayback()` | Start, pause, or flip playback. |
315
+ | `stop()` | Stop and reset position; track stays loaded. |
316
+ | `reset()` | Stop **and** clear the queue. |
317
+ | `seekTo(seconds)` / `seekBy(offset)` | Seek to an absolute / relative position. |
318
+ | `seekToLiveEdge()` | Jump to the live edge (no-op if not live). |
319
+ | `usePlayback()` / `getPlayback()` | Full `{ state, error }`; subscribe via `onPlaybackChanged`. |
320
+ | `retry()` | Re-attempt the current item while in the `'error'` state. |
321
+ | `usePlayingState()` | `{ playing, buffering }` booleans for a play/pause button. |
322
+ | `setPlayWhenReady(bool)` / `usePlayWhenReady()` | Play/pause _intent_, independent of buffering. |
323
+ | `usePolledProgress(intervalMs?)` | `{ position, duration, buffered }` via polling (ms) — works by default. |
324
+ | `useProgress()` / `getProgress()` | Progress via events (enable `progressUpdateEventInterval` first). |
325
+ | `getRate()` / `setRate(rate)` | Playback speed multiplier (`1` = normal). |
326
+ | `getVolume()` / `setVolume(0..1)` | This player's volume. |
327
+ | `getSystemVolume()` / `useSystemVolume()` | Device media volume (`setSystemVolume` is iOS no-op). |
328
+ | `trackPlaybackTime(cb, period)` | Heartbeat every `period` seconds of real playback. |
@@ -0,0 +1,300 @@
1
+ ---
2
+ description: 'Build and edit the queue, move between tracks with next and previous, and read it back for an "up next" UI.'
3
+ ---
4
+
5
+ # Queue
6
+
7
+ The **queue** is the ordered list of tracks the player works through. The track
8
+ at the current position is the **active track** — it's what plays, and what
9
+ next/previous move between. This guide covers building the queue, editing it,
10
+ moving between tracks, and reading it back for an "up next" UI.
11
+
12
+ For the first-time setup and the browse-tree concept, see
13
+ [Basic Usage](/guide/basic-usage#the-queue). For transport (play / pause / seek
14
+ _within_ the active track), see [Playback](/guide/playback). The system
15
+ surfaces (lock screen, car) are in [Now Playing](/guide/now-playing).
16
+
17
+ The UI snippets below import `View` / `Text` / `Button` / `FlatList` from
18
+ `react-native`; those import lines are omitted for brevity. Everything else
19
+ comes from `react-native-audio-browser`.
20
+
21
+ ## Setting the queue
22
+
23
+ [`setQueue`](/api/features/queue/#setqueue) replaces the entire queue.
24
+ Optionally pass which track to make active and where to start it:
25
+
26
+ ```ts
27
+ import { setQueue, play } from 'react-native-audio-browser'
28
+
29
+ setQueue(tracks) // replace; first track becomes active
30
+ setQueue(tracks, 2) // start on index 2
31
+ setQueue(tracks, 2, 30) // ...30 seconds in
32
+ ```
33
+
34
+ One thing to know:
35
+
36
+ - **It doesn't start playback.** `setQueue` leaves the play/pause state as-is —
37
+ if the player was paused it stays paused. Call
38
+ [`play()`](/api/features/playback/#play) to begin (see [Playback](/guide/playback)).
39
+
40
+ So the usual "load these and play" is two calls:
41
+
42
+ ```ts
43
+ setQueue(tracks) // or setQueue(tracks, startIndex)
44
+ play() // start playback
45
+ ```
46
+
47
+ ## Reading the queue
48
+
49
+ [`useQueue`](/api/features/queue/#usequeue) returns the current
50
+ [`Track[]`](/api/types/browser-nodes/#track) and re-renders whenever it changes
51
+ (add, remove, reorder, or metadata update):
52
+
53
+ ```tsx
54
+ import { useQueue } from 'react-native-audio-browser'
55
+
56
+ function QueueList() {
57
+ const queue = useQueue()
58
+ return (
59
+ <FlatList
60
+ data={queue}
61
+ keyExtractor={(track, i) => track.id ?? String(i)}
62
+ renderItem={({ item }) => <Text>{item.title}</Text>}
63
+ />
64
+ )
65
+ }
66
+ ```
67
+
68
+ Outside React, read a snapshot with
69
+ [`getQueue()`](/api/features/queue/#getqueue), or a single entry with
70
+ [`getTrack(index)`](/api/features/queue/#gettrack) (returns `undefined` if the
71
+ index is empty). To react to changes without a hook, subscribe to
72
+ [`onQueueChanged`](/api/features/queue/#onqueuechanged) — it fires with the new
73
+ queue on every add, remove, reorder, or metadata update.
74
+
75
+ ## The active track
76
+
77
+ [`useActiveTrack`](/api/features/queue/#useactivetrack) returns the currently
78
+ playing [`Track`](/api/types/browser-nodes/#track) (or `undefined` when nothing
79
+ is loaded):
80
+
81
+ ```tsx
82
+ import { useActiveTrack } from 'react-native-audio-browser'
83
+
84
+ function NowPlaying() {
85
+ const track = useActiveTrack()
86
+ return <Text>{track?.title ?? 'Nothing playing'}</Text>
87
+ }
88
+ ```
89
+
90
+ Outside React, use [`getActiveTrack()`](/api/features/queue/#getactivetrack) and
91
+ [`getActiveTrackIndex()`](/api/features/queue/#getactivetrackindex). To react to
92
+ _changes_ — e.g. for per-track analytics — subscribe to
93
+ [`onActiveTrackChanged`](/api/features/queue/#onactivetrackchanged), which also
94
+ reports the track you're leaving:
95
+
96
+ ```ts
97
+ import { onActiveTrackChanged } from 'react-native-audio-browser'
98
+
99
+ const unsubscribe = onActiveTrackChanged.addListener((event) => {
100
+ console.log('now playing', event.track?.title)
101
+ console.log('left off', event.lastTrack?.title, 'at', event.lastPosition)
102
+ })
103
+ ```
104
+
105
+ ## Moving between tracks
106
+
107
+ Jump to a track by index, or step to the next/previous one. Each optionally
108
+ takes a start position **in seconds**:
109
+
110
+ ```ts
111
+ import { skip, skipToNext, skipToPrevious } from 'react-native-audio-browser'
112
+
113
+ skip(3) // jump to index 3
114
+ skipToNext() // next track
115
+ skipToPrevious() // previous track
116
+ skipToNext(10) // next track, starting 10 seconds in
117
+ ```
118
+
119
+ This is how you move _between_ tracks
120
+ ([`skip`](/api/features/queue/#skip),
121
+ [`skipToNext`](/api/features/queue/#skiptonext),
122
+ [`skipToPrevious`](/api/features/queue/#skiptoprevious)); seeking _within_ the
123
+ active track (`seekTo` / `seekBy`) lives in [Playback](/guide/playback).
124
+
125
+ ## Editing the queue
126
+
127
+ [`add`](/api/features/queue/#add), [`move`](/api/features/queue/#move),
128
+ [`remove`](/api/features/queue/#remove),
129
+ [`removeUpcomingTracks`](/api/features/queue/#removeupcomingtracks), and
130
+ [`load`](/api/features/queue/#load) edit the queue without rebuilding it.
131
+ Indexes refer to positions in the current queue (the same order `useQueue`
132
+ returns).
133
+
134
+ ```ts
135
+ import {
136
+ add,
137
+ move,
138
+ remove,
139
+ removeUpcomingTracks,
140
+ load
141
+ } from 'react-native-audio-browser'
142
+
143
+ add(track) // append one track (also accepts a Track[])
144
+ add(track, 0) // insert before index 0 (front of the queue)
145
+
146
+ move(4, 1) // move index 4 to index 1
147
+ // toIndex past the end moves the track to the end.
148
+
149
+ remove(2) // remove index 2 (also accepts number[])
150
+ removeUpcomingTracks() // drop everything after the active track
151
+
152
+ load(track) // replace the active track (or start the queue if empty)
153
+ ```
154
+
155
+ The second argument to `add` is an **absolute** index, not "after the active
156
+ track". For a real **play-next** button, insert right after the active track:
157
+
158
+ ```ts
159
+ import { add, getActiveTrackIndex } from 'react-native-audio-browser'
160
+
161
+ const i = getActiveTrackIndex()
162
+ add(track, i === undefined ? 0 : i + 1)
163
+ ```
164
+
165
+ **Removing the active track** doesn't stop playback: the next track becomes
166
+ active, or — if you removed the last one — the first track does.
167
+
168
+ ## Repeat and shuffle
169
+
170
+ [Repeat mode](/api/features/queue/#userepeatmode) is one of `'off'`, `'track'`,
171
+ or `'queue'`:
172
+
173
+ | Mode | Behavior |
174
+ | --------- | ------------------------------------------------ |
175
+ | `'off'` | Stop when the last track finishes (the default). |
176
+ | `'track'` | Repeat the active track forever. |
177
+ | `'queue'` | Loop the whole queue. |
178
+
179
+ ```tsx
180
+ import {
181
+ setRepeatMode,
182
+ useRepeatMode,
183
+ toggleShuffle,
184
+ useShuffle
185
+ } from 'react-native-audio-browser'
186
+
187
+ function RepeatButton() {
188
+ const mode = useRepeatMode()
189
+ const next = mode === 'off' ? 'queue' : mode === 'queue' ? 'track' : 'off'
190
+ return (
191
+ <Button title={`Repeat: ${mode}`} onPress={() => setRepeatMode(next)} />
192
+ )
193
+ }
194
+
195
+ function ShuffleButton() {
196
+ const on = useShuffle()
197
+ return (
198
+ <Button
199
+ title={on ? 'Shuffle: on' : 'Shuffle: off'}
200
+ onPress={() => toggleShuffle()}
201
+ />
202
+ )
203
+ }
204
+ ```
205
+
206
+ [`setShuffle(true | false)`](/api/features/queue/#setshuffle) sets it directly;
207
+ [`toggleShuffle()`](/api/features/queue/#toggleshuffle) flips it.
208
+
209
+ ## When the queue ends
210
+
211
+ With repeat `'off'`, playback pauses when the last track finishes and the
212
+ playback state becomes `'ended'` (see [Playback](/guide/playback#playback-state)).
213
+ To react — autoplay more, log a session, show a prompt — subscribe to
214
+ [`onQueueEnded`](/api/features/queue/#onqueueended):
215
+
216
+ ```ts
217
+ import { onQueueEnded } from 'react-native-audio-browser'
218
+
219
+ const unsubscribe = onQueueEnded.addListener(({ track, position }) => {
220
+ // `track` is the index that was active; `position` is where it stopped.
221
+ loadMoreAndPlay()
222
+ })
223
+ ```
224
+
225
+ ## A complete "Up Next" screen
226
+
227
+ `useQueue` plus `useActiveTrack` is enough for a reorderable list with
228
+ tap-to-play and remove:
229
+
230
+ ```tsx
231
+ import { View, Text, Button, FlatList } from 'react-native'
232
+ import {
233
+ useQueue,
234
+ useActiveTrack,
235
+ getActiveTrackIndex,
236
+ skip,
237
+ move,
238
+ remove
239
+ } from 'react-native-audio-browser'
240
+
241
+ function UpNext() {
242
+ const queue = useQueue()
243
+ // `useActiveTrack` re-renders the list when the active track changes; we
244
+ // compare each row by index (more robust than by id, which is optional on a
245
+ // Track). `getActiveTrackIndex()` is fresh on each render.
246
+ const active = useActiveTrack()
247
+ const activeIndex = active ? getActiveTrackIndex() : undefined
248
+
249
+ return (
250
+ <FlatList
251
+ data={queue}
252
+ keyExtractor={(track, i) => track.id ?? String(i)}
253
+ renderItem={({ item, index }) => (
254
+ <View style={{ flexDirection: 'row', alignItems: 'center' }}>
255
+ <Text
256
+ onPress={() => skip(index)}
257
+ style={index === activeIndex ? { fontWeight: 'bold' } : null}
258
+ >
259
+ {item.title}
260
+ </Text>
261
+ {index > 0 && (
262
+ <Button title="↑" onPress={() => move(index, index - 1)} />
263
+ )}
264
+ <Button title="✕" onPress={() => remove(index)} />
265
+ </View>
266
+ )}
267
+ />
268
+ )
269
+ }
270
+ ```
271
+
272
+ A `<Button>` can't be a child of `<Text>`, so each row is a `<View>` with the
273
+ title and buttons as siblings. The `keyExtractor` falls back to the array index
274
+ when a track has no `id` — fine for a static list, but for a **reorderable**
275
+ list like this one, give your tracks a stable `id` so `move`/`remove` don't
276
+ confuse row identity.
277
+
278
+ ## A note on units
279
+
280
+ All position arguments are **seconds** — `seekTo`, `seekBy`, the
281
+ `initialPosition` on `skip` / `skipToNext` / `skipToPrevious`, and `setQueue`'s
282
+ `startPosition`.
283
+
284
+ ## API summary
285
+
286
+ | API | Purpose |
287
+ | ----------------------------------------------------------------- | --------------------------------------------------------------- |
288
+ | `setQueue(tracks, startIndex?, startPosition?)` | Replace the queue (doesn't auto-play; position in **seconds**). |
289
+ | `add(track \| tracks, insertBeforeIndex?)` | Append, or insert before an index. |
290
+ | `load(track)` | Replace the active track (or start the queue if empty). |
291
+ | `move(from, to)` | Reorder; `to` past the end → end. |
292
+ | `remove(index \| indexes)` | Remove track(s); active removal advances. |
293
+ | `removeUpcomingTracks()` | Drop everything after the active track. |
294
+ | `skip(index, initialPosition?)` | Jump to a track (position in **seconds**). |
295
+ | `skipToNext()` / `skipToPrevious()` | Step between tracks. |
296
+ | `useQueue()` / `getQueue()` / `getTrack(i)` | Read the queue. |
297
+ | `useActiveTrack()` / `getActiveTrack()` / `getActiveTrackIndex()` | Read the active track. |
298
+ | `onActiveTrackChanged` / `onQueueChanged` / `onQueueEnded` | Subscribe to changes. |
299
+ | `setRepeatMode(mode)` / `useRepeatMode()` | `'off'` / `'track'` / `'queue'`. |
300
+ | `setShuffle(bool)` / `toggleShuffle()` / `useShuffle()` | Shuffle order. |