@5stones/react-native-audio-browser 0.1.6 → 0.3.0

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 (593) hide show
  1. package/AudioBrowser.podspec +3 -1
  2. package/android/src/main/cpp/cpp-adapter.cpp +4 -1
  3. package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +15 -9
  4. package/android/src/main/java/com/audiobrowser/Service.kt +0 -2
  5. package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +5 -0
  6. package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +31 -0
  7. package/android/src/main/java/com/audiobrowser/browser/SimpleRouter.kt +10 -6
  8. package/android/src/main/java/com/audiobrowser/browser/TrackLoadHandler.kt +45 -0
  9. package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +39 -17
  10. package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +1 -0
  11. package/android/src/main/java/com/audiobrowser/player/Player.kt +1 -0
  12. package/android/src/main/java/com/audiobrowser/player/TransformingDataSource.kt +33 -11
  13. package/android/src/test/java/com/audiobrowser/browser/SimpleRouterTest.kt +104 -95
  14. package/ios/Browser/BrowserConfig.swift +31 -5
  15. package/ios/Browser/BrowserManager.swift +98 -23
  16. package/ios/Browser/JsonModels.swift +37 -0
  17. package/ios/CarPlay/CarPlayController.swift +256 -88
  18. package/ios/CarPlay/RNABAudioBrowser.h +23 -0
  19. package/ios/CarPlay/RNABAudioBrowser.m +22 -0
  20. package/ios/CarPlay/RNABMediaIntentHandler.swift +60 -0
  21. package/ios/Extension/ChapterMetadata+AVFoundation.swift +1 -1
  22. package/ios/Extension/CxxVectorConformances.swift +20 -0
  23. package/ios/Extension/TimedMetadata+AVFoundation.swift +5 -5
  24. package/ios/Extension/Track+AVPlayer.swift +5 -6
  25. package/ios/Extension/TrackMetadata+AVFoundation.swift +1 -1
  26. package/ios/HybridAudioBrowser.swift +126 -35
  27. package/ios/Model/MediaURL.swift +2 -1
  28. package/ios/Player/PlayingStateManager.swift +1 -0
  29. package/ios/Player/RetryManager.swift +26 -65
  30. package/ios/Player/SleepTimerManager.swift +6 -8
  31. package/ios/RemoteCommand/RemoteCommandController.swift +6 -0
  32. package/ios/Tests/SimpleRouterTests.swift +139 -0
  33. package/ios/TrackPlayer.swift +71 -53
  34. package/ios/Util/NetworkMonitor.swift +3 -6
  35. package/ios/Util/SFSymbolRenderer.swift +142 -0
  36. package/lib/commonjs/features/browser.js +1 -0
  37. package/lib/commonjs/features/browser.js.map +1 -1
  38. package/lib/commonjs/web/NativeAudioBrowser.js +32 -7
  39. package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
  40. package/lib/commonjs/web/SimpleRouter.js +4 -3
  41. package/lib/commonjs/web/SimpleRouter.js.map +1 -1
  42. package/lib/commonjs/web/SimpleRouter.test.js +174 -0
  43. package/lib/commonjs/web/SimpleRouter.test.js.map +1 -0
  44. package/lib/module/features/browser.js +1 -0
  45. package/lib/module/features/browser.js.map +1 -1
  46. package/lib/module/web/NativeAudioBrowser.js +32 -7
  47. package/lib/module/web/NativeAudioBrowser.js.map +1 -1
  48. package/lib/module/web/SimpleRouter.js +4 -3
  49. package/lib/module/web/SimpleRouter.js.map +1 -1
  50. package/lib/module/web/SimpleRouter.test.js +174 -0
  51. package/lib/module/web/SimpleRouter.test.js.map +1 -0
  52. package/lib/typescript/src/features/browser.d.ts.map +1 -1
  53. package/lib/typescript/src/types/browser-native.d.ts +2 -1
  54. package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
  55. package/lib/typescript/src/types/browser-nodes.d.ts +46 -1
  56. package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
  57. package/lib/typescript/src/types/browser.d.ts +32 -0
  58. package/lib/typescript/src/types/browser.d.ts.map +1 -1
  59. package/lib/typescript/src/web/NativeAudioBrowser.d.ts +7 -0
  60. package/lib/typescript/src/web/NativeAudioBrowser.d.ts.map +1 -1
  61. package/lib/typescript/src/web/SimpleRouter.d.ts.map +1 -1
  62. package/lib/typescript/src/web/SimpleRouter.test.d.ts +2 -0
  63. package/lib/typescript/src/web/SimpleRouter.test.d.ts.map +1 -0
  64. package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +1 -1
  65. package/nitrogen/generated/android/AudioBrowser+autolinking.gradle +1 -1
  66. package/nitrogen/generated/android/AudioBrowserOnLoad.cpp +67 -55
  67. package/nitrogen/generated/android/AudioBrowserOnLoad.hpp +14 -5
  68. package/nitrogen/generated/android/c++/JAndroidAudioContentType.hpp +6 -7
  69. package/nitrogen/generated/android/c++/JAndroidAudioOffloadSettings.hpp +1 -1
  70. package/nitrogen/generated/android/c++/JAndroidOptions.hpp +1 -1
  71. package/nitrogen/generated/android/c++/JAndroidPlayerWakeMode.hpp +4 -5
  72. package/nitrogen/generated/android/c++/JAndroidUpdateOptions.hpp +1 -1
  73. package/nitrogen/generated/android/c++/JAppKilledPlaybackBehavior.hpp +4 -5
  74. package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +4 -1
  75. package/nitrogen/generated/android/c++/JBatteryOptimizationStatus.hpp +4 -5
  76. package/nitrogen/generated/android/c++/JBatteryOptimizationStatusChangedEvent.hpp +1 -1
  77. package/nitrogen/generated/android/c++/JBatteryWarningPendingChangedEvent.hpp +1 -1
  78. package/nitrogen/generated/android/c++/JBrowseError.hpp +1 -1
  79. package/nitrogen/generated/android/c++/JBrowseResult.cpp +1 -1
  80. package/nitrogen/generated/android/c++/JBrowseResult.hpp +7 -3
  81. package/nitrogen/generated/android/c++/JBrowserSourceCallbackParam.hpp +1 -1
  82. package/nitrogen/generated/android/c++/JCarPlayNowPlayingButton.hpp +5 -6
  83. package/nitrogen/generated/android/c++/JCarPlaySiriListButtonPosition.hpp +58 -0
  84. package/nitrogen/generated/android/c++/JChapterMetadata.hpp +1 -1
  85. package/nitrogen/generated/android/c++/JEqualizerSettings.hpp +1 -1
  86. package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +4 -1
  87. package/nitrogen/generated/android/c++/JFormatNavigationErrorParams.hpp +1 -1
  88. package/nitrogen/generated/android/c++/JFormattedNavigationError.hpp +1 -1
  89. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.hpp +1 -1
  90. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.hpp +1 -1
  91. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____RequestConfig_std__optional_std__unordered_map_std__string__std__string__.hpp +1 -1
  92. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +4 -1
  93. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.hpp +5 -1
  94. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +3 -1
  95. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +139 -0
  96. package/nitrogen/generated/android/c++/JFunc_void.hpp +1 -1
  97. package/nitrogen/generated/android/c++/JFunc_void_BatteryOptimizationStatusChangedEvent.hpp +1 -1
  98. package/nitrogen/generated/android/c++/JFunc_void_BatteryWarningPendingChangedEvent.hpp +1 -1
  99. package/nitrogen/generated/android/c++/JFunc_void_EqualizerSettings.hpp +1 -1
  100. package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +4 -1
  101. package/nitrogen/generated/android/c++/JFunc_void_IosOutput.hpp +1 -1
  102. package/nitrogen/generated/android/c++/JFunc_void_NavigationErrorEvent.hpp +1 -1
  103. package/nitrogen/generated/android/c++/JFunc_void_NowPlayingMetadata.hpp +1 -1
  104. package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +1 -1
  105. package/nitrogen/generated/android/c++/JFunc_void_Playback.hpp +1 -1
  106. package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +4 -1
  107. package/nitrogen/generated/android/c++/JFunc_void_PlaybackErrorEvent.hpp +1 -1
  108. package/nitrogen/generated/android/c++/JFunc_void_PlaybackPlayWhenReadyChangedEvent.hpp +1 -1
  109. package/nitrogen/generated/android/c++/JFunc_void_PlaybackProgressUpdatedEvent.hpp +1 -1
  110. package/nitrogen/generated/android/c++/JFunc_void_PlaybackQueueEndedEvent.hpp +1 -1
  111. package/nitrogen/generated/android/c++/JFunc_void_PlayingState.hpp +1 -1
  112. package/nitrogen/generated/android/c++/JFunc_void_RemoteJumpBackwardEvent.hpp +1 -1
  113. package/nitrogen/generated/android/c++/JFunc_void_RemoteJumpForwardEvent.hpp +1 -1
  114. package/nitrogen/generated/android/c++/JFunc_void_RemotePlayIdEvent.hpp +1 -1
  115. package/nitrogen/generated/android/c++/JFunc_void_RemotePlaySearchEvent.hpp +1 -1
  116. package/nitrogen/generated/android/c++/JFunc_void_RemoteSeekEvent.hpp +1 -1
  117. package/nitrogen/generated/android/c++/JFunc_void_RemoteSetRatingEvent.hpp +1 -1
  118. package/nitrogen/generated/android/c++/JFunc_void_RemoteSkipEvent.hpp +1 -1
  119. package/nitrogen/generated/android/c++/JFunc_void_RepeatModeChangedEvent.hpp +1 -1
  120. package/nitrogen/generated/android/c++/JFunc_void_TimedMetadata.hpp +1 -1
  121. package/nitrogen/generated/android/c++/JFunc_void_TrackMetadata.hpp +1 -1
  122. package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +1 -1
  123. package/nitrogen/generated/android/c++/JFunc_void_double.hpp +1 -1
  124. package/nitrogen/generated/android/c++/JFunc_void_std__optional_FormattedNavigationError_.hpp +1 -1
  125. package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +5 -1
  126. package/nitrogen/generated/android/c++/JFunc_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.hpp +1 -1
  127. package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +1 -1
  128. package/nitrogen/generated/android/c++/JFunc_void_std__vector_ChapterMetadata_.hpp +1 -1
  129. package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +3 -1
  130. package/nitrogen/generated/android/c++/JHeartRating.hpp +1 -1
  131. package/nitrogen/generated/android/c++/JHttpMethod.hpp +8 -9
  132. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +230 -206
  133. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.hpp +20 -22
  134. package/nitrogen/generated/android/c++/JIOSCategory.hpp +7 -8
  135. package/nitrogen/generated/android/c++/JIOSCategoryMode.hpp +10 -11
  136. package/nitrogen/generated/android/c++/JIOSCategoryOptions.hpp +8 -9
  137. package/nitrogen/generated/android/c++/JIOSCategoryPolicy.hpp +4 -5
  138. package/nitrogen/generated/android/c++/JImageContext.hpp +1 -1
  139. package/nitrogen/generated/android/c++/JImageQueryParams.hpp +1 -1
  140. package/nitrogen/generated/android/c++/JImageRowItem.hpp +75 -0
  141. package/nitrogen/generated/android/c++/JImageSource.hpp +1 -1
  142. package/nitrogen/generated/android/c++/JIosOutput.hpp +1 -1
  143. package/nitrogen/generated/android/c++/JIosOutputType.hpp +12 -13
  144. package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +4 -1
  145. package/nitrogen/generated/android/c++/JMediaTransformParams.hpp +1 -1
  146. package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +22 -2
  147. package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +5 -1
  148. package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +1 -1
  149. package/nitrogen/generated/android/c++/JNavigationError.hpp +1 -1
  150. package/nitrogen/generated/android/c++/JNavigationErrorEvent.hpp +1 -1
  151. package/nitrogen/generated/android/c++/JNavigationErrorType.hpp +6 -7
  152. package/nitrogen/generated/android/c++/JNitroAndroidUpdateOptions.hpp +1 -1
  153. package/nitrogen/generated/android/c++/JNotificationButton.hpp +6 -7
  154. package/nitrogen/generated/android/c++/JNotificationButtonLayout.hpp +1 -1
  155. package/nitrogen/generated/android/c++/JNowPlayingMetadata.hpp +1 -1
  156. package/nitrogen/generated/android/c++/JNowPlayingUpdate.hpp +1 -1
  157. package/nitrogen/generated/android/c++/JOptions.hpp +1 -1
  158. package/nitrogen/generated/android/c++/JPartialAndroidSetupPlayerOptions.hpp +1 -1
  159. package/nitrogen/generated/android/c++/JPartialIOSSetupPlayerOptions.hpp +1 -1
  160. package/nitrogen/generated/android/c++/JPartialSetupPlayerOptions.hpp +1 -1
  161. package/nitrogen/generated/android/c++/JPercentageRating.hpp +1 -1
  162. package/nitrogen/generated/android/c++/JPlayback.hpp +1 -1
  163. package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +4 -1
  164. package/nitrogen/generated/android/c++/JPlaybackError.hpp +1 -1
  165. package/nitrogen/generated/android/c++/JPlaybackErrorEvent.hpp +1 -1
  166. package/nitrogen/generated/android/c++/JPlaybackPlayWhenReadyChangedEvent.hpp +1 -1
  167. package/nitrogen/generated/android/c++/JPlaybackProgressUpdatedEvent.hpp +1 -1
  168. package/nitrogen/generated/android/c++/JPlaybackQueueEndedEvent.hpp +1 -1
  169. package/nitrogen/generated/android/c++/JPlaybackState.hpp +10 -11
  170. package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +1 -1
  171. package/nitrogen/generated/android/c++/JPlayingState.hpp +1 -1
  172. package/nitrogen/generated/android/c++/JProgress.hpp +1 -1
  173. package/nitrogen/generated/android/c++/JRatingType.hpp +8 -9
  174. package/nitrogen/generated/android/c++/JRemoteJumpBackwardEvent.hpp +1 -1
  175. package/nitrogen/generated/android/c++/JRemoteJumpForwardEvent.hpp +1 -1
  176. package/nitrogen/generated/android/c++/JRemotePlayIdEvent.hpp +1 -1
  177. package/nitrogen/generated/android/c++/JRemotePlaySearchEvent.hpp +1 -1
  178. package/nitrogen/generated/android/c++/JRemoteSeekEvent.hpp +1 -1
  179. package/nitrogen/generated/android/c++/JRemoteSetRatingEvent.hpp +1 -1
  180. package/nitrogen/generated/android/c++/JRemoteSkipEvent.hpp +1 -1
  181. package/nitrogen/generated/android/c++/JRepeatMode.hpp +4 -5
  182. package/nitrogen/generated/android/c++/JRepeatModeChangedEvent.hpp +1 -1
  183. package/nitrogen/generated/android/c++/JRequestConfig.hpp +1 -1
  184. package/nitrogen/generated/android/c++/JResolvedTrack.hpp +34 -4
  185. package/nitrogen/generated/android/c++/JRetryConfig.hpp +1 -1
  186. package/nitrogen/generated/android/c++/JSearchMode.hpp +7 -8
  187. package/nitrogen/generated/android/c++/JSearchParams.hpp +1 -1
  188. package/nitrogen/generated/android/c++/JSleepTimer.cpp +1 -1
  189. package/nitrogen/generated/android/c++/JSleepTimer.hpp +4 -4
  190. package/nitrogen/generated/android/c++/JSleepTimerEndOfTrack.hpp +1 -1
  191. package/nitrogen/generated/android/c++/JSleepTimerTime.hpp +1 -1
  192. package/nitrogen/generated/android/c++/JStarRating.hpp +1 -1
  193. package/nitrogen/generated/android/c++/JThumbsRating.hpp +1 -1
  194. package/nitrogen/generated/android/c++/JTimedMetadata.hpp +1 -1
  195. package/nitrogen/generated/android/c++/JTrack.hpp +29 -4
  196. package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +96 -0
  197. package/nitrogen/generated/android/c++/JTrackMetadata.hpp +1 -1
  198. package/nitrogen/generated/android/c++/JTrackStyle.hpp +3 -4
  199. package/nitrogen/generated/android/c++/JTransformableRequestConfig.hpp +1 -1
  200. package/nitrogen/generated/android/c++/JUpdateOptions.hpp +1 -1
  201. package/nitrogen/generated/android/c++/JVariant_Boolean_AndroidAudioOffloadSettings.cpp +1 -1
  202. package/nitrogen/generated/android/c++/JVariant_Boolean_AndroidAudioOffloadSettings.hpp +3 -3
  203. package/nitrogen/generated/android/c++/JVariant_Boolean_RetryConfig.cpp +1 -1
  204. package/nitrogen/generated/android/c++/JVariant_Boolean_RetryConfig.hpp +3 -3
  205. package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.cpp +1 -1
  206. package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.hpp +5 -5
  207. package/nitrogen/generated/android/c++/JVariant_NullType_Double.cpp +1 -1
  208. package/nitrogen/generated/android/c++/JVariant_NullType_Double.hpp +3 -3
  209. package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.cpp +1 -1
  210. package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.hpp +3 -3
  211. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidAudioContentType.kt +3 -1
  212. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidAudioOffloadSettings.kt +2 -2
  213. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidOptions.kt +2 -2
  214. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidPlayerWakeMode.kt +3 -1
  215. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidUpdateOptions.kt +2 -2
  216. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AppKilledPlaybackBehavior.kt +3 -1
  217. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ArtworkRequestConfig.kt +2 -2
  218. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AudioBrowserOnLoad.kt +1 -1
  219. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryOptimizationStatus.kt +3 -1
  220. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryOptimizationStatusChangedEvent.kt +2 -2
  221. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryWarningPendingChangedEvent.kt +2 -2
  222. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowseError.kt +2 -2
  223. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowseResult.kt +1 -7
  224. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowserSourceCallbackParam.kt +2 -2
  225. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayNowPlayingButton.kt +3 -1
  226. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlaySiriListButtonPosition.kt +23 -0
  227. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ChapterMetadata.kt +2 -2
  228. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/EqualizerSettings.kt +2 -2
  229. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FavoriteChangedEvent.kt +2 -2
  230. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormatNavigationErrorParams.kt +2 -2
  231. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormattedNavigationError.kt +2 -2
  232. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.kt +1 -1
  233. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.kt +1 -1
  234. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____RequestConfig_std__optional_std__unordered_map_std__string__std__string__.kt +1 -1
  235. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.kt +1 -1
  236. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.kt +1 -1
  237. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.kt +1 -1
  238. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.kt +80 -0
  239. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void.kt +1 -1
  240. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_BatteryOptimizationStatusChangedEvent.kt +1 -1
  241. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_BatteryWarningPendingChangedEvent.kt +1 -1
  242. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_EqualizerSettings.kt +1 -1
  243. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_FavoriteChangedEvent.kt +1 -1
  244. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_IosOutput.kt +1 -1
  245. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_NavigationErrorEvent.kt +1 -1
  246. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_NowPlayingMetadata.kt +1 -1
  247. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_Options.kt +1 -1
  248. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_Playback.kt +1 -1
  249. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackActiveTrackChangedEvent.kt +1 -1
  250. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackErrorEvent.kt +1 -1
  251. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackPlayWhenReadyChangedEvent.kt +1 -1
  252. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackProgressUpdatedEvent.kt +1 -1
  253. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackQueueEndedEvent.kt +1 -1
  254. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlayingState.kt +1 -1
  255. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteJumpBackwardEvent.kt +1 -1
  256. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteJumpForwardEvent.kt +1 -1
  257. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemotePlayIdEvent.kt +1 -1
  258. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemotePlaySearchEvent.kt +1 -1
  259. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSeekEvent.kt +1 -1
  260. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSetRatingEvent.kt +1 -1
  261. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSkipEvent.kt +1 -1
  262. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RepeatModeChangedEvent.kt +1 -1
  263. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_TimedMetadata.kt +1 -1
  264. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_TrackMetadata.kt +1 -1
  265. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_bool.kt +1 -1
  266. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_double.kt +1 -1
  267. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_FormattedNavigationError_.kt +1 -1
  268. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_ResolvedTrack_.kt +1 -1
  269. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.kt +1 -1
  270. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__string.kt +1 -1
  271. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__vector_ChapterMetadata_.kt +1 -1
  272. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__vector_Track_.kt +1 -1
  273. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HeartRating.kt +2 -2
  274. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HttpMethod.kt +3 -1
  275. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HybridAudioBrowserSpec.kt +16 -19
  276. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategory.kt +3 -1
  277. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategoryMode.kt +3 -1
  278. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategoryOptions.kt +3 -1
  279. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategoryPolicy.kt +3 -1
  280. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageContext.kt +2 -2
  281. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageQueryParams.kt +2 -2
  282. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +47 -0
  283. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageSource.kt +2 -2
  284. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IosOutput.kt +2 -2
  285. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IosOutputType.kt +3 -1
  286. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaRequestConfig.kt +2 -2
  287. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaTransformParams.kt +2 -2
  288. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +9 -6
  289. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeRouteEntry.kt +2 -2
  290. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeUpdateOptions.kt +2 -2
  291. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationError.kt +2 -2
  292. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorEvent.kt +2 -2
  293. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorType.kt +3 -1
  294. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroAndroidUpdateOptions.kt +2 -2
  295. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButton.kt +3 -1
  296. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButtonLayout.kt +2 -2
  297. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingMetadata.kt +2 -2
  298. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingUpdate.kt +2 -2
  299. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Options.kt +2 -2
  300. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialAndroidSetupPlayerOptions.kt +2 -2
  301. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialIOSSetupPlayerOptions.kt +2 -2
  302. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialSetupPlayerOptions.kt +2 -2
  303. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PercentageRating.kt +2 -2
  304. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Playback.kt +2 -2
  305. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackActiveTrackChangedEvent.kt +2 -2
  306. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackError.kt +2 -2
  307. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackErrorEvent.kt +2 -2
  308. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackPlayWhenReadyChangedEvent.kt +2 -2
  309. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackProgressUpdatedEvent.kt +2 -2
  310. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackQueueEndedEvent.kt +2 -2
  311. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackState.kt +3 -1
  312. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
  313. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayingState.kt +2 -2
  314. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Progress.kt +2 -2
  315. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RatingType.kt +3 -1
  316. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteJumpBackwardEvent.kt +2 -2
  317. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteJumpForwardEvent.kt +2 -2
  318. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemotePlayIdEvent.kt +2 -2
  319. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemotePlaySearchEvent.kt +2 -2
  320. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSeekEvent.kt +2 -2
  321. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSetRatingEvent.kt +2 -2
  322. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSkipEvent.kt +2 -2
  323. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RepeatMode.kt +3 -1
  324. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RepeatModeChangedEvent.kt +2 -2
  325. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RequestConfig.kt +2 -2
  326. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +11 -5
  327. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RetryConfig.kt +2 -2
  328. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchMode.kt +3 -1
  329. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchParams.kt +2 -2
  330. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimer.kt +1 -8
  331. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimerEndOfTrack.kt +2 -2
  332. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimerTime.kt +2 -2
  333. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StarRating.kt +2 -2
  334. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ThumbsRating.kt +2 -2
  335. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TimedMetadata.kt +2 -2
  336. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +8 -5
  337. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackLoadEvent.kt +44 -0
  338. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackMetadata.kt +2 -2
  339. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackStyle.kt +3 -1
  340. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TransformableRequestConfig.kt +2 -2
  341. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/UpdateOptions.kt +2 -2
  342. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_AndroidAudioOffloadSettings.kt +1 -7
  343. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_RetryConfig.kt +1 -7
  344. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.kt +1 -9
  345. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_NullType_Double.kt +1 -7
  346. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_NullType_NotificationButtonLayout.kt +1 -7
  347. package/nitrogen/generated/ios/AudioBrowser+autolinking.rb +2 -2
  348. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.cpp +23 -6
  349. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +239 -102
  350. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +10 -1
  351. package/nitrogen/generated/ios/AudioBrowserAutolinking.mm +1 -1
  352. package/nitrogen/generated/ios/AudioBrowserAutolinking.swift +9 -8
  353. package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.cpp +1 -1
  354. package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +25 -1
  355. package/nitrogen/generated/ios/swift/AndroidAudioContentType.swift +1 -1
  356. package/nitrogen/generated/ios/swift/AndroidAudioOffloadSettings.swift +19 -44
  357. package/nitrogen/generated/ios/swift/AndroidOptions.swift +30 -74
  358. package/nitrogen/generated/ios/swift/AndroidPlayerWakeMode.swift +1 -1
  359. package/nitrogen/generated/ios/swift/AndroidUpdateOptions.swift +44 -112
  360. package/nitrogen/generated/ios/swift/AppKilledPlaybackBehavior.swift +1 -1
  361. package/nitrogen/generated/ios/swift/ArtworkRequestConfig.swift +152 -303
  362. package/nitrogen/generated/ios/swift/BatteryOptimizationStatus.swift +1 -1
  363. package/nitrogen/generated/ios/swift/BatteryOptimizationStatusChangedEvent.swift +3 -10
  364. package/nitrogen/generated/ios/swift/BatteryWarningPendingChangedEvent.swift +3 -10
  365. package/nitrogen/generated/ios/swift/BrowseError.swift +3 -10
  366. package/nitrogen/generated/ios/swift/BrowseResult.swift +1 -1
  367. package/nitrogen/generated/ios/swift/BrowserSourceCallbackParam.swift +20 -45
  368. package/nitrogen/generated/ios/swift/CarPlayNowPlayingButton.swift +1 -1
  369. package/nitrogen/generated/ios/swift/CarPlaySiriListButtonPosition.swift +40 -0
  370. package/nitrogen/generated/ios/swift/ChapterMetadata.swift +23 -60
  371. package/nitrogen/generated/ios/swift/EqualizerSettings.swift +24 -97
  372. package/nitrogen/generated/ios/swift/FavoriteChangedEvent.swift +5 -18
  373. package/nitrogen/generated/ios/swift/FormatNavigationErrorParams.swift +7 -26
  374. package/nitrogen/generated/ios/swift/FormattedNavigationError.swift +5 -18
  375. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.swift +1 -2
  376. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.swift +1 -2
  377. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____RequestConfig_std__optional_std__unordered_map_std__string__std__string__.swift +1 -2
  378. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.swift +1 -2
  379. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.swift +1 -2
  380. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.swift +1 -2
  381. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.swift +61 -0
  382. package/nitrogen/generated/ios/swift/Func_void.swift +1 -2
  383. package/nitrogen/generated/ios/swift/Func_void_BatteryOptimizationStatusChangedEvent.swift +1 -2
  384. package/nitrogen/generated/ios/swift/Func_void_BatteryWarningPendingChangedEvent.swift +1 -2
  385. package/nitrogen/generated/ios/swift/Func_void_EqualizerSettings.swift +1 -2
  386. package/nitrogen/generated/ios/swift/Func_void_FavoriteChangedEvent.swift +1 -2
  387. package/nitrogen/generated/ios/swift/Func_void_IosOutput.swift +1 -2
  388. package/nitrogen/generated/ios/swift/Func_void_NavigationErrorEvent.swift +1 -2
  389. package/nitrogen/generated/ios/swift/Func_void_NowPlayingMetadata.swift +1 -2
  390. package/nitrogen/generated/ios/swift/Func_void_Options.swift +1 -2
  391. package/nitrogen/generated/ios/swift/Func_void_Playback.swift +1 -2
  392. package/nitrogen/generated/ios/swift/Func_void_PlaybackActiveTrackChangedEvent.swift +1 -2
  393. package/nitrogen/generated/ios/swift/Func_void_PlaybackErrorEvent.swift +1 -2
  394. package/nitrogen/generated/ios/swift/Func_void_PlaybackPlayWhenReadyChangedEvent.swift +1 -2
  395. package/nitrogen/generated/ios/swift/Func_void_PlaybackProgressUpdatedEvent.swift +1 -2
  396. package/nitrogen/generated/ios/swift/Func_void_PlaybackQueueEndedEvent.swift +1 -2
  397. package/nitrogen/generated/ios/swift/Func_void_PlayingState.swift +1 -2
  398. package/nitrogen/generated/ios/swift/Func_void_RemoteJumpBackwardEvent.swift +1 -2
  399. package/nitrogen/generated/ios/swift/Func_void_RemoteJumpForwardEvent.swift +1 -2
  400. package/nitrogen/generated/ios/swift/Func_void_RemotePlayIdEvent.swift +1 -2
  401. package/nitrogen/generated/ios/swift/Func_void_RemotePlaySearchEvent.swift +1 -2
  402. package/nitrogen/generated/ios/swift/Func_void_RemoteSeekEvent.swift +1 -2
  403. package/nitrogen/generated/ios/swift/Func_void_RemoteSetRatingEvent.swift +1 -2
  404. package/nitrogen/generated/ios/swift/Func_void_RemoteSkipEvent.swift +1 -2
  405. package/nitrogen/generated/ios/swift/Func_void_RepeatModeChangedEvent.swift +1 -2
  406. package/nitrogen/generated/ios/swift/Func_void_RequestConfig.swift +1 -2
  407. package/nitrogen/generated/ios/swift/Func_void_TimedMetadata.swift +1 -2
  408. package/nitrogen/generated/ios/swift/Func_void_TrackMetadata.swift +1 -2
  409. package/nitrogen/generated/ios/swift/Func_void_bool.swift +1 -2
  410. package/nitrogen/generated/ios/swift/Func_void_double.swift +1 -2
  411. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +1 -2
  412. package/nitrogen/generated/ios/swift/Func_void_std__optional_FormattedNavigationError_.swift +1 -2
  413. package/nitrogen/generated/ios/swift/Func_void_std__optional_ResolvedTrack_.swift +1 -2
  414. package/nitrogen/generated/ios/swift/Func_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.swift +1 -2
  415. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_RequestConfig__.swift +1 -2
  416. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError___.swift +1 -2
  417. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_std__vector_Track___.swift +1 -2
  418. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_void__.swift +64 -0
  419. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +1 -2
  420. package/nitrogen/generated/ios/swift/Func_void_std__variant_ResolvedTrack__BrowseError_.swift +1 -2
  421. package/nitrogen/generated/ios/swift/Func_void_std__vector_ChapterMetadata_.swift +1 -2
  422. package/nitrogen/generated/ios/swift/Func_void_std__vector_Track_.swift +1 -2
  423. package/nitrogen/generated/ios/swift/HeartRating.swift +3 -10
  424. package/nitrogen/generated/ios/swift/HttpMethod.swift +1 -1
  425. package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec.swift +3 -4
  426. package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec_cxx.swift +56 -7
  427. package/nitrogen/generated/ios/swift/IOSCategory.swift +1 -1
  428. package/nitrogen/generated/ios/swift/IOSCategoryMode.swift +1 -1
  429. package/nitrogen/generated/ios/swift/IOSCategoryOptions.swift +1 -1
  430. package/nitrogen/generated/ios/swift/IOSCategoryPolicy.swift +1 -1
  431. package/nitrogen/generated/ios/swift/ImageContext.swift +19 -30
  432. package/nitrogen/generated/ios/swift/ImageQueryParams.swift +19 -44
  433. package/nitrogen/generated/ios/swift/ImageRowItem.swift +76 -0
  434. package/nitrogen/generated/ios/swift/ImageSource.swift +31 -80
  435. package/nitrogen/generated/ios/swift/IosOutput.swift +7 -26
  436. package/nitrogen/generated/ios/swift/IosOutputType.swift +1 -1
  437. package/nitrogen/generated/ios/swift/MediaRequestConfig.swift +162 -301
  438. package/nitrogen/generated/ios/swift/MediaTransformParams.swift +5 -24
  439. package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +143 -232
  440. package/nitrogen/generated/ios/swift/NativeRouteEntry.swift +81 -178
  441. package/nitrogen/generated/ios/swift/NativeUpdateOptions.swift +53 -125
  442. package/nitrogen/generated/ios/swift/NavigationError.swift +23 -53
  443. package/nitrogen/generated/ios/swift/NavigationErrorEvent.swift +3 -16
  444. package/nitrogen/generated/ios/swift/NavigationErrorType.swift +1 -1
  445. package/nitrogen/generated/ios/swift/NitroAndroidUpdateOptions.swift +44 -112
  446. package/nitrogen/generated/ios/swift/NotificationButton.swift +1 -1
  447. package/nitrogen/generated/ios/swift/NotificationButtonLayout.swift +18 -85
  448. package/nitrogen/generated/ios/swift/NowPlayingMetadata.swift +109 -227
  449. package/nitrogen/generated/ios/swift/NowPlayingUpdate.swift +19 -44
  450. package/nitrogen/generated/ios/swift/Options.swift +32 -88
  451. package/nitrogen/generated/ios/swift/PartialAndroidSetupPlayerOptions.swift +101 -201
  452. package/nitrogen/generated/ios/swift/PartialIOSSetupPlayerOptions.swift +25 -85
  453. package/nitrogen/generated/ios/swift/PartialSetupPlayerOptions.swift +35 -91
  454. package/nitrogen/generated/ios/swift/PercentageRating.swift +3 -10
  455. package/nitrogen/generated/ios/swift/Playback.swift +5 -24
  456. package/nitrogen/generated/ios/swift/PlaybackActiveTrackChangedEvent.swift +25 -66
  457. package/nitrogen/generated/ios/swift/PlaybackError.swift +5 -18
  458. package/nitrogen/generated/ios/swift/PlaybackErrorEvent.swift +3 -16
  459. package/nitrogen/generated/ios/swift/PlaybackPlayWhenReadyChangedEvent.swift +3 -10
  460. package/nitrogen/generated/ios/swift/PlaybackProgressUpdatedEvent.swift +9 -34
  461. package/nitrogen/generated/ios/swift/PlaybackQueueEndedEvent.swift +5 -18
  462. package/nitrogen/generated/ios/swift/PlaybackState.swift +1 -1
  463. package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +109 -254
  464. package/nitrogen/generated/ios/swift/PlayingState.swift +5 -18
  465. package/nitrogen/generated/ios/swift/Progress.swift +7 -26
  466. package/nitrogen/generated/ios/swift/RatingType.swift +1 -1
  467. package/nitrogen/generated/ios/swift/RemoteJumpBackwardEvent.swift +3 -10
  468. package/nitrogen/generated/ios/swift/RemoteJumpForwardEvent.swift +3 -10
  469. package/nitrogen/generated/ios/swift/RemotePlayIdEvent.swift +12 -24
  470. package/nitrogen/generated/ios/swift/RemotePlaySearchEvent.swift +3 -10
  471. package/nitrogen/generated/ios/swift/RemoteSeekEvent.swift +3 -10
  472. package/nitrogen/generated/ios/swift/RemoteSetRatingEvent.swift +21 -39
  473. package/nitrogen/generated/ios/swift/RemoteSkipEvent.swift +3 -10
  474. package/nitrogen/generated/ios/swift/RepeatMode.swift +1 -1
  475. package/nitrogen/generated/ios/swift/RepeatModeChangedEvent.swift +3 -10
  476. package/nitrogen/generated/ios/swift/RequestConfig.swift +82 -191
  477. package/nitrogen/generated/ios/swift/ResolvedTrack.swift +164 -333
  478. package/nitrogen/generated/ios/swift/RetryConfig.swift +12 -24
  479. package/nitrogen/generated/ios/swift/SearchMode.swift +1 -1
  480. package/nitrogen/generated/ios/swift/SearchParams.swift +50 -129
  481. package/nitrogen/generated/ios/swift/SleepTimer.swift +1 -1
  482. package/nitrogen/generated/ios/swift/SleepTimerEndOfTrack.swift +3 -10
  483. package/nitrogen/generated/ios/swift/SleepTimerTime.swift +3 -10
  484. package/nitrogen/generated/ios/swift/StarRating.swift +3 -10
  485. package/nitrogen/generated/ios/swift/ThumbsRating.swift +3 -10
  486. package/nitrogen/generated/ios/swift/TimedMetadata.swift +46 -107
  487. package/nitrogen/generated/ios/swift/Track.swift +151 -319
  488. package/nitrogen/generated/ios/swift/TrackLoadEvent.swift +45 -0
  489. package/nitrogen/generated/ios/swift/TrackMetadata.swift +145 -338
  490. package/nitrogen/generated/ios/swift/TrackStyle.swift +1 -1
  491. package/nitrogen/generated/ios/swift/TransformableRequestConfig.swift +128 -252
  492. package/nitrogen/generated/ios/swift/UpdateOptions.swift +53 -125
  493. package/nitrogen/generated/ios/swift/Variant_Bool_AndroidAudioOffloadSettings.swift +1 -1
  494. package/nitrogen/generated/ios/swift/Variant_Bool_RetryConfig.swift +1 -1
  495. package/nitrogen/generated/ios/swift/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.swift +1 -1
  496. package/nitrogen/generated/ios/swift/Variant_NullType_Double.swift +1 -1
  497. package/nitrogen/generated/ios/swift/Variant_NullType_NotificationButtonLayout.swift +1 -1
  498. package/nitrogen/generated/shared/c++/AndroidAudioContentType.hpp +1 -1
  499. package/nitrogen/generated/shared/c++/AndroidAudioOffloadSettings.hpp +16 -8
  500. package/nitrogen/generated/shared/c++/AndroidOptions.hpp +25 -17
  501. package/nitrogen/generated/shared/c++/AndroidPlayerWakeMode.hpp +1 -1
  502. package/nitrogen/generated/shared/c++/AndroidUpdateOptions.hpp +25 -17
  503. package/nitrogen/generated/shared/c++/AppKilledPlaybackBehavior.hpp +1 -1
  504. package/nitrogen/generated/shared/c++/ArtworkRequestConfig.hpp +43 -35
  505. package/nitrogen/generated/shared/c++/BatteryOptimizationStatus.hpp +1 -1
  506. package/nitrogen/generated/shared/c++/BatteryOptimizationStatusChangedEvent.hpp +13 -5
  507. package/nitrogen/generated/shared/c++/BatteryWarningPendingChangedEvent.hpp +13 -5
  508. package/nitrogen/generated/shared/c++/BrowseError.hpp +13 -5
  509. package/nitrogen/generated/shared/c++/BrowserSourceCallbackParam.hpp +16 -8
  510. package/nitrogen/generated/shared/c++/CarPlayNowPlayingButton.hpp +1 -1
  511. package/nitrogen/generated/shared/c++/CarPlaySiriListButtonPosition.hpp +76 -0
  512. package/nitrogen/generated/shared/c++/ChapterMetadata.hpp +22 -14
  513. package/nitrogen/generated/shared/c++/EqualizerSettings.hpp +34 -26
  514. package/nitrogen/generated/shared/c++/FavoriteChangedEvent.hpp +16 -8
  515. package/nitrogen/generated/shared/c++/FormatNavigationErrorParams.hpp +19 -11
  516. package/nitrogen/generated/shared/c++/FormattedNavigationError.hpp +16 -8
  517. package/nitrogen/generated/shared/c++/HeartRating.hpp +13 -5
  518. package/nitrogen/generated/shared/c++/HttpMethod.hpp +1 -1
  519. package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.cpp +1 -1
  520. package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.hpp +1 -1
  521. package/nitrogen/generated/shared/c++/IOSCategory.hpp +1 -1
  522. package/nitrogen/generated/shared/c++/IOSCategoryMode.hpp +1 -1
  523. package/nitrogen/generated/shared/c++/IOSCategoryOptions.hpp +1 -1
  524. package/nitrogen/generated/shared/c++/IOSCategoryPolicy.hpp +1 -1
  525. package/nitrogen/generated/shared/c++/ImageContext.hpp +16 -8
  526. package/nitrogen/generated/shared/c++/ImageQueryParams.hpp +16 -8
  527. package/nitrogen/generated/shared/c++/ImageRowItem.hpp +98 -0
  528. package/nitrogen/generated/shared/c++/ImageSource.hpp +22 -14
  529. package/nitrogen/generated/shared/c++/IosOutput.hpp +19 -11
  530. package/nitrogen/generated/shared/c++/IosOutputType.hpp +1 -1
  531. package/nitrogen/generated/shared/c++/MediaRequestConfig.hpp +40 -32
  532. package/nitrogen/generated/shared/c++/MediaTransformParams.hpp +16 -8
  533. package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +50 -35
  534. package/nitrogen/generated/shared/c++/NativeRouteEntry.hpp +34 -26
  535. package/nitrogen/generated/shared/c++/NativeUpdateOptions.hpp +28 -20
  536. package/nitrogen/generated/shared/c++/NavigationError.hpp +22 -14
  537. package/nitrogen/generated/shared/c++/NavigationErrorEvent.hpp +13 -5
  538. package/nitrogen/generated/shared/c++/NavigationErrorType.hpp +1 -1
  539. package/nitrogen/generated/shared/c++/NitroAndroidUpdateOptions.hpp +25 -17
  540. package/nitrogen/generated/shared/c++/NotificationButton.hpp +1 -1
  541. package/nitrogen/generated/shared/c++/NotificationButtonLayout.hpp +25 -17
  542. package/nitrogen/generated/shared/c++/NowPlayingMetadata.hpp +40 -32
  543. package/nitrogen/generated/shared/c++/NowPlayingUpdate.hpp +16 -8
  544. package/nitrogen/generated/shared/c++/Options.hpp +28 -20
  545. package/nitrogen/generated/shared/c++/PartialAndroidSetupPlayerOptions.hpp +40 -32
  546. package/nitrogen/generated/shared/c++/PartialIOSSetupPlayerOptions.hpp +25 -17
  547. package/nitrogen/generated/shared/c++/PartialSetupPlayerOptions.hpp +22 -14
  548. package/nitrogen/generated/shared/c++/PercentageRating.hpp +13 -5
  549. package/nitrogen/generated/shared/c++/Playback.hpp +16 -8
  550. package/nitrogen/generated/shared/c++/PlaybackActiveTrackChangedEvent.hpp +25 -17
  551. package/nitrogen/generated/shared/c++/PlaybackError.hpp +16 -8
  552. package/nitrogen/generated/shared/c++/PlaybackErrorEvent.hpp +13 -5
  553. package/nitrogen/generated/shared/c++/PlaybackPlayWhenReadyChangedEvent.hpp +13 -5
  554. package/nitrogen/generated/shared/c++/PlaybackProgressUpdatedEvent.hpp +22 -14
  555. package/nitrogen/generated/shared/c++/PlaybackQueueEndedEvent.hpp +16 -8
  556. package/nitrogen/generated/shared/c++/PlaybackState.hpp +1 -1
  557. package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +46 -38
  558. package/nitrogen/generated/shared/c++/PlayingState.hpp +16 -8
  559. package/nitrogen/generated/shared/c++/Progress.hpp +19 -11
  560. package/nitrogen/generated/shared/c++/RatingType.hpp +1 -1
  561. package/nitrogen/generated/shared/c++/RemoteJumpBackwardEvent.hpp +13 -5
  562. package/nitrogen/generated/shared/c++/RemoteJumpForwardEvent.hpp +13 -5
  563. package/nitrogen/generated/shared/c++/RemotePlayIdEvent.hpp +16 -8
  564. package/nitrogen/generated/shared/c++/RemotePlaySearchEvent.hpp +13 -5
  565. package/nitrogen/generated/shared/c++/RemoteSeekEvent.hpp +13 -5
  566. package/nitrogen/generated/shared/c++/RemoteSetRatingEvent.hpp +13 -5
  567. package/nitrogen/generated/shared/c++/RemoteSkipEvent.hpp +13 -5
  568. package/nitrogen/generated/shared/c++/RepeatMode.hpp +1 -1
  569. package/nitrogen/generated/shared/c++/RepeatModeChangedEvent.hpp +13 -5
  570. package/nitrogen/generated/shared/c++/RequestConfig.hpp +34 -26
  571. package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +79 -57
  572. package/nitrogen/generated/shared/c++/RetryConfig.hpp +16 -8
  573. package/nitrogen/generated/shared/c++/SearchMode.hpp +1 -1
  574. package/nitrogen/generated/shared/c++/SearchParams.hpp +31 -23
  575. package/nitrogen/generated/shared/c++/SleepTimerEndOfTrack.hpp +13 -5
  576. package/nitrogen/generated/shared/c++/SleepTimerTime.hpp +13 -5
  577. package/nitrogen/generated/shared/c++/StarRating.hpp +13 -5
  578. package/nitrogen/generated/shared/c++/ThumbsRating.hpp +13 -5
  579. package/nitrogen/generated/shared/c++/TimedMetadata.hpp +25 -17
  580. package/nitrogen/generated/shared/c++/Track.hpp +70 -54
  581. package/nitrogen/generated/shared/c++/TrackLoadEvent.hpp +93 -0
  582. package/nitrogen/generated/shared/c++/TrackMetadata.hpp +58 -50
  583. package/nitrogen/generated/shared/c++/TrackStyle.hpp +1 -1
  584. package/nitrogen/generated/shared/c++/TransformableRequestConfig.hpp +37 -29
  585. package/nitrogen/generated/shared/c++/UpdateOptions.hpp +28 -20
  586. package/package.json +6 -7
  587. package/src/features/browser.ts +1 -0
  588. package/src/types/browser-native.ts +2 -0
  589. package/src/types/browser-nodes.ts +49 -1
  590. package/src/types/browser.ts +36 -0
  591. package/src/web/NativeAudioBrowser.ts +33 -9
  592. package/src/web/SimpleRouter.test.ts +160 -0
  593. package/src/web/SimpleRouter.ts +10 -8
