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

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 (416) hide show
  1. package/README.md +14 -4
  2. package/android/build.gradle +20 -1
  3. package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +115 -26
  4. package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +262 -188
  5. package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +23 -3
  6. package/android/src/main/java/com/audiobrowser/browser/InertStyleDiagnostic.kt +267 -0
  7. package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +95 -58
  8. package/android/src/main/java/com/audiobrowser/browser/SectionScope.kt +68 -26
  9. package/android/src/main/java/com/audiobrowser/browser/StyleResolver.kt +60 -0
  10. package/android/src/main/java/com/audiobrowser/extension/ResolvedTrackExt.kt +19 -7
  11. package/android/src/main/java/com/audiobrowser/extension/TappedTrack.kt +20 -0
  12. package/android/src/main/java/com/audiobrowser/extension/TrackIdentity.kt +15 -0
  13. package/android/src/main/java/com/audiobrowser/model/PlayerUpdateOptions.kt +1 -1
  14. package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +120 -67
  15. package/android/src/main/java/com/audiobrowser/player/NowPlayingUpdater.kt +21 -24
  16. package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +109 -74
  17. package/android/src/main/java/com/audiobrowser/player/Player.kt +51 -30
  18. package/android/src/main/java/com/audiobrowser/player/PlayerCapabilitiesExt.kt +2 -15
  19. package/android/src/main/java/com/audiobrowser/player/ShuffleOrderLedBy.kt +30 -0
  20. package/android/src/main/java/com/audiobrowser/util/BrowserPathHelper.kt +44 -40
  21. package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +28 -23
  22. package/android/src/main/java/com/audiobrowser/util/StyleWire.kt +108 -0
  23. package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +52 -53
  24. package/android/src/test/java/com/audiobrowser/TestFixtures.kt +74 -41
  25. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerFavoritesTest.kt +153 -0
  26. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +229 -50
  27. package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +38 -0
  28. package/android/src/test/java/com/audiobrowser/browser/InertStyleDiagnosticTest.kt +277 -0
  29. package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +1 -1
  30. package/android/src/test/java/com/audiobrowser/browser/JsonStyleTest.kt +147 -0
  31. package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +128 -53
  32. package/android/src/test/java/com/audiobrowser/browser/StyleResolverTest.kt +154 -0
  33. package/android/src/test/java/com/audiobrowser/extension/TappedTrackTest.kt +43 -0
  34. package/android/src/test/java/com/audiobrowser/extension/TrackIdentityTest.kt +41 -0
  35. package/android/src/test/java/com/audiobrowser/player/CapabilityControlsTest.kt +1 -2
  36. package/android/src/test/java/com/audiobrowser/player/NowPlayingUpdaterTest.kt +42 -2
  37. package/android/src/test/java/com/audiobrowser/player/PlaybackStateStoreTrackJsonTest.kt +55 -0
  38. package/android/src/test/java/com/audiobrowser/player/ShuffleOrderLedByTest.kt +79 -0
  39. package/android/src/test/java/com/audiobrowser/util/BrowserPathHelperTest.kt +41 -16
  40. package/android/src/test/java/com/audiobrowser/util/MediaExtrasBuilderTest.kt +161 -0
  41. package/android/src/test/java/com/audiobrowser/util/TrackFactoryMediaIdTest.kt +7 -7
  42. package/ios/Browser/BrowserConfig.swift +102 -5
  43. package/ios/Browser/BrowserManager+URLResolution.swift +18 -14
  44. package/ios/Browser/BrowserManager.swift +229 -180
  45. package/ios/Browser/BrowserPathHelper.swift +44 -44
  46. package/ios/Browser/InertStyleDiagnostic.swift +279 -0
  47. package/ios/Browser/JsonModels.swift +258 -106
  48. package/ios/Browser/SearchDrillIn.swift +6 -6
  49. package/ios/Browser/SectionPresentation.swift +64 -0
  50. package/ios/Browser/SectionScope.swift +58 -24
  51. package/ios/Browser/StyleResolver.swift +58 -0
  52. package/ios/Browser/TabBarEntries.swift +9 -3
  53. package/ios/Browser/TrackIdTemplate.swift +37 -0
  54. package/ios/CarPlay/CarPlayArtworkResolver.swift +8 -7
  55. package/ios/CarPlay/CarPlayController.swift +227 -85
  56. package/ios/CarPlay/CarPlayImageLoader.swift +38 -18
  57. package/ios/CarPlay/CarPlayListItemFactory.swift +289 -84
  58. package/ios/CarPlay/CarPlayNowPlayingManager.swift +15 -12
  59. package/ios/Extension/Capability+RemoteCommand.swift +1 -1
  60. package/ios/Extension/PlayerCapabilities+Favorite.swift +1 -15
  61. package/ios/Extension/ResolvedTrack+Copying.swift +11 -15
  62. package/ios/Extension/Section+Copying.swift +31 -0
  63. package/ios/Extension/Track+Copying.swift +6 -12
  64. package/ios/Extension/Track+Identity.swift +18 -0
  65. package/ios/Extension/UIApplication+ActiveScene.swift +27 -0
  66. package/ios/Http/HttpClient.swift +8 -2
  67. package/ios/HybridAudioBrowser.swift +166 -45
  68. package/ios/Model/NitroTypeStubs.swift +106 -21
  69. package/ios/Model/PlayerUpdateOptions.swift +7 -0
  70. package/ios/Player/MediaIntentCriteria.swift +13 -5
  71. package/ios/Player/MediaLoader.swift +33 -9
  72. package/ios/Player/NowPlayingUpdater.swift +54 -6
  73. package/ios/Player/PlaybackCoordinator.swift +13 -6
  74. package/ios/Player/PlaybackTimer.swift +8 -2
  75. package/ios/Player/QueueManager.swift +36 -10
  76. package/ios/Player/RetryManager.swift +4 -3
  77. package/ios/Player/ShuffleOrder.swift +23 -0
  78. package/ios/Player/SleepTimerHandling.swift +13 -0
  79. package/ios/RemoteCommand/RemoteCommandController.swift +53 -18
  80. package/ios/Tests/BrowserPathHelperTests.swift +50 -20
  81. package/ios/Tests/CarPlayArtworkResolverTests.swift +24 -41
  82. package/ios/Tests/InertStyleDiagnosticTests.swift +200 -0
  83. package/ios/Tests/JsonModelsTests.swift +150 -1
  84. package/ios/Tests/PlaybackStateStoreTests.swift +4 -3
  85. package/ios/Tests/QueueManagerTests.swift +72 -6
  86. package/ios/Tests/RemoteCommandControllerTests.swift +16 -0
  87. package/ios/Tests/ResolvedTrackCopyingTests.swift +37 -35
  88. package/ios/Tests/SearchDrillInTests.swift +16 -16
  89. package/ios/Tests/SectionPresentationTests.swift +90 -0
  90. package/ios/Tests/SectionScopeTests.swift +87 -55
  91. package/ios/Tests/StyleResolverTests.swift +127 -0
  92. package/ios/Tests/Support/TestTypes.swift +7 -0
  93. package/ios/Tests/TabBarEntriesTests.swift +18 -18
  94. package/ios/Tests/TrackIdTemplateTests.swift +67 -0
  95. package/ios/Tests/TrackIdentityTests.swift +20 -0
  96. package/ios/Tests/TrackSelectorTests.swift +168 -33
  97. package/ios/TrackPlayer.swift +57 -34
  98. package/ios/TrackSelector.swift +45 -30
  99. package/ios/Util/ArtworkImageFetcher.swift +16 -1
  100. package/ios/Util/NetworkMonitor.swift +43 -26
  101. package/ios/Util/SFSymbolRenderer.swift +24 -2
  102. package/ios/Util/SVGProcessor.swift +9 -2
  103. package/lib/commonjs/AudioBrowser.js +11 -0
  104. package/lib/commonjs/AudioBrowser.js.map +1 -1
  105. package/lib/commonjs/features/browser-config.js +11 -8
  106. package/lib/commonjs/features/browser-config.js.map +1 -1
  107. package/lib/commonjs/features/browser.js +2 -2
  108. package/lib/commonjs/features/favorites.js +13 -10
  109. package/lib/commonjs/features/favorites.js.map +1 -1
  110. package/lib/commonjs/features/playback/controls.js +4 -2
  111. package/lib/commonjs/features/playback/controls.js.map +1 -1
  112. package/lib/commonjs/features/playback/progress.js +2 -1
  113. package/lib/commonjs/features/playback/progress.js.map +1 -1
  114. package/lib/commonjs/features/playback/rate.js +8 -1
  115. package/lib/commonjs/features/playback/rate.js.map +1 -1
  116. package/lib/commonjs/features/playback/state.js +2 -3
  117. package/lib/commonjs/features/playback/state.js.map +1 -1
  118. package/lib/commonjs/features/player/options.js.map +1 -1
  119. package/lib/commonjs/features/player/setup.js +3 -1
  120. package/lib/commonjs/features/player/setup.js.map +1 -1
  121. package/lib/commonjs/features/player/validateOptions.js +2 -0
  122. package/lib/commonjs/features/player/validateOptions.js.map +1 -1
  123. package/lib/commonjs/features/queue/activeTrack.js +14 -3
  124. package/lib/commonjs/features/queue/activeTrack.js.map +1 -1
  125. package/lib/commonjs/features/queue/queue.js +11 -4
  126. package/lib/commonjs/features/queue/queue.js.map +1 -1
  127. package/lib/commonjs/utils/LazyNativeEmitter.js +21 -10
  128. package/lib/commonjs/utils/LazyNativeEmitter.js.map +1 -1
  129. package/lib/commonjs/utils/NativeUpdatedValue.js +31 -13
  130. package/lib/commonjs/utils/NativeUpdatedValue.js.map +1 -1
  131. package/lib/commonjs/utils/getTrackIdentity.js +24 -0
  132. package/lib/commonjs/utils/getTrackIdentity.js.map +1 -0
  133. package/lib/commonjs/utils/useNativeValueRefreshedBy.js +33 -0
  134. package/lib/commonjs/utils/useNativeValueRefreshedBy.js.map +1 -0
  135. package/lib/commonjs/web/NativeAudioBrowser.js +32 -24
  136. package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
  137. package/lib/commonjs/web/TrackPlayer/QueueManager.js +14 -0
  138. package/lib/commonjs/web/TrackPlayer/QueueManager.js.map +1 -1
  139. package/lib/commonjs/web/browser/BrowserManager.js +144 -87
  140. package/lib/commonjs/web/browser/BrowserManager.js.map +1 -1
  141. package/lib/commonjs/web/browser/FavoriteManager.js +30 -21
  142. package/lib/commonjs/web/browser/FavoriteManager.js.map +1 -1
  143. package/lib/commonjs/web/browser/assertBrowsePageShape.js +2 -2
  144. package/lib/commonjs/web/browser/assertBrowsePageShape.js.map +1 -1
  145. package/lib/commonjs/web/browser/classifyTrackNavigation.js +9 -9
  146. package/lib/commonjs/web/browser/classifyTrackNavigation.js.map +1 -1
  147. package/lib/commonjs/web/browser/sections.js +89 -0
  148. package/lib/commonjs/web/browser/sections.js.map +1 -0
  149. package/lib/commonjs/web/player/NowPlayingManager.js +4 -3
  150. package/lib/commonjs/web/player/NowPlayingManager.js.map +1 -1
  151. package/lib/commonjs/web/util/BrowserPathHelper.js +56 -11
  152. package/lib/commonjs/web/util/BrowserPathHelper.js.map +1 -1
  153. package/lib/module/AudioBrowser.js +1 -0
  154. package/lib/module/AudioBrowser.js.map +1 -1
  155. package/lib/module/features/browser-config.js +11 -8
  156. package/lib/module/features/browser-config.js.map +1 -1
  157. package/lib/module/features/browser.js +2 -2
  158. package/lib/module/features/favorites.js +13 -10
  159. package/lib/module/features/favorites.js.map +1 -1
  160. package/lib/module/features/playback/controls.js +4 -2
  161. package/lib/module/features/playback/controls.js.map +1 -1
  162. package/lib/module/features/playback/progress.js +2 -1
  163. package/lib/module/features/playback/progress.js.map +1 -1
  164. package/lib/module/features/playback/rate.js +8 -1
  165. package/lib/module/features/playback/rate.js.map +1 -1
  166. package/lib/module/features/playback/state.js +2 -3
  167. package/lib/module/features/playback/state.js.map +1 -1
  168. package/lib/module/features/player/options.js.map +1 -1
  169. package/lib/module/features/player/setup.js +3 -1
  170. package/lib/module/features/player/setup.js.map +1 -1
  171. package/lib/module/features/player/validateOptions.js +2 -0
  172. package/lib/module/features/player/validateOptions.js.map +1 -1
  173. package/lib/module/features/queue/activeTrack.js +14 -3
  174. package/lib/module/features/queue/activeTrack.js.map +1 -1
  175. package/lib/module/features/queue/queue.js +11 -4
  176. package/lib/module/features/queue/queue.js.map +1 -1
  177. package/lib/module/utils/LazyNativeEmitter.js +21 -10
  178. package/lib/module/utils/LazyNativeEmitter.js.map +1 -1
  179. package/lib/module/utils/NativeUpdatedValue.js +31 -13
  180. package/lib/module/utils/NativeUpdatedValue.js.map +1 -1
  181. package/lib/module/utils/getTrackIdentity.js +20 -0
  182. package/lib/module/utils/getTrackIdentity.js.map +1 -0
  183. package/lib/module/utils/useNativeValueRefreshedBy.js +29 -0
  184. package/lib/module/utils/useNativeValueRefreshedBy.js.map +1 -0
  185. package/lib/module/web/NativeAudioBrowser.js +32 -24
  186. package/lib/module/web/NativeAudioBrowser.js.map +1 -1
  187. package/lib/module/web/TrackPlayer/QueueManager.js +14 -0
  188. package/lib/module/web/TrackPlayer/QueueManager.js.map +1 -1
  189. package/lib/module/web/browser/BrowserManager.js +144 -87
  190. package/lib/module/web/browser/BrowserManager.js.map +1 -1
  191. package/lib/module/web/browser/FavoriteManager.js +31 -21
  192. package/lib/module/web/browser/FavoriteManager.js.map +1 -1
  193. package/lib/module/web/browser/assertBrowsePageShape.js +2 -2
  194. package/lib/module/web/browser/assertBrowsePageShape.js.map +1 -1
  195. package/lib/module/web/browser/classifyTrackNavigation.js +9 -9
  196. package/lib/module/web/browser/classifyTrackNavigation.js.map +1 -1
  197. package/lib/module/web/browser/sections.js +83 -0
  198. package/lib/module/web/browser/sections.js.map +1 -0
  199. package/lib/module/web/player/NowPlayingManager.js +4 -3
  200. package/lib/module/web/player/NowPlayingManager.js.map +1 -1
  201. package/lib/module/web/util/BrowserPathHelper.js +56 -11
  202. package/lib/module/web/util/BrowserPathHelper.js.map +1 -1
  203. package/lib/typescript/src/AudioBrowser.d.ts +1 -0
  204. package/lib/typescript/src/AudioBrowser.d.ts.map +1 -1
  205. package/lib/typescript/src/features/browser-config.d.ts.map +1 -1
  206. package/lib/typescript/src/features/browser.d.ts +2 -2
  207. package/lib/typescript/src/features/favorites.d.ts +13 -10
  208. package/lib/typescript/src/features/favorites.d.ts.map +1 -1
  209. package/lib/typescript/src/features/playback/controls.d.ts +4 -2
  210. package/lib/typescript/src/features/playback/controls.d.ts.map +1 -1
  211. package/lib/typescript/src/features/playback/progress.d.ts.map +1 -1
  212. package/lib/typescript/src/features/playback/rate.d.ts +8 -1
  213. package/lib/typescript/src/features/playback/rate.d.ts.map +1 -1
  214. package/lib/typescript/src/features/playback/state.d.ts +2 -3
  215. package/lib/typescript/src/features/playback/state.d.ts.map +1 -1
  216. package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts +1 -1
  217. package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts.map +1 -1
  218. package/lib/typescript/src/features/player/options.d.ts +21 -19
  219. package/lib/typescript/src/features/player/options.d.ts.map +1 -1
  220. package/lib/typescript/src/features/player/setup.d.ts.map +1 -1
  221. package/lib/typescript/src/features/player/validateOptions.d.ts +1 -8
  222. package/lib/typescript/src/features/player/validateOptions.d.ts.map +1 -1
  223. package/lib/typescript/src/features/queue/activeTrack.d.ts +8 -1
  224. package/lib/typescript/src/features/queue/activeTrack.d.ts.map +1 -1
  225. package/lib/typescript/src/features/queue/queue.d.ts +5 -2
  226. package/lib/typescript/src/features/queue/queue.d.ts.map +1 -1
  227. package/lib/typescript/src/types/browser-native.d.ts +2 -2
  228. package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
  229. package/lib/typescript/src/types/browser-nodes.d.ts +361 -126
  230. package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
  231. package/lib/typescript/src/types/browser.d.ts +33 -53
  232. package/lib/typescript/src/types/browser.d.ts.map +1 -1
  233. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +16 -17
  234. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts.map +1 -1
  235. package/lib/typescript/src/utils/NativeUpdatedValue.d.ts +24 -19
  236. package/lib/typescript/src/utils/NativeUpdatedValue.d.ts.map +1 -1
  237. package/lib/typescript/src/utils/getTrackIdentity.d.ts +18 -0
  238. package/lib/typescript/src/utils/getTrackIdentity.d.ts.map +1 -0
  239. package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts +21 -0
  240. package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts.map +1 -0
  241. package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +0 -1
  242. package/nitrogen/generated/android/c++/{JFavoritesMatchMode.hpp → JArtworkRendering.hpp} +15 -15
  243. package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +8 -3
  244. package/nitrogen/generated/android/c++/JBrowseResult.hpp +16 -4
  245. package/nitrogen/generated/android/c++/JCarPlayPlayingIndicatorLocation.hpp +58 -0
  246. package/nitrogen/generated/android/c++/JCardImage.hpp +58 -0
  247. package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +8 -3
  248. package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +8 -3
  249. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +8 -3
  250. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +8 -3
  251. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +8 -3
  252. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +8 -3
  253. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +8 -2
  254. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +8 -2
  255. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.hpp +16 -4
  256. package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +8 -3
  257. package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +2 -5
  258. package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +8 -3
  259. package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +15 -3
  260. package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +8 -2
  261. package/nitrogen/generated/android/c++/JGridTile.hpp +61 -0
  262. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +33 -14
  263. package/nitrogen/generated/android/c++/JIOSOptions.hpp +9 -3
  264. package/nitrogen/generated/android/c++/JImageShape.hpp +58 -0
  265. package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +8 -3
  266. package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +22 -10
  267. package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +14 -2
  268. package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +10 -7
  269. package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +2 -5
  270. package/nitrogen/generated/android/c++/JNitroIOSUpdateOptions.hpp +9 -3
  271. package/nitrogen/generated/android/c++/JOptions.hpp +2 -5
  272. package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +8 -3
  273. package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +5 -11
  274. package/nitrogen/generated/android/c++/JResolvedTrack.hpp +55 -51
  275. package/nitrogen/generated/android/c++/JSection.hpp +120 -0
  276. package/nitrogen/generated/android/c++/JSectionStyle.hpp +96 -0
  277. package/nitrogen/generated/android/c++/JStyleDisplay.hpp +58 -0
  278. package/nitrogen/generated/android/c++/JTrack.hpp +23 -48
  279. package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +8 -2
  280. package/nitrogen/generated/android/c++/JTrackStyle.hpp +46 -18
  281. package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.hpp +16 -4
  282. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoritesMatchMode.kt → ArtworkRendering.kt} +5 -5
  283. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayPlayingIndicatorLocation.kt +23 -0
  284. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CardImage.kt +23 -0
  285. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/GridTile.kt +24 -0
  286. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSOptions.kt +6 -3
  287. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageShape.kt +23 -0
  288. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +5 -5
  289. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroIOSUpdateOptions.kt +6 -3
  290. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
  291. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +12 -18
  292. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoriteConfig.kt → Section.kt} +18 -6
  293. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SectionStyle.kt +59 -0
  294. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StyleDisplay.kt +23 -0
  295. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +6 -15
  296. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackStyle.kt +35 -5
  297. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +158 -82
  298. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +25 -10
  299. package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +25 -10
  300. package/nitrogen/generated/ios/swift/ArtworkRendering.swift +40 -0
  301. package/nitrogen/generated/ios/swift/CarPlayPlayingIndicatorLocation.swift +40 -0
  302. package/nitrogen/generated/ios/swift/CardImage.swift +40 -0
  303. package/nitrogen/generated/ios/swift/GridTile.swift +44 -0
  304. package/nitrogen/generated/ios/swift/IOSOptions.swift +7 -2
  305. package/nitrogen/generated/ios/swift/ImageShape.swift +40 -0
  306. package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +5 -5
  307. package/nitrogen/generated/ios/swift/NitroIOSUpdateOptions.swift +12 -1
  308. package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +8 -27
  309. package/nitrogen/generated/ios/swift/ResolvedTrack.swift +54 -83
  310. package/nitrogen/generated/ios/swift/Section.swift +100 -0
  311. package/nitrogen/generated/ios/swift/SectionStyle.swift +133 -0
  312. package/nitrogen/generated/ios/swift/StyleDisplay.swift +40 -0
  313. package/nitrogen/generated/ios/swift/Track.swift +20 -73
  314. package/nitrogen/generated/ios/swift/TrackStyle.swift +86 -22
  315. package/nitrogen/generated/shared/c++/{FavoritesMatchMode.hpp → ArtworkRendering.hpp} +17 -17
  316. package/nitrogen/generated/shared/c++/CarPlayPlayingIndicatorLocation.hpp +76 -0
  317. package/nitrogen/generated/shared/c++/CardImage.hpp +76 -0
  318. package/nitrogen/generated/shared/c++/GridTile.hpp +80 -0
  319. package/nitrogen/generated/shared/c++/IOSOptions.hpp +9 -2
  320. package/nitrogen/generated/shared/c++/ImageShape.hpp +76 -0
  321. package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +6 -6
  322. package/nitrogen/generated/shared/c++/NitroIOSUpdateOptions.hpp +9 -2
  323. package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +6 -9
  324. package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +30 -38
  325. package/nitrogen/generated/shared/c++/Section.hpp +106 -0
  326. package/nitrogen/generated/shared/c++/SectionStyle.hpp +126 -0
  327. package/nitrogen/generated/shared/c++/StyleDisplay.hpp +76 -0
  328. package/nitrogen/generated/shared/c++/Track.hpp +15 -31
  329. package/nitrogen/generated/shared/c++/TrackStyle.hpp +73 -34
  330. package/package.json +7 -2
  331. package/src/AudioBrowser.ts +1 -0
  332. package/src/features/browser-config.test.ts +21 -6
  333. package/src/features/browser-config.ts +11 -8
  334. package/src/features/browser.test.ts +1 -1
  335. package/src/features/browser.ts +2 -2
  336. package/src/features/favorites.ts +13 -10
  337. package/src/features/hook-wiring.test.ts +63 -15
  338. package/src/features/playback/controls.ts +4 -2
  339. package/src/features/playback/progress.ts +2 -1
  340. package/src/features/playback/rate.ts +8 -1
  341. package/src/features/playback/state.ts +2 -3
  342. package/src/features/playback/trackPlaybackTime.ts +1 -1
  343. package/src/features/player/options.ts +27 -19
  344. package/src/features/player/setup.test.ts +12 -3
  345. package/src/features/player/setup.ts +3 -1
  346. package/src/features/player/validateOptions.ts +2 -0
  347. package/src/features/queue/activeTrack.ts +14 -3
  348. package/src/features/queue/queue.ts +11 -4
  349. package/src/nitro-stub-drift.test.ts +40 -0
  350. package/src/public-surface.test.ts +40 -0
  351. package/src/specs/audio-browser.nitro.ts +4 -3
  352. package/src/style-resolution.test.ts +210 -0
  353. package/src/types/browser-native.ts +2 -2
  354. package/src/types/browser-nodes.ts +377 -135
  355. package/src/types/browser.ts +34 -55
  356. package/src/utils/LazyNativeEmitter.ts +20 -10
  357. package/src/utils/NativeUpdatedValue.ts +29 -13
  358. package/src/utils/getTrackIdentity.ts +20 -0
  359. package/src/utils/useNativeValueRefreshedBy.ts +38 -0
  360. package/src/web/NativeAudioBrowser.ts +37 -22
  361. package/src/web/TrackPlayer/QueueManager.test.ts +29 -0
  362. package/src/web/TrackPlayer/QueueManager.ts +14 -0
  363. package/src/web/browser/BrowserManager.ts +176 -95
  364. package/src/web/browser/FavoriteManager.test.ts +84 -0
  365. package/src/web/browser/FavoriteManager.ts +28 -23
  366. package/src/web/browser/assertBrowsePageShape.test.ts +1 -1
  367. package/src/web/browser/assertBrowsePageShape.ts +5 -3
  368. package/src/web/browser/classifyTrackNavigation.test.ts +10 -8
  369. package/src/web/browser/classifyTrackNavigation.ts +9 -9
  370. package/src/web/browser/parseSearchResponse.test.ts +8 -2
  371. package/src/web/browser/sections.test.ts +91 -0
  372. package/src/web/browser/sections.ts +72 -0
  373. package/src/web/player/NowPlayingManager.ts +4 -3
  374. package/src/web/util/BrowserPathHelper.test.ts +52 -0
  375. package/src/web/util/BrowserPathHelper.ts +61 -13
  376. package/website/guide/android-auto.md +114 -0
  377. package/website/guide/android-certificates.md +409 -0
  378. package/website/guide/artwork.md +255 -0
  379. package/website/guide/audio-output.md +135 -0
  380. package/website/guide/automotive.md +86 -0
  381. package/website/guide/basic-usage.md +151 -0
  382. package/website/guide/battery.md +115 -0
  383. package/website/guide/browser.md +581 -0
  384. package/website/guide/carplay.md +620 -0
  385. package/website/guide/configuration.md +173 -0
  386. package/website/guide/equalizer.md +231 -0
  387. package/website/guide/errors.md +310 -0
  388. package/website/guide/favorites.md +154 -0
  389. package/website/guide/gate.md +143 -0
  390. package/website/guide/getting-started.md +46 -0
  391. package/website/guide/hooks.md +238 -0
  392. package/website/guide/live-streams.md +125 -0
  393. package/website/guide/metadata.md +239 -0
  394. package/website/guide/migrating-from-track-player.md +244 -0
  395. package/website/guide/native-callback-fetch.md +127 -0
  396. package/website/guide/network.md +86 -0
  397. package/website/guide/now-playing.md +175 -0
  398. package/website/guide/playback.md +328 -0
  399. package/website/guide/queue.md +300 -0
  400. package/website/guide/remote-controls.md +256 -0
  401. package/website/guide/search.md +255 -0
  402. package/website/guide/sleep-timer.md +268 -0
  403. package/website/guide/track.md +246 -0
  404. package/ios/CarPlay/ImageRowItem+CarPlay.swift +0 -19
  405. package/nitrogen/generated/android/c++/JFavoriteConfig.hpp +0 -58
  406. package/nitrogen/generated/android/c++/JImageRowItem.hpp +0 -105
  407. package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.cpp +0 -26
  408. package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.hpp +0 -71
  409. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +0 -68
  410. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_FavoriteConfig.kt +0 -53
  411. package/nitrogen/generated/ios/swift/FavoriteConfig.swift +0 -29
  412. package/nitrogen/generated/ios/swift/FavoritesMatchMode.swift +0 -40
  413. package/nitrogen/generated/ios/swift/ImageRowItem.swift +0 -195
  414. package/nitrogen/generated/ios/swift/Variant_Bool_FavoriteConfig.swift +0 -18
  415. package/nitrogen/generated/shared/c++/FavoriteConfig.hpp +0 -84
  416. package/nitrogen/generated/shared/c++/ImageRowItem.hpp +0 -129
