@5stones/react-native-audio-browser 0.2.0 → 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 (605) 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 +8 -27
  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 +3 -21
  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/test/java/com/audiobrowser/browser/SimpleRouterTest.kt +104 -95
  13. package/ios/Browser/BrowserConfig.swift +31 -5
  14. package/ios/Browser/BrowserManager.swift +96 -6
  15. package/ios/Browser/JsonModels.swift +37 -0
  16. package/ios/CarPlay/CarPlayController.swift +219 -99
  17. package/ios/CarPlay/RNABAudioBrowser.h +23 -0
  18. package/ios/CarPlay/RNABAudioBrowser.m +22 -0
  19. package/ios/CarPlay/RNABMediaIntentHandler.swift +60 -0
  20. package/ios/Extension/ChapterMetadata+AVFoundation.swift +1 -1
  21. package/ios/Extension/CxxVectorConformances.swift +20 -0
  22. package/ios/Extension/TimedMetadata+AVFoundation.swift +5 -5
  23. package/ios/Extension/Track+AVPlayer.swift +5 -6
  24. package/ios/Extension/TrackMetadata+AVFoundation.swift +1 -1
  25. package/ios/HybridAudioBrowser.swift +107 -46
  26. package/ios/Model/MediaURL.swift +2 -1
  27. package/ios/Player/PlayingStateManager.swift +1 -0
  28. package/ios/Player/RetryManager.swift +26 -65
  29. package/ios/Player/SleepTimerManager.swift +6 -8
  30. package/ios/RemoteCommand/RemoteCommandController.swift +6 -0
  31. package/ios/Tests/SimpleRouterTests.swift +139 -0
  32. package/ios/TrackPlayer.swift +35 -24
  33. package/ios/Util/NetworkMonitor.swift +3 -6
  34. package/ios/Util/SFSymbolRenderer.swift +142 -0
  35. package/lib/commonjs/features/browser.js +1 -0
  36. package/lib/commonjs/features/browser.js.map +1 -1
  37. package/lib/commonjs/features/remoteControls.js +1 -24
  38. package/lib/commonjs/features/remoteControls.js.map +1 -1
  39. package/lib/commonjs/web/NativeAudioBrowser.js +20 -24
  40. package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
  41. package/lib/commonjs/web/SimpleRouter.js +4 -3
  42. package/lib/commonjs/web/SimpleRouter.js.map +1 -1
  43. package/lib/commonjs/web/SimpleRouter.test.js +174 -0
  44. package/lib/commonjs/web/SimpleRouter.test.js.map +1 -0
  45. package/lib/module/features/browser.js +1 -0
  46. package/lib/module/features/browser.js.map +1 -1
  47. package/lib/module/features/remoteControls.js +0 -22
  48. package/lib/module/features/remoteControls.js.map +1 -1
  49. package/lib/module/web/NativeAudioBrowser.js +20 -24
  50. package/lib/module/web/NativeAudioBrowser.js.map +1 -1
  51. package/lib/module/web/SimpleRouter.js +4 -3
  52. package/lib/module/web/SimpleRouter.js.map +1 -1
  53. package/lib/module/web/SimpleRouter.test.js +174 -0
  54. package/lib/module/web/SimpleRouter.test.js.map +1 -0
  55. package/lib/typescript/src/features/browser.d.ts.map +1 -1
  56. package/lib/typescript/src/features/remoteControls.d.ts +0 -26
  57. package/lib/typescript/src/features/remoteControls.d.ts.map +1 -1
  58. package/lib/typescript/src/specs/audio-browser.nitro.d.ts +1 -3
  59. package/lib/typescript/src/specs/audio-browser.nitro.d.ts.map +1 -1
  60. package/lib/typescript/src/types/browser-native.d.ts +2 -1
  61. package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
  62. package/lib/typescript/src/types/browser-nodes.d.ts +46 -1
  63. package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
  64. package/lib/typescript/src/types/browser.d.ts +32 -0
  65. package/lib/typescript/src/types/browser.d.ts.map +1 -1
  66. package/lib/typescript/src/web/NativeAudioBrowser.d.ts +3 -6
  67. package/lib/typescript/src/web/NativeAudioBrowser.d.ts.map +1 -1
  68. package/lib/typescript/src/web/SimpleRouter.d.ts.map +1 -1
  69. package/lib/typescript/src/web/SimpleRouter.test.d.ts +2 -0
  70. package/lib/typescript/src/web/SimpleRouter.test.d.ts.map +1 -0
  71. package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +1 -1
  72. package/nitrogen/generated/android/AudioBrowser+autolinking.gradle +1 -1
  73. package/nitrogen/generated/android/AudioBrowserOnLoad.cpp +67 -57
  74. package/nitrogen/generated/android/AudioBrowserOnLoad.hpp +14 -5
  75. package/nitrogen/generated/android/c++/JAndroidAudioContentType.hpp +6 -7
  76. package/nitrogen/generated/android/c++/JAndroidAudioOffloadSettings.hpp +1 -1
  77. package/nitrogen/generated/android/c++/JAndroidOptions.hpp +1 -1
  78. package/nitrogen/generated/android/c++/JAndroidPlayerWakeMode.hpp +4 -5
  79. package/nitrogen/generated/android/c++/JAndroidUpdateOptions.hpp +1 -1
  80. package/nitrogen/generated/android/c++/JAppKilledPlaybackBehavior.hpp +4 -5
  81. package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +4 -1
  82. package/nitrogen/generated/android/c++/JBatteryOptimizationStatus.hpp +4 -5
  83. package/nitrogen/generated/android/c++/JBatteryOptimizationStatusChangedEvent.hpp +1 -1
  84. package/nitrogen/generated/android/c++/JBatteryWarningPendingChangedEvent.hpp +1 -1
  85. package/nitrogen/generated/android/c++/JBrowseError.hpp +1 -1
  86. package/nitrogen/generated/android/c++/JBrowseResult.cpp +1 -1
  87. package/nitrogen/generated/android/c++/JBrowseResult.hpp +7 -3
  88. package/nitrogen/generated/android/c++/JBrowserSourceCallbackParam.hpp +1 -1
  89. package/nitrogen/generated/android/c++/JCarPlayNowPlayingButton.hpp +5 -6
  90. package/nitrogen/generated/android/c++/JCarPlaySiriListButtonPosition.hpp +58 -0
  91. package/nitrogen/generated/android/c++/JChapterMetadata.hpp +1 -1
  92. package/nitrogen/generated/android/c++/JEqualizerSettings.hpp +1 -1
  93. package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +4 -1
  94. package/nitrogen/generated/android/c++/JFormatNavigationErrorParams.hpp +1 -1
  95. package/nitrogen/generated/android/c++/JFormattedNavigationError.hpp +1 -1
  96. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.hpp +1 -1
  97. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.hpp +1 -1
  98. 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
  99. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +4 -1
  100. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.hpp +5 -1
  101. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +3 -1
  102. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +139 -0
  103. package/nitrogen/generated/android/c++/JFunc_void.hpp +1 -1
  104. package/nitrogen/generated/android/c++/JFunc_void_BatteryOptimizationStatusChangedEvent.hpp +1 -1
  105. package/nitrogen/generated/android/c++/JFunc_void_BatteryWarningPendingChangedEvent.hpp +1 -1
  106. package/nitrogen/generated/android/c++/JFunc_void_EqualizerSettings.hpp +1 -1
  107. package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +4 -1
  108. package/nitrogen/generated/android/c++/JFunc_void_IosOutput.hpp +1 -1
  109. package/nitrogen/generated/android/c++/JFunc_void_NavigationErrorEvent.hpp +1 -1
  110. package/nitrogen/generated/android/c++/JFunc_void_NowPlayingMetadata.hpp +1 -1
  111. package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +1 -1
  112. package/nitrogen/generated/android/c++/JFunc_void_Playback.hpp +1 -1
  113. package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +4 -1
  114. package/nitrogen/generated/android/c++/JFunc_void_PlaybackErrorEvent.hpp +1 -1
  115. package/nitrogen/generated/android/c++/JFunc_void_PlaybackPlayWhenReadyChangedEvent.hpp +1 -1
  116. package/nitrogen/generated/android/c++/JFunc_void_PlaybackProgressUpdatedEvent.hpp +1 -1
  117. package/nitrogen/generated/android/c++/JFunc_void_PlaybackQueueEndedEvent.hpp +1 -1
  118. package/nitrogen/generated/android/c++/JFunc_void_PlayingState.hpp +1 -1
  119. package/nitrogen/generated/android/c++/JFunc_void_RemoteJumpBackwardEvent.hpp +1 -1
  120. package/nitrogen/generated/android/c++/JFunc_void_RemoteJumpForwardEvent.hpp +1 -1
  121. package/nitrogen/generated/android/c++/JFunc_void_RemotePlayIdEvent.hpp +1 -1
  122. package/nitrogen/generated/android/c++/JFunc_void_RemotePlaySearchEvent.hpp +1 -1
  123. package/nitrogen/generated/android/c++/JFunc_void_RemoteSeekEvent.hpp +1 -1
  124. package/nitrogen/generated/android/c++/JFunc_void_RemoteSetRatingEvent.hpp +1 -1
  125. package/nitrogen/generated/android/c++/JFunc_void_RemoteSkipEvent.hpp +1 -1
  126. package/nitrogen/generated/android/c++/JFunc_void_RepeatModeChangedEvent.hpp +1 -1
  127. package/nitrogen/generated/android/c++/JFunc_void_TimedMetadata.hpp +1 -1
  128. package/nitrogen/generated/android/c++/JFunc_void_TrackMetadata.hpp +1 -1
  129. package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +1 -1
  130. package/nitrogen/generated/android/c++/JFunc_void_double.hpp +1 -1
  131. package/nitrogen/generated/android/c++/JFunc_void_std__optional_FormattedNavigationError_.hpp +1 -1
  132. package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +5 -1
  133. package/nitrogen/generated/android/c++/JFunc_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.hpp +1 -1
  134. package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +1 -1
  135. package/nitrogen/generated/android/c++/JFunc_void_std__vector_ChapterMetadata_.hpp +1 -1
  136. package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +3 -1
  137. package/nitrogen/generated/android/c++/JHeartRating.hpp +1 -1
  138. package/nitrogen/generated/android/c++/JHttpMethod.hpp +8 -9
  139. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +230 -245
  140. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.hpp +20 -26
  141. package/nitrogen/generated/android/c++/JIOSCategory.hpp +7 -8
  142. package/nitrogen/generated/android/c++/JIOSCategoryMode.hpp +10 -11
  143. package/nitrogen/generated/android/c++/JIOSCategoryOptions.hpp +8 -9
  144. package/nitrogen/generated/android/c++/JIOSCategoryPolicy.hpp +4 -5
  145. package/nitrogen/generated/android/c++/JImageContext.hpp +1 -1
  146. package/nitrogen/generated/android/c++/JImageQueryParams.hpp +1 -1
  147. package/nitrogen/generated/android/c++/JImageRowItem.hpp +75 -0
  148. package/nitrogen/generated/android/c++/JImageSource.hpp +1 -1
  149. package/nitrogen/generated/android/c++/JIosOutput.hpp +1 -1
  150. package/nitrogen/generated/android/c++/JIosOutputType.hpp +12 -13
  151. package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +4 -1
  152. package/nitrogen/generated/android/c++/JMediaTransformParams.hpp +1 -1
  153. package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +22 -2
  154. package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +5 -1
  155. package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +1 -1
  156. package/nitrogen/generated/android/c++/JNavigationError.hpp +1 -1
  157. package/nitrogen/generated/android/c++/JNavigationErrorEvent.hpp +1 -1
  158. package/nitrogen/generated/android/c++/JNavigationErrorType.hpp +6 -7
  159. package/nitrogen/generated/android/c++/JNitroAndroidUpdateOptions.hpp +1 -1
  160. package/nitrogen/generated/android/c++/JNotificationButton.hpp +6 -7
  161. package/nitrogen/generated/android/c++/JNotificationButtonLayout.hpp +1 -1
  162. package/nitrogen/generated/android/c++/JNowPlayingMetadata.hpp +1 -1
  163. package/nitrogen/generated/android/c++/JNowPlayingUpdate.hpp +1 -1
  164. package/nitrogen/generated/android/c++/JOptions.hpp +1 -1
  165. package/nitrogen/generated/android/c++/JPartialAndroidSetupPlayerOptions.hpp +1 -1
  166. package/nitrogen/generated/android/c++/JPartialIOSSetupPlayerOptions.hpp +1 -1
  167. package/nitrogen/generated/android/c++/JPartialSetupPlayerOptions.hpp +1 -1
  168. package/nitrogen/generated/android/c++/JPercentageRating.hpp +1 -1
  169. package/nitrogen/generated/android/c++/JPlayback.hpp +1 -1
  170. package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +4 -1
  171. package/nitrogen/generated/android/c++/JPlaybackError.hpp +1 -1
  172. package/nitrogen/generated/android/c++/JPlaybackErrorEvent.hpp +1 -1
  173. package/nitrogen/generated/android/c++/JPlaybackPlayWhenReadyChangedEvent.hpp +1 -1
  174. package/nitrogen/generated/android/c++/JPlaybackProgressUpdatedEvent.hpp +1 -1
  175. package/nitrogen/generated/android/c++/JPlaybackQueueEndedEvent.hpp +1 -1
  176. package/nitrogen/generated/android/c++/JPlaybackState.hpp +10 -11
  177. package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +1 -1
  178. package/nitrogen/generated/android/c++/JPlayingState.hpp +1 -1
  179. package/nitrogen/generated/android/c++/JProgress.hpp +1 -1
  180. package/nitrogen/generated/android/c++/JRatingType.hpp +8 -9
  181. package/nitrogen/generated/android/c++/JRemoteJumpBackwardEvent.hpp +1 -1
  182. package/nitrogen/generated/android/c++/JRemoteJumpForwardEvent.hpp +1 -1
  183. package/nitrogen/generated/android/c++/JRemotePlayIdEvent.hpp +1 -1
  184. package/nitrogen/generated/android/c++/JRemotePlaySearchEvent.hpp +1 -1
  185. package/nitrogen/generated/android/c++/JRemoteSeekEvent.hpp +1 -1
  186. package/nitrogen/generated/android/c++/JRemoteSetRatingEvent.hpp +1 -1
  187. package/nitrogen/generated/android/c++/JRemoteSkipEvent.hpp +1 -1
  188. package/nitrogen/generated/android/c++/JRepeatMode.hpp +4 -5
  189. package/nitrogen/generated/android/c++/JRepeatModeChangedEvent.hpp +1 -1
  190. package/nitrogen/generated/android/c++/JRequestConfig.hpp +1 -1
  191. package/nitrogen/generated/android/c++/JResolvedTrack.hpp +34 -4
  192. package/nitrogen/generated/android/c++/JRetryConfig.hpp +1 -1
  193. package/nitrogen/generated/android/c++/JSearchMode.hpp +7 -8
  194. package/nitrogen/generated/android/c++/JSearchParams.hpp +1 -1
  195. package/nitrogen/generated/android/c++/JSleepTimer.cpp +1 -1
  196. package/nitrogen/generated/android/c++/JSleepTimer.hpp +4 -4
  197. package/nitrogen/generated/android/c++/JSleepTimerEndOfTrack.hpp +1 -1
  198. package/nitrogen/generated/android/c++/JSleepTimerTime.hpp +1 -1
  199. package/nitrogen/generated/android/c++/JStarRating.hpp +1 -1
  200. package/nitrogen/generated/android/c++/JThumbsRating.hpp +1 -1
  201. package/nitrogen/generated/android/c++/JTimedMetadata.hpp +1 -1
  202. package/nitrogen/generated/android/c++/JTrack.hpp +29 -4
  203. package/nitrogen/generated/android/c++/{JRemoteLoadEvent.hpp → JTrackLoadEvent.hpp} +13 -11
  204. package/nitrogen/generated/android/c++/JTrackMetadata.hpp +1 -1
  205. package/nitrogen/generated/android/c++/JTrackStyle.hpp +3 -4
  206. package/nitrogen/generated/android/c++/JTransformableRequestConfig.hpp +1 -1
  207. package/nitrogen/generated/android/c++/JUpdateOptions.hpp +1 -1
  208. package/nitrogen/generated/android/c++/JVariant_Boolean_AndroidAudioOffloadSettings.cpp +1 -1
  209. package/nitrogen/generated/android/c++/JVariant_Boolean_AndroidAudioOffloadSettings.hpp +3 -3
  210. package/nitrogen/generated/android/c++/JVariant_Boolean_RetryConfig.cpp +1 -1
  211. package/nitrogen/generated/android/c++/JVariant_Boolean_RetryConfig.hpp +3 -3
  212. package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.cpp +1 -1
  213. package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.hpp +5 -5
  214. package/nitrogen/generated/android/c++/JVariant_NullType_Double.cpp +1 -1
  215. package/nitrogen/generated/android/c++/JVariant_NullType_Double.hpp +3 -3
  216. package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.cpp +1 -1
  217. package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.hpp +3 -3
  218. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidAudioContentType.kt +3 -1
  219. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidAudioOffloadSettings.kt +2 -2
  220. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidOptions.kt +2 -2
  221. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidPlayerWakeMode.kt +3 -1
  222. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidUpdateOptions.kt +2 -2
  223. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AppKilledPlaybackBehavior.kt +3 -1
  224. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ArtworkRequestConfig.kt +2 -2
  225. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AudioBrowserOnLoad.kt +1 -1
  226. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryOptimizationStatus.kt +3 -1
  227. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryOptimizationStatusChangedEvent.kt +2 -2
  228. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryWarningPendingChangedEvent.kt +2 -2
  229. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowseError.kt +2 -2
  230. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowseResult.kt +1 -7
  231. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowserSourceCallbackParam.kt +2 -2
  232. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayNowPlayingButton.kt +3 -1
  233. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlaySiriListButtonPosition.kt +23 -0
  234. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ChapterMetadata.kt +2 -2
  235. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/EqualizerSettings.kt +2 -2
  236. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FavoriteChangedEvent.kt +2 -2
  237. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormatNavigationErrorParams.kt +2 -2
  238. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormattedNavigationError.kt +2 -2
  239. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.kt +1 -1
  240. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.kt +1 -1
  241. 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
  242. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.kt +1 -1
  243. 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
  244. 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
  245. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Func_void_RemoteLoadEvent.kt → Func_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.kt} +14 -14
  246. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void.kt +1 -1
  247. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_BatteryOptimizationStatusChangedEvent.kt +1 -1
  248. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_BatteryWarningPendingChangedEvent.kt +1 -1
  249. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_EqualizerSettings.kt +1 -1
  250. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_FavoriteChangedEvent.kt +1 -1
  251. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_IosOutput.kt +1 -1
  252. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_NavigationErrorEvent.kt +1 -1
  253. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_NowPlayingMetadata.kt +1 -1
  254. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_Options.kt +1 -1
  255. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_Playback.kt +1 -1
  256. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackActiveTrackChangedEvent.kt +1 -1
  257. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackErrorEvent.kt +1 -1
  258. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackPlayWhenReadyChangedEvent.kt +1 -1
  259. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackProgressUpdatedEvent.kt +1 -1
  260. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackQueueEndedEvent.kt +1 -1
  261. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlayingState.kt +1 -1
  262. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteJumpBackwardEvent.kt +1 -1
  263. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteJumpForwardEvent.kt +1 -1
  264. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemotePlayIdEvent.kt +1 -1
  265. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemotePlaySearchEvent.kt +1 -1
  266. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSeekEvent.kt +1 -1
  267. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSetRatingEvent.kt +1 -1
  268. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSkipEvent.kt +1 -1
  269. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RepeatModeChangedEvent.kt +1 -1
  270. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_TimedMetadata.kt +1 -1
  271. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_TrackMetadata.kt +1 -1
  272. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_bool.kt +1 -1
  273. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_double.kt +1 -1
  274. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_FormattedNavigationError_.kt +1 -1
  275. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_ResolvedTrack_.kt +1 -1
  276. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.kt +1 -1
  277. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__string.kt +1 -1
  278. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__vector_ChapterMetadata_.kt +1 -1
  279. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__vector_Track_.kt +1 -1
  280. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HeartRating.kt +2 -2
  281. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HttpMethod.kt +3 -1
  282. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HybridAudioBrowserSpec.kt +16 -47
  283. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategory.kt +3 -1
  284. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategoryMode.kt +3 -1
  285. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategoryOptions.kt +3 -1
  286. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategoryPolicy.kt +3 -1
  287. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageContext.kt +2 -2
  288. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageQueryParams.kt +2 -2
  289. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +47 -0
  290. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageSource.kt +2 -2
  291. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IosOutput.kt +2 -2
  292. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IosOutputType.kt +3 -1
  293. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaRequestConfig.kt +2 -2
  294. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaTransformParams.kt +2 -2
  295. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +9 -6
  296. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeRouteEntry.kt +2 -2
  297. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeUpdateOptions.kt +2 -2
  298. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationError.kt +2 -2
  299. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorEvent.kt +2 -2
  300. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorType.kt +3 -1
  301. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroAndroidUpdateOptions.kt +2 -2
  302. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButton.kt +3 -1
  303. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButtonLayout.kt +2 -2
  304. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingMetadata.kt +2 -2
  305. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingUpdate.kt +2 -2
  306. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Options.kt +2 -2
  307. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialAndroidSetupPlayerOptions.kt +2 -2
  308. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialIOSSetupPlayerOptions.kt +2 -2
  309. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialSetupPlayerOptions.kt +2 -2
  310. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PercentageRating.kt +2 -2
  311. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Playback.kt +2 -2
  312. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackActiveTrackChangedEvent.kt +2 -2
  313. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackError.kt +2 -2
  314. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackErrorEvent.kt +2 -2
  315. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackPlayWhenReadyChangedEvent.kt +2 -2
  316. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackProgressUpdatedEvent.kt +2 -2
  317. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackQueueEndedEvent.kt +2 -2
  318. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackState.kt +3 -1
  319. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
  320. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayingState.kt +2 -2
  321. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Progress.kt +2 -2
  322. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RatingType.kt +3 -1
  323. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteJumpBackwardEvent.kt +2 -2
  324. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteJumpForwardEvent.kt +2 -2
  325. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemotePlayIdEvent.kt +2 -2
  326. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemotePlaySearchEvent.kt +2 -2
  327. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSeekEvent.kt +2 -2
  328. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSetRatingEvent.kt +2 -2
  329. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSkipEvent.kt +2 -2
  330. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RepeatMode.kt +3 -1
  331. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RepeatModeChangedEvent.kt +2 -2
  332. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RequestConfig.kt +2 -2
  333. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +11 -5
  334. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RetryConfig.kt +2 -2
  335. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchMode.kt +3 -1
  336. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchParams.kt +2 -2
  337. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimer.kt +1 -8
  338. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimerEndOfTrack.kt +2 -2
  339. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimerTime.kt +2 -2
  340. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StarRating.kt +2 -2
  341. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ThumbsRating.kt +2 -2
  342. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TimedMetadata.kt +2 -2
  343. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +8 -5
  344. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{RemoteLoadEvent.kt → TrackLoadEvent.kt} +7 -7
  345. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackMetadata.kt +2 -2
  346. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackStyle.kt +3 -1
  347. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TransformableRequestConfig.kt +2 -2
  348. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/UpdateOptions.kt +2 -2
  349. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_AndroidAudioOffloadSettings.kt +1 -7
  350. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_RetryConfig.kt +1 -7
  351. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.kt +1 -9
  352. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_NullType_Double.kt +1 -7
  353. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_NullType_NotificationButtonLayout.kt +1 -7
  354. package/nitrogen/generated/ios/AudioBrowser+autolinking.rb +2 -2
  355. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.cpp +23 -14
  356. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +239 -142
  357. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +10 -4
  358. package/nitrogen/generated/ios/AudioBrowserAutolinking.mm +1 -1
  359. package/nitrogen/generated/ios/AudioBrowserAutolinking.swift +9 -8
  360. package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.cpp +1 -1
  361. package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +25 -18
  362. package/nitrogen/generated/ios/swift/AndroidAudioContentType.swift +1 -1
  363. package/nitrogen/generated/ios/swift/AndroidAudioOffloadSettings.swift +19 -44
  364. package/nitrogen/generated/ios/swift/AndroidOptions.swift +30 -74
  365. package/nitrogen/generated/ios/swift/AndroidPlayerWakeMode.swift +1 -1
  366. package/nitrogen/generated/ios/swift/AndroidUpdateOptions.swift +44 -112
  367. package/nitrogen/generated/ios/swift/AppKilledPlaybackBehavior.swift +1 -1
  368. package/nitrogen/generated/ios/swift/ArtworkRequestConfig.swift +152 -303
  369. package/nitrogen/generated/ios/swift/BatteryOptimizationStatus.swift +1 -1
  370. package/nitrogen/generated/ios/swift/BatteryOptimizationStatusChangedEvent.swift +3 -10
  371. package/nitrogen/generated/ios/swift/BatteryWarningPendingChangedEvent.swift +3 -10
  372. package/nitrogen/generated/ios/swift/BrowseError.swift +3 -10
  373. package/nitrogen/generated/ios/swift/BrowseResult.swift +1 -1
  374. package/nitrogen/generated/ios/swift/BrowserSourceCallbackParam.swift +20 -45
  375. package/nitrogen/generated/ios/swift/CarPlayNowPlayingButton.swift +1 -1
  376. package/nitrogen/generated/ios/swift/CarPlaySiriListButtonPosition.swift +40 -0
  377. package/nitrogen/generated/ios/swift/ChapterMetadata.swift +23 -60
  378. package/nitrogen/generated/ios/swift/EqualizerSettings.swift +24 -97
  379. package/nitrogen/generated/ios/swift/FavoriteChangedEvent.swift +5 -18
  380. package/nitrogen/generated/ios/swift/FormatNavigationErrorParams.swift +7 -26
  381. package/nitrogen/generated/ios/swift/FormattedNavigationError.swift +5 -18
  382. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.swift +1 -2
  383. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.swift +1 -2
  384. 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
  385. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.swift +1 -2
  386. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.swift +1 -2
  387. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.swift +1 -2
  388. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.swift +61 -0
  389. package/nitrogen/generated/ios/swift/Func_void.swift +1 -2
  390. package/nitrogen/generated/ios/swift/Func_void_BatteryOptimizationStatusChangedEvent.swift +1 -2
  391. package/nitrogen/generated/ios/swift/Func_void_BatteryWarningPendingChangedEvent.swift +1 -2
  392. package/nitrogen/generated/ios/swift/Func_void_EqualizerSettings.swift +1 -2
  393. package/nitrogen/generated/ios/swift/Func_void_FavoriteChangedEvent.swift +1 -2
  394. package/nitrogen/generated/ios/swift/Func_void_IosOutput.swift +1 -2
  395. package/nitrogen/generated/ios/swift/Func_void_NavigationErrorEvent.swift +1 -2
  396. package/nitrogen/generated/ios/swift/Func_void_NowPlayingMetadata.swift +1 -2
  397. package/nitrogen/generated/ios/swift/Func_void_Options.swift +1 -2
  398. package/nitrogen/generated/ios/swift/Func_void_Playback.swift +1 -2
  399. package/nitrogen/generated/ios/swift/Func_void_PlaybackActiveTrackChangedEvent.swift +1 -2
  400. package/nitrogen/generated/ios/swift/Func_void_PlaybackErrorEvent.swift +1 -2
  401. package/nitrogen/generated/ios/swift/Func_void_PlaybackPlayWhenReadyChangedEvent.swift +1 -2
  402. package/nitrogen/generated/ios/swift/Func_void_PlaybackProgressUpdatedEvent.swift +1 -2
  403. package/nitrogen/generated/ios/swift/Func_void_PlaybackQueueEndedEvent.swift +1 -2
  404. package/nitrogen/generated/ios/swift/Func_void_PlayingState.swift +1 -2
  405. package/nitrogen/generated/ios/swift/Func_void_RemoteJumpBackwardEvent.swift +1 -2
  406. package/nitrogen/generated/ios/swift/Func_void_RemoteJumpForwardEvent.swift +1 -2
  407. package/nitrogen/generated/ios/swift/Func_void_RemotePlayIdEvent.swift +1 -2
  408. package/nitrogen/generated/ios/swift/Func_void_RemotePlaySearchEvent.swift +1 -2
  409. package/nitrogen/generated/ios/swift/Func_void_RemoteSeekEvent.swift +1 -2
  410. package/nitrogen/generated/ios/swift/Func_void_RemoteSetRatingEvent.swift +1 -2
  411. package/nitrogen/generated/ios/swift/Func_void_RemoteSkipEvent.swift +1 -2
  412. package/nitrogen/generated/ios/swift/Func_void_RepeatModeChangedEvent.swift +1 -2
  413. package/nitrogen/generated/ios/swift/Func_void_RequestConfig.swift +1 -2
  414. package/nitrogen/generated/ios/swift/Func_void_TimedMetadata.swift +1 -2
  415. package/nitrogen/generated/ios/swift/Func_void_TrackMetadata.swift +1 -2
  416. package/nitrogen/generated/ios/swift/Func_void_bool.swift +1 -2
  417. package/nitrogen/generated/ios/swift/Func_void_double.swift +1 -2
  418. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +1 -2
  419. package/nitrogen/generated/ios/swift/Func_void_std__optional_FormattedNavigationError_.swift +1 -2
  420. package/nitrogen/generated/ios/swift/Func_void_std__optional_ResolvedTrack_.swift +1 -2
  421. package/nitrogen/generated/ios/swift/Func_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.swift +1 -2
  422. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_RequestConfig__.swift +1 -2
  423. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError___.swift +1 -2
  424. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_std__vector_Track___.swift +1 -2
  425. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_void__.swift +64 -0
  426. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +1 -2
  427. package/nitrogen/generated/ios/swift/Func_void_std__variant_ResolvedTrack__BrowseError_.swift +1 -2
  428. package/nitrogen/generated/ios/swift/Func_void_std__vector_ChapterMetadata_.swift +1 -2
  429. package/nitrogen/generated/ios/swift/Func_void_std__vector_Track_.swift +1 -2
  430. package/nitrogen/generated/ios/swift/HeartRating.swift +3 -10
  431. package/nitrogen/generated/ios/swift/HttpMethod.swift +1 -1
  432. package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec.swift +3 -6
  433. package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec_cxx.swift +56 -58
  434. package/nitrogen/generated/ios/swift/IOSCategory.swift +1 -1
  435. package/nitrogen/generated/ios/swift/IOSCategoryMode.swift +1 -1
  436. package/nitrogen/generated/ios/swift/IOSCategoryOptions.swift +1 -1
  437. package/nitrogen/generated/ios/swift/IOSCategoryPolicy.swift +1 -1
  438. package/nitrogen/generated/ios/swift/ImageContext.swift +19 -30
  439. package/nitrogen/generated/ios/swift/ImageQueryParams.swift +19 -44
  440. package/nitrogen/generated/ios/swift/ImageRowItem.swift +76 -0
  441. package/nitrogen/generated/ios/swift/ImageSource.swift +31 -80
  442. package/nitrogen/generated/ios/swift/IosOutput.swift +7 -26
  443. package/nitrogen/generated/ios/swift/IosOutputType.swift +1 -1
  444. package/nitrogen/generated/ios/swift/MediaRequestConfig.swift +162 -301
  445. package/nitrogen/generated/ios/swift/MediaTransformParams.swift +5 -24
  446. package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +143 -232
  447. package/nitrogen/generated/ios/swift/NativeRouteEntry.swift +81 -178
  448. package/nitrogen/generated/ios/swift/NativeUpdateOptions.swift +53 -125
  449. package/nitrogen/generated/ios/swift/NavigationError.swift +23 -53
  450. package/nitrogen/generated/ios/swift/NavigationErrorEvent.swift +3 -16
  451. package/nitrogen/generated/ios/swift/NavigationErrorType.swift +1 -1
  452. package/nitrogen/generated/ios/swift/NitroAndroidUpdateOptions.swift +44 -112
  453. package/nitrogen/generated/ios/swift/NotificationButton.swift +1 -1
  454. package/nitrogen/generated/ios/swift/NotificationButtonLayout.swift +18 -85
  455. package/nitrogen/generated/ios/swift/NowPlayingMetadata.swift +109 -227
  456. package/nitrogen/generated/ios/swift/NowPlayingUpdate.swift +19 -44
  457. package/nitrogen/generated/ios/swift/Options.swift +32 -88
  458. package/nitrogen/generated/ios/swift/PartialAndroidSetupPlayerOptions.swift +101 -201
  459. package/nitrogen/generated/ios/swift/PartialIOSSetupPlayerOptions.swift +25 -85
  460. package/nitrogen/generated/ios/swift/PartialSetupPlayerOptions.swift +35 -91
  461. package/nitrogen/generated/ios/swift/PercentageRating.swift +3 -10
  462. package/nitrogen/generated/ios/swift/Playback.swift +5 -24
  463. package/nitrogen/generated/ios/swift/PlaybackActiveTrackChangedEvent.swift +25 -66
  464. package/nitrogen/generated/ios/swift/PlaybackError.swift +5 -18
  465. package/nitrogen/generated/ios/swift/PlaybackErrorEvent.swift +3 -16
  466. package/nitrogen/generated/ios/swift/PlaybackPlayWhenReadyChangedEvent.swift +3 -10
  467. package/nitrogen/generated/ios/swift/PlaybackProgressUpdatedEvent.swift +9 -34
  468. package/nitrogen/generated/ios/swift/PlaybackQueueEndedEvent.swift +5 -18
  469. package/nitrogen/generated/ios/swift/PlaybackState.swift +1 -1
  470. package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +109 -254
  471. package/nitrogen/generated/ios/swift/PlayingState.swift +5 -18
  472. package/nitrogen/generated/ios/swift/Progress.swift +7 -26
  473. package/nitrogen/generated/ios/swift/RatingType.swift +1 -1
  474. package/nitrogen/generated/ios/swift/RemoteJumpBackwardEvent.swift +3 -10
  475. package/nitrogen/generated/ios/swift/RemoteJumpForwardEvent.swift +3 -10
  476. package/nitrogen/generated/ios/swift/RemotePlayIdEvent.swift +12 -24
  477. package/nitrogen/generated/ios/swift/RemotePlaySearchEvent.swift +3 -10
  478. package/nitrogen/generated/ios/swift/RemoteSeekEvent.swift +3 -10
  479. package/nitrogen/generated/ios/swift/RemoteSetRatingEvent.swift +21 -39
  480. package/nitrogen/generated/ios/swift/RemoteSkipEvent.swift +3 -10
  481. package/nitrogen/generated/ios/swift/RepeatMode.swift +1 -1
  482. package/nitrogen/generated/ios/swift/RepeatModeChangedEvent.swift +3 -10
  483. package/nitrogen/generated/ios/swift/RequestConfig.swift +82 -191
  484. package/nitrogen/generated/ios/swift/ResolvedTrack.swift +164 -333
  485. package/nitrogen/generated/ios/swift/RetryConfig.swift +12 -24
  486. package/nitrogen/generated/ios/swift/SearchMode.swift +1 -1
  487. package/nitrogen/generated/ios/swift/SearchParams.swift +50 -129
  488. package/nitrogen/generated/ios/swift/SleepTimer.swift +1 -1
  489. package/nitrogen/generated/ios/swift/SleepTimerEndOfTrack.swift +3 -10
  490. package/nitrogen/generated/ios/swift/SleepTimerTime.swift +3 -10
  491. package/nitrogen/generated/ios/swift/StarRating.swift +3 -10
  492. package/nitrogen/generated/ios/swift/ThumbsRating.swift +3 -10
  493. package/nitrogen/generated/ios/swift/TimedMetadata.swift +46 -107
  494. package/nitrogen/generated/ios/swift/Track.swift +151 -319
  495. package/nitrogen/generated/ios/swift/TrackLoadEvent.swift +45 -0
  496. package/nitrogen/generated/ios/swift/TrackMetadata.swift +145 -338
  497. package/nitrogen/generated/ios/swift/TrackStyle.swift +1 -1
  498. package/nitrogen/generated/ios/swift/TransformableRequestConfig.swift +128 -252
  499. package/nitrogen/generated/ios/swift/UpdateOptions.swift +53 -125
  500. package/nitrogen/generated/ios/swift/Variant_Bool_AndroidAudioOffloadSettings.swift +1 -1
  501. package/nitrogen/generated/ios/swift/Variant_Bool_RetryConfig.swift +1 -1
  502. package/nitrogen/generated/ios/swift/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.swift +1 -1
  503. package/nitrogen/generated/ios/swift/Variant_NullType_Double.swift +1 -1
  504. package/nitrogen/generated/ios/swift/Variant_NullType_NotificationButtonLayout.swift +1 -1
  505. package/nitrogen/generated/shared/c++/AndroidAudioContentType.hpp +1 -1
  506. package/nitrogen/generated/shared/c++/AndroidAudioOffloadSettings.hpp +16 -8
  507. package/nitrogen/generated/shared/c++/AndroidOptions.hpp +25 -17
  508. package/nitrogen/generated/shared/c++/AndroidPlayerWakeMode.hpp +1 -1
  509. package/nitrogen/generated/shared/c++/AndroidUpdateOptions.hpp +25 -17
  510. package/nitrogen/generated/shared/c++/AppKilledPlaybackBehavior.hpp +1 -1
  511. package/nitrogen/generated/shared/c++/ArtworkRequestConfig.hpp +43 -35
  512. package/nitrogen/generated/shared/c++/BatteryOptimizationStatus.hpp +1 -1
  513. package/nitrogen/generated/shared/c++/BatteryOptimizationStatusChangedEvent.hpp +13 -5
  514. package/nitrogen/generated/shared/c++/BatteryWarningPendingChangedEvent.hpp +13 -5
  515. package/nitrogen/generated/shared/c++/BrowseError.hpp +13 -5
  516. package/nitrogen/generated/shared/c++/BrowserSourceCallbackParam.hpp +16 -8
  517. package/nitrogen/generated/shared/c++/CarPlayNowPlayingButton.hpp +1 -1
  518. package/nitrogen/generated/shared/c++/CarPlaySiriListButtonPosition.hpp +76 -0
  519. package/nitrogen/generated/shared/c++/ChapterMetadata.hpp +22 -14
  520. package/nitrogen/generated/shared/c++/EqualizerSettings.hpp +34 -26
  521. package/nitrogen/generated/shared/c++/FavoriteChangedEvent.hpp +16 -8
  522. package/nitrogen/generated/shared/c++/FormatNavigationErrorParams.hpp +19 -11
  523. package/nitrogen/generated/shared/c++/FormattedNavigationError.hpp +16 -8
  524. package/nitrogen/generated/shared/c++/HeartRating.hpp +13 -5
  525. package/nitrogen/generated/shared/c++/HttpMethod.hpp +1 -1
  526. package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.cpp +1 -5
  527. package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.hpp +1 -8
  528. package/nitrogen/generated/shared/c++/IOSCategory.hpp +1 -1
  529. package/nitrogen/generated/shared/c++/IOSCategoryMode.hpp +1 -1
  530. package/nitrogen/generated/shared/c++/IOSCategoryOptions.hpp +1 -1
  531. package/nitrogen/generated/shared/c++/IOSCategoryPolicy.hpp +1 -1
  532. package/nitrogen/generated/shared/c++/ImageContext.hpp +16 -8
  533. package/nitrogen/generated/shared/c++/ImageQueryParams.hpp +16 -8
  534. package/nitrogen/generated/shared/c++/ImageRowItem.hpp +98 -0
  535. package/nitrogen/generated/shared/c++/ImageSource.hpp +22 -14
  536. package/nitrogen/generated/shared/c++/IosOutput.hpp +19 -11
  537. package/nitrogen/generated/shared/c++/IosOutputType.hpp +1 -1
  538. package/nitrogen/generated/shared/c++/MediaRequestConfig.hpp +40 -32
  539. package/nitrogen/generated/shared/c++/MediaTransformParams.hpp +16 -8
  540. package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +50 -35
  541. package/nitrogen/generated/shared/c++/NativeRouteEntry.hpp +34 -26
  542. package/nitrogen/generated/shared/c++/NativeUpdateOptions.hpp +28 -20
  543. package/nitrogen/generated/shared/c++/NavigationError.hpp +22 -14
  544. package/nitrogen/generated/shared/c++/NavigationErrorEvent.hpp +13 -5
  545. package/nitrogen/generated/shared/c++/NavigationErrorType.hpp +1 -1
  546. package/nitrogen/generated/shared/c++/NitroAndroidUpdateOptions.hpp +25 -17
  547. package/nitrogen/generated/shared/c++/NotificationButton.hpp +1 -1
  548. package/nitrogen/generated/shared/c++/NotificationButtonLayout.hpp +25 -17
  549. package/nitrogen/generated/shared/c++/NowPlayingMetadata.hpp +40 -32
  550. package/nitrogen/generated/shared/c++/NowPlayingUpdate.hpp +16 -8
  551. package/nitrogen/generated/shared/c++/Options.hpp +28 -20
  552. package/nitrogen/generated/shared/c++/PartialAndroidSetupPlayerOptions.hpp +40 -32
  553. package/nitrogen/generated/shared/c++/PartialIOSSetupPlayerOptions.hpp +25 -17
  554. package/nitrogen/generated/shared/c++/PartialSetupPlayerOptions.hpp +22 -14
  555. package/nitrogen/generated/shared/c++/PercentageRating.hpp +13 -5
  556. package/nitrogen/generated/shared/c++/Playback.hpp +16 -8
  557. package/nitrogen/generated/shared/c++/PlaybackActiveTrackChangedEvent.hpp +25 -17
  558. package/nitrogen/generated/shared/c++/PlaybackError.hpp +16 -8
  559. package/nitrogen/generated/shared/c++/PlaybackErrorEvent.hpp +13 -5
  560. package/nitrogen/generated/shared/c++/PlaybackPlayWhenReadyChangedEvent.hpp +13 -5
  561. package/nitrogen/generated/shared/c++/PlaybackProgressUpdatedEvent.hpp +22 -14
  562. package/nitrogen/generated/shared/c++/PlaybackQueueEndedEvent.hpp +16 -8
  563. package/nitrogen/generated/shared/c++/PlaybackState.hpp +1 -1
  564. package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +46 -38
  565. package/nitrogen/generated/shared/c++/PlayingState.hpp +16 -8
  566. package/nitrogen/generated/shared/c++/Progress.hpp +19 -11
  567. package/nitrogen/generated/shared/c++/RatingType.hpp +1 -1
  568. package/nitrogen/generated/shared/c++/RemoteJumpBackwardEvent.hpp +13 -5
  569. package/nitrogen/generated/shared/c++/RemoteJumpForwardEvent.hpp +13 -5
  570. package/nitrogen/generated/shared/c++/RemotePlayIdEvent.hpp +16 -8
  571. package/nitrogen/generated/shared/c++/RemotePlaySearchEvent.hpp +13 -5
  572. package/nitrogen/generated/shared/c++/RemoteSeekEvent.hpp +13 -5
  573. package/nitrogen/generated/shared/c++/RemoteSetRatingEvent.hpp +13 -5
  574. package/nitrogen/generated/shared/c++/RemoteSkipEvent.hpp +13 -5
  575. package/nitrogen/generated/shared/c++/RepeatMode.hpp +1 -1
  576. package/nitrogen/generated/shared/c++/RepeatModeChangedEvent.hpp +13 -5
  577. package/nitrogen/generated/shared/c++/RequestConfig.hpp +34 -26
  578. package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +79 -57
  579. package/nitrogen/generated/shared/c++/RetryConfig.hpp +16 -8
  580. package/nitrogen/generated/shared/c++/SearchMode.hpp +1 -1
  581. package/nitrogen/generated/shared/c++/SearchParams.hpp +31 -23
  582. package/nitrogen/generated/shared/c++/SleepTimerEndOfTrack.hpp +13 -5
  583. package/nitrogen/generated/shared/c++/SleepTimerTime.hpp +13 -5
  584. package/nitrogen/generated/shared/c++/StarRating.hpp +13 -5
  585. package/nitrogen/generated/shared/c++/ThumbsRating.hpp +13 -5
  586. package/nitrogen/generated/shared/c++/TimedMetadata.hpp +25 -17
  587. package/nitrogen/generated/shared/c++/Track.hpp +70 -54
  588. package/nitrogen/generated/shared/c++/{RemoteLoadEvent.hpp → TrackLoadEvent.hpp} +28 -20
  589. package/nitrogen/generated/shared/c++/TrackMetadata.hpp +58 -50
  590. package/nitrogen/generated/shared/c++/TrackStyle.hpp +1 -1
  591. package/nitrogen/generated/shared/c++/TransformableRequestConfig.hpp +37 -29
  592. package/nitrogen/generated/shared/c++/UpdateOptions.hpp +28 -20
  593. package/package.json +6 -7
  594. package/src/features/browser.ts +1 -0
  595. package/src/features/remoteControls.ts +0 -35
  596. package/src/specs/audio-browser.nitro.ts +0 -3
  597. package/src/types/browser-native.ts +2 -0
  598. package/src/types/browser-nodes.ts +49 -1
  599. package/src/types/browser.ts +36 -0
  600. package/src/web/NativeAudioBrowser.ts +19 -24
  601. package/src/web/SimpleRouter.test.ts +160 -0
  602. package/src/web/SimpleRouter.ts +10 -8
  603. package/nitrogen/generated/android/c++/JFunc_void_RemoteLoadEvent.hpp +0 -89
  604. package/nitrogen/generated/ios/swift/Func_void_RemoteLoadEvent.swift +0 -47
  605. package/nitrogen/generated/ios/swift/RemoteLoadEvent.swift +0 -70