@@ -4,6 +4,23 @@ import NitroModules
4
4
  /// JSON serializable models for parsing API responses.
5
5
  /// These will be converted to Nitro types after parsing.
6
6
 
7
+ /// JSON model for image row items (horizontal thumbnail row).
8
+ struct JsonImageRowItem: Codable {
9
+ let url: String?
10
+ let artwork: String?
11
+ let title: String
12
+
13
+ init(
14
+ url: String? = nil,
15
+ artwork: String? = nil,
16
+ title: String,
17
+ ) {
18
+ self.url = url
19
+ self.artwork = artwork
20
+ self.title = title
21
+ }
22
+ }
23
+
7
24
  /// JSON model for resolved track (container with children).
8
25
  struct JsonResolvedTrack: Codable {
9
26
  let url: String
@@ -21,6 +38,7 @@ struct JsonResolvedTrack: Codable {
21
38
  let childrenStyle: String?
22
39
  let groupTitle: String?
23
40
  let live: Bool?
41
+ let carPlaySiriListButton: String?
24
42
 
25
43
  init(
26
44
  url: String,
@@ -38,6 +56,7 @@ struct JsonResolvedTrack: Codable {
38
56
  childrenStyle: String? = nil,
39
57
  groupTitle: String? = nil,
40
58
  live: Bool? = nil,
59
+ carPlaySiriListButton: String? = nil,
41
60
  ) {
42
61
  self.url = url
43
62
  self.title = title
@@ -54,6 +73,7 @@ struct JsonResolvedTrack: Codable {
54
73
  self.childrenStyle = childrenStyle
55
74
  self.groupTitle = groupTitle
56
75
  self.live = live
76
+ self.carPlaySiriListButton = carPlaySiriListButton
57
77
  }
58
78
  }
59
79
 
@@ -73,6 +93,7 @@ struct JsonTrack: Codable {
73
93
  let childrenStyle: String?
74
94
  let groupTitle: String?
75
95
  let live: Bool?
96
+ let imageRow: [JsonImageRowItem]?
76
97
 
77
98
  init(
78
99
  url: String? = nil,
@@ -89,6 +110,7 @@ struct JsonTrack: Codable {
89
110
  childrenStyle: String? = nil,
90
111
  groupTitle: String? = nil,
91
112
  live: Bool? = nil,
113
+ imageRow: [JsonImageRowItem]? = nil,
92
114
  ) {
93
115
  self.url = url
94
116
  self.title = title
@@ -104,6 +126,7 @@ struct JsonTrack: Codable {
104
126
  self.childrenStyle = childrenStyle
105
127
  self.groupTitle = groupTitle
106
128
  self.live = live
129
+ self.imageRow = imageRow
107
130
  }
108
131
  }
109
132
 
@@ -115,11 +138,23 @@ private extension String {
115
138
  }
116
139
  }
117
140
 
141
+ extension JsonImageRowItem {
142
+ func toNitro() -> ImageRowItem {
143
+ ImageRowItem(
144
+ url: url,
145
+ artwork: artwork,
146
+ artworkSource: nil,
147
+ title: title,
148
+ )
149
+ }
150
+ }
151
+
118
152
  extension JsonResolvedTrack {
119
153
  func toNitro() -> ResolvedTrack {
120
154
  ResolvedTrack(
121
155
  url: url,
122
156
  children: children?.map { $0.toNitro() },
157
+ carPlaySiriListButton: carPlaySiriListButton.flatMap { CarPlaySiriListButtonPosition(fromString: $0) },
123
158
  src: src,
124
159
  artwork: artwork,
125
160
  artworkSource: nil,
@@ -136,6 +171,7 @@ extension JsonResolvedTrack {
136
171
  favorited: nil,
137
172
  groupTitle: groupTitle,
138
173
  live: live,
174
+ imageRow: nil,
139
175
  )
140
176
  }
141
177
  }
@@ -160,6 +196,7 @@ extension JsonTrack {
160
196
  favorited: nil,
161
197
  groupTitle: groupTitle,
162
198
  live: live,
199
+ imageRow: imageRow?.map { $0.toNitro() },
163
200
  )
164
201
  }
165
202
  }
@@ -17,6 +17,9 @@ import os.log
17
17
  @MainActor
18
18
  @objc(RNABCarPlayController)
19
19
  public final class RNABCarPlayController: NSObject {
20
+ // Force the linker to include RNABMediaIntentHandler so NSClassFromString can find it
21
+ @objc public static let mediaIntentHandlerClass: AnyClass = RNABMediaIntentHandler.self
22
+
20
23
  private let logger = Logger(subsystem: "com.audiobrowser", category: "CarPlayController")
21
24
 
22
25
  private let interfaceController: CPInterfaceController
@@ -229,12 +232,8 @@ public final class RNABCarPlayController: NSObject {
229
232
 
230
233
  let maxTabs = CPTabBarTemplate.maximumTabCount
231
234
 
232
- // Reserve one slot for search if configured
233
- let hasSearch = config.hasSearch
234
- let maxContentTabs = hasSearch ? maxTabs - 1 : maxTabs
235
-
236
235
  // Create tab templates synchronously (empty shells) - don't block on content loading
237
- let tabTemplates: [CPListTemplate] = tabs.prefix(maxContentTabs).map { tab in
236
+ let tabTemplates: [CPListTemplate] = tabs.prefix(maxTabs).map { tab in
238
237
  createTabTemplate(for: tab)
239
238
  }
240
239
 
@@ -269,9 +268,8 @@ public final class RNABCarPlayController: NSObject {
269
268
  // https://developer.apple.com/download/files/CarPlay-Developer-Guide.pdf
270
269
  template.tabImage = defaultTabImage()
271
270
 
272
- // Support SF Symbols via "sf:" prefix (e.g., "sf:heart.fill")
273
- if let artwork = track.artwork, artwork.hasPrefix("sf:") {
274
- let symbolName = String(artwork.dropFirst(3))
271
+ if let artwork = track.artwork, SFSymbolRenderer.isSFSymbol(artwork) {
272
+ let (symbolName, _, _) = SFSymbolRenderer.parseArtwork(artwork)
275
273
  if let image = sfSymbolImage(symbolName) {
276
274
  template.tabImage = image
277
275
  }
@@ -299,9 +297,9 @@ public final class RNABCarPlayController: NSObject {
299
297
  ) -> CPListTemplate {
300
298
  let template = CPListTemplate(
301
299
  title: resolvedTrack.title,
302
- sections: createSections(from: resolvedTrack),
300
+ sections: [],
303
301
  )
304
-
302
+ updateTemplate(template, with: resolvedTrack)
305
303
  template.userInfo = ["path": path] as [String: Any]
306
304
 
307
305
  return template
@@ -312,6 +310,29 @@ public final class RNABCarPlayController: NSObject {
312
310
  (template.userInfo as? [String: Any])?["path"] as? String
313
311
  }
314
312
 
313
+ /// Updates a template's sections and assistant cell from resolved content.
314
+ private func updateTemplate(_ template: CPListTemplate, with resolvedTrack: ResolvedTrack) {
315
+ let sections = createSections(from: resolvedTrack)
316
+ template.updateSections(sections)
317
+ configureAssistantCell(on: template, from: resolvedTrack)
318
+ }
319
+
320
+ /// Configures the assistant cell ("Ask Siri to Play Audio") on a template
321
+ /// based on the `carPlaySiriListButton` property of the resolved content.
322
+ private func configureAssistantCell(on template: CPListTemplate, from resolvedTrack: ResolvedTrack) {
323
+ guard #available(iOS 15.4, *) else { return }
324
+ guard let position = resolvedTrack.carPlaySiriListButton else {
325
+ template.assistantCellConfiguration = nil
326
+ return
327
+ }
328
+ let cellPosition: CPListItem.AssistantCellPosition = position == .top ? .top : .bottom
329
+ template.assistantCellConfiguration = CPAssistantCellConfiguration(
330
+ position: cellPosition,
331
+ visibility: .always,
332
+ assistantAction: .playMedia,
333
+ )
334
+ }
335
+
315
336
  private func createSections(from resolvedTrack: ResolvedTrack) -> [CPListSection] {
316
337
  guard let children = resolvedTrack.children else {
317
338
  return []
@@ -334,7 +355,12 @@ public final class RNABCarPlayController: NSObject {
334
355
  // Ungrouped items first
335
356
  if let ungrouped = groups[nil], !ungrouped.isEmpty {
336
357
  let availableSlots = maxTotalItems - totalItemCount
337
- let items = ungrouped.prefix(availableSlots).map { createListItem(for: $0) }
358
+ let items: [CPListTemplateItem] = ungrouped.prefix(availableSlots).map { track in
359
+ if track.imageRow != nil {
360
+ return createImageRowItem(for: track)
361
+ }
362
+ return createListItem(for: track)
363
+ }
338
364
  if !items.isEmpty {
339
365
  sections.append(CPListSection(items: items))
340
366
  totalItemCount += items.count
@@ -348,7 +374,12 @@ public final class RNABCarPlayController: NSObject {
348
374
  guard groupTitle != nil else { continue }
349
375
 
350
376
  let availableSlots = maxTotalItems - totalItemCount
351
- let items = tracks.prefix(availableSlots).map { createListItem(for: $0) }
377
+ let items: [CPListTemplateItem] = tracks.prefix(availableSlots).map { track in
378
+ if track.imageRow != nil {
379
+ return createImageRowItem(for: track)
380
+ }
381
+ return createListItem(for: track)
382
+ }
352
383
  if !items.isEmpty {
353
384
  sections.append(CPListSection(items: items, header: groupTitle, sectionIndexTitle: nil))
354
385
  totalItemCount += items.count
@@ -393,13 +424,7 @@ public final class RNABCarPlayController: NSObject {
393
424
  }
394
425
 
395
426
  // Load artwork with size context for proper CDN optimization
396
- // Support SF Symbols via "sf:" prefix (e.g., "sf:heart.fill")
397
- if let artwork = track.artwork, artwork.hasPrefix("sf:") {
398
- let symbolName = String(artwork.dropFirst(3))
399
- if let image = sfSymbolImageForListItem(symbolName) {
400
- item.setImage(image)
401
- }
402
- } else if track.artwork != nil || track.artworkSource != nil {
427
+ if track.artwork != nil || track.artworkSource != nil {
403
428
  // Set empty placeholder to reserve space while loading
404
429
  item.setImage(placeholderImage)
405
430
  loadArtwork(for: track, size: CPListItem.maximumImageSize) { [weak item] image in
@@ -421,6 +446,111 @@ public final class RNABCarPlayController: NSObject {
421
446
  return item
422
447
  }
423
448
 
449
+ /// Creates a CPListImageRowItem for a track that has an imageRow.
450
+ /// Renders as a horizontal row of tappable artwork thumbnails with a header title.
451
+ private func createImageRowItem(for track: Track) -> CPListImageRowItem {
452
+ guard let imageRowItems = track.imageRow else {
453
+ fatalError("createImageRowItem called without imageRow")
454
+ }
455
+
456
+ // CPListImageRowItem requires images at init — start with placeholders
457
+ let maxImages = CPMaximumNumberOfGridImages
458
+ let visibleItems = Array(imageRowItems.prefix(maxImages))
459
+ let placeholders = visibleItems.map { _ in placeholderImage ?? UIImage() }
460
+ let titles = visibleItems.map(\.title)
461
+
462
+ // Use imageTitles variant on iOS 17.4+ to show titles below each thumbnail
463
+ let item = if #available(iOS 17.4, *) {
464
+ CPListImageRowItem(text: track.title, images: placeholders, imageTitles: titles)
465
+ } else {
466
+ CPListImageRowItem(text: track.title, images: placeholders)
467
+ }
468
+
469
+ // Store track info for identification
470
+ item.userInfo = [
471
+ "url": track.url as Any,
472
+ "src": track.src as Any,
473
+ "hasSrc": track.src != nil,
474
+ "hasUrl": track.url != nil,
475
+ ]
476
+
477
+ // Handler for row header tap → navigate to track.url if present
478
+ item.handler = { [weak self] _, completion in
479
+ self?.handleItemSelection(track: track, completion: completion)
480
+ }
481
+
482
+ // Handler for individual image taps
483
+ item.listImageRowHandler = { [weak self] _, index, completion in
484
+ guard let self, index < visibleItems.count else {
485
+ completion()
486
+ return
487
+ }
488
+ let tappedItem = visibleItems[index]
489
+ // Create a minimal Track to reuse handleItemSelection
490
+ let itemTrack = Track(
491
+ url: tappedItem.url,
492
+ src: nil,
493
+ artwork: tappedItem.artwork,
494
+ artworkSource: tappedItem.artworkSource,
495
+ artworkCarPlayTinted: nil,
496
+ title: tappedItem.title,
497
+ subtitle: nil,
498
+ artist: nil,
499
+ album: nil,
500
+ description: nil,
501
+ genre: nil,
502
+ duration: nil,
503
+ style: nil,
504
+ childrenStyle: nil,
505
+ favorited: nil,
506
+ groupTitle: nil,
507
+ live: nil,
508
+ imageRow: nil,
509
+ )
510
+ self.handleItemSelection(track: itemTrack, completion: completion)
511
+ }
512
+
513
+ // Load artwork for each visible image row item asynchronously
514
+ for (index, imageRowItem) in visibleItems.enumerated() {
515
+ guard imageRowItem.artwork != nil || imageRowItem.artworkSource != nil else { continue }
516
+
517
+ // Create a minimal Track for the artwork loader
518
+ let itemTrack = Track(
519
+ url: imageRowItem.url,
520
+ src: nil,
521
+ artwork: imageRowItem.artwork,
522
+ artworkSource: imageRowItem.artworkSource,
523
+ artworkCarPlayTinted: nil,
524
+ title: imageRowItem.title,
525
+ subtitle: nil,
526
+ artist: nil,
527
+ album: nil,
528
+ description: nil,
529
+ genre: nil,
530
+ duration: nil,
531
+ style: nil,
532
+ childrenStyle: nil,
533
+ favorited: nil,
534
+ groupTitle: nil,
535
+ live: nil,
536
+ imageRow: nil,
537
+ )
538
+
539
+ loadArtwork(for: itemTrack, size: CPListImageRowItem.maximumImageSize) { [weak item] image in
540
+ Task { @MainActor in
541
+ guard let item, let image else { return }
542
+ var images = item.gridImages
543
+ if index < images.count {
544
+ images[index] = image
545
+ item.update(images)
546
+ }
547
+ }
548
+ }
549
+ }
550
+
551
+ return item
552
+ }
553
+
424
554
  // MARK: - Content Loading
425
555
 
426
556
  @MainActor
@@ -429,8 +559,7 @@ public final class RNABCarPlayController: NSObject {
429
559
 
430
560
  do {
431
561
  let resolved = try await audioBrowser.browserManager.resolve(path, useCache: true)
432
- let sections = createSections(from: resolved)
433
- template.updateSections(sections)
562
+ updateTemplate(template, with: resolved)
434
563
  } catch {
435
564
  logger.error("Failed to load content for \(path): \(error.localizedDescription)")
436
565
  }
@@ -438,6 +567,28 @@ public final class RNABCarPlayController: NSObject {
438
567
 
439
568
  // MARK: - Selection Handling
440
569
 
570
+ /// Centralizes handleTrackLoad interception for CarPlay selection paths.
571
+ /// If handleTrackLoad is set on config, awaits it (intercepted). Otherwise runs defaultBehavior.
572
+ /// Always fires showNowPlaying and completion afterward, even if the handler throws.
573
+ /// This is intentional: the completion handler must be called to dismiss the CarPlay list
574
+ /// item spinner, and transitioning to Now Playing avoids leaving the UI in a stuck state.
575
+ @discardableResult
576
+ private func handleLoadAsync(
577
+ track: Track, queue: [Track], startIndex: Double,
578
+ audioBrowser: HybridAudioBrowser,
579
+ completion: @escaping () -> Void,
580
+ defaultBehavior: () async -> Void
581
+ ) async -> Bool {
582
+ let event = TrackLoadEvent(track: track, queue: queue, startIndex: startIndex)
583
+ if await audioBrowser.browserManager.config.awaitTrackLoadHandler(event: event) {
584
+ await MainActor.run { self.showNowPlaying(); completion() }
585
+ return true
586
+ }
587
+ await defaultBehavior()
588
+ await MainActor.run { self.showNowPlaying(); completion() }
589
+ return false
590
+ }
591
+
441
592
  private func handleItemSelection(track: Track, completion: @escaping () -> Void) {
442
593
  logger.info("Selected track: \(track.title)")
443
594
 
@@ -465,10 +616,12 @@ public final class RNABCarPlayController: NSObject {
465
616
  parentPath == player?.queueSourcePath,
466
617
  let index = player?.tracks.firstIndex(where: { $0.src == trackId })
467
618
  {
468
- logger.debug("Queue already from \(parentPath), skipping to index \(index)")
469
- try? player?.skipTo(index, playWhenReady: true)
470
- showNowPlaying()
471
- completion()
619
+ let queue = player?.tracks ?? []
620
+ Task {
621
+ await handleLoadAsync(track: track, queue: queue, startIndex: Double(index), audioBrowser: audioBrowser, completion: completion) {
622
+ try? player?.skipTo(index, playWhenReady: true)
623
+ }
624
+ }
472
625
  return
473
626
  }
474
627
 
@@ -477,42 +630,41 @@ public final class RNABCarPlayController: NSObject {
477
630
  // Expand the queue from the contextual URL
478
631
  if let expanded = try await audioBrowser.browserManager.expandQueueFromContextualUrl(url) {
479
632
  let (tracks, startIndex) = expanded
480
-
481
- await MainActor.run {
482
- // Replace queue and start at the selected track
483
- audioBrowser.getPlayer()?.setQueue(tracks, initialIndex: startIndex, playWhenReady: true, sourcePath: parentPath)
484
-
485
- // Show now playing template
486
- self.showNowPlaying()
487
- completion()
633
+ await handleLoadAsync(track: track, queue: tracks, startIndex: Double(startIndex), audioBrowser: audioBrowser, completion: completion) {
634
+ await MainActor.run {
635
+ // Replace queue and start at the selected track
636
+ audioBrowser.getPlayer()?.setQueue(tracks, initialIndex: startIndex, playWhenReady: true, sourcePath: parentPath)
637
+ }
488
638
  }
489
639
  } else {
490
640
  // Fallback: just load the single track
491
- await MainActor.run {
492
- try? audioBrowser.load(track: track)
493
- try? audioBrowser.play()
494
- self.showNowPlaying()
495
- completion()
641
+ await handleLoadAsync(track: track, queue: [track], startIndex: 0, audioBrowser: audioBrowser, completion: completion) {
642
+ await MainActor.run {
643
+ try? audioBrowser.load(track: track)
644
+ try? audioBrowser.play()
645
+ }
496
646
  }
497
647
  }
498
648
  } catch {
499
649
  logger.error("Error expanding queue: \(error.localizedDescription)")
500
- await MainActor.run {
501
- try? audioBrowser.load(track: track)
502
- try? audioBrowser.play()
503
- self.showNowPlaying()
504
- completion()
650
+ await handleLoadAsync(track: track, queue: [track], startIndex: 0, audioBrowser: audioBrowser, completion: completion) {
651
+ await MainActor.run {
652
+ try? audioBrowser.load(track: track)
653
+ try? audioBrowser.play()
654
+ }
505
655
  }
506
656
  }
507
657
  }
508
658
  }
509
659
  // If track has src, it's playable - load it
510
660
  else if track.src != nil {
511
- Task { @MainActor in
512
- try? audioBrowser.load(track: track)
513
- try? audioBrowser.play()
514
- showNowPlaying()
515
- completion()
661
+ Task {
662
+ await handleLoadAsync(track: track, queue: [track], startIndex: 0, audioBrowser: audioBrowser, completion: completion) {
663
+ await MainActor.run {
664
+ try? audioBrowser.load(track: track)
665
+ try? audioBrowser.play()
666
+ }
667
+ }
516
668
  }
517
669
  }
518
670
  // If track has url, it's browsable - navigate to it
@@ -833,8 +985,7 @@ public final class RNABCarPlayController: NSObject {
833
985
  else { continue }
834
986
 
835
987
  logger.info("Refreshing tab template for path: \(path)")
836
- let sections = createSections(from: content)
837
- listTemplate.updateSections(sections)
988
+ updateTemplate(listTemplate, with: content)
838
989
  }
839
990
  }
840
991
 
@@ -845,8 +996,7 @@ public final class RNABCarPlayController: NSObject {
845
996
  templatePath == path
846
997
  {
847
998
  logger.info("Refreshing top template for path: \(path)")
848
- let sections = createSections(from: content)
849
- topTemplate.updateSections(sections)
999
+ updateTemplate(topTemplate, with: content)
850
1000
  }
851
1001
  }
852
1002
 
@@ -978,18 +1128,31 @@ public final class RNABCarPlayController: NSObject {
978
1128
  UIImage(systemName: symbolName)
979
1129
  }
980
1130
 
981
- /// Creates an SF Symbol image for list items with light/dark mode support
982
- private func sfSymbolImageForListItem(_ symbolName: String) -> UIImage? {
983
- guard let symbol = UIImage(systemName: symbolName) else { return nil }
1131
+ /// Renders an SF Symbol from an artwork string (e.g. "sf:heart.fill?bg=#000&fg=#fff").
1132
+ private func sfSymbolImage(forArtwork artwork: String, canvasSize: CGSize) -> UIImage? {
1133
+ let (symbolName, bg, fg) = SFSymbolRenderer.parseArtwork(artwork)
1134
+ return sfSymbolImageForSize(symbolName, canvasSize: canvasSize, backgroundColor: bg, symbolColor: fg)
1135
+ }
1136
+
1137
+ /// Creates an SF Symbol image rendered at the given canvas size.
1138
+ /// When explicit colors are provided, uses them directly.
1139
+ /// Otherwise falls back to automatic light/dark variants.
1140
+ private func sfSymbolImageForSize(_ symbolName: String, canvasSize: CGSize, backgroundColor: UIColor? = nil, symbolColor: UIColor? = nil) -> UIImage? {
1141
+ let scale = interfaceController.carTraitCollection.displayScale
1142
+ let symbolPointSize = min(canvasSize.width, canvasSize.height) * 0.45
1143
+
1144
+ let config = UIImage.SymbolConfiguration(pointSize: symbolPointSize, weight: .medium)
1145
+ guard let symbol = UIImage(systemName: symbolName, withConfiguration: config) else { return nil }
984
1146
 
985
- let size = symbol.size
986
- let scale = symbol.scale
1147
+ // Explicit colors: single image, no light/dark variants needed
1148
+ if let symbolColor {
1149
+ return renderSymbolInCanvas(symbol, tintColor: symbolColor, backgroundColor: backgroundColor, canvasSize: canvasSize, scale: scale)
1150
+ }
987
1151
 
988
- // Create both light and dark bitmap variants
989
- let lightImage = renderSymbolToBitmap(symbol, tintColor: .black, size: size, scale: scale)
990
- let darkImage = renderSymbolToBitmap(symbol, tintColor: .white, size: size, scale: scale)
1152
+ // Auto light/dark variants
1153
+ let lightImage = renderSymbolInCanvas(symbol, tintColor: .black, backgroundColor: nil, canvasSize: canvasSize, scale: scale)
1154
+ let darkImage = renderSymbolInCanvas(symbol, tintColor: .white, backgroundColor: nil, canvasSize: canvasSize, scale: scale)
991
1155
 
992
- // Combine with UIImageAsset for automatic light/dark switching
993
1156
  let asset = UIImageAsset()
994
1157
  asset.register(lightImage, with: UITraitCollection(userInterfaceStyle: .light))
995
1158
  asset.register(darkImage, with: UITraitCollection(userInterfaceStyle: .dark))
@@ -997,18 +1160,27 @@ public final class RNABCarPlayController: NSObject {
997
1160
  return asset.image(with: interfaceController.carTraitCollection)
998
1161
  }
999
1162
 
1000
- /// Renders an SF Symbol to a bitmap with the specified tint color
1001
- private nonisolated func renderSymbolToBitmap(_ symbol: UIImage, tintColor: UIColor, size: CGSize, scale: CGFloat) -> UIImage {
1002
- UIGraphicsBeginImageContextWithOptions(size, false, scale)
1003
- defer { UIGraphicsEndImageContext() }
1004
-
1005
- tintColor.set()
1006
- symbol.withRenderingMode(.alwaysTemplate).draw(in: CGRect(origin: .zero, size: size))
1007
-
1008
- guard let rendered = UIGraphicsGetImageFromCurrentImageContext() else {
1009
- return symbol // Fallback to original if rendering fails
1010
- }
1011
- return rendered.withRenderingMode(.alwaysOriginal)
1163
+ /// Renders an SF Symbol centered in a canvas with a background fill.
1164
+ /// When `backgroundColor` is nil, derives a default from the tint color (light/dark).
1165
+ private nonisolated func renderSymbolInCanvas(_ symbol: UIImage, tintColor: UIColor, backgroundColor: UIColor?, canvasSize: CGSize, scale: CGFloat) -> UIImage {
1166
+ let renderer = UIGraphicsImageRenderer(size: canvasSize, format: {
1167
+ let fmt = UIGraphicsImageRendererFormat()
1168
+ fmt.scale = scale
1169
+ return fmt
1170
+ }())
1171
+
1172
+ return renderer.image { _ in
1173
+ let bgColor = backgroundColor ?? (tintColor == .white ? UIColor(white: 0.15, alpha: 1) : UIColor(white: 0.92, alpha: 1))
1174
+ bgColor.setFill()
1175
+ UIRectFill(CGRect(origin: .zero, size: canvasSize))
1176
+
1177
+ let symbolSize = symbol.size
1178
+ let x = (canvasSize.width - symbolSize.width) / 2
1179
+ let y = (canvasSize.height - symbolSize.height) / 2
1180
+
1181
+ tintColor.set()
1182
+ symbol.withRenderingMode(.alwaysTemplate).draw(in: CGRect(x: x, y: y, width: symbolSize.width, height: symbolSize.height))
1183
+ }.withRenderingMode(.alwaysOriginal)
1012
1184
  }
1013
1185
 
1014
1186
  private func defaultTabImage() -> UIImage? {
@@ -1030,9 +1202,14 @@ public final class RNABCarPlayController: NSObject {
1030
1202
  /// - size: The target size in points (will be multiplied by CarPlay display scale)
1031
1203
  /// - completion: Called with the loaded image, or nil on failure
1032
1204
  private func loadArtwork(for track: Track, size: CGSize, completion: @escaping @Sendable (UIImage?) -> Void) {
1205
+ if let artwork = track.artwork, SFSymbolRenderer.isSFSymbol(artwork) {
1206
+ completion(sfSymbolImage(forArtwork: artwork, canvasSize: size))
1207
+ return
1208
+ }
1209
+
1033
1210
  guard let browserManager = audioBrowser?.browserManager else {
1034
1211
  // Fall back to direct URL loading
1035
- loadArtworkDirect(track: track, completion: completion)
1212
+ loadArtworkDirect(track: track, size: size, completion: completion)
1036
1213
  return
1037
1214
  }
1038
1215
 
@@ -1051,16 +1228,9 @@ public final class RNABCarPlayController: NSObject {
1051
1228
 
1052
1229
  await MainActor.run {
1053
1230
  if let imageSource {
1054
- // Check for SF Symbol URI (e.g., "sf:heart.fill")
1055
- if imageSource.uri.hasPrefix("sf:") {
1056
- let symbolName = String(imageSource.uri.dropFirst(3))
1057
- completion(self.sfSymbolImageForListItem(symbolName))
1058
- return
1059
- }
1060
-
1061
1231
  // Parse URL - skip if invalid
1062
1232
  guard let url = URL(string: imageSource.uri) else {
1063
- self.loadArtworkDirect(track: track, completion: completion)
1233
+ self.loadArtworkDirect(track: track, size: size, completion: completion)
1064
1234
  return
1065
1235
  }
1066
1236
 
@@ -1105,23 +1275,21 @@ public final class RNABCarPlayController: NSObject {
1105
1275
  }
1106
1276
  } else {
1107
1277
  // No resolved URL - try direct loading as fallback
1108
- self.loadArtworkDirect(track: track, completion: completion)
1278
+ self.loadArtworkDirect(track: track, size: size, completion: completion)
1109
1279
  }
1110
1280
  }
1111
1281
  }
1112
1282
  }
1113
1283
 
1114
1284
  /// Loads artwork directly from track's artwork URL without transform.
1115
- private func loadArtworkDirect(track: Track, completion: @escaping @Sendable (UIImage?) -> Void) {
1285
+ private func loadArtworkDirect(track: Track, size: CGSize, completion: @escaping @Sendable (UIImage?) -> Void) {
1116
1286
  guard let artworkUrl = track.artwork ?? track.artworkSource?.uri else {
1117
1287
  completion(nil)
1118
1288
  return
1119
1289
  }
1120
1290
 
1121
- // Check for SF Symbol URI (e.g., "sf:heart.fill")
1122
- if artworkUrl.hasPrefix("sf:") {
1123
- let symbolName = String(artworkUrl.dropFirst(3))
1124
- completion(sfSymbolImageForListItem(symbolName))
1291
+ if SFSymbolRenderer.isSFSymbol(artworkUrl) {
1292
+ completion(sfSymbolImage(forArtwork: artworkUrl, canvasSize: size))
1125
1293
  return
1126
1294
  }
1127
1295
 
@@ -0,0 +1,23 @@
1
+ #import <Foundation/Foundation.h>
2
+ #import <Intents/Intents.h>
3
+
4
+ NS_ASSUME_NONNULL_BEGIN
5
+
6
+ /// Public entry point for AudioBrowser library functionality that host apps
7
+ /// need to call from their AppDelegate or other Swift/ObjC code.
8
+ ///
9
+ /// Usage (add to your bridging header: #import <AudioBrowser/RNABAudioBrowser.h>):
10
+ /// @code
11
+ /// func application(_ application: UIApplication, handle intent: INIntent, completionHandler: @escaping (INIntentResponse) -> Void) {
12
+ /// RNABAudioBrowser.handleMediaIntent(intent, completionHandler: completionHandler)
13
+ /// }
14
+ /// @endcode
15
+ @interface RNABAudioBrowser : NSObject
16
+
17
+ /// Handle an INPlayMediaIntent forwarded from an Intents Extension via .handleInApp.
18
+ /// Searches using the configured browser search route, queues results, and starts playback.
19
+ + (void)handleMediaIntent:(INIntent *)intent completionHandler:(void (^)(INIntentResponse *))completionHandler;
20
+
21
+ @end
22
+
23
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,22 @@
1
+ #import "RNABAudioBrowser.h"
2
+
3
+ @implementation RNABAudioBrowser
4
+
5
+ + (void)handleMediaIntent:(INIntent *)intent completionHandler:(void (^)(INIntentResponse *))completionHandler {
6
+ Class cls = NSClassFromString(@"RNABMediaIntentHandler");
7
+ SEL sel = NSSelectorFromString(@"handleMediaIntent:completionHandler:");
8
+ if (cls && [cls respondsToSelector:sel]) {
9
+ #pragma clang diagnostic push
10
+ #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
11
+ // RNABMediaIntentHandler.handleMediaIntent(_:completionHandler:) is a static @objc method
12
+ // that handles INPlayMediaIntent search and playback.
13
+ typedef void (*HandleFn)(id, SEL, INIntent *, void (^)(INIntentResponse *));
14
+ HandleFn fn = (HandleFn)[cls methodForSelector:sel];
15
+ fn(cls, sel, intent, completionHandler);
16
+ #pragma clang diagnostic pop
17
+ } else {
18
+ completionHandler([[INPlayMediaIntentResponse alloc] initWithCode:INPlayMediaIntentResponseCodeFailureRequiringAppLaunch userActivity:nil]);
19
+ }
20
+ }
21
+
22
+ @end