@@ -136,7 +136,7 @@ class TrackPlayer {
136
136
  var previousTracks: [Track] { coordinator.previousTracks }
137
137
  var isLastInPlaybackOrder: Bool { coordinator.isLastInPlaybackOrder }
138
138
  var playbackActive: Bool { coordinator.playbackActive }
139
- var sleepTimerManager: SleepTimerManager { coordinator.sleepTimerManager as! SleepTimerManager }
139
+ var sleepTimerManager: any SleepTimerHandling { coordinator.sleepTimerManager }
140
140
  var queue: QueueManager { coordinator.queue }
141
141
  var loadSeekCoordinator: LoadSeekCoordinator { coordinator.loadSeekCoordinator }
142
142
  var playingStateManager: PlayingStateManager { coordinator.playingStateManager }
@@ -195,12 +195,14 @@ class TrackPlayer {
195
195
  return seconds.isNaN ? 0 : seconds
196
196
  }
197
197
 
198
+ /// The current item's duration, or 0 when it has none (a live stream).
199
+ ///
200
+ /// Don't reintroduce `item.asset.duration`: it is deprecated as of the iOS 16
201
+ /// minimum and blocks the main actor fetching a remote asset's duration. Read
202
+ /// on every progress tick.
198
203
  var duration: Double {
199
204
  guard let item = avPlayer.currentItem else { return 0.0 }
200
205
 
201
- if !item.asset.duration.seconds.isNaN {
202
- return item.asset.duration.seconds
203
- }
204
206
  if !item.duration.seconds.isNaN {
205
207
  return item.duration.seconds
206
208
  }
@@ -252,8 +254,22 @@ class TrackPlayer {
252
254
  var rate: Float {
253
255
  get { coordinator.rate }
254
256
  set {
257
+ // A non-positive rate leaves the player unable to play at all — and would
258
+ // poison the next play() through `defaultRate` below. Rejected here, at
259
+ // the one setter every source funnels through (JS, remote command, CarPlay
260
+ // rate cycling, a restored snapshot), rather than at each of them.
261
+ guard newValue > 0 else { return }
255
262
  coordinator.rate = newValue
256
- avPlayer.rate = newValue
263
+ // Assigning a nonzero `AVPlayer.rate` IS `play()` — so setting the speed
264
+ // while paused would start audible playback behind the user's back, with
265
+ // `playWhenReady` still false (the lock screen would read "paused" over
266
+ // sound). On Android and web the speed control is independent of the play
267
+ // intent; this keeps iOS the same.
268
+ avPlayer.defaultRate = newValue
269
+ if playWhenReady { avPlayer.rate = newValue }
270
+ // Same reason as the repeat/shuffle edges below — a speed changed while
271
+ // paused would otherwise not reach the snapshot the cold resume restores.
272
+ persistPlaybackState()
257
273
  }
258
274
  }
259
275
 
@@ -312,17 +328,6 @@ class TrackPlayer {
312
328
  coordinator.load(track, playWhenReady: playWhenReady)
313
329
  }
314
330
 
315
- func togglePlaying() {
316
- switch avPlayer.timeControlStatus {
317
- case .playing, .waitingToPlayAtSpecifiedRate:
318
- pause()
319
- case .paused:
320
- play()
321
- @unknown default:
322
- fatalError("Unknown AVPlayer.timeControlStatus")
323
- }
324
- }
325
-
326
331
  func play() { coordinator.play() }
327
332
  func pause() { coordinator.pause() }
328
333
  func togglePlayback() { coordinator.togglePlayback() }
@@ -456,13 +461,17 @@ class TrackPlayer {
456
461
  )
457
462
  }
458
463
 
464
+ /// Empties the queue and the published now-playing info. Unlinking the
465
+ /// session belongs in `destroy()`: `avPlayer` survives a clear, and only
466
+ /// `setupAVPlayer()` re-links.
459
467
  func clear() {
460
468
  coordinator.clear()
461
- nowPlayingInfoController.unlinkPlayer()
462
469
  }
463
470
 
464
471
  func destroy() {
465
472
  clear()
473
+ // The player is going away for good — now the session must go with it.
474
+ nowPlayingInfoController.unlinkPlayer()
466
475
  // An AVPlayer retains its time observers: one left registered is still attached when the
467
476
  // player is released, and outlives this object.
468
477
  playerTimeObserver.unregisterForBoundaryTimeEvents()
@@ -550,10 +559,12 @@ class TrackPlayer {
550
559
 
551
560
  nowPlayingInfoController.linkPlayer(avPlayer)
552
561
 
562
+ // Stage the rate unconditionally, so a freshly recreated player carries it
563
+ // before anything plays — `rate`'s setter holds the same invariant, and on
564
+ // the playWhenReady branch below `defaultRate` was previously left at 1.0.
565
+ avPlayer.defaultRate = rate
553
566
  if playWhenReady {
554
567
  startPlayback()
555
- } else {
556
- avPlayer.defaultRate = rate
557
568
  }
558
569
  }
559
570
 
@@ -755,13 +766,28 @@ extension TrackPlayer {
755
766
  PersistedPlaybackState(
756
767
  track: JsonTrack(from: track),
757
768
  positionMs: positionMs,
758
- repeatMode: repeatMode.persistedString,
769
+ repeatMode: repeatMode.stringValue,
759
770
  shuffleEnabled: shuffleEnabled,
760
771
  playbackSpeed: rate,
761
772
  ),
762
773
  )
763
774
  }
764
775
 
776
+ /// Applies the player settings a snapshot carries — the inverse of
777
+ /// `persistPlaybackState()`, and the twin of the Kotlin store's `restore()`.
778
+ ///
779
+ /// Call BEFORE building the queue: `setQueue` rebuilds the shuffle order
780
+ /// pinned to the starting track, so shuffle has to be set for that order to
781
+ /// be the one playback uses (and the mode events then precede the
782
+ /// queue-changed event, as on Android). An unrecognized repeat mode restores
783
+ /// as `.off` rather than failing the whole resume over one field; a
784
+ /// non-positive speed is rejected by `rate`'s own setter.
785
+ func restorePlaybackSettings(from state: PersistedPlaybackState) {
786
+ repeatMode = RepeatMode(fromString: state.repeatMode) ?? .off
787
+ shuffleEnabled = state.shuffleEnabled
788
+ rate = state.playbackSpeed
789
+ }
790
+
765
791
  /// Start a 5 s repeating save while playback is active. A previous task is
766
792
  /// cancelled first so there is never more than one running at a time.
767
793
  private func startPeriodicSave() {
@@ -781,17 +807,6 @@ extension TrackPlayer {
781
807
  }
782
808
  }
783
809
 
784
- private extension RepeatMode {
785
- /// String representation stored in `PersistedPlaybackState.repeatMode`.
786
- var persistedString: String {
787
- switch self {
788
- case .off: "off"
789
- case .track: "track"
790
- case .queue: "queue"
791
- }
792
- }
793
- }
794
-
795
810
  // MARK: - PlaybackEffectHandler
796
811
 
797
812
  extension TrackPlayer: PlaybackEffectHandler {
@@ -857,15 +872,23 @@ extension TrackPlayer: PlaybackEffectHandler {
857
872
  }
858
873
 
859
874
  func clearNowPlaying() {
860
- nowPlayingInfoController.clear()
875
+ nowPlayingUpdater.clearNowPlaying()
861
876
  }
862
877
 
878
+ // Both persist: a snapshot is otherwise only written on track load, on pause,
879
+ // and every 5s while playing, so a mode toggled while paused was lost — the
880
+ // cold-start resume would restore the value from before the toggle. Android
881
+ // persists on every setting change (`PlayerListener.onRepeatModeChanged` /
882
+ // `onShuffleModeEnabledChanged`); these are the same two edges, and the
883
+ // coordinator only calls them on a real change.
863
884
  func updateRemoteRepeatMode(_ mode: RepeatMode) {
864
885
  remoteCommandController.updateRepeatMode(mode)
886
+ persistPlaybackState()
865
887
  }
866
888
 
867
889
  func updateRemoteShuffleMode(_ enabled: Bool) {
868
890
  remoteCommandController.updateShuffleMode(enabled)
891
+ persistPlaybackState()
869
892
  }
870
893
 
871
894
  func updateSkipAvailability(canNext: Bool, canPrevious: Bool) {
@@ -884,8 +907,8 @@ extension TrackPlayer: TrackSelectionPlayer {}
884
907
  // MARK: - Queue Methods (thin forwarders)
885
908
 
886
909
  extension TrackPlayer {
887
- func replace(_ index: Int, _ track: Track) {
888
- coordinator.replace(index, track)
910
+ func replace(_ index: Int, _ track: Track) throws {
911
+ try coordinator.replace(index, track)
889
912
  }
890
913
 
891
914
  func setQueue(
@@ -5,7 +5,7 @@ import os.log
5
5
 
6
6
  @MainActor protocol TrackSelectionBrowser {
7
7
  func awaitTrackLoadHandler(event: TrackLoadEvent) async -> Bool
8
- func expandQueueFromContextualUrl(_ url: String) async throws -> (tracks: [Track], selectedIndex: Int)?
8
+ func expandQueueFromContextualPath(_ path: String) async throws -> (tracks: [Track], selectedIndex: Int)?
9
9
  }
10
10
 
11
11
  @MainActor protocol TrackSelectionPlayer {
@@ -36,9 +36,9 @@ class TrackSelector {
36
36
  case play(PlaybackIntent)
37
37
  /// JS handleTrackLoad handler intercepted — caller should not play.
38
38
  case intercepted
39
- /// Track is browsable — caller should navigate to this URL.
40
- case browse(url: String)
41
- /// Nothing to do (no src, no url).
39
+ /// Track is browsable — caller should navigate to this path.
40
+ case browse(path: String)
41
+ /// Nothing to do (no src, no path).
42
42
  case none
43
43
  }
44
44
 
@@ -54,16 +54,22 @@ class TrackSelector {
54
54
  // MARK: - Selection
55
55
 
56
56
  /// Resolves a track selection to a concrete action.
57
- /// Handles contextual URL expansion, queue reuse, and handler interception.
57
+ /// Handles contextual path expansion, queue reuse, and handler interception.
58
58
  func select(
59
59
  track: Track,
60
60
  player: some TrackSelectionPlayer,
61
61
  ) async -> SelectionResult {
62
- let url = track.url
62
+ // A disabled track is unavailable — it never plays, whichever surface or
63
+ // stale resume path delivered the selection (Track.disabled).
64
+ if track.disabled == true {
65
+ return .none
66
+ }
67
+
68
+ let path = track.path
63
69
 
64
- // 1. Contextual URL (playable-only track with queue context)
65
- if let url, BrowserPathHelper.isContextual(url) {
66
- return await handleContextualUrl(url, track: track, player: player)
70
+ // 1. Contextual path (playable-only track with queue context)
71
+ if let path, BrowserPathHelper.isContextual(path) {
72
+ return await handleContextualPath(path, track: track, player: player)
67
73
  }
68
74
 
69
75
  // 2. Has src — single playable track
@@ -71,9 +77,9 @@ class TrackSelector {
71
77
  return await handlePlayableTrack(track, player: player)
72
78
  }
73
79
 
74
- // 3. Has url — browsable
75
- if let url {
76
- return .browse(url: url)
80
+ // 3. Has path — browsable
81
+ if let path {
82
+ return .browse(path: path)
77
83
  }
78
84
 
79
85
  // 4. Neither
@@ -82,31 +88,40 @@ class TrackSelector {
82
88
 
83
89
  // MARK: - Private Helpers
84
90
 
85
- private func handleContextualUrl(
86
- _ url: String,
91
+ private func handleContextualPath(
92
+ _ path: String,
87
93
  track: Track,
88
94
  player: some TrackSelectionPlayer,
89
95
  ) async -> SelectionResult {
90
- let parentPath = BrowserPathHelper.stripTrackId(url)
91
- let trackId = BrowserPathHelper.extractTrackId(url)
92
-
93
- // Check if queue already came from this parent path — just skip to the track
94
- if let trackId,
95
- parentPath == player.queueSourcePath,
96
- let index = player.tracks.firstIndex(where: { $0.src == trackId })
97
- {
98
- logger.debug("Queue already from \(parentPath), skipping to index \(index)")
99
- let queue = player.tracks
100
- let event = TrackLoadEvent(track: track, queue: queue, startIndex: Double(index))
101
- if await browserManager.awaitTrackLoadHandler(event: event) {
102
- return .intercepted
96
+ let parentPath = BrowserPathHelper.stripTrackId(path)
97
+ let trackId = BrowserPathHelper.extractTrackId(path)
98
+
99
+ // Check if queue already came from this parent path — just skip to the
100
+ // track. Exact-surface match first: a contextual path carries the tapped
101
+ // page position (`__index`), so path equality pins the exact copy when
102
+ // the page holds the same identity more than once. The identity match
103
+ // remains for index-less paths (e.g. pre-stamp persisted state); an
104
+ // index-stamped path with no exact match falls through to expansion,
105
+ // which re-scopes the queue to the tapped section.
106
+ if parentPath == player.queueSourcePath {
107
+ var skipIndex = player.tracks.firstIndex(where: { $0.path == path })
108
+ if skipIndex == nil, BrowserPathHelper.extractIndex(path) == nil, let trackId {
109
+ skipIndex = player.tracks.firstIndex(where: { $0.identity == trackId })
110
+ }
111
+ if let index = skipIndex {
112
+ logger.debug("Queue already from \(parentPath), skipping to index \(index)")
113
+ let queue = player.tracks
114
+ let event = TrackLoadEvent(track: track, queue: queue, startIndex: Double(index))
115
+ if await browserManager.awaitTrackLoadHandler(event: event) {
116
+ return .intercepted
117
+ }
118
+ return .play(.skipTo(index: index))
103
119
  }
104
- return .play(.skipTo(index: index))
105
120
  }
106
121
 
107
- // Expand the queue from the contextual URL
122
+ // Expand the queue from the contextual path
108
123
  do {
109
- if let expanded = try await browserManager.expandQueueFromContextualUrl(url) {
124
+ if let expanded = try await browserManager.expandQueueFromContextualPath(path) {
110
125
  let (tracks, startIndex) = expanded
111
126
  let event = TrackLoadEvent(track: track, queue: tracks, startIndex: Double(startIndex))
112
127
  if await browserManager.awaitTrackLoadHandler(event: event) {
@@ -8,7 +8,11 @@ enum ArtworkImageFetcher {
8
8
  private static let logger = Logger(subsystem: "com.audiobrowser", category: "ArtworkImageFetcher")
9
9
 
10
10
  @MainActor
11
- static func fetchImage(from source: ImageSource, svgScale: CGFloat? = nil) async -> UIImage? {
11
+ static func fetchImage(
12
+ from source: ImageSource,
13
+ svgScale: CGFloat? = nil,
14
+ downsampleTo: (size: CGSize, scale: CGFloat)? = nil,
15
+ ) async -> UIImage? {
12
16
  guard let url = URL(string: source.uri) else { return nil }
13
17
 
14
18
  var options: KingfisherOptionsInfo = []
@@ -24,6 +28,17 @@ enum ArtworkImageFetcher {
24
28
  }
25
29
  if let svgScale {
26
30
  options.append(.processor(SVGProcessor(size: nil, scale: svgScale)))
31
+ } else if let downsampleTo {
32
+ // Downsample rasters at decode time. Any size hint passed upstream (the
33
+ // resolver's ImageContext) is advisory — a CDN can ignore it and return
34
+ // the original — so this is the only sizing that is guaranteed to
35
+ // happen. The processed image is cached under a size-qualified key;
36
+ // cacheOriginalImage keeps the untouched original in the disk cache so
37
+ // the same URL at another target size re-processes instead of
38
+ // re-downloading.
39
+ options.append(.processor(DownsamplingImageProcessor(size: downsampleTo.size)))
40
+ options.append(.scaleFactor(downsampleTo.scale))
41
+ options.append(.cacheOriginalImage)
27
42
  }
28
43
 
29
44
  do {
@@ -11,13 +11,36 @@ final class NetworkMonitor: @unchecked Sendable {
11
11
  private let monitor: NWPathMonitor
12
12
  private let queue = DispatchQueue(label: "com.audiobrowser.networkmonitor")
13
13
 
14
- /// Current network connectivity state. Must only be set on main thread.
15
- private(set) var isOnline: Bool = false {
16
- didSet {
17
- if oldValue != isOnline {
18
- logger.notice("Network status changed: \(oldValue) -> \(self.isOnline)")
19
- onChanged?(isOnline)
20
- }
14
+ /// Guards `_isOnline` only. Never held across `onChanged` — see `apply`.
15
+ private let lock = NSLock()
16
+ private var _isOnline = false
17
+
18
+ /// Current network connectivity state. Readable from any thread: the value is
19
+ /// lock-protected rather than confined, so callers on the JS thread (Nitro's
20
+ /// `getOnline`) don't have to block on a main-queue hop to read a Bool.
21
+ ///
22
+ /// The broadcast is main-confined even though the value isn't — `onChanged`
23
+ /// fans out to the JS bridge, a now-playing re-render and a player reload, so
24
+ /// it must not run under the lock (reentrancy) or off the main actor.
25
+ var isOnline: Bool {
26
+ lock.lock()
27
+ defer { lock.unlock() }
28
+ return _isOnline
29
+ }
30
+
31
+ /// Stores a new status and, if it actually changed, broadcasts on main —
32
+ /// outside the lock.
33
+ private func apply(_ newStatus: Bool) {
34
+ lock.lock()
35
+ let changed = _isOnline != newStatus
36
+ let oldValue = _isOnline
37
+ _isOnline = newStatus
38
+ lock.unlock()
39
+
40
+ guard changed else { return }
41
+ logger.notice("Network status changed: \(oldValue) -> \(newStatus)")
42
+ DispatchQueue.main.async { [weak self] in
43
+ self?.onChanged?(newStatus)
21
44
  }
22
45
  }
23
46
 
@@ -31,29 +54,23 @@ final class NetworkMonitor: @unchecked Sendable {
31
54
  init() {
32
55
  monitor = NWPathMonitor()
33
56
 
34
- // Set up handler before starting
35
- monitor.pathUpdateHandler = { [weak self] path in
36
- let newStatus = path.status == .satisfied
37
- DispatchQueue.main.async { [weak self] in
38
- self?.isOnline = newStatus
39
- }
40
- }
41
-
42
- // Start monitoring
43
- monitor.start(queue: queue)
44
-
45
- // Read initial state after starting (currentPath is now valid)
57
+ // Seed BEFORE `start`. `start` publishes `self` to the monitor queue, so any
58
+ // write after it races the handler's locked write — and would clobber a real
59
+ // update with a `currentPath` the monitor hasn't finished evaluating. Nothing
60
+ // recovers from that: the handler has already fired, `onChanged` isn't wired
61
+ // until setupPlayer, and the stale value then drives `getOnline()`, the JS
62
+ // event, and RetryManager's offline parking until the next genuine path
63
+ // change. Seeding first is a best-effort guess; the handler fires shortly
64
+ // after `start` and is the authoritative last writer.
46
65
  let initialStatus = monitor.currentPath.status == .satisfied
47
66
  logger.notice("NetworkMonitor initialized, initial isOnline=\(initialStatus)")
48
- isOnline = initialStatus
49
- }
67
+ _isOnline = initialStatus
50
68
 
51
- // MARK: - Public Methods
69
+ monitor.pathUpdateHandler = { [weak self] path in
70
+ self?.apply(path.status == .satisfied)
71
+ }
52
72
 
53
- /// Gets the current network connectivity state.
54
- /// - Returns: true if device is online, false otherwise
55
- func getOnline() -> Bool {
56
- isOnline
73
+ monitor.start(queue: queue)
57
74
  }
58
75
 
59
76
  /// Stops monitoring and cleans up resources.
@@ -11,13 +11,21 @@ final class SFSymbolRenderer: @unchecked Sendable {
11
11
  @MainActor static let shared = SFSymbolRenderer()
12
12
  static let defaultCanvasSize = CGSize(width: 200, height: 200)
13
13
 
14
+ /// Bumped whenever the rendering below changes (symbol point-size factor,
15
+ /// centering, tinting, background fill). It is part of the cache filename
16
+ /// because `.cachesDirectory` survives app updates and the existence check is
17
+ /// the only cache validation — without a version key, every device that had
18
+ /// rendered a symbol once would keep serving the OLD pixels forever after a
19
+ /// render change.
20
+ private static let renderVersion = 1
21
+
14
22
  private let logger = Logger(subsystem: "com.audiobrowser", category: "SFSymbolRenderer")
15
23
  private let scale: CGFloat
16
24
  private let cacheDirectory: URL
17
25
 
18
26
  @MainActor
19
27
  private init() {
20
- scale = UIScreen.main.scale
28
+ scale = appDisplayScale
21
29
 
22
30
  let caches = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
23
31
  cacheDirectory = caches.appendingPathComponent("sf-symbols", isDirectory: true)
@@ -45,7 +53,8 @@ final class SFSymbolRenderer: @unchecked Sendable {
45
53
  let safeArtwork = artworkValue.unicodeScalars
46
54
  .filter { CharacterSet.alphanumerics.contains($0) || $0 == "_" }
47
55
  .map(String.init).joined()
48
- let fileName = "\(safeArtwork)_\(Int(canvasSize.width))x\(Int(canvasSize.height))_\(Int(scale))x"
56
+ let fileName =
57
+ "\(safeArtwork)_\(Int(canvasSize.width))x\(Int(canvasSize.height))_\(Int(scale))x_v\(Self.renderVersion)"
49
58
  let fileURL = cacheDirectory.appendingPathComponent("\(fileName).png")
50
59
 
51
60
  if FileManager.default.fileExists(atPath: fileURL.path) {
@@ -139,4 +148,17 @@ extension UIColor {
139
148
  self.init(white: 0, alpha: 1)
140
149
  }
141
150
  }
151
+
152
+ /// Failable form for *declared* colors (`style.cardTint`): anything but a
153
+ /// 3- or 6-digit hex value is nil, so an unparseable declaration degrades
154
+ /// to "no declaration" (the system default) instead of rendering black —
155
+ /// matching how unknown enum values decode. `init(hex:)` keeps its lenient
156
+ /// black fallback for the `sf:` artwork params it has always served.
157
+ convenience init?(declaredHex hex: String) {
158
+ let digits = hex.trimmingCharacters(in: CharacterSet(charactersIn: "#"))
159
+ guard [3, 6].contains(digits.count),
160
+ digits.allSatisfy(\.isHexDigit)
161
+ else { return nil }
162
+ self.init(hex: hex)
163
+ }
142
164
  }
@@ -4,7 +4,14 @@ import UIKit
4
4
 
5
5
  /// Kingfisher processor that renders SVG data to UIImage using SwiftDraw.
6
6
  struct SVGProcessor: ImageProcessor {
7
- let identifier = "com.audiobrowser.svgprocessor"
7
+ /// Kingfisher keys its cache on `identifier` alone (`ImageCache.computedKey`),
8
+ /// and `.scaleFactor` never enters that key — so the render parameters have to,
9
+ /// or two different rasterizations of the same URL would collide. Today only
10
+ /// CarPlay rasterizes SVGs (one screen, one scale), so this is insurance
11
+ /// against a second call site rather than a live fix.
12
+ var identifier: String {
13
+ "com.audiobrowser.svgprocessor(\(size?.width ?? -1)x\(size?.height ?? -1)@\(scale))"
14
+ }
8
15
 
9
16
  /// Target size for rendering (in points). If nil, uses SVG's intrinsic size.
10
17
  let size: CGSize?
@@ -15,7 +22,7 @@ struct SVGProcessor: ImageProcessor {
15
22
  @MainActor
16
23
  init(size: CGSize? = nil, scale: CGFloat? = nil) {
17
24
  self.size = size
18
- self.scale = scale ?? UIScreen.main.scale
25
+ self.scale = scale ?? appDisplayScale
19
26
  }
20
27
 
21
28
  func process(item: ImageProcessItem, options _: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
@@ -25,6 +25,17 @@ Object.keys(_types).forEach(function (key) {
25
25
  }
26
26
  });
27
27
  });
28
+ var _getTrackIdentity = require("./utils/getTrackIdentity");
29
+ Object.keys(_getTrackIdentity).forEach(function (key) {
30
+ if (key === "default" || key === "__esModule") return;
31
+ if (key in exports && exports[key] === _getTrackIdentity[key]) return;
32
+ Object.defineProperty(exports, key, {
33
+ enumerable: true,
34
+ get: function () {
35
+ return _getTrackIdentity[key];
36
+ }
37
+ });
38
+ });
28
39
  var _useDebug = require("./utils/useDebug");
29
40
  Object.keys(_useDebug).forEach(function (key) {
30
41
  if (key === "default" || key === "__esModule") return;
@@ -1 +1 @@
1
- {"version":3,"names":["_features","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_types","_useDebug"],"sourceRoot":"../../src","sources":["AudioBrowser.ts"],"mappings":";;;;;AACA,IAAAA,SAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,SAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,SAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,SAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,MAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,MAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,MAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,MAAA,CAAAL,GAAA;IAAA;EAAA;AAAA;AACA,IAAAM,SAAA,GAAAV,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAQ,SAAA,EAAAP,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAM,SAAA,CAAAN,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAE,SAAA,CAAAN,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
1
+ {"version":3,"names":["_features","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_types","_getTrackIdentity","_useDebug"],"sourceRoot":"../../src","sources":["AudioBrowser.ts"],"mappings":";;;;;AACA,IAAAA,SAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,SAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,SAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,SAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,MAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,MAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,MAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,MAAA,CAAAL,GAAA;IAAA;EAAA;AAAA;AACA,IAAAM,iBAAA,GAAAV,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAQ,iBAAA,EAAAP,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAM,iBAAA,CAAAN,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAE,iBAAA,CAAAN,GAAA;IAAA;EAAA;AAAA;AACA,IAAAO,SAAA,GAAAX,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAS,SAAA,EAAAR,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAO,SAAA,CAAAP,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAG,SAAA,CAAAP,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
@@ -22,9 +22,12 @@ function isObjectValue(value) {
22
22
  }
23
23
  function isTransformableRequestConfig(source) {
24
24
  if (!isObjectValue(source)) return false;
25
- // Any RequestConfig key marks a request config. A static ResolvedTrack
26
- // shares none of these at the top level (its per-track request override is
27
- // nested under `request`).
25
+ // A static ResolvedTrack page also carries a top-level `path`, so `path`
26
+ // alone cannot mark a request config. A page is recognised by its required
27
+ // `title` — no RequestConfig field is named `title`.
28
+ if ('title' in source) return false;
29
+ // Any RequestConfig key marks a request config. (A static ResolvedTrack's
30
+ // per-track request override is nested under `request`, not top-level.)
28
31
  return 'baseUrl' in source || 'path' in source || 'headers' in source || 'query' in source || 'method' in source || 'body' in source || 'contentType' in source || 'userAgent' in source || 'transform' in source || 'transformSync' in source;
29
32
  }
30
33
  function isRouteConfig(source) {
@@ -87,7 +90,7 @@ function searchSourceToRouteEntry(source) {
87
90
  */
88
91
  function wrapTracksAsResolvedTrack(tracks) {
89
92
  return {
90
- url: TABS_ROUTE_PATH,
93
+ path: TABS_ROUTE_PATH,
91
94
  title: 'Tabs',
92
95
  children: tracks
93
96
  };
@@ -191,10 +194,10 @@ function validateBrowserConfiguration(config) {
191
194
  continue;
192
195
  }
193
196
  if (!isCallback(source) && !isRouteConfig(source) && !isTransformableRequestConfig(source)) {
194
- // Falls through to the static-page branch; a page needs url + title.
197
+ // Falls through to the static-page branch; a page needs path + title.
195
198
  const page = source;
196
- if (typeof page.url !== 'string' || typeof page.title !== 'string') {
197
- warn(`route "${path}" matched no source shape — expected a callback, ` + `a request config ({ baseUrl, path, headers, ... }), a ` + `RouteConfig ({ browse, media, artwork }), or a static page ` + `({ url, title, children? }). It will be served as static ` + `content and likely render a blank screen.`);
199
+ if (typeof page.path !== 'string' || typeof page.title !== 'string') {
200
+ warn(`route "${path}" matched no source shape — expected a callback, ` + `a request config ({ baseUrl, path, headers, ... }), a ` + `RouteConfig ({ browse, media, artwork }), or a static page ` + `({ path, title, children? }). It will be served as static ` + `content and likely render a blank screen.`);
198
201
  }
199
202
  }
200
203
  }
@@ -220,7 +223,7 @@ function toNativeConfig(config) {
220
223
  handleTrackLoad: config.handleTrackLoad,
221
224
  androidControllerOfflineError: config.androidControllerOfflineError,
222
225
  carPlayLoadingTitle: config.carPlayLoadingTitle,
223
- resolveAlbumUrl: config.resolveAlbumUrl,
226
+ resolveAlbumPath: config.resolveAlbumPath,
224
227
  formatNavigationError: config.formatNavigationError
225
228
  };
226
229
  }
@@ -1 +1 @@
1
- {"version":3,"names":["isCallback","source","isObjectValue","value","isTransformableRequestConfig","isRouteConfig","artwork","splitLayer","layer","resolve","resolver","Promise","config","flattenBrowseSource","browseCallback","browseConfig","browseStatic","searchSourceToRouteEntry","path","SEARCH_ROUTE_PATH","searchCallback","searchConfig","wrapTracksAsResolvedTrack","tracks","url","TABS_ROUTE_PATH","title","children","tabsSourceToRouteEntry","Array","isArray","wrappedCallback","flattenRouteEntry","browse","media","DEFAULT_ROUTE_PATH","exports","flattenRoutes","routes","tabs","search","entries","Object","push","length","undefined","MAX_TABS","validateBrowserConfiguration","warn","message","console","startsWith","page","toNativeConfig","request","requestResolver","browseResolver","nowPlayingArtwork","singleTrack","handleTrackLoad","androidControllerOfflineError","carPlayLoadingTitle","resolveAlbumUrl","formatNavigationError"],"sourceRoot":"../../../src","sources":["features/browser-config.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["isCallback","source","isObjectValue","value","isTransformableRequestConfig","isRouteConfig","artwork","splitLayer","layer","resolve","resolver","Promise","config","flattenBrowseSource","browseCallback","browseConfig","browseStatic","searchSourceToRouteEntry","path","SEARCH_ROUTE_PATH","searchCallback","searchConfig","wrapTracksAsResolvedTrack","tracks","TABS_ROUTE_PATH","title","children","tabsSourceToRouteEntry","Array","isArray","wrappedCallback","flattenRouteEntry","browse","media","DEFAULT_ROUTE_PATH","exports","flattenRoutes","routes","tabs","search","entries","Object","push","length","undefined","MAX_TABS","validateBrowserConfiguration","warn","message","console","startsWith","page","toNativeConfig","request","requestResolver","browseResolver","nowPlayingArtwork","singleTrack","handleTrackLoad","androidControllerOfflineError","carPlayLoadingTitle","resolveAlbumPath","formatNavigationError"],"sourceRoot":"../../../src","sources":["features/browser-config.ts"],"mappings":"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","ignoreList":[]}
@@ -55,8 +55,8 @@ let currentConfiguration;
55
55
  * }
56
56
  * },
57
57
  * tabs: [
58
- * { title: 'Home', url: '/' },
59
- * { title: 'Search', url: '/search' }
58
+ * { title: 'Home', path: '/' },
59
+ * { title: 'Search', path: '/search' }
60
60
  * ]
61
61
  * })
62
62
  * ```