react-native-audio-browser 0.2.0-next.11 → 0.2.0-next.12

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 (333) hide show
  1. package/README.md +4 -4
  2. package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +110 -25
  3. package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +254 -188
  4. package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +23 -3
  5. package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +77 -58
  6. package/android/src/main/java/com/audiobrowser/browser/SectionScope.kt +68 -26
  7. package/android/src/main/java/com/audiobrowser/browser/StyleResolver.kt +49 -0
  8. package/android/src/main/java/com/audiobrowser/extension/ResolvedTrackExt.kt +9 -7
  9. package/android/src/main/java/com/audiobrowser/extension/TappedTrack.kt +20 -0
  10. package/android/src/main/java/com/audiobrowser/extension/TrackIdentity.kt +15 -0
  11. package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +120 -67
  12. package/android/src/main/java/com/audiobrowser/player/NowPlayingUpdater.kt +21 -24
  13. package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +93 -73
  14. package/android/src/main/java/com/audiobrowser/player/Player.kt +48 -30
  15. package/android/src/main/java/com/audiobrowser/player/PlayerCapabilitiesExt.kt +2 -15
  16. package/android/src/main/java/com/audiobrowser/util/BrowserPathHelper.kt +44 -40
  17. package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +28 -23
  18. package/android/src/main/java/com/audiobrowser/util/StyleWire.kt +35 -0
  19. package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +45 -53
  20. package/android/src/test/java/com/audiobrowser/TestFixtures.kt +26 -39
  21. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerFavoritesTest.kt +153 -0
  22. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +228 -50
  23. package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +38 -0
  24. package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +1 -1
  25. package/android/src/test/java/com/audiobrowser/browser/JsonStyleTest.kt +91 -0
  26. package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +128 -53
  27. package/android/src/test/java/com/audiobrowser/browser/StyleResolverTest.kt +87 -0
  28. package/android/src/test/java/com/audiobrowser/extension/TappedTrackTest.kt +43 -0
  29. package/android/src/test/java/com/audiobrowser/extension/TrackIdentityTest.kt +41 -0
  30. package/android/src/test/java/com/audiobrowser/player/CapabilityControlsTest.kt +1 -2
  31. package/android/src/test/java/com/audiobrowser/player/NowPlayingUpdaterTest.kt +42 -2
  32. package/android/src/test/java/com/audiobrowser/player/PlaybackStateStoreTrackJsonTest.kt +55 -0
  33. package/android/src/test/java/com/audiobrowser/util/BrowserPathHelperTest.kt +41 -16
  34. package/android/src/test/java/com/audiobrowser/util/MediaExtrasBuilderTest.kt +161 -0
  35. package/android/src/test/java/com/audiobrowser/util/TrackFactoryMediaIdTest.kt +7 -7
  36. package/ios/Browser/BrowserConfig.swift +102 -5
  37. package/ios/Browser/BrowserManager+URLResolution.swift +18 -14
  38. package/ios/Browser/BrowserManager.swift +131 -143
  39. package/ios/Browser/BrowserPathHelper.swift +44 -44
  40. package/ios/Browser/JsonModels.swift +187 -106
  41. package/ios/Browser/SearchDrillIn.swift +6 -6
  42. package/ios/Browser/SectionPresentation.swift +34 -0
  43. package/ios/Browser/SectionScope.swift +58 -24
  44. package/ios/Browser/StyleResolver.swift +47 -0
  45. package/ios/Browser/TabBarEntries.swift +2 -2
  46. package/ios/Browser/TrackIdTemplate.swift +37 -0
  47. package/ios/CarPlay/CarPlayArtworkResolver.swift +8 -7
  48. package/ios/CarPlay/CarPlayController.swift +105 -67
  49. package/ios/CarPlay/CarPlayImageLoader.swift +38 -18
  50. package/ios/CarPlay/CarPlayListItemFactory.swift +217 -84
  51. package/ios/CarPlay/CarPlayNowPlayingManager.swift +15 -12
  52. package/ios/Extension/Capability+RemoteCommand.swift +1 -1
  53. package/ios/Extension/PlayerCapabilities+Favorite.swift +1 -15
  54. package/ios/Extension/ResolvedTrack+Copying.swift +11 -15
  55. package/ios/Extension/Section+Copying.swift +31 -0
  56. package/ios/Extension/Track+Copying.swift +6 -12
  57. package/ios/Extension/Track+Identity.swift +18 -0
  58. package/ios/HybridAudioBrowser.swift +113 -35
  59. package/ios/Model/NitroTypeStubs.swift +46 -21
  60. package/ios/Model/PlayerUpdateOptions.swift +7 -0
  61. package/ios/Player/NowPlayingUpdater.swift +1 -1
  62. package/ios/Player/PlaybackCoordinator.swift +2 -2
  63. package/ios/Player/RetryManager.swift +4 -3
  64. package/ios/Tests/BrowserPathHelperTests.swift +50 -20
  65. package/ios/Tests/CarPlayArtworkResolverTests.swift +24 -41
  66. package/ios/Tests/JsonModelsTests.swift +75 -1
  67. package/ios/Tests/PlaybackStateStoreTests.swift +4 -3
  68. package/ios/Tests/ResolvedTrackCopyingTests.swift +37 -35
  69. package/ios/Tests/SearchDrillInTests.swift +16 -16
  70. package/ios/Tests/SectionPresentationTests.swift +61 -0
  71. package/ios/Tests/SectionScopeTests.swift +87 -55
  72. package/ios/Tests/StyleResolverTests.swift +67 -0
  73. package/ios/Tests/TabBarEntriesTests.swift +18 -18
  74. package/ios/Tests/TrackIdTemplateTests.swift +67 -0
  75. package/ios/Tests/TrackIdentityTests.swift +20 -0
  76. package/ios/Tests/TrackSelectorTests.swift +168 -33
  77. package/ios/TrackSelector.swift +45 -30
  78. package/ios/Util/ArtworkImageFetcher.swift +16 -1
  79. package/lib/commonjs/AudioBrowser.js +11 -0
  80. package/lib/commonjs/AudioBrowser.js.map +1 -1
  81. package/lib/commonjs/features/browser-config.js +11 -8
  82. package/lib/commonjs/features/browser-config.js.map +1 -1
  83. package/lib/commonjs/features/browser.js +2 -2
  84. package/lib/commonjs/features/favorites.js +13 -10
  85. package/lib/commonjs/features/favorites.js.map +1 -1
  86. package/lib/commonjs/features/playback/controls.js +4 -2
  87. package/lib/commonjs/features/playback/controls.js.map +1 -1
  88. package/lib/commonjs/features/playback/state.js +2 -3
  89. package/lib/commonjs/features/playback/state.js.map +1 -1
  90. package/lib/commonjs/features/player/options.js.map +1 -1
  91. package/lib/commonjs/features/player/setup.js +3 -1
  92. package/lib/commonjs/features/player/setup.js.map +1 -1
  93. package/lib/commonjs/features/player/validateOptions.js +2 -0
  94. package/lib/commonjs/features/player/validateOptions.js.map +1 -1
  95. package/lib/commonjs/features/queue/activeTrack.js +14 -3
  96. package/lib/commonjs/features/queue/activeTrack.js.map +1 -1
  97. package/lib/commonjs/features/queue/queue.js +11 -4
  98. package/lib/commonjs/features/queue/queue.js.map +1 -1
  99. package/lib/commonjs/utils/LazyNativeEmitter.js +21 -10
  100. package/lib/commonjs/utils/LazyNativeEmitter.js.map +1 -1
  101. package/lib/commonjs/utils/NativeUpdatedValue.js +31 -13
  102. package/lib/commonjs/utils/NativeUpdatedValue.js.map +1 -1
  103. package/lib/commonjs/utils/getTrackIdentity.js +24 -0
  104. package/lib/commonjs/utils/getTrackIdentity.js.map +1 -0
  105. package/lib/commonjs/utils/useNativeValueRefreshedBy.js +33 -0
  106. package/lib/commonjs/utils/useNativeValueRefreshedBy.js.map +1 -0
  107. package/lib/commonjs/web/NativeAudioBrowser.js +32 -24
  108. package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
  109. package/lib/commonjs/web/browser/BrowserManager.js +144 -87
  110. package/lib/commonjs/web/browser/BrowserManager.js.map +1 -1
  111. package/lib/commonjs/web/browser/FavoriteManager.js +30 -21
  112. package/lib/commonjs/web/browser/FavoriteManager.js.map +1 -1
  113. package/lib/commonjs/web/browser/assertBrowsePageShape.js +2 -2
  114. package/lib/commonjs/web/browser/assertBrowsePageShape.js.map +1 -1
  115. package/lib/commonjs/web/browser/classifyTrackNavigation.js +9 -9
  116. package/lib/commonjs/web/browser/classifyTrackNavigation.js.map +1 -1
  117. package/lib/commonjs/web/browser/sections.js +89 -0
  118. package/lib/commonjs/web/browser/sections.js.map +1 -0
  119. package/lib/commonjs/web/player/NowPlayingManager.js +4 -3
  120. package/lib/commonjs/web/player/NowPlayingManager.js.map +1 -1
  121. package/lib/commonjs/web/util/BrowserPathHelper.js +56 -11
  122. package/lib/commonjs/web/util/BrowserPathHelper.js.map +1 -1
  123. package/lib/module/AudioBrowser.js +1 -0
  124. package/lib/module/AudioBrowser.js.map +1 -1
  125. package/lib/module/features/browser-config.js +11 -8
  126. package/lib/module/features/browser-config.js.map +1 -1
  127. package/lib/module/features/browser.js +2 -2
  128. package/lib/module/features/favorites.js +13 -10
  129. package/lib/module/features/favorites.js.map +1 -1
  130. package/lib/module/features/playback/controls.js +4 -2
  131. package/lib/module/features/playback/controls.js.map +1 -1
  132. package/lib/module/features/playback/state.js +2 -3
  133. package/lib/module/features/playback/state.js.map +1 -1
  134. package/lib/module/features/player/options.js.map +1 -1
  135. package/lib/module/features/player/setup.js +3 -1
  136. package/lib/module/features/player/setup.js.map +1 -1
  137. package/lib/module/features/player/validateOptions.js +2 -0
  138. package/lib/module/features/player/validateOptions.js.map +1 -1
  139. package/lib/module/features/queue/activeTrack.js +14 -3
  140. package/lib/module/features/queue/activeTrack.js.map +1 -1
  141. package/lib/module/features/queue/queue.js +11 -4
  142. package/lib/module/features/queue/queue.js.map +1 -1
  143. package/lib/module/utils/LazyNativeEmitter.js +21 -10
  144. package/lib/module/utils/LazyNativeEmitter.js.map +1 -1
  145. package/lib/module/utils/NativeUpdatedValue.js +31 -13
  146. package/lib/module/utils/NativeUpdatedValue.js.map +1 -1
  147. package/lib/module/utils/getTrackIdentity.js +20 -0
  148. package/lib/module/utils/getTrackIdentity.js.map +1 -0
  149. package/lib/module/utils/useNativeValueRefreshedBy.js +29 -0
  150. package/lib/module/utils/useNativeValueRefreshedBy.js.map +1 -0
  151. package/lib/module/web/NativeAudioBrowser.js +32 -24
  152. package/lib/module/web/NativeAudioBrowser.js.map +1 -1
  153. package/lib/module/web/browser/BrowserManager.js +144 -87
  154. package/lib/module/web/browser/BrowserManager.js.map +1 -1
  155. package/lib/module/web/browser/FavoriteManager.js +31 -21
  156. package/lib/module/web/browser/FavoriteManager.js.map +1 -1
  157. package/lib/module/web/browser/assertBrowsePageShape.js +2 -2
  158. package/lib/module/web/browser/assertBrowsePageShape.js.map +1 -1
  159. package/lib/module/web/browser/classifyTrackNavigation.js +9 -9
  160. package/lib/module/web/browser/classifyTrackNavigation.js.map +1 -1
  161. package/lib/module/web/browser/sections.js +83 -0
  162. package/lib/module/web/browser/sections.js.map +1 -0
  163. package/lib/module/web/player/NowPlayingManager.js +4 -3
  164. package/lib/module/web/player/NowPlayingManager.js.map +1 -1
  165. package/lib/module/web/util/BrowserPathHelper.js +56 -11
  166. package/lib/module/web/util/BrowserPathHelper.js.map +1 -1
  167. package/lib/typescript/src/AudioBrowser.d.ts +1 -0
  168. package/lib/typescript/src/AudioBrowser.d.ts.map +1 -1
  169. package/lib/typescript/src/features/browser-config.d.ts.map +1 -1
  170. package/lib/typescript/src/features/browser.d.ts +2 -2
  171. package/lib/typescript/src/features/favorites.d.ts +13 -10
  172. package/lib/typescript/src/features/favorites.d.ts.map +1 -1
  173. package/lib/typescript/src/features/playback/controls.d.ts +4 -2
  174. package/lib/typescript/src/features/playback/controls.d.ts.map +1 -1
  175. package/lib/typescript/src/features/playback/state.d.ts +2 -3
  176. package/lib/typescript/src/features/playback/state.d.ts.map +1 -1
  177. package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts +1 -1
  178. package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts.map +1 -1
  179. package/lib/typescript/src/features/player/options.d.ts +21 -19
  180. package/lib/typescript/src/features/player/options.d.ts.map +1 -1
  181. package/lib/typescript/src/features/player/setup.d.ts.map +1 -1
  182. package/lib/typescript/src/features/player/validateOptions.d.ts +1 -8
  183. package/lib/typescript/src/features/player/validateOptions.d.ts.map +1 -1
  184. package/lib/typescript/src/features/queue/activeTrack.d.ts +8 -1
  185. package/lib/typescript/src/features/queue/activeTrack.d.ts.map +1 -1
  186. package/lib/typescript/src/features/queue/queue.d.ts +5 -2
  187. package/lib/typescript/src/features/queue/queue.d.ts.map +1 -1
  188. package/lib/typescript/src/types/browser-native.d.ts +2 -2
  189. package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
  190. package/lib/typescript/src/types/browser-nodes.d.ts +260 -127
  191. package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
  192. package/lib/typescript/src/types/browser.d.ts +33 -53
  193. package/lib/typescript/src/types/browser.d.ts.map +1 -1
  194. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +16 -17
  195. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts.map +1 -1
  196. package/lib/typescript/src/utils/NativeUpdatedValue.d.ts +24 -19
  197. package/lib/typescript/src/utils/NativeUpdatedValue.d.ts.map +1 -1
  198. package/lib/typescript/src/utils/getTrackIdentity.d.ts +18 -0
  199. package/lib/typescript/src/utils/getTrackIdentity.d.ts.map +1 -0
  200. package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts +21 -0
  201. package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts.map +1 -0
  202. package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +0 -1
  203. package/nitrogen/generated/android/c++/{JFavoritesMatchMode.hpp → JArtworkRendering.hpp} +15 -15
  204. package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +4 -3
  205. package/nitrogen/generated/android/c++/JBrowseResult.hpp +10 -4
  206. package/nitrogen/generated/android/c++/JCarPlayPlayingIndicatorLocation.hpp +58 -0
  207. package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +4 -3
  208. package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +4 -3
  209. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +4 -3
  210. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +4 -3
  211. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +4 -3
  212. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +4 -3
  213. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +4 -2
  214. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +4 -2
  215. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.hpp +10 -4
  216. package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +4 -3
  217. package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +2 -5
  218. package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +4 -3
  219. package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +9 -3
  220. package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +4 -2
  221. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +21 -14
  222. package/nitrogen/generated/android/c++/JIOSOptions.hpp +9 -3
  223. package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +4 -3
  224. package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +16 -10
  225. package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +8 -2
  226. package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +6 -7
  227. package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +2 -5
  228. package/nitrogen/generated/android/c++/JNitroIOSUpdateOptions.hpp +9 -3
  229. package/nitrogen/generated/android/c++/JOptions.hpp +2 -5
  230. package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +4 -3
  231. package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +5 -11
  232. package/nitrogen/generated/android/c++/JResolvedTrack.hpp +49 -51
  233. package/nitrogen/generated/android/c++/JSection.hpp +114 -0
  234. package/nitrogen/generated/android/c++/JSectionStyle.hpp +69 -0
  235. package/nitrogen/generated/android/c++/JStyleDisplay.hpp +58 -0
  236. package/nitrogen/generated/android/c++/JTrack.hpp +19 -48
  237. package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +4 -2
  238. package/nitrogen/generated/android/c++/JTrackStyle.hpp +25 -18
  239. package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.hpp +10 -4
  240. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoritesMatchMode.kt → ArtworkRendering.kt} +5 -5
  241. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayPlayingIndicatorLocation.kt +23 -0
  242. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSOptions.kt +6 -3
  243. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +5 -5
  244. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroIOSUpdateOptions.kt +6 -3
  245. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
  246. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +12 -18
  247. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Section.kt +50 -0
  248. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoriteConfig.kt → SectionStyle.kt} +12 -6
  249. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StyleDisplay.kt +23 -0
  250. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +6 -15
  251. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackStyle.kt +23 -5
  252. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +104 -82
  253. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +16 -10
  254. package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +16 -10
  255. package/nitrogen/generated/ios/swift/ArtworkRendering.swift +40 -0
  256. package/nitrogen/generated/ios/swift/CarPlayPlayingIndicatorLocation.swift +40 -0
  257. package/nitrogen/generated/ios/swift/IOSOptions.swift +7 -2
  258. package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +5 -5
  259. package/nitrogen/generated/ios/swift/NitroIOSUpdateOptions.swift +12 -1
  260. package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +8 -27
  261. package/nitrogen/generated/ios/swift/ResolvedTrack.swift +54 -83
  262. package/nitrogen/generated/ios/swift/Section.swift +100 -0
  263. package/nitrogen/generated/ios/swift/SectionStyle.swift +64 -0
  264. package/nitrogen/generated/ios/swift/StyleDisplay.swift +40 -0
  265. package/nitrogen/generated/ios/swift/Track.swift +20 -73
  266. package/nitrogen/generated/ios/swift/TrackStyle.swift +28 -22
  267. package/nitrogen/generated/shared/c++/{FavoritesMatchMode.hpp → ArtworkRendering.hpp} +17 -17
  268. package/nitrogen/generated/shared/c++/CarPlayPlayingIndicatorLocation.hpp +76 -0
  269. package/nitrogen/generated/shared/c++/IOSOptions.hpp +9 -2
  270. package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +6 -6
  271. package/nitrogen/generated/shared/c++/NitroIOSUpdateOptions.hpp +9 -2
  272. package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +6 -9
  273. package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +30 -38
  274. package/nitrogen/generated/shared/c++/Section.hpp +106 -0
  275. package/nitrogen/generated/shared/c++/SectionStyle.hpp +96 -0
  276. package/nitrogen/generated/shared/c++/StyleDisplay.hpp +76 -0
  277. package/nitrogen/generated/shared/c++/Track.hpp +15 -31
  278. package/nitrogen/generated/shared/c++/TrackStyle.hpp +50 -34
  279. package/package.json +1 -1
  280. package/src/AudioBrowser.ts +1 -0
  281. package/src/features/browser-config.test.ts +21 -6
  282. package/src/features/browser-config.ts +11 -8
  283. package/src/features/browser.test.ts +1 -1
  284. package/src/features/browser.ts +2 -2
  285. package/src/features/favorites.ts +13 -10
  286. package/src/features/hook-wiring.test.ts +63 -15
  287. package/src/features/playback/controls.ts +4 -2
  288. package/src/features/playback/state.ts +2 -3
  289. package/src/features/playback/trackPlaybackTime.ts +1 -1
  290. package/src/features/player/options.ts +27 -19
  291. package/src/features/player/setup.test.ts +12 -3
  292. package/src/features/player/setup.ts +3 -1
  293. package/src/features/player/validateOptions.ts +2 -0
  294. package/src/features/queue/activeTrack.ts +14 -3
  295. package/src/features/queue/queue.ts +11 -4
  296. package/src/nitro-stub-drift.test.ts +40 -0
  297. package/src/public-surface.test.ts +40 -0
  298. package/src/specs/audio-browser.nitro.ts +4 -3
  299. package/src/style-resolution.test.ts +139 -0
  300. package/src/types/browser-native.ts +2 -2
  301. package/src/types/browser-nodes.ts +268 -136
  302. package/src/types/browser.ts +34 -55
  303. package/src/utils/LazyNativeEmitter.ts +20 -10
  304. package/src/utils/NativeUpdatedValue.ts +29 -13
  305. package/src/utils/getTrackIdentity.ts +20 -0
  306. package/src/utils/useNativeValueRefreshedBy.ts +38 -0
  307. package/src/web/NativeAudioBrowser.ts +37 -22
  308. package/src/web/browser/BrowserManager.ts +176 -95
  309. package/src/web/browser/FavoriteManager.test.ts +84 -0
  310. package/src/web/browser/FavoriteManager.ts +28 -23
  311. package/src/web/browser/assertBrowsePageShape.test.ts +1 -1
  312. package/src/web/browser/assertBrowsePageShape.ts +5 -3
  313. package/src/web/browser/classifyTrackNavigation.test.ts +10 -8
  314. package/src/web/browser/classifyTrackNavigation.ts +9 -9
  315. package/src/web/browser/parseSearchResponse.test.ts +8 -2
  316. package/src/web/browser/sections.test.ts +91 -0
  317. package/src/web/browser/sections.ts +72 -0
  318. package/src/web/player/NowPlayingManager.ts +4 -3
  319. package/src/web/util/BrowserPathHelper.test.ts +52 -0
  320. package/src/web/util/BrowserPathHelper.ts +61 -13
  321. package/ios/CarPlay/ImageRowItem+CarPlay.swift +0 -19
  322. package/nitrogen/generated/android/c++/JFavoriteConfig.hpp +0 -58
  323. package/nitrogen/generated/android/c++/JImageRowItem.hpp +0 -105
  324. package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.cpp +0 -26
  325. package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.hpp +0 -71
  326. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +0 -68
  327. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_FavoriteConfig.kt +0 -53
  328. package/nitrogen/generated/ios/swift/FavoriteConfig.swift +0 -29
  329. package/nitrogen/generated/ios/swift/FavoritesMatchMode.swift +0 -40
  330. package/nitrogen/generated/ios/swift/ImageRowItem.swift +0 -195
  331. package/nitrogen/generated/ios/swift/Variant_Bool_FavoriteConfig.swift +0 -18
  332. package/nitrogen/generated/shared/c++/FavoriteConfig.hpp +0 -84
  333. package/nitrogen/generated/shared/c++/ImageRowItem.hpp +0 -129
