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
@@ -62,41 +62,193 @@ extension JsonArtwork {
62
62
  }
63
63
  }
64
64
 
65
- /// JSON model for image row items (horizontal thumbnail row).
66
- struct JsonImageRowItem: Codable {
67
- let id: String?
68
- let url: String?
69
- let src: String?
70
- let artwork: String?
71
- let title: String
72
- let artist: String?
73
- let album: String?
74
- let albumUrl: String?
75
- let live: Bool?
76
- let request: JsonTrackRequest?
65
+ /// A style declaration block on the wire (ADR 0011):
66
+ /// `{ display?, gridWrap?, artworkRendering? }`.
67
+ ///
68
+ /// One JSON model serves both the `TrackStyle` and `SectionStyle` positions —
69
+ /// keys that don't exist at the narrower position simply don't map.
70
+ ///
71
+ /// Decoding is tolerant by design: a stale payload — the retired string
72
+ /// styles, a wrong-typed field, an unknown enum value — must degrade to "no
73
+ /// declaration", never fail the page or the persisted playback state (the
74
+ /// decoders above this are strict, so a throw here would kill the whole
75
+ /// payload). `init(from:)` therefore never throws, and unknown enum values
76
+ /// map to nil at `toNitro` time.
77
+ struct JsonStyle: Codable, Equatable {
78
+ let display: String?
79
+ let gridWrap: Bool?
80
+ let gridTile: String?
81
+ let artworkRendering: String?
82
+ let imageShape: String?
83
+ let accessorySymbol: String?
84
+ let cardTint: String?
85
+ let cardImage: String?
77
86
 
78
87
  init(
79
- id: String? = nil,
80
- url: String? = nil,
81
- src: String? = nil,
82
- artwork: String? = nil,
83
- title: String,
84
- artist: String? = nil,
85
- album: String? = nil,
86
- albumUrl: String? = nil,
87
- live: Bool? = nil,
88
- request: JsonTrackRequest? = nil,
88
+ display: String? = nil,
89
+ gridWrap: Bool? = nil,
90
+ gridTile: String? = nil,
91
+ artworkRendering: String? = nil,
92
+ imageShape: String? = nil,
93
+ accessorySymbol: String? = nil,
94
+ cardTint: String? = nil,
95
+ cardImage: String? = nil,
96
+ ) {
97
+ self.display = display
98
+ self.gridWrap = gridWrap
99
+ self.gridTile = gridTile
100
+ self.artworkRendering = artworkRendering
101
+ self.imageShape = imageShape
102
+ self.accessorySymbol = accessorySymbol
103
+ self.cardTint = cardTint
104
+ self.cardImage = cardImage
105
+ }
106
+
107
+ init(from decoder: Decoder) throws {
108
+ // A non-object value (the retired `style: 'grid'` string) decodes as an
109
+ // empty block rather than failing the parent.
110
+ guard let container = try? decoder.container(keyedBy: CodingKeys.self) else {
111
+ self.init()
112
+ return
113
+ }
114
+ self.init(
115
+ display: (try? container.decodeIfPresent(String.self, forKey: .display)) ?? nil,
116
+ gridWrap: (try? container.decodeIfPresent(Bool.self, forKey: .gridWrap)) ?? nil,
117
+ gridTile: (try? container.decodeIfPresent(String.self, forKey: .gridTile)) ?? nil,
118
+ artworkRendering: (try? container.decodeIfPresent(String.self, forKey: .artworkRendering)) ?? nil,
119
+ imageShape: (try? container.decodeIfPresent(String.self, forKey: .imageShape)) ?? nil,
120
+ accessorySymbol: (try? container.decodeIfPresent(String.self, forKey: .accessorySymbol)) ?? nil,
121
+ cardTint: (try? container.decodeIfPresent(String.self, forKey: .cardTint)) ?? nil,
122
+ cardImage: (try? container.decodeIfPresent(String.self, forKey: .cardImage)) ?? nil,
123
+ )
124
+ }
125
+ }
126
+
127
+ extension JsonStyle {
128
+ /// The wire strings map to Nitro enums here, tolerantly: an unknown value
129
+ /// (a future `display` mode, say) is no declaration, not an error. A block
130
+ /// that resolves to no declarations at all — `{}`, the tolerant decoder's
131
+ /// empty result for the retired string vocabulary, or all-unknown values —
132
+ /// maps to nil, so "no declaration" has one shape on every platform
133
+ /// (Android's lenient mapper makes the same collapse).
134
+ func toTrackStyle() -> TrackStyle? {
135
+ let display = display.flatMap { StyleDisplay(fromString: $0.lowercased()) }
136
+ let artworkRendering = artworkRendering.flatMap { ArtworkRendering(fromString: $0.lowercased()) }
137
+ let imageShape = imageShape.flatMap { ImageShape(fromString: $0.lowercased()) }
138
+ // The 'none' sentinel is a legitimate value; only emptiness collapses.
139
+ let accessorySymbol = accessorySymbol?.isEmpty == false ? accessorySymbol : nil
140
+ let cardTint = cardTint?.isEmpty == false ? cardTint : nil
141
+ let cardImage = cardImage.flatMap { CardImage(fromString: $0.lowercased()) }
142
+ guard display != nil || artworkRendering != nil || imageShape != nil
143
+ || accessorySymbol != nil || cardTint != nil || cardImage != nil
144
+ else { return nil }
145
+ return TrackStyle(
146
+ display: display,
147
+ artworkRendering: artworkRendering,
148
+ imageShape: imageShape,
149
+ accessorySymbol: accessorySymbol,
150
+ cardTint: cardTint,
151
+ cardImage: cardImage,
152
+ )
153
+ }
154
+
155
+ func toSectionStyle() -> SectionStyle? {
156
+ let display = display.flatMap { StyleDisplay(fromString: $0.lowercased()) }
157
+ let gridTile = gridTile.flatMap { GridTile(fromString: $0.lowercased()) }
158
+ let artworkRendering = artworkRendering.flatMap { ArtworkRendering(fromString: $0.lowercased()) }
159
+ let imageShape = imageShape.flatMap { ImageShape(fromString: $0.lowercased()) }
160
+ let accessorySymbol = accessorySymbol?.isEmpty == false ? accessorySymbol : nil
161
+ let cardTint = cardTint?.isEmpty == false ? cardTint : nil
162
+ let cardImage = cardImage.flatMap { CardImage(fromString: $0.lowercased()) }
163
+ guard display != nil || artworkRendering != nil || gridWrap != nil
164
+ || gridTile != nil || imageShape != nil || accessorySymbol != nil
165
+ || cardTint != nil || cardImage != nil
166
+ else { return nil }
167
+ // Argument order is the generated init's (own properties before
168
+ // inherited ones — Nitro flattens `extends` own-props-first).
169
+ return SectionStyle(
170
+ gridWrap: gridWrap,
171
+ gridTile: gridTile,
172
+ display: display,
173
+ artworkRendering: artworkRendering,
174
+ imageShape: imageShape,
175
+ accessorySymbol: accessorySymbol,
176
+ cardTint: cardTint,
177
+ cardImage: cardImage,
178
+ )
179
+ }
180
+
181
+ /// Snapshot a live track block back to its JSON model (for persistence).
182
+ /// An all-nil block snapshots as no block — the decoders collapse it to
183
+ /// "no declaration" anyway, so never persist the distinction.
184
+ init?(_ style: TrackStyle?) {
185
+ guard let style,
186
+ style.display != nil || style.artworkRendering != nil
187
+ || style.imageShape != nil || style.accessorySymbol != nil
188
+ || style.cardTint != nil || style.cardImage != nil
189
+ else { return nil }
190
+ self.init(
191
+ display: Self.string(style.display),
192
+ artworkRendering: Self.string(style.artworkRendering),
193
+ imageShape: Self.string(style.imageShape),
194
+ accessorySymbol: style.accessorySymbol,
195
+ cardTint: style.cardTint,
196
+ cardImage: Self.string(style.cardImage),
197
+ )
198
+ }
199
+
200
+ private static func string(_ display: StyleDisplay?) -> String? {
201
+ switch display {
202
+ case .list: "list"
203
+ case .grid: "grid"
204
+ case nil: nil
205
+ }
206
+ }
207
+
208
+ private static func string(_ rendering: ArtworkRendering?) -> String? {
209
+ switch rendering {
210
+ case .original: "original"
211
+ case .stencil: "stencil"
212
+ case nil: nil
213
+ }
214
+ }
215
+
216
+ private static func string(_ shape: ImageShape?) -> String? {
217
+ switch shape {
218
+ case .circular: "circular"
219
+ case .roundedRectangle: "rounded-rectangle"
220
+ case nil: nil
221
+ }
222
+ }
223
+
224
+ private static func string(_ mode: CardImage?) -> String? {
225
+ switch mode {
226
+ case .normal: "normal"
227
+ case .background: "background"
228
+ case nil: nil
229
+ }
230
+ }
231
+ }
232
+
233
+ /// JSON model for a page section (ADR 0010). Legacy `groupTitle`/`imageRow`
234
+ /// keys in payloads are simply unknown to these models and decode as
235
+ /// ignored dead weight.
236
+ struct JsonSection: Codable {
237
+ let title: String?
238
+ let style: JsonStyle?
239
+ let path: String?
240
+ let children: [JsonTrack]
241
+
242
+ init(
243
+ title: String? = nil,
244
+ style: JsonStyle? = nil,
245
+ path: String? = nil,
246
+ children: [JsonTrack],
89
247
  ) {
90
- self.id = id
91
- self.url = url
92
- self.src = src
93
- self.artwork = artwork
94
248
  self.title = title
95
- self.artist = artist
96
- self.album = album
97
- self.albumUrl = albumUrl
98
- self.live = live
99
- self.request = request
249
+ self.style = style
250
+ self.path = path
251
+ self.children = children
100
252
  }
101
253
  }
102
254
 
@@ -116,60 +268,63 @@ struct JsonTrackRequest: Codable {
116
268
  /// JSON model for resolved track (container with children).
117
269
  struct JsonResolvedTrack: Codable {
118
270
  let id: String?
119
- let url: String
271
+ let path: String
120
272
  let title: String
121
273
  let subtitle: String?
122
274
  let artwork: JsonArtwork?
123
275
  let artist: String?
124
- let albumUrl: String?
276
+ let albumPath: String?
125
277
  let album: String?
126
278
  let description: String?
127
279
  let genre: String?
128
280
  let duration: Double?
281
+ let sections: [JsonSection]?
129
282
  let children: [JsonTrack]?
130
283
  let src: String?
131
- let style: String?
132
- let childrenStyle: String?
133
- let groupTitle: String?
284
+ let style: JsonStyle?
285
+ let disabled: Bool?
134
286
  let live: Bool?
287
+ let icyCharset: String?
135
288
  let carPlaySiriListButton: String?
136
289
 
137
290
  init(
138
291
  id: String? = nil,
139
- url: String,
292
+ path: String,
140
293
  title: String,
141
294
  subtitle: String? = nil,
142
295
  artwork: JsonArtwork? = nil,
143
296
  artist: String? = nil,
144
- albumUrl: String? = nil,
297
+ albumPath: String? = nil,
145
298
  album: String? = nil,
146
299
  description: String? = nil,
147
300
  genre: String? = nil,
148
301
  duration: Double? = nil,
302
+ sections: [JsonSection]? = nil,
149
303
  children: [JsonTrack]? = nil,
150
304
  src: String? = nil,
151
- style: String? = nil,
152
- childrenStyle: String? = nil,
153
- groupTitle: String? = nil,
305
+ style: JsonStyle? = nil,
306
+ disabled: Bool? = nil,
154
307
  live: Bool? = nil,
308
+ icyCharset: String? = nil,
155
309
  carPlaySiriListButton: String? = nil,
156
310
  ) {
157
- self.url = url
311
+ self.path = path
158
312
  self.title = title
159
313
  self.subtitle = subtitle
160
314
  self.artwork = artwork
161
315
  self.artist = artist
162
- self.albumUrl = albumUrl
316
+ self.albumPath = albumPath
163
317
  self.album = album
164
318
  self.description = description
165
319
  self.genre = genre
166
320
  self.duration = duration
321
+ self.sections = sections
167
322
  self.children = children
168
323
  self.src = src
169
324
  self.style = style
170
- self.childrenStyle = childrenStyle
171
- self.groupTitle = groupTitle
325
+ self.disabled = disabled
172
326
  self.live = live
327
+ self.icyCharset = icyCharset
173
328
  self.carPlaySiriListButton = carPlaySiriListButton
174
329
  self.id = id
175
330
  }
@@ -178,50 +333,48 @@ struct JsonResolvedTrack: Codable {
178
333
  /// JSON model for individual tracks.
179
334
  struct JsonTrack: Codable {
180
335
  let id: String?
181
- let url: String?
336
+ let path: String?
182
337
  let title: String
183
338
  let subtitle: String?
184
339
  let artwork: JsonArtwork?
185
340
  let artist: String?
186
- let albumUrl: String?
341
+ let albumPath: String?
187
342
  let album: String?
188
343
  let description: String?
189
344
  let genre: String?
190
345
  let duration: Double?
191
346
  let src: String?
192
347
  let request: JsonTrackRequest?
193
- let style: String?
194
- let childrenStyle: String?
195
- let groupTitle: String?
348
+ let style: JsonStyle?
349
+ let disabled: Bool?
196
350
  let live: Bool?
197
- let imageRow: [JsonImageRowItem]?
351
+ let icyCharset: String?
198
352
 
199
353
  init(
200
354
  id: String? = nil,
201
- url: String? = nil,
355
+ path: String? = nil,
202
356
  title: String,
203
357
  subtitle: String? = nil,
204
358
  artwork: JsonArtwork? = nil,
205
359
  artist: String? = nil,
206
- albumUrl: String? = nil,
360
+ albumPath: String? = nil,
207
361
  album: String? = nil,
208
362
  description: String? = nil,
209
363
  genre: String? = nil,
210
364
  duration: Double? = nil,
211
365
  src: String? = nil,
212
366
  request: JsonTrackRequest? = nil,
213
- style: String? = nil,
214
- childrenStyle: String? = nil,
215
- groupTitle: String? = nil,
367
+ style: JsonStyle? = nil,
368
+ disabled: Bool? = nil,
216
369
  live: Bool? = nil,
217
- imageRow: [JsonImageRowItem]? = nil,
370
+ icyCharset: String? = nil,
218
371
  ) {
219
- self.url = url
372
+ self.path = path
220
373
  self.title = title
221
374
  self.subtitle = subtitle
222
375
  self.artwork = artwork
223
376
  self.artist = artist
224
- self.albumUrl = albumUrl
377
+ self.albumPath = albumPath
225
378
  self.album = album
226
379
  self.description = description
227
380
  self.genre = genre
@@ -229,10 +382,9 @@ struct JsonTrack: Codable {
229
382
  self.src = src
230
383
  self.request = request
231
384
  self.style = style
232
- self.childrenStyle = childrenStyle
233
- self.groupTitle = groupTitle
385
+ self.disabled = disabled
234
386
  self.live = live
235
- self.imageRow = imageRow
387
+ self.icyCharset = icyCharset
236
388
  self.id = id
237
389
  }
238
390
  }
@@ -250,26 +402,28 @@ struct JsonTrack: Codable {
250
402
 
251
403
  extension JsonTrack {
252
404
  /// Snapshot the persistable subset of a live Track (inverse of `toNitro()`).
405
+ /// The track's own declared style block and `disabled` persist (ADR 0011);
406
+ /// section/page-inherited values are never stamped onto tracks and
407
+ /// re-resolve at render, exactly as they do live.
253
408
  init(from track: Track) {
254
409
  self.init(
255
410
  id: track.id,
256
- url: track.url,
411
+ path: track.path,
257
412
  title: track.title,
258
413
  subtitle: track.subtitle,
259
414
  artwork: JsonArtwork(track.artwork),
260
415
  artist: track.artist,
261
- albumUrl: track.albumUrl,
416
+ albumPath: track.albumPath,
262
417
  album: track.album,
263
418
  description: track.description,
264
419
  genre: track.genre,
265
420
  duration: track.duration,
266
421
  src: track.src,
267
422
  request: track.request.map(JsonTrackRequest.init(from:)),
268
- style: nil,
269
- childrenStyle: nil,
270
- groupTitle: track.groupTitle,
423
+ style: JsonStyle(track.style),
424
+ disabled: track.disabled,
271
425
  live: track.live,
272
- imageRow: nil,
426
+ icyCharset: track.icyCharset,
273
427
  )
274
428
  }
275
429
  }
@@ -289,15 +443,18 @@ struct JsonTrack: Codable {
289
443
  init(from track: Track) {
290
444
  self.init(
291
445
  id: track.id,
292
- url: track.url,
446
+ path: track.path,
293
447
  title: track.title,
294
448
  artwork: JsonArtwork(track.artwork),
295
449
  artist: track.artist,
296
- albumUrl: track.albumUrl,
450
+ albumPath: track.albumPath,
297
451
  album: track.album,
298
452
  src: track.src,
299
453
  request: track.request.map(JsonTrackRequest.init(from:)),
454
+ style: JsonStyle(track.style),
455
+ disabled: track.disabled,
300
456
  live: track.live,
457
+ icyCharset: track.icyCharset,
301
458
  )
302
459
  }
303
460
  }
@@ -308,26 +465,13 @@ struct JsonTrack: Codable {
308
465
 
309
466
  #if canImport(NitroModules)
310
467
 
311
- private extension String {
312
- func toTrackStyle() -> TrackStyle? {
313
- TrackStyle(fromString: lowercased())
314
- }
315
- }
316
-
317
- extension JsonImageRowItem {
318
- func toNitro() -> ImageRowItem {
319
- ImageRowItem(
320
- id: id,
321
- url: url,
322
- src: src,
323
- artwork: artwork,
324
- artworkSource: nil,
468
+ extension JsonSection {
469
+ func toNitro() -> Section {
470
+ Section(
325
471
  title: title,
326
- artist: artist,
327
- album: album,
328
- albumUrl: albumUrl,
329
- live: live,
330
- request: request?.toNitro(),
472
+ style: style?.toSectionStyle(),
473
+ path: path,
474
+ children: children.map { $0.toNitro() },
331
475
  )
332
476
  }
333
477
  }
@@ -335,28 +479,27 @@ struct JsonTrack: Codable {
335
479
  extension JsonResolvedTrack {
336
480
  func toNitro() -> ResolvedTrack {
337
481
  ResolvedTrack(
338
- url: url,
482
+ path: path,
483
+ style: style?.toSectionStyle(),
484
+ sections: sections?.map { $0.toNitro() },
339
485
  children: children?.map { $0.toNitro() },
340
486
  carPlaySiriListButton: carPlaySiriListButton.flatMap { CarPlaySiriListButtonPosition(fromString: $0) },
341
487
  id: id,
342
488
  src: src,
343
489
  artwork: artwork?.toNitro(),
344
490
  artworkSource: nil, request: nil,
345
- artworkCarPlayTinted: nil,
346
491
  title: title,
347
492
  subtitle: subtitle,
348
493
  artist: artist,
349
- albumUrl: albumUrl,
494
+ albumPath: albumPath,
350
495
  album: album,
351
496
  description: description,
352
497
  genre: genre,
353
498
  duration: duration,
354
- style: style?.toTrackStyle(),
355
- childrenStyle: childrenStyle?.toTrackStyle(),
499
+ disabled: disabled,
356
500
  favorited: nil,
357
- groupTitle: groupTitle,
358
501
  live: live,
359
- imageRow: nil,
502
+ icyCharset: icyCharset,
360
503
  )
361
504
  }
362
505
  }
@@ -365,26 +508,24 @@ struct JsonTrack: Codable {
365
508
  func toNitro() -> Track {
366
509
  Track(
367
510
  id: id,
368
- url: url,
511
+ path: path,
369
512
  src: src,
370
513
  artwork: artwork?.toNitro(),
371
514
  artworkSource: nil,
372
515
  request: request?.toNitro(),
373
- artworkCarPlayTinted: nil,
374
516
  title: title,
375
517
  subtitle: subtitle,
376
518
  artist: artist,
377
- albumUrl: albumUrl,
519
+ albumPath: albumPath,
378
520
  album: album,
379
521
  description: description,
380
522
  genre: genre,
381
523
  duration: duration,
382
524
  style: style?.toTrackStyle(),
383
- childrenStyle: childrenStyle?.toTrackStyle(),
525
+ disabled: disabled,
384
526
  favorited: nil,
385
- groupTitle: groupTitle,
386
527
  live: live,
387
- imageRow: imageRow?.map { $0.toNitro() },
528
+ icyCharset: icyCharset,
388
529
  )
389
530
  }
390
531
  }
@@ -396,15 +537,29 @@ struct JsonTrack: Codable {
396
537
  func toNitro() -> Track {
397
538
  Track(
398
539
  id: id ?? "",
399
- url: url,
540
+ path: path,
400
541
  src: src,
542
+ artwork: artwork?.toNitro(),
401
543
  request: request.map { TrackRequest(userAgent: $0.userAgent, headers: $0.headers, query: $0.query) },
402
544
  title: title,
403
545
  artist: artist,
404
- albumUrl: albumUrl,
546
+ albumPath: albumPath,
405
547
  album: album,
548
+ style: style?.toTrackStyle(),
549
+ disabled: disabled,
406
550
  live: live,
407
- artwork: artwork?.toNitro(),
551
+ icyCharset: icyCharset,
552
+ )
553
+ }
554
+ }
555
+
556
+ extension JsonSection {
557
+ func toNitro() -> Section {
558
+ Section(
559
+ title: title,
560
+ style: style?.toSectionStyle(),
561
+ path: path,
562
+ children: children.map { $0.toNitro() },
408
563
  )
409
564
  }
410
565
  }
@@ -412,10 +567,13 @@ struct JsonTrack: Codable {
412
567
  extension JsonResolvedTrack {
413
568
  func toNitro() -> ResolvedTrack {
414
569
  ResolvedTrack(
415
- url: url,
570
+ path: path,
571
+ style: style?.toSectionStyle(),
572
+ sections: sections?.map { $0.toNitro() },
416
573
  children: children?.map { $0.toNitro() },
417
574
  artwork: artwork?.toNitro(),
418
575
  title: title,
576
+ disabled: disabled,
419
577
  )
420
578
  }
421
579
  }
@@ -1,18 +1,18 @@
1
1
  import Foundation
2
2
 
3
3
  /// A search result that may or may not be directly playable. `src` is the
4
- /// playable stream; `url` is a browsable container path. Abstracting these two
4
+ /// playable stream; `path` is a browsable container path. Abstracting these two
5
5
  /// fields keeps the drill-in decision free of the Nitro `Track` type so it can
6
6
  /// be unit-tested.
7
7
  protocol PlayableSearchItem {
8
8
  var src: String? { get }
9
- var url: String? { get }
9
+ var path: String? { get }
10
10
  }
11
11
 
12
12
  enum SearchDrillIn {
13
13
  /// Picks the playable items for a "play «X»" voice search.
14
14
  ///
15
- /// If the first result is browsable-only (a `url` container with no `src` — a
15
+ /// If the first result is browsable-only (a `path` container with no `src` — a
16
16
  /// place/genre page), drills into it via `resolveChildren` and uses its
17
17
  /// playable children, so we play the first station *inside* the page rather
18
18
  /// than skipping the page for a later inline station. Falls back to the flat
@@ -20,13 +20,13 @@ enum SearchDrillIn {
20
20
  /// yields nothing. Returns nil when nothing is playable.
21
21
  static func playable<Item: PlayableSearchItem>(
22
22
  from children: [Item],
23
- resolveChildren: sending (String) async throws -> [Item]
23
+ resolveChildren: sending (String) async throws -> [Item],
24
24
  ) async throws -> [Item]? {
25
25
  guard !children.isEmpty else { return nil }
26
26
 
27
27
  let candidates: [Item]
28
- if let first = children.first, first.src == nil, let url = first.url {
29
- let drilled = try await resolveChildren(url).filter { $0.src != nil }
28
+ if let first = children.first, first.src == nil, let path = first.path {
29
+ let drilled = try await resolveChildren(path).filter { $0.src != nil }
30
30
  candidates = drilled.isEmpty ? children : drilled
31
31
  } else {
32
32
  candidates = children
@@ -37,7 +37,7 @@ enum SearchDrillIn {
37
37
  }
38
38
  }
39
39
 
40
- // The real Nitro `Track` already carries `src`/`url`; conform it for the app
40
+ // The real Nitro `Track` already carries `src`/`path`; conform it for the app
41
41
  // build. (The testable target builds without NitroModules and uses a stub item.)
42
42
  #if canImport(NitroModules)
43
43
  extension Track: PlayableSearchItem {}
@@ -0,0 +1,64 @@
1
+ #if canImport(NitroModules)
2
+ import NitroModules
3
+ #endif
4
+
5
+ /// The rendered form of a section — the single place where (resolved style,
6
+ /// platform capability) maps to what CarPlay draws. Degradation drops
7
+ /// decorations before layout (ADR 0011): a *wrapping* grid can only reach the
8
+ /// tile path where the platform has a wrapping tile container (CarPlay:
9
+ /// iOS 26+'s element API); without one it becomes a list, where every item
10
+ /// stays reachable instead of truncating at an unknowable width. A
11
+ /// single-line grid (`gridWrap: false`) renders everywhere — the legacy image
12
+ /// row IS the single-line presentation.
13
+ enum SectionPresentation: Equatable {
14
+ case list
15
+ case singleLineRow
16
+ case wrappingGrid
17
+
18
+ /// - Parameter supportsWrappingGrid: whether the platform has a wrapping
19
+ /// tile container. Injected (rather than read via `#available` here) so
20
+ /// the mapping is testable off-device.
21
+ init(for style: SectionStyle?, supportsWrappingGrid: Bool) {
22
+ guard style?.display == .grid else {
23
+ self = .list
24
+ return
25
+ }
26
+ if style?.gridWrap == false {
27
+ self = .singleLineRow
28
+ } else if supportsWrappingGrid {
29
+ self = .wrappingGrid
30
+ } else {
31
+ self = .list
32
+ }
33
+ }
34
+
35
+ /// The accessory symbol a resolved block actually draws: nil when
36
+ /// undeclared, and nil for the `'none'` sentinel — the inheritance escape
37
+ /// that restores the derived accessory (a browsable row's chevron). Here,
38
+ /// not in the CarPlay factory, so the sentinel rule is testable off-device.
39
+ static func effectiveAccessorySymbol(_ style: TrackStyle?) -> String? {
40
+ guard let symbol = style?.accessorySymbol, symbol != "none" else { return nil }
41
+ return symbol
42
+ }
43
+
44
+ /// The element family a tile presentation renders on iOS 26+ — here, not
45
+ /// in the CarPlay factory, so the style→family mapping is testable
46
+ /// off-device. `gridTile` picks the family (plain by default); the plain
47
+ /// single-line shelf keeps row elements, the one plain element with a
48
+ /// subtitle slot. Pre-26 has no element API at all: the treatment drops
49
+ /// with the legacy image row (decorations drop before layout).
50
+ enum TileElementFamily: Equatable {
51
+ case rowElements
52
+ case imageGridElements
53
+ case cardElements
54
+ case condensedElements
55
+ }
56
+
57
+ static func tileFamily(for style: SectionStyle?, singleLine: Bool) -> TileElementFamily {
58
+ switch style?.gridTile {
59
+ case .card: .cardElements
60
+ case .condensed: .condensedElements
61
+ case .plain, nil: singleLine ? .rowElements : .imageGridElements
62
+ }
63
+ }
64
+ }