@@ -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,34 +567,11 @@ public final class RNABCarPlayController: NSObject {
438
567
 
439
568
  // MARK: - Selection Handling
440
569
 
441
- /// Centralizes handleRemoteLoad interception for synchronous CarPlay selection paths.
442
- /// If handleRemoteLoad is set, calls it (intercepted). Otherwise runs defaultBehavior.
443
- /// Always fires onRemoteLoad, showNowPlaying, and completion afterward.
444
- @discardableResult
445
- private func handleLoad(
446
- track: Track, queue: [Track], startIndex: Double,
447
- audioBrowser: HybridAudioBrowser,
448
- completion: @escaping () -> Void,
449
- defaultBehavior: () -> Void
450
- ) -> Bool {
451
- let event = RemoteLoadEvent(track: track, queue: queue, startIndex: startIndex)
452
- let handled: Bool
453
- if let handler = audioBrowser.handleRemoteLoad {
454
- handler(event)
455
- handled = true
456
- } else {
457
- defaultBehavior()
458
- handled = false
459
- }
460
- audioBrowser.onRemoteLoad(event)
461
- showNowPlaying()
462
- completion()
463
- return handled
464
- }
465
-
466
- /// Centralizes handleRemoteLoad interception for async CarPlay selection paths (queue expansion).
467
- /// If handleRemoteLoad is set, calls it (intercepted). Otherwise runs defaultBehavior.
468
- /// Always fires onRemoteLoad, showNowPlaying, and completion afterward.
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.
469
575
  @discardableResult
470
576
  private func handleLoadAsync(
471
577
  track: Track, queue: [Track], startIndex: Double,
@@ -473,18 +579,14 @@ public final class RNABCarPlayController: NSObject {
473
579
  completion: @escaping () -> Void,
474
580
  defaultBehavior: () async -> Void
475
581
  ) async -> Bool {
476
- let event = RemoteLoadEvent(track: track, queue: queue, startIndex: startIndex)
477
- let handled: Bool
478
- if let handler = audioBrowser.handleRemoteLoad {
479
- handler(event)
480
- handled = true
481
- } else {
482
- await defaultBehavior()
483
- handled = false
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
484
586
  }
485
- audioBrowser.onRemoteLoad(event)
587
+ await defaultBehavior()
486
588
  await MainActor.run { self.showNowPlaying(); completion() }
487
- return handled
589
+ return false
488
590
  }
489
591
 
490
592
  private func handleItemSelection(track: Track, completion: @escaping () -> Void) {
@@ -515,8 +617,10 @@ public final class RNABCarPlayController: NSObject {
515
617
  let index = player?.tracks.firstIndex(where: { $0.src == trackId })
516
618
  {
517
619
  let queue = player?.tracks ?? []
518
- handleLoad(track: track, queue: queue, startIndex: Double(index), audioBrowser: audioBrowser, completion: completion) {
519
- try? player?.skipTo(index, playWhenReady: true)
620
+ Task {
621
+ await handleLoadAsync(track: track, queue: queue, startIndex: Double(index), audioBrowser: audioBrowser, completion: completion) {
622
+ try? player?.skipTo(index, playWhenReady: true)
623
+ }
520
624
  }
521
625
  return
522
626
  }
@@ -881,8 +985,7 @@ public final class RNABCarPlayController: NSObject {
881
985
  else { continue }
882
986
 
883
987
  logger.info("Refreshing tab template for path: \(path)")
884
- let sections = createSections(from: content)
885
- listTemplate.updateSections(sections)
988
+ updateTemplate(listTemplate, with: content)
886
989
  }
887
990
  }
888
991
 
@@ -893,8 +996,7 @@ public final class RNABCarPlayController: NSObject {
893
996
  templatePath == path
894
997
  {
895
998
  logger.info("Refreshing top template for path: \(path)")
896
- let sections = createSections(from: content)
897
- topTemplate.updateSections(sections)
999
+ updateTemplate(topTemplate, with: content)
898
1000
  }
899
1001
  }
900
1002
 
@@ -1026,18 +1128,31 @@ public final class RNABCarPlayController: NSObject {
1026
1128
  UIImage(systemName: symbolName)
1027
1129
  }
1028
1130
 
1029
- /// Creates an SF Symbol image for list items with light/dark mode support
1030
- private func sfSymbolImageForListItem(_ symbolName: String) -> UIImage? {
1031
- 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
1032
1143
 
1033
- let size = symbol.size
1034
- let scale = symbol.scale
1144
+ let config = UIImage.SymbolConfiguration(pointSize: symbolPointSize, weight: .medium)
1145
+ guard let symbol = UIImage(systemName: symbolName, withConfiguration: config) else { return nil }
1146
+
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
+ }
1035
1151
 
1036
- // Create both light and dark bitmap variants
1037
- let lightImage = renderSymbolToBitmap(symbol, tintColor: .black, size: size, scale: scale)
1038
- 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)
1039
1155
 
1040
- // Combine with UIImageAsset for automatic light/dark switching
1041
1156
  let asset = UIImageAsset()
1042
1157
  asset.register(lightImage, with: UITraitCollection(userInterfaceStyle: .light))
1043
1158
  asset.register(darkImage, with: UITraitCollection(userInterfaceStyle: .dark))
@@ -1045,18 +1160,27 @@ public final class RNABCarPlayController: NSObject {
1045
1160
  return asset.image(with: interfaceController.carTraitCollection)
1046
1161
  }
1047
1162
 
1048
- /// Renders an SF Symbol to a bitmap with the specified tint color
1049
- private nonisolated func renderSymbolToBitmap(_ symbol: UIImage, tintColor: UIColor, size: CGSize, scale: CGFloat) -> UIImage {
1050
- UIGraphicsBeginImageContextWithOptions(size, false, scale)
1051
- defer { UIGraphicsEndImageContext() }
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
+ }())
1052
1171
 
1053
- tintColor.set()
1054
- symbol.withRenderingMode(.alwaysTemplate).draw(in: CGRect(origin: .zero, size: size))
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))
1055
1176
 