package/README.md CHANGED
@@ -63,7 +63,7 @@ import AudioBrowser from 'react-native-audio-browser'
63
63
  await AudioBrowser.setupPlayer()
64
64
 
65
65
  AudioBrowser.configureBrowser({
66
- tabs: [{ title: 'Browse', url: '/browse' }],
66
+ tabs: [{ title: 'Browse', path: '/browse' }],
67
67
  routes: {
68
68
  // Every path under /browse is fetched from your API, on demand.
69
69
  '/browse/**': { baseUrl: 'https://api.example.com' }
@@ -71,15 +71,15 @@ AudioBrowser.configureBrowser({
71
71
  })
72
72
  ```
73
73
 
74
- Each route returns a page of children — a child with a `url` is browsable (open it for more), one with a `src` is a playable track (plus optional `artist`, `artwork`, …):
74
+ Each route returns a page of children — a child with a `path` is browsable (open it for more), one with a `src` is a playable track (plus optional `artist`, `artwork`, …):
75
75
 
76
76
  ```jsonc
77
77
  // GET https://api.example.com/browse/jazz →
78
78
  {
79
- "url": "/browse/jazz",
79
+ "path": "/browse/jazz",
80
80
  "title": "Jazz",
81
81
  "children": [
82
- { "title": "Smooth Floret FM", "url": "/browse/jazz/floret-fm" }, // url → open for children
82
+ { "title": "Smooth Floret FM", "path": "/browse/jazz/floret-fm" }, // path → open for children
83
83
  { "title": "The Stalk 88.5", "src": "https://stream.example.com/stalk.mp3" } // src → play this stream
84
84
  ]
85
85
  }
@@ -23,6 +23,7 @@ import com.audiobrowser.browser.NetworkException
23
23
  import com.audiobrowser.browser.handleTrackLoad
24
24
  import com.audiobrowser.browser.resolveMediaUrl
25
25
  import com.audiobrowser.extension.NumberExt.Companion.toSeconds
26
+ import com.audiobrowser.extension.indexOfTappedTrack
26
27
  import com.audiobrowser.model.PlayerSetupOptions
27
28
  import com.audiobrowser.model.PlayerUpdateOptions
28
29
  import com.audiobrowser.player.Player
@@ -35,6 +36,7 @@ import com.audiobrowser.util.SystemVolumeMonitor
35
36
  import com.facebook.proguard.annotations.DoNotStrip
36
37
  import com.google.common.util.concurrent.ListenableFuture
37
38
  import com.margelo.nitro.NitroModules
39
+ import com.margelo.nitro.audiobrowser.ArtworkRequestConfig
38
40
  import com.margelo.nitro.audiobrowser.BatteryOptimizationStatus
39
41
  import com.margelo.nitro.audiobrowser.BatteryOptimizationStatusChangedEvent
40
42
  import com.margelo.nitro.audiobrowser.BatteryWarningPendingChangedEvent
@@ -50,6 +52,7 @@ import com.margelo.nitro.audiobrowser.HybridAudioBrowserSpec
50
52
  import com.margelo.nitro.audiobrowser.MediaRequestConfig
51
53
  import com.margelo.nitro.audiobrowser.NativeBrowserConfiguration
52
54
  import com.margelo.nitro.audiobrowser.NativeGateRequest
55
+ import com.margelo.nitro.audiobrowser.NativeRouteEntry
53
56
  import com.margelo.nitro.audiobrowser.NativeSetupPlayerOptions
54
57
  import com.margelo.nitro.audiobrowser.NativeUpdateOptions
55
58
  import com.margelo.nitro.audiobrowser.NavigationError
@@ -82,6 +85,7 @@ import com.margelo.nitro.audiobrowser.SleepTimer
82
85
  import com.margelo.nitro.audiobrowser.TimedMetadata
83
86
  import com.margelo.nitro.audiobrowser.Track
84
87
  import com.margelo.nitro.audiobrowser.TrackMetadata
88
+ import com.margelo.nitro.audiobrowser.TransformableRequestConfig
85
89
  import com.margelo.nitro.core.Promise
86
90
  import java.util.concurrent.TimeUnit
87
91
  import java.util.concurrent.atomic.AtomicReference
@@ -121,6 +125,12 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
121
125
  // Only when still ours: on a reload the replacement may already own the slot.
122
126
  carConnectionTarget.compareAndSet(onCarConnectedChanged, null)
123
127
 
128
+ // The runtime behind the config's JS functions is going away, but anything still holding
129
+ // this instance (an in-flight browse coroutine, the running player) can invoke them after
130
+ // it's gone — each invoke then throws instead of answering, so browse takes its error path
131
+ // rather than its fallback.
132
+ dropStaleJSCallbacks()
133
+
124
134
  handler.post {
125
135
  connectedService?.let { service ->
126
136
  // Identity-guarded: both instances bind to the same singleton Service, so a late dispose
@@ -129,6 +139,10 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
129
139
  if (service.player.browser === this) {
130
140
  service.player.browser = null
131
141
  service.player.forgetBrowserRegistration()
142
+ // The formatter wraps a JS callback from this instance's runtime (installed by our
143
+ // setup(); browser still being ours means no replacement has run setup yet). Without
144
+ // this, every track change until the next setup() throws into the updater's fallback.
145
+ service.player.nowPlaying.formatter = null
132
146
  }
133
147
  if (service.onBatteryWarningPendingChanged === onBatteryWarningPending) {
134
148
  service.onBatteryWarningPendingChanged = null
@@ -152,6 +166,20 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
152
166
  super.dispose()
153
167
  }
154
168
 
169
+ /**
170
+ * Demotes the config to data-only (deep strip of every JS function field) and reverts the JS
171
+ * callbacks stored outside the config tree ([resolveGate]; the now-playing formatter is cleared
172
+ * in [dispose]'s service block, identity-guarded). Stale paths then degrade the same way as a
173
+ * config that never had callbacks — static request/browse layers, default error copy, fail-closed
174
+ * gate — instead of throwing into the error path. Mirrors iOS `dropStaleJSCallbacks`, where the
175
+ * same invoke is fatal rather than a throw.
176
+ */
177
+ private fun dropStaleJSCallbacks() {
178
+ _configuration = _configuration.strippingJSCallbacks()
179
+ browserManager.config = buildConfig()
180
+ resolveGate = defaultResolveGate
181
+ }
182
+
155
183
  private val mainScope = MainScope()
156
184
  private var navigationJob: Job? = null
157
185
  private val handler = Handler(Looper.getMainLooper())
@@ -175,7 +203,7 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
175
203
  handleTrackLoad = null,
176
204
  androidControllerOfflineError = null,
177
205
  carPlayLoadingTitle = null,
178
- resolveAlbumUrl = null,
206
+ resolveAlbumPath = null,
179
207
  formatNavigationError = null,
180
208
  )
181
209
 
@@ -220,14 +248,14 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
220
248
  override var onFormattedNavigationError: (FormattedNavigationError?) -> Unit = {}
221
249
 
222
250
  // MARK: Gate callbacks (native→JS; set from JS, native CALLS them)
223
- // Default resolver: only reachable in the init window where the native side has recorded
224
- // hasResolver=true but JS hasn't yet assigned the real `resolveGate` slot. It DENIES by default
251
+ // Default resolver: only reachable while hasResolver=true but no live runtime has the real
252
+ // `resolveGate` bound — the init window before JS assigns it, or after [dispose] reverts a dead
253
+ // runtime's resolver. It DENIES by default
225
254
  // (gated=true) so an active gate never serves content during that window — same fail-closed
226
255
  // direction as the resolver-error path in [gateDecision]. The static-gate fast path skips it
227
256
  // entirely once a resolver-less gate is set.
228
- override var resolveGate: (request: NativeGateRequest) -> Promise<Promise<GateDecision>> = {
229
- Promise.resolved(Promise.resolved(GateDecision(gated = true, gate = null)))
230
- }
257
+ override var resolveGate: (request: NativeGateRequest) -> Promise<Promise<GateDecision>> =
258
+ defaultResolveGate
231
259
  override var onGate: (event: GateEvent) -> Unit = {}
232
260
 
233
261
  // MARK: Player callbacks
@@ -373,8 +401,8 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
373
401
  browserManager.config = buildConfig()
374
402
  val tabs = browserManager.queryTabs()
375
403
  if (tabs.isNotEmpty()) {
376
- Timber.d("Using first tab as default path: ${tabs[0].url}")
377
- tabs[0].url
404
+ Timber.d("Using first tab as default path: ${tabs[0].path}")
405
+ tabs[0].path
378
406
  } else {
379
407
  Timber.d("Using root path as default: /")
380
408
  "/"
@@ -612,26 +640,38 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
612
640
  }
613
641
 
614
642
  override fun navigateTrack(track: Track) {
643
+ // A disabled track is unavailable — it never plays, whichever surface or
644
+ // stale resume path delivered the selection (Track.disabled; mirrors iOS
645
+ // TrackSelector.select). Refused before any state changes: an inert tap
646
+ // must not clear an unrelated navigation error or cancel an in-flight
647
+ // navigation.
648
+ if (track.disabled == true) {
649
+ Timber.d("Ignoring selection of disabled track: ${track.title}")
650
+ return
651
+ }
652
+
615
653
  clearNavigationError()
616
654
 
617
655
  // Cancel previous navigation to avoid race conditions
618
656
  navigationJob?.cancel()
619
657
 
620
- val url = track.url
658
+ val path = track.path
621
659
  navigationJob =
622
660
  mainScope.launch {
623
661
  try {
624
662
  when {
625
- // Check if this is a contextual URL (playable-only track with queue context)
626
- url != null && BrowserPathHelper.isContextual(url) -> {
627
- Timber.d("Navigating to contextual track URL: $url")
663
+ // Check if this is a contextual path (playable-only track with queue context)
664
+ path != null && BrowserPathHelper.isContextual(path) -> {
665
+ Timber.d("Navigating to contextual track path: $path")
628
666
 
629
- val parentPath = BrowserPathHelper.stripTrackId(url)
630
- val trackId = BrowserPathHelper.extractTrackId(url)
667
+ val parentPath = BrowserPathHelper.stripTrackId(path)
668
+ val trackId = BrowserPathHelper.extractTrackId(path)
631
669
 
632
- // Check if queue already came from this parent path - just skip to the track
670
+ // Check if queue already came from this parent path - just skip
671
+ // to the tapped surface (exact path first, identity for
672
+ // index-less paths — see indexOfTappedTrack)
633
673
  if (trackId != null && parentPath == player.queueSourcePath) {
634
- val index = player.tracks.indexOfFirst { it.src == trackId }
674
+ val index = player.tracks.indexOfTappedTrack(path, trackId)
635
675
  if (index >= 0) {
636
676
  Timber.d("Queue already from $parentPath, skipping to index $index")
637
677
  handleTrackLoad(
@@ -649,8 +689,8 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
649
689
  }
650
690
  }
651
691
 
652
- // Expand the queue from the contextual URL
653
- val expanded = browserManager.expandQueueFromContextualUrl(url)
692
+ // Expand the queue from the contextual path
693
+ val expanded = browserManager.expandQueueFromContextualPath(path)
654
694
 
655
695
  if (expanded != null) {
656
696
  val (tracks, startIndex) = expanded
@@ -685,9 +725,9 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
685
725
  }
686
726
  }
687
727
  // Navigate to browsable track to show browsing UI
688
- url != null -> {
689
- Timber.d("Navigating to browsable track: $url")
690
- browserManager.navigate(url)
728
+ path != null -> {
729
+ Timber.d("Navigating to browsable track: $path")
730
+ browserManager.navigate(path)
691
731
  }
692
732
  // If track is playable (has src), load it into player
693
733
  track.src != null -> {
@@ -702,13 +742,13 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
702
742
  )
703
743
  }
704
744
  else -> {
705
- throw IllegalArgumentException("Track must have either an 'url' or an 'src' property")
745
+ throw IllegalArgumentException("Track must have either a 'path' or an 'src' property")
706
746
  }
707
747
  }
708
748
  } catch (e: CancellationException) {
709
749
  throw e // Rethrow to properly cancel
710
750
  } catch (e: Exception) {
711
- handleBrowserException(e, url ?: track.src ?: "", "navigating to track: ${track.title}")
751
+ handleBrowserException(e, path ?: track.src ?: "", "navigating to track: ${track.title}")
712
752
  }
713
753
  }
714
754
  }
@@ -1027,12 +1067,15 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
1027
1067
  player.setQueue(tracks, startIndex?.toInt() ?: 0, ((startPosition ?: 0.0) * 1000).toLong())
1028
1068
  }
1029
1069
 
1030
- override fun setActiveTrackFavorited(favorited: Boolean) = runBlockingOnMain {
1070
+ override fun setActiveTrackFavorited(favorited: Boolean): Unit = runBlockingOnMain {
1071
+ // Applied-result is for MediaSession honesty; the JS API stays fire-and-forget.
1031
1072
  player.setActiveTrackFavorited(favorited)
1073
+ Unit
1032
1074
  }
1033
1075
 
1034
- override fun toggleActiveTrackFavorited() = runBlockingOnMain {
1076
+ override fun toggleActiveTrackFavorited(): Unit = runBlockingOnMain {
1035
1077
  player.toggleActiveTrackFavorited()
1078
+ Unit
1036
1079
  }
1037
1080
 
1038
1081
  override fun getQueue(): Array<Track> = runBlockingOnMain { player.tracks }
@@ -1494,6 +1537,11 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
1494
1537
  current.getAndSet(null)?.dispose()
1495
1538
  }
1496
1539
 
1540
+ /** Shared by the [resolveGate] initializer and [dispose], which reverts to it. */
1541
+ private val defaultResolveGate: (NativeGateRequest) -> Promise<Promise<GateDecision>> = {
1542
+ Promise.resolved(Promise.resolved(GateDecision(gated = true, gate = null)))
1543
+ }
1544
+
1497
1545
  private fun startCarConnectionObserver(context: Context, handler: Handler) {
1498
1546
  // Posted to main: LiveData observation is main-thread only, and the
1499
1547
  // single-start guard is then only ever touched from one thread.
@@ -1510,3 +1558,40 @@ class AudioBrowser : HybridAudioBrowserSpec(), ServiceConnection {
1510
1558
  }
1511
1559
  }
1512
1560
  }
1561
+
1562
+ // MARK: Deep JS-callback stripping (used by dispose)
1563
+ // Functions live at every level of the config, not just the top; each type's strip nils its own.
1564
+
1565
+ private fun NativeBrowserConfiguration.strippingJSCallbacks() =
1566
+ copy(
1567
+ requestResolver = null,
1568
+ browseResolver = null,
1569
+ handleTrackLoad = null,
1570
+ resolveAlbumPath = null,
1571
+ formatNavigationError = null,
1572
+ request = request?.strippingJSCallbacks(),
1573
+ browse = browse?.strippingJSCallbacks(),
1574
+ media = media?.strippingJSCallbacks(),
1575
+ artwork = artwork?.strippingJSCallbacks(),
1576
+ nowPlayingArtwork = nowPlayingArtwork?.strippingJSCallbacks(),
1577
+ routes = routes?.map { it.strippingJSCallbacks() }?.toTypedArray(),
1578
+ )
1579
+
1580
+ private fun TransformableRequestConfig.strippingJSCallbacks() =
1581
+ copy(transform = null, transformSync = null)
1582
+
1583
+ private fun MediaRequestConfig.strippingJSCallbacks() =
1584
+ copy(resolve = null, resolveSync = null, transform = null, transformSync = null)
1585
+
1586
+ private fun ArtworkRequestConfig.strippingJSCallbacks() =
1587
+ copy(resolve = null, resolveSync = null, transform = null, transformSync = null)
1588
+
1589
+ private fun NativeRouteEntry.strippingJSCallbacks() =
1590
+ copy(
1591
+ browseCallback = null,
1592
+ browseConfig = browseConfig?.strippingJSCallbacks(),
1593
+ searchCallback = null,
1594
+ searchConfig = searchConfig?.strippingJSCallbacks(),
1595
+ media = media?.strippingJSCallbacks(),
1596
+ artwork = artwork?.strippingJSCallbacks(),
1597
+ )