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