1056
- guard let rendered = UIGraphicsGetImageFromCurrentImageContext() else {
1057
- return symbol // Fallback to original if rendering fails
1058
- }
1059
- return rendered.withRenderingMode(.alwaysOriginal)
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)
1060
1184
  }
1061
1185
 
1062
1186
  private func defaultTabImage() -> UIImage? {
@@ -1078,9 +1202,14 @@ public final class RNABCarPlayController: NSObject {
1078
1202
  /// - size: The target size in points (will be multiplied by CarPlay display scale)
1079
1203
  /// - completion: Called with the loaded image, or nil on failure
1080
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
+
1081
1210
  guard let browserManager = audioBrowser?.browserManager else {
1082
1211
  // Fall back to direct URL loading
1083
- loadArtworkDirect(track: track, completion: completion)
1212
+ loadArtworkDirect(track: track, size: size, completion: completion)
1084
1213
  return
1085
1214
  }
1086
1215
 
@@ -1099,16 +1228,9 @@ public final class RNABCarPlayController: NSObject {
1099
1228
 
1100
1229
  await MainActor.run {
1101
1230
  if let imageSource {
1102
- // Check for SF Symbol URI (e.g., "sf:heart.fill")
1103
- if imageSource.uri.hasPrefix("sf:") {
1104
- let symbolName = String(imageSource.uri.dropFirst(3))
1105
- completion(self.sfSymbolImageForListItem(symbolName))
1106
- return
1107
- }
1108
-
1109
1231
  // Parse URL - skip if invalid
1110
1232
  guard let url = URL(string: imageSource.uri) else {
1111
- self.loadArtworkDirect(track: track, completion: completion)
1233
+ self.loadArtworkDirect(track: track, size: size, completion: completion)
1112
1234
  return
1113
1235
  }
1114
1236
 
@@ -1153,23 +1275,21 @@ public final class RNABCarPlayController: NSObject {
1153
1275
  }
1154
1276
  } else {
1155
1277
  // No resolved URL - try direct loading as fallback
1156
- self.loadArtworkDirect(track: track, completion: completion)
1278
+ self.loadArtworkDirect(track: track, size: size, completion: completion)
1157
1279
  }
1158
1280
  }
1159
1281
  }
1160
1282
  }
1161
1283
 
1162
1284
  /// Loads artwork directly from track's artwork URL without transform.
1163
- private func loadArtworkDirect(track: Track, completion: @escaping @Sendable (UIImage?) -> Void) {
1285
+ private func loadArtworkDirect(track: Track, size: CGSize, completion: @escaping @Sendable (UIImage?) -> Void) {
1164
1286
  guard let artworkUrl = track.artwork ?? track.artworkSource?.uri else {
1165
1287
  completion(nil)
1166
1288
  return
1167
1289
  }
1168
1290
 
1169
- // Check for SF Symbol URI (e.g., "sf:heart.fill")
1170
- if artworkUrl.hasPrefix("sf:") {
1171
- let symbolName = String(artworkUrl.dropFirst(3))
1172
- completion(sfSymbolImageForListItem(symbolName))
1291
+ if SFSymbolRenderer.isSFSymbol(artworkUrl) {
1292
+ completion(sfSymbolImage(forArtwork: artworkUrl, canvasSize: size))
1173
1293
  return
1174
1294
  }
1175
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
@@ -0,0 +1,60 @@
1
+ import Foundation
2
+ import Intents
3
+ import os.log
4
+
5
+ /// Handles INPlayMediaIntent for Siri voice search (e.g. from CarPlay).
6
+ ///
7
+ /// The class is internal (not public) to avoid exposing Intents types in the
8
+ /// generated AudioBrowser-Swift.h header, but is registered with the ObjC
9
+ /// runtime via `@objc(RNABMediaIntentHandler)` for NSClassFromString lookup.
10
+ ///
11
+ /// Host apps call the static method from `application(_:handle:completionHandler:)`:
12
+ /// ```swift
13
+ /// @objc private protocol RNABMediaIntentHandling {
14
+ /// static func handleMediaIntent(_ intent: INIntent, completionHandler: @escaping (INIntentResponse) -> Void)
15
+ /// }
16
+ ///
17
+ /// func application(_ application: UIApplication, handle intent: INIntent, completionHandler: @escaping (INIntentResponse) -> Void) {
18
+ /// (NSClassFromString("RNABMediaIntentHandler") as? RNABMediaIntentHandling.Type)?
19
+ /// .handleMediaIntent(intent, completionHandler: completionHandler)
20
+ /// }
21
+ /// ```
22
+ @objc(RNABMediaIntentHandler)
23
+ class RNABMediaIntentHandler: NSObject, INPlayMediaIntentHandling {
24
+ private static let logger = Logger(subsystem: "com.audiobrowser", category: "MediaIntentHandler")
25
+
26
+ // MARK: - Static Entry Point
27
+
28
+ /// Convenience entry point for host apps. Handles the full INPlayMediaIntent flow:
29
+ /// type checking, search, queue, and playback.
30
+ @objc static func handleMediaIntent(_ intent: INIntent, completionHandler: @escaping @Sendable (INIntentResponse) -> Void) {
31
+ guard let playIntent = intent as? INPlayMediaIntent else {
32
+ completionHandler(INPlayMediaIntentResponse(code: .failure, userActivity: nil))
33
+ return
34
+ }
35
+ let handler = RNABMediaIntentHandler()
36
+ handler.handle(intent: playIntent) { response in
37
+ completionHandler(response)
38
+ }
39
+ }
40
+
41
+ // MARK: - INPlayMediaIntentHandling
42
+
43
+ func handle(intent: INPlayMediaIntent, completion: @escaping @Sendable (INPlayMediaIntentResponse) -> Void) {
44
+ let searchTerm = intent.mediaSearch?.mediaName ?? ""
45
+ Self.logger.info("Handling play media intent with search term: \(searchTerm)")
46
+
47
+ guard let browser = HybridAudioBrowser.shared else {
48
+ Self.logger.error("HybridAudioBrowser.shared is nil — app may not be initialized yet")
49
+ completion(INPlayMediaIntentResponse(code: .failureRequiringAppLaunch, userActivity: nil))
50
+ return
51
+ }
52
+
53
+ browser.handlePlayMediaIntent(searchTerm: searchTerm) { success in
54
+ completion(INPlayMediaIntentResponse(
55
+ code: success ? .success : .failure,
56
+ userActivity: nil,
57
+ ))
58
+ }
59
+ }
60
+ }
@@ -30,7 +30,7 @@ extension ChapterMetadata {
30
30
  startTime: startTime,
31
31
  endTime: endTime,
32
32
  title: title,
33
- url: url
33
+ url: url,
34
34
  )
35
35
  }
36
36
  }
@@ -0,0 +1,20 @@
1
+ import NitroModules
2
+
3
+ // Workaround for a Nitro Modules upstream issue.
4
+ //
5
+ // Nitrogen-generated Swift code (e.g. Func_void_std__vector_Track_.swift) calls
6
+ // .map() on std::vector<T>, which requires CxxRandomAccessCollection conformance.
7
+ // Swift's C++ interop synthesizes this conformance lazily, but in incremental
8
+ // builds the conformance may not be available in the compilation batch that needs
9
+ // it, causing: "Value of type 'std::vector<T>' has no member 'map'"
10
+ //
11
+ // This should be fixed upstream in Nitro Modules. Until then, explicitly
12
+ // declaring the conformance here guarantees it's available regardless of
13
+ // compilation order.
14
+ //
15
+ // To identify which types need conformance, search the generated Swift files for
16
+ // .map() calls on bridge.std__vector_<T>_ types:
17
+ //
18
+ // grep -r '\.map(' nitrogen/generated/ios/swift/ | grep std__vector
19
+
20
+ extension margelo.nitro.audiobrowser.bridge.swift.std__vector_Track_: @retroactive CxxRandomAccessCollection {}
@@ -36,7 +36,7 @@ extension TimedMetadata {
36
36
  artist: nil,
37
37
  album: nil,
38
38
  date: nil,
39
- genre: nil
39
+ genre: nil,
40
40
  )
41
41
  }
42
42
 
@@ -57,9 +57,9 @@ extension TimedMetadata {
57
57
  case .id3MetadataAlbumTitle, .id3MetadataOriginalAlbumTitle:
58
58
  album = item.stringValue
59
59
  case .id3MetadataRecordingTime:
60
- date = item.stringValue // TDRC takes precedence (ID3v2.4, more precise)
60
+ date = item.stringValue // TDRC takes precedence (ID3v2.4, more precise)
61
61
  case .id3MetadataYear:
62
- date = date ?? item.stringValue // TYER only if TDRC not found (ID3v2.3)
62
+ date = date ?? item.stringValue // TYER only if TDRC not found (ID3v2.3)
63
63
  case .id3MetadataContentType:
64
64
  genre = item.stringValue
65
65
  default:
@@ -73,7 +73,7 @@ extension TimedMetadata {
73
73
  artist: artist,
74
74
  album: album,
75
75
  date: date,
76
- genre: genre
76
+ genre: genre,
77
77
  )
78
78
  }
79
79
 
@@ -120,7 +120,7 @@ extension TimedMetadata {
120
120
  artist: artist,
121
121
  album: album,
122
122
  date: date,
123
- genre: genre
123
+ genre: genre,
124
124
  )
125
125
  }
126
126
  }