@5stones/react-native-audio-browser 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AudioBrowser.podspec +43 -0
- package/LICENSE +21 -0
- package/README.md +5 -0
- package/android/CMakeLists.txt +32 -0
- package/android/build.gradle +210 -0
- package/android/fix-prefab.gradle +51 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +36 -0
- package/android/src/main/cpp/cpp-adapter.cpp +6 -0
- package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +1191 -0
- package/android/src/main/java/com/audiobrowser/AudioBrowserPackage.kt +21 -0
- package/android/src/main/java/com/audiobrowser/Callbacks.kt +92 -0
- package/android/src/main/java/com/audiobrowser/HeadlessTaskService.kt +59 -0
- package/android/src/main/java/com/audiobrowser/Service.kt +336 -0
- package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +1169 -0
- package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +103 -0
- package/android/src/main/java/com/audiobrowser/browser/RouteMatch.kt +9 -0
- package/android/src/main/java/com/audiobrowser/browser/SimpleRouter.kt +150 -0
- package/android/src/main/java/com/audiobrowser/extension/EnumExtensions.kt +5 -0
- package/android/src/main/java/com/audiobrowser/extension/NumberExt.kt +13 -0
- package/android/src/main/java/com/audiobrowser/http/HttpClient.kt +171 -0
- package/android/src/main/java/com/audiobrowser/http/RequestConfigBuilder.kt +251 -0
- package/android/src/main/java/com/audiobrowser/model/PlaybackMetadata.kt +80 -0
- package/android/src/main/java/com/audiobrowser/model/PlayerSetupOptions.kt +101 -0
- package/android/src/main/java/com/audiobrowser/model/PlayerUpdateOptions.kt +125 -0
- package/android/src/main/java/com/audiobrowser/player/AutomaticBufferManager.kt +256 -0
- package/android/src/main/java/com/audiobrowser/player/DynamicLoadControl.kt +163 -0
- package/android/src/main/java/com/audiobrowser/player/MediaFactory.kt +177 -0
- package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +580 -0
- package/android/src/main/java/com/audiobrowser/player/MediaSessionCommandManager.kt +578 -0
- package/android/src/main/java/com/audiobrowser/player/PlaybackProgressUpdateManager.kt +58 -0
- package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +245 -0
- package/android/src/main/java/com/audiobrowser/player/Player.kt +1509 -0
- package/android/src/main/java/com/audiobrowser/player/PlayerListener.kt +230 -0
- package/android/src/main/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicy.kt +191 -0
- package/android/src/main/java/com/audiobrowser/player/SleepTimer.kt +80 -0
- package/android/src/main/java/com/audiobrowser/util/AndroidAudioContentTypeFactory.kt +17 -0
- package/android/src/main/java/com/audiobrowser/util/BatteryOptimizationHelper.kt +95 -0
- package/android/src/main/java/com/audiobrowser/util/BatteryWarningStore.kt +38 -0
- package/android/src/main/java/com/audiobrowser/util/BrowserPathHelper.kt +155 -0
- package/android/src/main/java/com/audiobrowser/util/CoilBitmapLoader.kt +390 -0
- package/android/src/main/java/com/audiobrowser/util/EqualizerManager.kt +197 -0
- package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +75 -0
- package/android/src/main/java/com/audiobrowser/util/MetadataAdapter.kt +97 -0
- package/android/src/main/java/com/audiobrowser/util/NetworkConnectivityMonitor.kt +121 -0
- package/android/src/main/java/com/audiobrowser/util/PlayingStateFactory.kt +25 -0
- package/android/src/main/java/com/audiobrowser/util/RatingFactory.kt +72 -0
- package/android/src/main/java/com/audiobrowser/util/RepeatModeFactory.kt +22 -0
- package/android/src/main/java/com/audiobrowser/util/ResolvedTrackFactory.kt +36 -0
- package/android/src/main/java/com/audiobrowser/util/SvgArtworkRenderer.kt +130 -0
- package/android/src/main/java/com/audiobrowser/util/SystemVolumeMonitor.kt +50 -0
- package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +125 -0
- package/android/src/main/res/values/strings.xml +6 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +273 -0
- package/android/src/test/java/com/audiobrowser/browser/SimpleBrowserTest.kt +33 -0
- package/android/src/test/java/com/audiobrowser/browser/SimpleRouterTest.kt +156 -0
- package/android/src/test/java/com/audiobrowser/http/RequestConfigBuilderTest.kt +240 -0
- package/ios/Bridge.h +8 -0
- package/ios/Browser/BrowserConfig.swift +85 -0
- package/ios/Browser/BrowserManager.swift +985 -0
- package/ios/Browser/BrowserPathHelper.swift +156 -0
- package/ios/Browser/JsonModels.swift +165 -0
- package/ios/Browser/SimpleRouter.swift +184 -0
- package/ios/CarPlay/CarPlayController.swift +1342 -0
- package/ios/CarPlay/RNABCarPlaySceneDelegate.h +15 -0
- package/ios/CarPlay/RNABCarPlaySceneDelegate.m +59 -0
- package/ios/CarPlay/Track+CarPlay.swift +49 -0
- package/ios/Extension/Capability+RemoteCommand.swift +76 -0
- package/ios/Extension/ChapterMetadata+AVFoundation.swift +37 -0
- package/ios/Extension/TimedMetadata+AVFoundation.swift +126 -0
- package/ios/Extension/Track+AVPlayer.swift +68 -0
- package/ios/Extension/TrackMetadata+AVFoundation.swift +128 -0
- package/ios/Http/HttpClient.swift +237 -0
- package/ios/HybridAudioBrowser.swift +1309 -0
- package/ios/Model/MediaURL.swift +66 -0
- package/ios/Model/PlayerUpdateOptions.swift +116 -0
- package/ios/Model/RemoteCommand.swift +71 -0
- package/ios/Model/SourceType.swift +6 -0
- package/ios/Model/TrackPlayerError.swift +69 -0
- package/ios/NowPlayingInfo/MediaItemProperty.swift +78 -0
- package/ios/NowPlayingInfo/NowPlayingInfoCenter.swift +9 -0
- package/ios/NowPlayingInfo/NowPlayingInfoController.swift +283 -0
- package/ios/NowPlayingInfo/NowPlayingInfoKeyValue.swift +6 -0
- package/ios/NowPlayingInfo/NowPlayingInfoProperty.swift +220 -0
- package/ios/Observer/PlayerItemNotificationObserver.swift +83 -0
- package/ios/Observer/PlayerItemPropertyObserver.swift +110 -0
- package/ios/Observer/PlayerStateObserver.swift +52 -0
- package/ios/Observer/PlayerTimeObserver.swift +109 -0
- package/ios/Option/PitchAlgorithms.swift +17 -0
- package/ios/Option/SessionCategories.swift +100 -0
- package/ios/Option/TimeEventFrequency.swift +18 -0
- package/ios/Player/PlaybackProgressUpdateManager.swift +60 -0
- package/ios/Player/PlayingStateManager.swift +29 -0
- package/ios/Player/RetryManager.swift +281 -0
- package/ios/Player/ShuffleOrder.swift +191 -0
- package/ios/Player/SleepTimerManager.swift +137 -0
- package/ios/RemoteCommand/RemoteCommandController.swift +400 -0
- package/ios/Support/RNTrackPlayer-Bridging-Header.h +7 -0
- package/ios/TrackPlayer.swift +1590 -0
- package/ios/TrackPlayerCallbacks.swift +121 -0
- package/ios/Util/Emitter.swift +46 -0
- package/ios/Util/LRUCache.swift +182 -0
- package/ios/Util/MetadataAdapter.swift +131 -0
- package/ios/Util/NetworkMonitor.swift +68 -0
- package/ios/Util/OnceValue.swift +70 -0
- package/ios/Util/SVGProcessor.swift +56 -0
- package/lib/commonjs/AudioBrowser.js +50 -0
- package/lib/commonjs/AudioBrowser.js.map +1 -0
- package/lib/commonjs/features/battery.js +154 -0
- package/lib/commonjs/features/battery.js.map +1 -0
- package/lib/commonjs/features/browser.js +271 -0
- package/lib/commonjs/features/browser.js.map +1 -0
- package/lib/commonjs/features/equalizer.js +69 -0
- package/lib/commonjs/features/equalizer.js.map +1 -0
- package/lib/commonjs/features/errors.js +165 -0
- package/lib/commonjs/features/errors.js.map +1 -0
- package/lib/commonjs/features/favorites.js +101 -0
- package/lib/commonjs/features/favorites.js.map +1 -0
- package/lib/commonjs/features/index.js +160 -0
- package/lib/commonjs/features/index.js.map +1 -0
- package/lib/commonjs/features/metadata.js +54 -0
- package/lib/commonjs/features/metadata.js.map +1 -0
- package/lib/commonjs/features/network.js +40 -0
- package/lib/commonjs/features/network.js.map +1 -0
- package/lib/commonjs/features/nowPlaying.js +61 -0
- package/lib/commonjs/features/nowPlaying.js.map +1 -0
- package/lib/commonjs/features/output.js +54 -0
- package/lib/commonjs/features/output.js.map +1 -0
- package/lib/commonjs/features/playback/controls.js +79 -0
- package/lib/commonjs/features/playback/controls.js.map +1 -0
- package/lib/commonjs/features/playback/index.js +83 -0
- package/lib/commonjs/features/playback/index.js.map +1 -0
- package/lib/commonjs/features/playback/playWhenReady.js +55 -0
- package/lib/commonjs/features/playback/playWhenReady.js.map +1 -0
- package/lib/commonjs/features/playback/playing.js +41 -0
- package/lib/commonjs/features/playback/playing.js.map +1 -0
- package/lib/commonjs/features/playback/progress.js +104 -0
- package/lib/commonjs/features/playback/progress.js.map +1 -0
- package/lib/commonjs/features/playback/rate.js +29 -0
- package/lib/commonjs/features/playback/rate.js.map +1 -0
- package/lib/commonjs/features/playback/state.js +62 -0
- package/lib/commonjs/features/playback/state.js.map +1 -0
- package/lib/commonjs/features/playback/volume.js +68 -0
- package/lib/commonjs/features/playback/volume.js.map +1 -0
- package/lib/commonjs/features/player/index.js +28 -0
- package/lib/commonjs/features/player/index.js.map +1 -0
- package/lib/commonjs/features/player/options.js +182 -0
- package/lib/commonjs/features/player/options.js.map +1 -0
- package/lib/commonjs/features/player/setup.js +143 -0
- package/lib/commonjs/features/player/setup.js.map +1 -0
- package/lib/commonjs/features/queue/activeTrack.js +52 -0
- package/lib/commonjs/features/queue/activeTrack.js.map +1 -0
- package/lib/commonjs/features/queue/index.js +50 -0
- package/lib/commonjs/features/queue/index.js.map +1 -0
- package/lib/commonjs/features/queue/queue.js +177 -0
- package/lib/commonjs/features/queue/queue.js.map +1 -0
- package/lib/commonjs/features/queue/repeatMode.js +58 -0
- package/lib/commonjs/features/queue/repeatMode.js.map +1 -0
- package/lib/commonjs/features/queue/shuffle.js +57 -0
- package/lib/commonjs/features/queue/shuffle.js.map +1 -0
- package/lib/commonjs/features/rating.js +2 -0
- package/lib/commonjs/features/rating.js.map +1 -0
- package/lib/commonjs/features/remoteControls.js +286 -0
- package/lib/commonjs/features/remoteControls.js.map +1 -0
- package/lib/commonjs/features/sleepTimer.js +164 -0
- package/lib/commonjs/features/sleepTimer.js.map +1 -0
- package/lib/commonjs/index.js +22 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/native.js +9 -0
- package/lib/commonjs/native.js.map +1 -0
- package/lib/commonjs/native.web.js +10 -0
- package/lib/commonjs/native.web.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/specs/audio-browser.nitro.js +6 -0
- package/lib/commonjs/specs/audio-browser.nitro.js.map +1 -0
- package/lib/commonjs/types/browser-native.js +6 -0
- package/lib/commonjs/types/browser-native.js.map +1 -0
- package/lib/commonjs/types/browser-nodes.js +6 -0
- package/lib/commonjs/types/browser-nodes.js.map +1 -0
- package/lib/commonjs/types/browser.js +6 -0
- package/lib/commonjs/types/browser.js.map +1 -0
- package/lib/commonjs/types/index.js +28 -0
- package/lib/commonjs/types/index.js.map +1 -0
- package/lib/commonjs/types/player.js +2 -0
- package/lib/commonjs/types/player.js.map +1 -0
- package/lib/commonjs/utils/LazyNativeEmitter.js +58 -0
- package/lib/commonjs/utils/LazyNativeEmitter.js.map +1 -0
- package/lib/commonjs/utils/NativeUpdatedValue.js +59 -0
- package/lib/commonjs/utils/NativeUpdatedValue.js.map +1 -0
- package/lib/commonjs/utils/resolveAssetSource.js +11 -0
- package/lib/commonjs/utils/resolveAssetSource.js.map +1 -0
- package/lib/commonjs/utils/useDebug.js +221 -0
- package/lib/commonjs/utils/useDebug.js.map +1 -0
- package/lib/commonjs/utils/useNativeUpdatedValue.js +44 -0
- package/lib/commonjs/utils/useNativeUpdatedValue.js.map +1 -0
- package/lib/commonjs/web/NativeAudioBrowser.js +668 -0
- package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -0
- package/lib/commonjs/web/SimpleRouter.js +144 -0
- package/lib/commonjs/web/SimpleRouter.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/Event.js +19 -0
- package/lib/commonjs/web/TrackPlayer/Event.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/Player.js +276 -0
- package/lib/commonjs/web/TrackPlayer/Player.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/PlaylistPlayer.js +284 -0
- package/lib/commonjs/web/TrackPlayer/PlaylistPlayer.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/RepeatMode.js +12 -0
- package/lib/commonjs/web/TrackPlayer/RepeatMode.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/SetupNotCalledError.js +13 -0
- package/lib/commonjs/web/TrackPlayer/SetupNotCalledError.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/SleepTimer.js +75 -0
- package/lib/commonjs/web/TrackPlayer/SleepTimer.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/State.js +18 -0
- package/lib/commonjs/web/TrackPlayer/State.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/index.js +52 -0
- package/lib/commonjs/web/TrackPlayer/index.js.map +1 -0
- package/lib/commonjs/web/browser/BrowserManager.js +594 -0
- package/lib/commonjs/web/browser/BrowserManager.js.map +1 -0
- package/lib/commonjs/web/browser/FavoriteManager.js +80 -0
- package/lib/commonjs/web/browser/FavoriteManager.js.map +1 -0
- package/lib/commonjs/web/browser/NavigationErrorManager.js +106 -0
- package/lib/commonjs/web/browser/NavigationErrorManager.js.map +1 -0
- package/lib/commonjs/web/browser/SearchManager.js +80 -0
- package/lib/commonjs/web/browser/SearchManager.js.map +1 -0
- package/lib/commonjs/web/http/HttpClient.js +81 -0
- package/lib/commonjs/web/http/HttpClient.js.map +1 -0
- package/lib/commonjs/web/http/RequestConfigBuilder.js +294 -0
- package/lib/commonjs/web/http/RequestConfigBuilder.js.map +1 -0
- package/lib/commonjs/web/player/NowPlayingManager.js +70 -0
- package/lib/commonjs/web/player/NowPlayingManager.js.map +1 -0
- package/lib/commonjs/web/player/OptionsManager.js +88 -0
- package/lib/commonjs/web/player/OptionsManager.js.map +1 -0
- package/lib/commonjs/web/util/BrowserPathHelper.js +138 -0
- package/lib/commonjs/web/util/BrowserPathHelper.js.map +1 -0
- package/lib/commonjs/web/util/shuffle.js +21 -0
- package/lib/commonjs/web/util/shuffle.js.map +1 -0
- package/lib/module/AudioBrowser.js +7 -0
- package/lib/module/AudioBrowser.js.map +1 -0
- package/lib/module/features/battery.js +144 -0
- package/lib/module/features/battery.js.map +1 -0
- package/lib/module/features/browser.js +257 -0
- package/lib/module/features/browser.js.map +1 -0
- package/lib/module/features/equalizer.js +60 -0
- package/lib/module/features/equalizer.js.map +1 -0
- package/lib/module/features/errors.js +156 -0
- package/lib/module/features/errors.js.map +1 -0
- package/lib/module/features/favorites.js +95 -0
- package/lib/module/features/favorites.js.map +1 -0
- package/lib/module/features/index.js +26 -0
- package/lib/module/features/index.js.map +1 -0
- package/lib/module/features/metadata.js +51 -0
- package/lib/module/features/metadata.js.map +1 -0
- package/lib/module/features/network.js +35 -0
- package/lib/module/features/network.js.map +1 -0
- package/lib/module/features/nowPlaying.js +54 -0
- package/lib/module/features/nowPlaying.js.map +1 -0
- package/lib/module/features/output.js +47 -0
- package/lib/module/features/output.js.map +1 -0
- package/lib/module/features/playback/controls.js +69 -0
- package/lib/module/features/playback/controls.js.map +1 -0
- package/lib/module/features/playback/index.js +10 -0
- package/lib/module/features/playback/index.js.map +1 -0
- package/lib/module/features/playback/playWhenReady.js +49 -0
- package/lib/module/features/playback/playWhenReady.js.map +1 -0
- package/lib/module/features/playback/playing.js +36 -0
- package/lib/module/features/playback/playing.js.map +1 -0
- package/lib/module/features/playback/progress.js +98 -0
- package/lib/module/features/playback/progress.js.map +1 -0
- package/lib/module/features/playback/rate.js +25 -0
- package/lib/module/features/playback/rate.js.map +1 -0
- package/lib/module/features/playback/state.js +57 -0
- package/lib/module/features/playback/state.js.map +1 -0
- package/lib/module/features/playback/volume.js +60 -0
- package/lib/module/features/playback/volume.js.map +1 -0
- package/lib/module/features/player/index.js +5 -0
- package/lib/module/features/player/index.js.map +1 -0
- package/lib/module/features/player/options.js +176 -0
- package/lib/module/features/player/options.js.map +1 -0
- package/lib/module/features/player/setup.js +140 -0
- package/lib/module/features/player/setup.js.map +1 -0
- package/lib/module/features/queue/activeTrack.js +46 -0
- package/lib/module/features/queue/activeTrack.js.map +1 -0
- package/lib/module/features/queue/index.js +7 -0
- package/lib/module/features/queue/index.js.map +1 -0
- package/lib/module/features/queue/queue.js +162 -0
- package/lib/module/features/queue/queue.js.map +1 -0
- package/lib/module/features/queue/repeatMode.js +52 -0
- package/lib/module/features/queue/repeatMode.js.map +1 -0
- package/lib/module/features/queue/shuffle.js +50 -0
- package/lib/module/features/queue/shuffle.js.map +1 -0
- package/lib/module/features/rating.js +2 -0
- package/lib/module/features/rating.js.map +1 -0
- package/lib/module/features/remoteControls.js +275 -0
- package/lib/module/features/remoteControls.js.map +1 -0
- package/lib/module/features/sleepTimer.js +155 -0
- package/lib/module/features/sleepTimer.js.map +1 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/native.js +5 -0
- package/lib/module/native.js.map +1 -0
- package/lib/module/native.web.js +7 -0
- package/lib/module/native.web.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/specs/audio-browser.nitro.js +4 -0
- package/lib/module/specs/audio-browser.nitro.js.map +1 -0
- package/lib/module/types/browser-native.js +4 -0
- package/lib/module/types/browser-native.js.map +1 -0
- package/lib/module/types/browser-nodes.js +4 -0
- package/lib/module/types/browser-nodes.js.map +1 -0
- package/lib/module/types/browser.js +4 -0
- package/lib/module/types/browser.js.map +1 -0
- package/lib/module/types/index.js +5 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/module/types/player.js +2 -0
- package/lib/module/types/player.js.map +1 -0
- package/lib/module/utils/LazyNativeEmitter.js +53 -0
- package/lib/module/utils/LazyNativeEmitter.js.map +1 -0
- package/lib/module/utils/NativeUpdatedValue.js +54 -0
- package/lib/module/utils/NativeUpdatedValue.js.map +1 -0
- package/lib/module/utils/resolveAssetSource.js +7 -0
- package/lib/module/utils/resolveAssetSource.js.map +1 -0
- package/lib/module/utils/useDebug.js +218 -0
- package/lib/module/utils/useDebug.js.map +1 -0
- package/lib/module/utils/useNativeUpdatedValue.js +40 -0
- package/lib/module/utils/useNativeUpdatedValue.js.map +1 -0
- package/lib/module/web/NativeAudioBrowser.js +664 -0
- package/lib/module/web/NativeAudioBrowser.js.map +1 -0
- package/lib/module/web/SimpleRouter.js +139 -0
- package/lib/module/web/SimpleRouter.js.map +1 -0
- package/lib/module/web/TrackPlayer/Event.js +15 -0
- package/lib/module/web/TrackPlayer/Event.js.map +1 -0
- package/lib/module/web/TrackPlayer/Player.js +271 -0
- package/lib/module/web/TrackPlayer/Player.js.map +1 -0
- package/lib/module/web/TrackPlayer/PlaylistPlayer.js +279 -0
- package/lib/module/web/TrackPlayer/PlaylistPlayer.js.map +1 -0
- package/lib/module/web/TrackPlayer/RepeatMode.js +8 -0
- package/lib/module/web/TrackPlayer/RepeatMode.js.map +1 -0
- package/lib/module/web/TrackPlayer/SetupNotCalledError.js +8 -0
- package/lib/module/web/TrackPlayer/SetupNotCalledError.js.map +1 -0
- package/lib/module/web/TrackPlayer/SleepTimer.js +70 -0
- package/lib/module/web/TrackPlayer/SleepTimer.js.map +1 -0
- package/lib/module/web/TrackPlayer/State.js +14 -0
- package/lib/module/web/TrackPlayer/State.js.map +1 -0
- package/lib/module/web/TrackPlayer/index.js +7 -0
- package/lib/module/web/TrackPlayer/index.js.map +1 -0
- package/lib/module/web/browser/BrowserManager.js +590 -0
- package/lib/module/web/browser/BrowserManager.js.map +1 -0
- package/lib/module/web/browser/FavoriteManager.js +75 -0
- package/lib/module/web/browser/FavoriteManager.js.map +1 -0
- package/lib/module/web/browser/NavigationErrorManager.js +101 -0
- package/lib/module/web/browser/NavigationErrorManager.js.map +1 -0
- package/lib/module/web/browser/SearchManager.js +76 -0
- package/lib/module/web/browser/SearchManager.js.map +1 -0
- package/lib/module/web/http/HttpClient.js +76 -0
- package/lib/module/web/http/HttpClient.js.map +1 -0
- package/lib/module/web/http/RequestConfigBuilder.js +291 -0
- package/lib/module/web/http/RequestConfigBuilder.js.map +1 -0
- package/lib/module/web/player/NowPlayingManager.js +65 -0
- package/lib/module/web/player/NowPlayingManager.js.map +1 -0
- package/lib/module/web/player/OptionsManager.js +83 -0
- package/lib/module/web/player/OptionsManager.js.map +1 -0
- package/lib/module/web/util/BrowserPathHelper.js +134 -0
- package/lib/module/web/util/BrowserPathHelper.js.map +1 -0
- package/lib/module/web/util/shuffle.js +17 -0
- package/lib/module/web/util/shuffle.js.map +1 -0
- package/lib/typescript/src/AudioBrowser.d.ts +5 -0
- package/lib/typescript/src/AudioBrowser.d.ts.map +1 -0
- package/lib/typescript/src/features/battery.d.ts +112 -0
- package/lib/typescript/src/features/battery.d.ts.map +1 -0
- package/lib/typescript/src/features/browser.d.ts +68 -0
- package/lib/typescript/src/features/browser.d.ts.map +1 -0
- package/lib/typescript/src/features/equalizer.d.ts +35 -0
- package/lib/typescript/src/features/equalizer.d.ts.map +1 -0
- package/lib/typescript/src/features/errors.d.ts +136 -0
- package/lib/typescript/src/features/errors.d.ts.map +1 -0
- package/lib/typescript/src/features/favorites.d.ts +84 -0
- package/lib/typescript/src/features/favorites.d.ts.map +1 -0
- package/lib/typescript/src/features/index.d.ts +23 -0
- package/lib/typescript/src/features/index.d.ts.map +1 -0
- package/lib/typescript/src/features/metadata.d.ts +103 -0
- package/lib/typescript/src/features/metadata.d.ts.map +1 -0
- package/lib/typescript/src/features/network.d.ts +18 -0
- package/lib/typescript/src/features/network.d.ts.map +1 -0
- package/lib/typescript/src/features/nowPlaying.d.ts +36 -0
- package/lib/typescript/src/features/nowPlaying.d.ts.map +1 -0
- package/lib/typescript/src/features/output.d.ts +28 -0
- package/lib/typescript/src/features/output.d.ts.map +1 -0
- package/lib/typescript/src/features/playback/controls.d.ts +40 -0
- package/lib/typescript/src/features/playback/controls.d.ts.map +1 -0
- package/lib/typescript/src/features/playback/index.d.ts +8 -0
- package/lib/typescript/src/features/playback/index.d.ts.map +1 -0
- package/lib/typescript/src/features/playback/playWhenReady.d.ts +30 -0
- package/lib/typescript/src/features/playback/playWhenReady.d.ts.map +1 -0
- package/lib/typescript/src/features/playback/playing.d.ts +21 -0
- package/lib/typescript/src/features/playback/playing.d.ts.map +1 -0
- package/lib/typescript/src/features/playback/progress.d.ts +51 -0
- package/lib/typescript/src/features/playback/progress.d.ts.map +1 -0
- package/lib/typescript/src/features/playback/rate.d.ts +12 -0
- package/lib/typescript/src/features/playback/rate.d.ts.map +1 -0
- package/lib/typescript/src/features/playback/state.d.ts +43 -0
- package/lib/typescript/src/features/playback/state.d.ts.map +1 -0
- package/lib/typescript/src/features/playback/volume.d.ts +32 -0
- package/lib/typescript/src/features/playback/volume.d.ts.map +1 -0
- package/lib/typescript/src/features/player/index.d.ts +3 -0
- package/lib/typescript/src/features/player/index.d.ts.map +1 -0
- package/lib/typescript/src/features/player/options.d.ts +413 -0
- package/lib/typescript/src/features/player/options.d.ts.map +1 -0
- package/lib/typescript/src/features/player/setup.d.ts +471 -0
- package/lib/typescript/src/features/player/setup.d.ts.map +1 -0
- package/lib/typescript/src/features/queue/activeTrack.d.ts +38 -0
- package/lib/typescript/src/features/queue/activeTrack.d.ts.map +1 -0
- package/lib/typescript/src/features/queue/index.d.ts +5 -0
- package/lib/typescript/src/features/queue/index.d.ts.map +1 -0
- package/lib/typescript/src/features/queue/queue.d.ts +111 -0
- package/lib/typescript/src/features/queue/queue.d.ts.map +1 -0
- package/lib/typescript/src/features/queue/repeatMode.d.ts +34 -0
- package/lib/typescript/src/features/queue/repeatMode.d.ts.map +1 -0
- package/lib/typescript/src/features/queue/shuffle.d.ts +27 -0
- package/lib/typescript/src/features/queue/shuffle.d.ts.map +1 -0
- package/lib/typescript/src/features/rating.d.ts +14 -0
- package/lib/typescript/src/features/rating.d.ts.map +1 -0
- package/lib/typescript/src/features/remoteControls.d.ts +164 -0
- package/lib/typescript/src/features/remoteControls.d.ts.map +1 -0
- package/lib/typescript/src/features/sleepTimer.d.ts +80 -0
- package/lib/typescript/src/features/sleepTimer.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/native.d.ts +3 -0
- package/lib/typescript/src/native.d.ts.map +1 -0
- package/lib/typescript/src/native.web.d.ts +3 -0
- package/lib/typescript/src/native.web.d.ts.map +1 -0
- package/lib/typescript/src/specs/audio-browser.nitro.d.ts +242 -0
- package/lib/typescript/src/specs/audio-browser.nitro.d.ts.map +1 -0
- package/lib/typescript/src/types/browser-native.d.ts +39 -0
- package/lib/typescript/src/types/browser-native.d.ts.map +1 -0
- package/lib/typescript/src/types/browser-nodes.d.ts +153 -0
- package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -0
- package/lib/typescript/src/types/browser.d.ts +710 -0
- package/lib/typescript/src/types/browser.d.ts.map +1 -0
- package/lib/typescript/src/types/index.d.ts +3 -0
- package/lib/typescript/src/types/index.d.ts.map +1 -0
- package/lib/typescript/src/types/player.d.ts +64 -0
- package/lib/typescript/src/types/player.d.ts.map +1 -0
- package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +35 -0
- package/lib/typescript/src/utils/LazyNativeEmitter.d.ts.map +1 -0
- package/lib/typescript/src/utils/NativeUpdatedValue.d.ts +39 -0
- package/lib/typescript/src/utils/NativeUpdatedValue.d.ts.map +1 -0
- package/lib/typescript/src/utils/resolveAssetSource.d.ts +4 -0
- package/lib/typescript/src/utils/resolveAssetSource.d.ts.map +1 -0
- package/lib/typescript/src/utils/useDebug.d.ts +65 -0
- package/lib/typescript/src/utils/useDebug.d.ts.map +1 -0
- package/lib/typescript/src/utils/useNativeUpdatedValue.d.ts +14 -0
- package/lib/typescript/src/utils/useNativeUpdatedValue.d.ts.map +1 -0
- package/lib/typescript/src/web/NativeAudioBrowser.d.ts +176 -0
- package/lib/typescript/src/web/NativeAudioBrowser.d.ts.map +1 -0
- package/lib/typescript/src/web/SimpleRouter.d.ts +40 -0
- package/lib/typescript/src/web/SimpleRouter.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/Event.d.ts +11 -0
- package/lib/typescript/src/web/TrackPlayer/Event.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/Player.d.ts +71 -0
- package/lib/typescript/src/web/TrackPlayer/Player.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/PlaylistPlayer.d.ts +39 -0
- package/lib/typescript/src/web/TrackPlayer/PlaylistPlayer.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/RepeatMode.d.ts +6 -0
- package/lib/typescript/src/web/TrackPlayer/RepeatMode.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/SetupNotCalledError.d.ts +4 -0
- package/lib/typescript/src/web/TrackPlayer/SetupNotCalledError.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/SleepTimer.d.ts +34 -0
- package/lib/typescript/src/web/TrackPlayer/SleepTimer.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/State.d.ts +13 -0
- package/lib/typescript/src/web/TrackPlayer/State.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/index.d.ts +5 -0
- package/lib/typescript/src/web/TrackPlayer/index.d.ts.map +1 -0
- package/lib/typescript/src/web/browser/BrowserManager.d.ts +154 -0
- package/lib/typescript/src/web/browser/BrowserManager.d.ts.map +1 -0
- package/lib/typescript/src/web/browser/FavoriteManager.d.ts +42 -0
- package/lib/typescript/src/web/browser/FavoriteManager.d.ts.map +1 -0
- package/lib/typescript/src/web/browser/NavigationErrorManager.d.ts +40 -0
- package/lib/typescript/src/web/browser/NavigationErrorManager.d.ts.map +1 -0
- package/lib/typescript/src/web/browser/SearchManager.d.ts +22 -0
- package/lib/typescript/src/web/browser/SearchManager.d.ts.map +1 -0
- package/lib/typescript/src/web/http/HttpClient.d.ts +25 -0
- package/lib/typescript/src/web/http/HttpClient.d.ts.map +1 -0
- package/lib/typescript/src/web/http/RequestConfigBuilder.d.ts +98 -0
- package/lib/typescript/src/web/http/RequestConfigBuilder.d.ts.map +1 -0
- package/lib/typescript/src/web/player/NowPlayingManager.d.ts +34 -0
- package/lib/typescript/src/web/player/NowPlayingManager.d.ts.map +1 -0
- package/lib/typescript/src/web/player/OptionsManager.d.ts +32 -0
- package/lib/typescript/src/web/player/OptionsManager.d.ts.map +1 -0
- package/lib/typescript/src/web/util/BrowserPathHelper.d.ts +69 -0
- package/lib/typescript/src/web/util/BrowserPathHelper.d.ts.map +1 -0
- package/lib/typescript/src/web/util/shuffle.d.ts +8 -0
- package/lib/typescript/src/web/util/shuffle.d.ts.map +1 -0
- package/nitro.json +24 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +88 -0
- package/nitrogen/generated/android/AudioBrowser+autolinking.gradle +27 -0
- package/nitrogen/generated/android/AudioBrowserOnLoad.cpp +124 -0
- package/nitrogen/generated/android/AudioBrowserOnLoad.hpp +25 -0
- package/nitrogen/generated/android/c++/JAndroidAudioContentType.hpp +68 -0
- package/nitrogen/generated/android/c++/JAndroidAudioOffloadSettings.hpp +61 -0
- package/nitrogen/generated/android/c++/JAndroidOptions.hpp +86 -0
- package/nitrogen/generated/android/c++/JAndroidPlayerWakeMode.hpp +62 -0
- package/nitrogen/generated/android/c++/JAndroidUpdateOptions.hpp +86 -0
- package/nitrogen/generated/android/c++/JAppKilledPlaybackBehavior.hpp +62 -0
- package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +163 -0
- package/nitrogen/generated/android/c++/JBatteryOptimizationStatus.hpp +62 -0
- package/nitrogen/generated/android/c++/JBatteryOptimizationStatusChangedEvent.hpp +58 -0
- package/nitrogen/generated/android/c++/JBatteryWarningPendingChangedEvent.hpp +57 -0
- package/nitrogen/generated/android/c++/JBrowseError.hpp +57 -0
- package/nitrogen/generated/android/c++/JBrowseResult.cpp +26 -0
- package/nitrogen/generated/android/c++/JBrowseResult.hpp +83 -0
- package/nitrogen/generated/android/c++/JBrowserSourceCallbackParam.hpp +76 -0
- package/nitrogen/generated/android/c++/JCarPlayNowPlayingButton.hpp +65 -0
- package/nitrogen/generated/android/c++/JChapterMetadata.hpp +70 -0
- package/nitrogen/generated/android/c++/JEqualizerSettings.hpp +125 -0
- package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +71 -0
- package/nitrogen/generated/android/c++/JFormatNavigationErrorParams.hpp +72 -0
- package/nitrogen/generated/android/c++/JFormattedNavigationError.hpp +61 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.hpp +111 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.hpp +134 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____RequestConfig_std__optional_std__unordered_map_std__string__std__string__.hpp +143 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +136 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.hpp +143 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +157 -0
- package/nitrogen/generated/android/c++/JFunc_void.hpp +75 -0
- package/nitrogen/generated/android/c++/JFunc_void_BatteryOptimizationStatusChangedEvent.hpp +79 -0
- package/nitrogen/generated/android/c++/JFunc_void_BatteryWarningPendingChangedEvent.hpp +77 -0
- package/nitrogen/generated/android/c++/JFunc_void_EqualizerSettings.hpp +80 -0
- package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +88 -0
- package/nitrogen/generated/android/c++/JFunc_void_IosOutput.hpp +80 -0
- package/nitrogen/generated/android/c++/JFunc_void_NavigationErrorEvent.hpp +83 -0
- package/nitrogen/generated/android/c++/JFunc_void_NowPlayingMetadata.hpp +89 -0
- package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +98 -0
- package/nitrogen/generated/android/c++/JFunc_void_Playback.hpp +83 -0
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +88 -0
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackErrorEvent.hpp +81 -0
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackPlayWhenReadyChangedEvent.hpp +77 -0
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackProgressUpdatedEvent.hpp +77 -0
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackQueueEndedEvent.hpp +77 -0
- package/nitrogen/generated/android/c++/JFunc_void_PlayingState.hpp +77 -0
- package/nitrogen/generated/android/c++/JFunc_void_RemoteJumpBackwardEvent.hpp +77 -0
- package/nitrogen/generated/android/c++/JFunc_void_RemoteJumpForwardEvent.hpp +77 -0
- package/nitrogen/generated/android/c++/JFunc_void_RemotePlayIdEvent.hpp +79 -0
- package/nitrogen/generated/android/c++/JFunc_void_RemotePlaySearchEvent.hpp +78 -0
- package/nitrogen/generated/android/c++/JFunc_void_RemoteSeekEvent.hpp +77 -0
- package/nitrogen/generated/android/c++/JFunc_void_RemoteSetRatingEvent.hpp +87 -0
- package/nitrogen/generated/android/c++/JFunc_void_RemoteSkipEvent.hpp +77 -0
- package/nitrogen/generated/android/c++/JFunc_void_RepeatModeChangedEvent.hpp +79 -0
- package/nitrogen/generated/android/c++/JFunc_void_TimedMetadata.hpp +79 -0
- package/nitrogen/generated/android/c++/JFunc_void_TrackMetadata.hpp +79 -0
- package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +75 -0
- package/nitrogen/generated/android/c++/JFunc_void_double.hpp +75 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_FormattedNavigationError_.hpp +79 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +89 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.hpp +84 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +76 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_ChapterMetadata_.hpp +98 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +105 -0
- package/nitrogen/generated/android/c++/JHeartRating.hpp +57 -0
- package/nitrogen/generated/android/c++/JHttpMethod.hpp +74 -0
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +1811 -0
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.hpp +250 -0
- package/nitrogen/generated/android/c++/JIOSCategory.hpp +71 -0
- package/nitrogen/generated/android/c++/JIOSCategoryMode.hpp +80 -0
- package/nitrogen/generated/android/c++/JIOSCategoryOptions.hpp +74 -0
- package/nitrogen/generated/android/c++/JIOSCategoryPolicy.hpp +62 -0
- package/nitrogen/generated/android/c++/JImageContext.hpp +61 -0
- package/nitrogen/generated/android/c++/JImageQueryParams.hpp +62 -0
- package/nitrogen/generated/android/c++/JImageSource.hpp +86 -0
- package/nitrogen/generated/android/c++/JIosOutput.hpp +67 -0
- package/nitrogen/generated/android/c++/JIosOutputType.hpp +86 -0
- package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +153 -0
- package/nitrogen/generated/android/c++/JMediaTransformParams.hpp +69 -0
- package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +196 -0
- package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +147 -0
- package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +105 -0
- package/nitrogen/generated/android/c++/JNavigationError.hpp +72 -0
- package/nitrogen/generated/android/c++/JNavigationErrorEvent.hpp +62 -0
- package/nitrogen/generated/android/c++/JNavigationErrorType.hpp +68 -0
- package/nitrogen/generated/android/c++/JNitroAndroidUpdateOptions.hpp +86 -0
- package/nitrogen/generated/android/c++/JNotificationButton.hpp +68 -0
- package/nitrogen/generated/android/c++/JNotificationButtonLayout.hpp +94 -0
- package/nitrogen/generated/android/c++/JNowPlayingMetadata.hpp +104 -0
- package/nitrogen/generated/android/c++/JNowPlayingUpdate.hpp +62 -0
- package/nitrogen/generated/android/c++/JOptions.hpp +97 -0
- package/nitrogen/generated/android/c++/JPartialAndroidSetupPlayerOptions.hpp +104 -0
- package/nitrogen/generated/android/c++/JPartialIOSSetupPlayerOptions.hpp +100 -0
- package/nitrogen/generated/android/c++/JPartialSetupPlayerOptions.hpp +96 -0
- package/nitrogen/generated/android/c++/JPercentageRating.hpp +57 -0
- package/nitrogen/generated/android/c++/JPlayback.hpp +66 -0
- package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +83 -0
- package/nitrogen/generated/android/c++/JPlaybackError.hpp +61 -0
- package/nitrogen/generated/android/c++/JPlaybackErrorEvent.hpp +60 -0
- package/nitrogen/generated/android/c++/JPlaybackPlayWhenReadyChangedEvent.hpp +57 -0
- package/nitrogen/generated/android/c++/JPlaybackProgressUpdatedEvent.hpp +69 -0
- package/nitrogen/generated/android/c++/JPlaybackQueueEndedEvent.hpp +61 -0
- package/nitrogen/generated/android/c++/JPlaybackState.hpp +80 -0
- package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +101 -0
- package/nitrogen/generated/android/c++/JPlayingState.hpp +61 -0
- package/nitrogen/generated/android/c++/JProgress.hpp +65 -0
- package/nitrogen/generated/android/c++/JRatingType.hpp +74 -0
- package/nitrogen/generated/android/c++/JRemoteJumpBackwardEvent.hpp +57 -0
- package/nitrogen/generated/android/c++/JRemoteJumpForwardEvent.hpp +57 -0
- package/nitrogen/generated/android/c++/JRemotePlayIdEvent.hpp +62 -0
- package/nitrogen/generated/android/c++/JRemotePlaySearchEvent.hpp +57 -0
- package/nitrogen/generated/android/c++/JRemoteSeekEvent.hpp +57 -0
- package/nitrogen/generated/android/c++/JRemoteSetRatingEvent.hpp +66 -0
- package/nitrogen/generated/android/c++/JRemoteSkipEvent.hpp +57 -0
- package/nitrogen/generated/android/c++/JRepeatMode.hpp +62 -0
- package/nitrogen/generated/android/c++/JRepeatModeChangedEvent.hpp +58 -0
- package/nitrogen/generated/android/c++/JRequestConfig.hpp +115 -0
- package/nitrogen/generated/android/c++/JResolvedTrack.hpp +154 -0
- package/nitrogen/generated/android/c++/JRetryConfig.hpp +61 -0
- package/nitrogen/generated/android/c++/JSearchMode.hpp +71 -0
- package/nitrogen/generated/android/c++/JSearchParams.hpp +84 -0
- package/nitrogen/generated/android/c++/JSleepTimer.cpp +30 -0
- package/nitrogen/generated/android/c++/JSleepTimer.hpp +88 -0
- package/nitrogen/generated/android/c++/JSleepTimerEndOfTrack.hpp +57 -0
- package/nitrogen/generated/android/c++/JSleepTimerTime.hpp +57 -0
- package/nitrogen/generated/android/c++/JStarRating.hpp +57 -0
- package/nitrogen/generated/android/c++/JThumbsRating.hpp +57 -0
- package/nitrogen/generated/android/c++/JTimedMetadata.hpp +74 -0
- package/nitrogen/generated/android/c++/JTrack.hpp +129 -0
- package/nitrogen/generated/android/c++/JTrackMetadata.hpp +118 -0
- package/nitrogen/generated/android/c++/JTrackStyle.hpp +59 -0
- package/nitrogen/generated/android/c++/JTransformableRequestConfig.hpp +134 -0
- package/nitrogen/generated/android/c++/JUpdateOptions.hpp +105 -0
- package/nitrogen/generated/android/c++/JVariant_Boolean_AndroidAudioOffloadSettings.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_Boolean_AndroidAudioOffloadSettings.hpp +70 -0
- package/nitrogen/generated/android/c++/JVariant_Boolean_RetryConfig.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_Boolean_RetryConfig.hpp +70 -0
- package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.cpp +34 -0
- package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.hpp +105 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_Double.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_Double.hpp +69 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.hpp +75 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidAudioContentType.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidAudioOffloadSettings.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidOptions.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidPlayerWakeMode.kt +22 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidUpdateOptions.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AppKilledPlaybackBehavior.kt +22 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ArtworkRequestConfig.kt +72 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AudioBrowserOnLoad.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryOptimizationStatus.kt +22 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryOptimizationStatusChangedEvent.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryWarningPendingChangedEvent.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowseError.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowseResult.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowserSourceCallbackParam.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayNowPlayingButton.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ChapterMetadata.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/EqualizerSettings.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FavoriteChangedEvent.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormatNavigationErrorParams.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormattedNavigationError.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____RequestConfig_std__optional_std__unordered_map_std__string__std__string__.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_BatteryOptimizationStatusChangedEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_BatteryWarningPendingChangedEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_EqualizerSettings.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_FavoriteChangedEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_IosOutput.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_NavigationErrorEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_NowPlayingMetadata.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_Options.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_Playback.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackActiveTrackChangedEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackErrorEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackPlayWhenReadyChangedEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackProgressUpdatedEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackQueueEndedEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlayingState.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteJumpBackwardEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteJumpForwardEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemotePlayIdEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemotePlaySearchEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSeekEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSetRatingEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSkipEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RepeatModeChangedEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_TimedMetadata.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_TrackMetadata.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_bool.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_double.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_FormattedNavigationError_.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_ResolvedTrack_.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__string.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__vector_ChapterMetadata_.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__vector_Track_.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HeartRating.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HttpMethod.kt +26 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HybridAudioBrowserSpec.kt +1137 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategory.kt +25 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategoryMode.kt +28 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategoryOptions.kt +26 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategoryPolicy.kt +22 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageContext.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageQueryParams.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageSource.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IosOutput.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IosOutputType.kt +30 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaRequestConfig.kt +69 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaTransformParams.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +69 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeRouteEntry.kt +63 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeUpdateOptions.kt +53 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationError.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorEvent.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorType.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroAndroidUpdateOptions.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButton.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButtonLayout.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingMetadata.kt +65 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingUpdate.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Options.kt +53 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialAndroidSetupPlayerOptions.kt +65 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialIOSSetupPlayerOptions.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialSetupPlayerOptions.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PercentageRating.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Playback.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackActiveTrackChangedEvent.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackError.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackErrorEvent.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackPlayWhenReadyChangedEvent.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackProgressUpdatedEvent.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackQueueEndedEvent.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackState.kt +28 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +71 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayingState.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Progress.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RatingType.kt +26 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteJumpBackwardEvent.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteJumpForwardEvent.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemotePlayIdEvent.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemotePlaySearchEvent.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSeekEvent.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSetRatingEvent.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSkipEvent.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RepeatMode.kt +22 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RepeatModeChangedEvent.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RequestConfig.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +89 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RetryConfig.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchMode.kt +25 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchParams.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimer.kt +72 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimerEndOfTrack.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimerTime.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StarRating.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ThumbsRating.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TimedMetadata.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +86 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackMetadata.kt +83 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackStyle.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TransformableRequestConfig.kt +66 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/UpdateOptions.kt +53 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_AndroidAudioOffloadSettings.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_RetryConfig.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.kt +85 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_NullType_Double.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_NullType_NotificationButtonLayout.kt +59 -0
- package/nitrogen/generated/ios/AudioBrowser+autolinking.rb +60 -0
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.cpp +407 -0
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +2822 -0
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +300 -0
- package/nitrogen/generated/ios/AudioBrowserAutolinking.mm +33 -0
- package/nitrogen/generated/ios/AudioBrowserAutolinking.swift +25 -0
- package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +1190 -0
- package/nitrogen/generated/ios/swift/AndroidAudioContentType.swift +52 -0
- package/nitrogen/generated/ios/swift/AndroidAudioOffloadSettings.swift +85 -0
- package/nitrogen/generated/ios/swift/AndroidOptions.swift +125 -0
- package/nitrogen/generated/ios/swift/AndroidPlayerWakeMode.swift +44 -0
- package/nitrogen/generated/ios/swift/AndroidUpdateOptions.swift +187 -0
- package/nitrogen/generated/ios/swift/AppKilledPlaybackBehavior.swift +44 -0
- package/nitrogen/generated/ios/swift/ArtworkRequestConfig.swift +445 -0
- package/nitrogen/generated/ios/swift/BatteryOptimizationStatus.swift +44 -0
- package/nitrogen/generated/ios/swift/BatteryOptimizationStatusChangedEvent.swift +36 -0
- package/nitrogen/generated/ios/swift/BatteryWarningPendingChangedEvent.swift +36 -0
- package/nitrogen/generated/ios/swift/BrowseError.swift +36 -0
- package/nitrogen/generated/ios/swift/BrowseResult.swift +18 -0
- package/nitrogen/generated/ios/swift/BrowserSourceCallbackParam.swift +86 -0
- package/nitrogen/generated/ios/swift/CarPlayNowPlayingButton.swift +48 -0
- package/nitrogen/generated/ios/swift/ChapterMetadata.swift +107 -0
- package/nitrogen/generated/ios/swift/EqualizerSettings.swift +168 -0
- package/nitrogen/generated/ios/swift/FavoriteChangedEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/FormatNavigationErrorParams.swift +58 -0
- package/nitrogen/generated/ios/swift/FormattedNavigationError.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.swift +61 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.swift +62 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____RequestConfig_std__optional_std__unordered_map_std__string__std__string__.swift +77 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.swift +62 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.swift +69 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.swift +68 -0
- package/nitrogen/generated/ios/swift/Func_void.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_BatteryOptimizationStatusChangedEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_BatteryWarningPendingChangedEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_EqualizerSettings.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_FavoriteChangedEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_IosOutput.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_NavigationErrorEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_NowPlayingMetadata.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_Options.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_Playback.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_PlaybackActiveTrackChangedEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_PlaybackErrorEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_PlaybackPlayWhenReadyChangedEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_PlaybackProgressUpdatedEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_PlaybackQueueEndedEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_PlayingState.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_RemoteJumpBackwardEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_RemoteJumpForwardEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_RemotePlayIdEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_RemotePlaySearchEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_RemoteSeekEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_RemoteSetRatingEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_RemoteSkipEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_RepeatModeChangedEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_RequestConfig.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_TimedMetadata.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_TrackMetadata.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_bool.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_double.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__optional_FormattedNavigationError_.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__optional_ResolvedTrack_.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.swift +69 -0
- package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_RequestConfig__.swift +67 -0
- package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError___.swift +67 -0
- package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_std__vector_Track___.swift +67 -0
- package/nitrogen/generated/ios/swift/Func_void_std__string.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__variant_ResolvedTrack__BrowseError_.swift +59 -0
- package/nitrogen/generated/ios/swift/Func_void_std__vector_ChapterMetadata_.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__vector_Track_.swift +47 -0
- package/nitrogen/generated/ios/swift/HeartRating.swift +36 -0
- package/nitrogen/generated/ios/swift/HttpMethod.swift +60 -0
- package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec.swift +181 -0
- package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec_cxx.swift +2352 -0
- package/nitrogen/generated/ios/swift/IOSCategory.swift +56 -0
- package/nitrogen/generated/ios/swift/IOSCategoryMode.swift +68 -0
- package/nitrogen/generated/ios/swift/IOSCategoryOptions.swift +60 -0
- package/nitrogen/generated/ios/swift/IOSCategoryPolicy.swift +44 -0
- package/nitrogen/generated/ios/swift/ImageContext.swift +71 -0
- package/nitrogen/generated/ios/swift/ImageQueryParams.swift +85 -0
- package/nitrogen/generated/ios/swift/ImageSource.swift +139 -0
- package/nitrogen/generated/ios/swift/IosOutput.swift +58 -0
- package/nitrogen/generated/ios/swift/IosOutputType.swift +76 -0
- package/nitrogen/generated/ios/swift/MediaRequestConfig.swift +434 -0
- package/nitrogen/generated/ios/swift/MediaTransformParams.swift +59 -0
- package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +360 -0
- package/nitrogen/generated/ios/swift/NativeRouteEntry.swift +275 -0
- package/nitrogen/generated/ios/swift/NativeUpdateOptions.swift +215 -0
- package/nitrogen/generated/ios/swift/NavigationError.swift +100 -0
- package/nitrogen/generated/ios/swift/NavigationErrorEvent.swift +48 -0
- package/nitrogen/generated/ios/swift/NavigationErrorType.swift +52 -0
- package/nitrogen/generated/ios/swift/NitroAndroidUpdateOptions.swift +187 -0
- package/nitrogen/generated/ios/swift/NotificationButton.swift +52 -0
- package/nitrogen/generated/ios/swift/NotificationButtonLayout.swift +159 -0
- package/nitrogen/generated/ios/swift/NowPlayingMetadata.swift +351 -0
- package/nitrogen/generated/ios/swift/NowPlayingUpdate.swift +85 -0
- package/nitrogen/generated/ios/swift/Options.swift +148 -0
- package/nitrogen/generated/ios/swift/PartialAndroidSetupPlayerOptions.swift +328 -0
- package/nitrogen/generated/ios/swift/PartialIOSSetupPlayerOptions.swift +159 -0
- package/nitrogen/generated/ios/swift/PartialSetupPlayerOptions.swift +157 -0
- package/nitrogen/generated/ios/swift/PercentageRating.swift +36 -0
- package/nitrogen/generated/ios/swift/Playback.swift +59 -0
- package/nitrogen/generated/ios/swift/PlaybackActiveTrackChangedEvent.swift +128 -0
- package/nitrogen/generated/ios/swift/PlaybackError.swift +47 -0
- package/nitrogen/generated/ios/swift/PlaybackErrorEvent.swift +48 -0
- package/nitrogen/generated/ios/swift/PlaybackPlayWhenReadyChangedEvent.swift +36 -0
- package/nitrogen/generated/ios/swift/PlaybackProgressUpdatedEvent.swift +69 -0
- package/nitrogen/generated/ios/swift/PlaybackQueueEndedEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/PlaybackState.swift +68 -0
- package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +385 -0
- package/nitrogen/generated/ios/swift/PlayingState.swift +47 -0
- package/nitrogen/generated/ios/swift/Progress.swift +58 -0
- package/nitrogen/generated/ios/swift/RatingType.swift +60 -0
- package/nitrogen/generated/ios/swift/RemoteJumpBackwardEvent.swift +36 -0
- package/nitrogen/generated/ios/swift/RemoteJumpForwardEvent.swift +36 -0
- package/nitrogen/generated/ios/swift/RemotePlayIdEvent.swift +59 -0
- package/nitrogen/generated/ios/swift/RemotePlaySearchEvent.swift +36 -0
- package/nitrogen/generated/ios/swift/RemoteSeekEvent.swift +36 -0
- package/nitrogen/generated/ios/swift/RemoteSetRatingEvent.swift +76 -0
- package/nitrogen/generated/ios/swift/RemoteSkipEvent.swift +36 -0
- package/nitrogen/generated/ios/swift/RepeatMode.swift +44 -0
- package/nitrogen/generated/ios/swift/RepeatModeChangedEvent.swift +36 -0
- package/nitrogen/generated/ios/swift/RequestConfig.swift +298 -0
- package/nitrogen/generated/ios/swift/ResolvedTrack.swift +511 -0
- package/nitrogen/generated/ios/swift/RetryConfig.swift +59 -0
- package/nitrogen/generated/ios/swift/SearchMode.swift +56 -0
- package/nitrogen/generated/ios/swift/SearchParams.swift +209 -0
- package/nitrogen/generated/ios/swift/SleepTimer.swift +19 -0
- package/nitrogen/generated/ios/swift/SleepTimerEndOfTrack.swift +36 -0
- package/nitrogen/generated/ios/swift/SleepTimerTime.swift +36 -0
- package/nitrogen/generated/ios/swift/StarRating.swift +36 -0
- package/nitrogen/generated/ios/swift/ThumbsRating.swift +36 -0
- package/nitrogen/generated/ios/swift/TimedMetadata.swift +175 -0
- package/nitrogen/generated/ios/swift/Track.swift +488 -0
- package/nitrogen/generated/ios/swift/TrackMetadata.swift +505 -0
- package/nitrogen/generated/ios/swift/TrackStyle.swift +40 -0
- package/nitrogen/generated/ios/swift/TransformableRequestConfig.swift +372 -0
- package/nitrogen/generated/ios/swift/UpdateOptions.swift +215 -0
- package/nitrogen/generated/ios/swift/Variant_Bool_AndroidAudioOffloadSettings.swift +18 -0
- package/nitrogen/generated/ios/swift/Variant_Bool_RetryConfig.swift +18 -0
- package/nitrogen/generated/ios/swift/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.swift +20 -0
- package/nitrogen/generated/ios/swift/Variant_NullType_Double.swift +18 -0
- package/nitrogen/generated/ios/swift/Variant_NullType_NotificationButtonLayout.swift +18 -0
- package/nitrogen/generated/shared/c++/AndroidAudioContentType.hpp +88 -0
- package/nitrogen/generated/shared/c++/AndroidAudioOffloadSettings.hpp +79 -0
- package/nitrogen/generated/shared/c++/AndroidOptions.hpp +101 -0
- package/nitrogen/generated/shared/c++/AndroidPlayerWakeMode.hpp +80 -0
- package/nitrogen/generated/shared/c++/AndroidUpdateOptions.hpp +101 -0
- package/nitrogen/generated/shared/c++/AppKilledPlaybackBehavior.hpp +80 -0
- package/nitrogen/generated/shared/c++/ArtworkRequestConfig.hpp +133 -0
- package/nitrogen/generated/shared/c++/BatteryOptimizationStatus.hpp +80 -0
- package/nitrogen/generated/shared/c++/BatteryOptimizationStatusChangedEvent.hpp +76 -0
- package/nitrogen/generated/shared/c++/BatteryWarningPendingChangedEvent.hpp +75 -0
- package/nitrogen/generated/shared/c++/BrowseError.hpp +75 -0
- package/nitrogen/generated/shared/c++/BrowserSourceCallbackParam.hpp +81 -0
- package/nitrogen/generated/shared/c++/CarPlayNowPlayingButton.hpp +84 -0
- package/nitrogen/generated/shared/c++/ChapterMetadata.hpp +88 -0
- package/nitrogen/generated/shared/c++/EqualizerSettings.hpp +105 -0
- package/nitrogen/generated/shared/c++/FavoriteChangedEvent.hpp +80 -0
- package/nitrogen/generated/shared/c++/FormatNavigationErrorParams.hpp +88 -0
- package/nitrogen/generated/shared/c++/FormattedNavigationError.hpp +79 -0
- package/nitrogen/generated/shared/c++/HeartRating.hpp +75 -0
- package/nitrogen/generated/shared/c++/HttpMethod.hpp +96 -0
- package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.cpp +207 -0
- package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.hpp +375 -0
- package/nitrogen/generated/shared/c++/IOSCategory.hpp +92 -0
- package/nitrogen/generated/shared/c++/IOSCategoryMode.hpp +104 -0
- package/nitrogen/generated/shared/c++/IOSCategoryOptions.hpp +96 -0
- package/nitrogen/generated/shared/c++/IOSCategoryPolicy.hpp +80 -0
- package/nitrogen/generated/shared/c++/ImageContext.hpp +79 -0
- package/nitrogen/generated/shared/c++/ImageQueryParams.hpp +80 -0
- package/nitrogen/generated/shared/c++/ImageSource.hpp +91 -0
- package/nitrogen/generated/shared/c++/IosOutput.hpp +85 -0
- package/nitrogen/generated/shared/c++/IosOutputType.hpp +112 -0
- package/nitrogen/generated/shared/c++/MediaRequestConfig.hpp +123 -0
- package/nitrogen/generated/shared/c++/MediaTransformParams.hpp +84 -0
- package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +135 -0
- package/nitrogen/generated/shared/c++/NativeRouteEntry.hpp +131 -0
- package/nitrogen/generated/shared/c++/NativeUpdateOptions.hpp +103 -0
- package/nitrogen/generated/shared/c++/NavigationError.hpp +90 -0
- package/nitrogen/generated/shared/c++/NavigationErrorEvent.hpp +77 -0
- package/nitrogen/generated/shared/c++/NavigationErrorType.hpp +88 -0
- package/nitrogen/generated/shared/c++/NitroAndroidUpdateOptions.hpp +101 -0
- package/nitrogen/generated/shared/c++/NotificationButton.hpp +88 -0
- package/nitrogen/generated/shared/c++/NotificationButtonLayout.hpp +94 -0
- package/nitrogen/generated/shared/c++/NowPlayingMetadata.hpp +124 -0
- package/nitrogen/generated/shared/c++/NowPlayingUpdate.hpp +80 -0
- package/nitrogen/generated/shared/c++/Options.hpp +105 -0
- package/nitrogen/generated/shared/c++/PartialAndroidSetupPlayerOptions.hpp +121 -0
- package/nitrogen/generated/shared/c++/PartialIOSSetupPlayerOptions.hpp +103 -0
- package/nitrogen/generated/shared/c++/PartialSetupPlayerOptions.hpp +96 -0
- package/nitrogen/generated/shared/c++/PercentageRating.hpp +75 -0
- package/nitrogen/generated/shared/c++/Playback.hpp +84 -0
- package/nitrogen/generated/shared/c++/PlaybackActiveTrackChangedEvent.hpp +93 -0
- package/nitrogen/generated/shared/c++/PlaybackError.hpp +79 -0
- package/nitrogen/generated/shared/c++/PlaybackErrorEvent.hpp +77 -0
- package/nitrogen/generated/shared/c++/PlaybackPlayWhenReadyChangedEvent.hpp +75 -0
- package/nitrogen/generated/shared/c++/PlaybackProgressUpdatedEvent.hpp +87 -0
- package/nitrogen/generated/shared/c++/PlaybackQueueEndedEvent.hpp +79 -0
- package/nitrogen/generated/shared/c++/PlaybackState.hpp +104 -0
- package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +119 -0
- package/nitrogen/generated/shared/c++/PlayingState.hpp +79 -0
- package/nitrogen/generated/shared/c++/Progress.hpp +83 -0
- package/nitrogen/generated/shared/c++/RatingType.hpp +96 -0
- package/nitrogen/generated/shared/c++/RemoteJumpBackwardEvent.hpp +75 -0
- package/nitrogen/generated/shared/c++/RemoteJumpForwardEvent.hpp +75 -0
- package/nitrogen/generated/shared/c++/RemotePlayIdEvent.hpp +80 -0
- package/nitrogen/generated/shared/c++/RemotePlaySearchEvent.hpp +75 -0
- package/nitrogen/generated/shared/c++/RemoteSeekEvent.hpp +75 -0
- package/nitrogen/generated/shared/c++/RemoteSetRatingEvent.hpp +86 -0
- package/nitrogen/generated/shared/c++/RemoteSkipEvent.hpp +75 -0
- package/nitrogen/generated/shared/c++/RepeatMode.hpp +80 -0
- package/nitrogen/generated/shared/c++/RepeatModeChangedEvent.hpp +76 -0
- package/nitrogen/generated/shared/c++/RequestConfig.hpp +107 -0
- package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +153 -0
- package/nitrogen/generated/shared/c++/RetryConfig.hpp +79 -0
- package/nitrogen/generated/shared/c++/SearchMode.hpp +92 -0
- package/nitrogen/generated/shared/c++/SearchParams.hpp +102 -0
- package/nitrogen/generated/shared/c++/SleepTimerEndOfTrack.hpp +75 -0
- package/nitrogen/generated/shared/c++/SleepTimerTime.hpp +75 -0
- package/nitrogen/generated/shared/c++/StarRating.hpp +75 -0
- package/nitrogen/generated/shared/c++/ThumbsRating.hpp +75 -0
- package/nitrogen/generated/shared/c++/TimedMetadata.hpp +92 -0
- package/nitrogen/generated/shared/c++/Track.hpp +145 -0
- package/nitrogen/generated/shared/c++/TrackMetadata.hpp +136 -0
- package/nitrogen/generated/shared/c++/TrackStyle.hpp +76 -0
- package/nitrogen/generated/shared/c++/TransformableRequestConfig.hpp +116 -0
- package/nitrogen/generated/shared/c++/UpdateOptions.hpp +103 -0
- package/package.json +120 -0
- package/src/AudioBrowser.ts +4 -0
- package/src/features/battery.ts +176 -0
- package/src/features/browser.ts +315 -0
- package/src/features/equalizer.ts +64 -0
- package/src/features/errors.ts +196 -0
- package/src/features/favorites.ts +102 -0
- package/src/features/index.ts +23 -0
- package/src/features/metadata.ts +130 -0
- package/src/features/network.ts +34 -0
- package/src/features/nowPlaying.ts +56 -0
- package/src/features/output.ts +50 -0
- package/src/features/playback/controls.ts +66 -0
- package/src/features/playback/index.ts +7 -0
- package/src/features/playback/playWhenReady.ts +57 -0
- package/src/features/playback/playing.ts +40 -0
- package/src/features/playback/progress.ts +122 -0
- package/src/features/playback/rate.ts +22 -0
- package/src/features/playback/state.ts +72 -0
- package/src/features/playback/volume.ts +59 -0
- package/src/features/player/index.ts +2 -0
- package/src/features/player/options.ts +479 -0
- package/src/features/player/setup.ts +551 -0
- package/src/features/queue/activeTrack.ts +59 -0
- package/src/features/queue/index.ts +4 -0
- package/src/features/queue/queue.ts +173 -0
- package/src/features/queue/repeatMode.ts +58 -0
- package/src/features/queue/shuffle.ts +49 -0
- package/src/features/rating.ts +17 -0
- package/src/features/remoteControls.ts +341 -0
- package/src/features/sleepTimer.ts +186 -0
- package/src/index.ts +5 -0
- package/src/native.ts +5 -0
- package/src/native.web.ts +4 -0
- package/src/specs/audio-browser.nitro.ts +326 -0
- package/src/types/browser-native.ts +66 -0
- package/src/types/browser-nodes.ts +174 -0
- package/src/types/browser.ts +792 -0
- package/src/types/index.ts +2 -0
- package/src/types/player.ts +69 -0
- package/src/utils/LazyNativeEmitter.ts +58 -0
- package/src/utils/NativeUpdatedValue.ts +56 -0
- package/src/utils/resolveAssetSource.ts +4 -0
- package/src/utils/useDebug.ts +283 -0
- package/src/utils/useNativeUpdatedValue.ts +41 -0
- package/src/web/NativeAudioBrowser.ts +781 -0
- package/src/web/SimpleRouter.ts +177 -0
- package/src/web/TrackPlayer/Event.ts +11 -0
- package/src/web/TrackPlayer/Player.ts +323 -0
- package/src/web/TrackPlayer/PlaylistPlayer.ts +337 -0
- package/src/web/TrackPlayer/RepeatMode.ts +7 -0
- package/src/web/TrackPlayer/SetupNotCalledError.ts +5 -0
- package/src/web/TrackPlayer/SleepTimer.ts +71 -0
- package/src/web/TrackPlayer/State.ts +15 -0
- package/src/web/TrackPlayer/index.ts +4 -0
- package/src/web/browser/BrowserManager.ts +642 -0
- package/src/web/browser/FavoriteManager.ts +77 -0
- package/src/web/browser/NavigationErrorManager.ts +112 -0
- package/src/web/browser/SearchManager.ts +82 -0
- package/src/web/http/HttpClient.ts +107 -0
- package/src/web/http/RequestConfigBuilder.ts +347 -0
- package/src/web/player/NowPlayingManager.ts +83 -0
- package/src/web/player/OptionsManager.ts +101 -0
- package/src/web/util/BrowserPathHelper.ts +147 -0
- package/src/web/util/shuffle.ts +14 -0
|
@@ -0,0 +1,1169 @@
|
|
|
1
|
+
package com.audiobrowser.browser
|
|
2
|
+
|
|
3
|
+
import android.util.LruCache
|
|
4
|
+
import androidx.media3.common.MediaItem
|
|
5
|
+
import androidx.media3.session.MediaSession
|
|
6
|
+
import com.audiobrowser.http.HttpClient
|
|
7
|
+
import com.audiobrowser.http.RequestConfigBuilder
|
|
8
|
+
import com.audiobrowser.util.BrowserPathHelper
|
|
9
|
+
import com.audiobrowser.util.TrackFactory
|
|
10
|
+
import com.margelo.nitro.audiobrowser.ArtworkRequestConfig
|
|
11
|
+
import com.margelo.nitro.audiobrowser.BrowserSourceCallbackParam
|
|
12
|
+
import com.margelo.nitro.audiobrowser.ImageContext
|
|
13
|
+
import com.margelo.nitro.audiobrowser.ImageSource
|
|
14
|
+
import com.margelo.nitro.audiobrowser.MediaRequestConfig
|
|
15
|
+
import com.margelo.nitro.audiobrowser.NativeRouteEntry
|
|
16
|
+
import com.margelo.nitro.audiobrowser.RequestConfig
|
|
17
|
+
import com.margelo.nitro.audiobrowser.ResolvedTrack
|
|
18
|
+
import com.margelo.nitro.audiobrowser.SearchParams
|
|
19
|
+
import com.margelo.nitro.audiobrowser.Track
|
|
20
|
+
import com.margelo.nitro.audiobrowser.TransformableRequestConfig
|
|
21
|
+
import kotlinx.coroutines.Dispatchers
|
|
22
|
+
import kotlinx.coroutines.async
|
|
23
|
+
import kotlinx.coroutines.awaitAll
|
|
24
|
+
import kotlinx.coroutines.coroutineScope
|
|
25
|
+
import kotlinx.coroutines.withContext
|
|
26
|
+
import kotlinx.serialization.json.Json
|
|
27
|
+
import timber.log.Timber
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Core browser manager that handles navigation, search, and media browsing.
|
|
31
|
+
*
|
|
32
|
+
* This class contains the main business logic for:
|
|
33
|
+
* - Route resolution and path matching with parameter extraction
|
|
34
|
+
* - HTTP API requests and response processing
|
|
35
|
+
* - JavaScript callback invocation
|
|
36
|
+
* - Fallback handling and error management
|
|
37
|
+
*/
|
|
38
|
+
class BrowserManager {
|
|
39
|
+
private val router = SimpleRouter()
|
|
40
|
+
private val httpClient = HttpClient()
|
|
41
|
+
private val json = Json {
|
|
42
|
+
ignoreUnknownKeys = true
|
|
43
|
+
isLenient = true
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private var onPathChanged: ((String) -> Unit)? = null
|
|
47
|
+
private var onContentChanged: ((ResolvedTrack?) -> Unit)? = null
|
|
48
|
+
private var onTabsChanged: ((Array<Track>) -> Unit)? = null
|
|
49
|
+
|
|
50
|
+
private var path: String = "/"
|
|
51
|
+
set(value) {
|
|
52
|
+
val previous = field
|
|
53
|
+
field = value
|
|
54
|
+
if (previous != value) {
|
|
55
|
+
onPathChanged?.invoke(value)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private var content: ResolvedTrack? = null
|
|
60
|
+
set(value) {
|
|
61
|
+
val previous = field
|
|
62
|
+
field = value
|
|
63
|
+
if (previous != value) {
|
|
64
|
+
onContentChanged?.invoke(value)
|
|
65
|
+
Timber.d("content changed", content?.title)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private var tabs: Array<Track>? = null
|
|
70
|
+
set(value) {
|
|
71
|
+
val previous = field
|
|
72
|
+
field = value
|
|
73
|
+
// Arrays need contentEquals for comparison
|
|
74
|
+
if (value != null && !value.contentEquals(previous)) {
|
|
75
|
+
onTabsChanged?.invoke(value)
|
|
76
|
+
} else if (value == null && previous != null) {
|
|
77
|
+
onTabsChanged?.invoke(emptyArray())
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// LRU cache for individual tracks - keyed by both url and src for O(1) lookup
|
|
82
|
+
private val trackCache = LruCache<String, Track>(3000)
|
|
83
|
+
|
|
84
|
+
// LRU cache for resolved content - keyed by path
|
|
85
|
+
// Keeps recently visited paths cached for fast back navigation and tab switching
|
|
86
|
+
// Invalidated via invalidateContentCache() when content changes
|
|
87
|
+
private val contentCache = LruCache<String, ResolvedTrack>(20)
|
|
88
|
+
|
|
89
|
+
// Cache for search results - keyed by query string
|
|
90
|
+
private var lastSearchQuery: String? = null
|
|
91
|
+
private var lastSearchResults: Array<Track>? = null
|
|
92
|
+
|
|
93
|
+
// Set of favorited track identifiers (src)
|
|
94
|
+
private var favoriteIds = setOf<String>()
|
|
95
|
+
|
|
96
|
+
// Navigation tracking to prevent race conditions
|
|
97
|
+
@Volatile private var currentNavigationId = 0
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Browser configuration containing routes, search, tabs, and request settings. This can be
|
|
101
|
+
* updated dynamically when the configuration changes.
|
|
102
|
+
*/
|
|
103
|
+
var config: BrowserConfig = BrowserConfig()
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Callback to transform artwork URLs for tracks. Takes a track and optional per-route artwork
|
|
107
|
+
* config, returns ImageSource or null. Injected by AudioBrowser when artwork config is set.
|
|
108
|
+
* The ImageContext parameter provides size hints for CDN URL generation.
|
|
109
|
+
*/
|
|
110
|
+
var artworkUrlResolver: (suspend (Track, ArtworkRequestConfig?, ImageContext?) -> ImageSource?)? = null
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Sets the favorited track identifiers. Tracks will have their favorited field hydrated based on
|
|
114
|
+
* this list during browsing.
|
|
115
|
+
*/
|
|
116
|
+
fun setFavorites(favorites: List<String>) {
|
|
117
|
+
favoriteIds = favorites.toSet()
|
|
118
|
+
Timber.d("Set ${favoriteIds.size} favorite IDs")
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Updates the favorite state for a single track identifier. Called when the heart button is
|
|
123
|
+
* tapped in media controllers.
|
|
124
|
+
*/
|
|
125
|
+
fun updateFavorite(id: String, favorited: Boolean) {
|
|
126
|
+
favoriteIds =
|
|
127
|
+
if (favorited) {
|
|
128
|
+
favoriteIds + id
|
|
129
|
+
} else {
|
|
130
|
+
favoriteIds - id
|
|
131
|
+
}
|
|
132
|
+
Timber.d("Updated favorite for '$id' to $favorited (total: ${favoriteIds.size})")
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Hydrates the favorited field on a track based on the favoriteIds set. Only hydrates if
|
|
137
|
+
* track.favorited is null (doesn't overwrite API-provided values). Only tracks with src can be
|
|
138
|
+
* favorited.
|
|
139
|
+
*/
|
|
140
|
+
private fun hydrateFavorite(track: Track): Track {
|
|
141
|
+
// Don't overwrite API-provided favorites
|
|
142
|
+
if (track.favorited != null) return track
|
|
143
|
+
if (favoriteIds.isEmpty()) return track
|
|
144
|
+
|
|
145
|
+
val isFavorited = track.src?.let { favoriteIds.contains(it) } ?: false
|
|
146
|
+
if (!isFavorited) return track
|
|
147
|
+
|
|
148
|
+
return Track(
|
|
149
|
+
url = track.url,
|
|
150
|
+
src = track.src,
|
|
151
|
+
artwork = track.artwork,
|
|
152
|
+
artworkSource = track.artworkSource,
|
|
153
|
+
artworkCarPlayTinted = track.artworkCarPlayTinted,
|
|
154
|
+
title = track.title,
|
|
155
|
+
subtitle = track.subtitle,
|
|
156
|
+
artist = track.artist,
|
|
157
|
+
album = track.album,
|
|
158
|
+
description = track.description,
|
|
159
|
+
genre = track.genre,
|
|
160
|
+
duration = track.duration,
|
|
161
|
+
style = track.style,
|
|
162
|
+
childrenStyle = track.childrenStyle,
|
|
163
|
+
favorited = true,
|
|
164
|
+
groupTitle = track.groupTitle,
|
|
165
|
+
live = track.live,
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Hydrates favorites on all children of a ResolvedTrack. */
|
|
170
|
+
private fun hydrateChildren(resolvedTrack: ResolvedTrack): ResolvedTrack {
|
|
171
|
+
val children = resolvedTrack.children ?: return resolvedTrack
|
|
172
|
+
val hydratedChildren = children.map { hydrateFavorite(it) }.toTypedArray()
|
|
173
|
+
return resolvedTrack.copy(children = hydratedChildren)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** Cache a track by both url and src for O(1) lookup from either key. */
|
|
177
|
+
private fun cacheTrack(track: Track) {
|
|
178
|
+
track.url?.let { trackCache.put(it, track) }
|
|
179
|
+
track.src?.let { trackCache.put(it, track) }
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private fun cacheChildren(resolvedTrack: ResolvedTrack) {
|
|
183
|
+
resolvedTrack.children?.forEach { track -> cacheTrack(track) }
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Get a cached Track by mediaId (url or src), or null if not cached. Used by Media3 to rehydrate
|
|
188
|
+
* MediaItem shells with full track metadata. Re-hydrates favorites in case setFavoriteStates was
|
|
189
|
+
* called after caching.
|
|
190
|
+
*/
|
|
191
|
+
fun getCachedTrack(mediaId: String): Track? {
|
|
192
|
+
// Try direct lookup first (matches url or src)
|
|
193
|
+
trackCache.get(mediaId)?.let { track ->
|
|
194
|
+
val hydratedTrack = hydrateFavorite(track)
|
|
195
|
+
Timber.d("Cache HIT for mediaId='$mediaId' → '${track.title}'")
|
|
196
|
+
return hydratedTrack
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Try extracting src from contextual URL
|
|
200
|
+
val trackId = BrowserPathHelper.extractTrackId(mediaId)
|
|
201
|
+
if (trackId != null) {
|
|
202
|
+
trackCache.get(trackId)?.let { track ->
|
|
203
|
+
val hydratedTrack = hydrateFavorite(track)
|
|
204
|
+
Timber.d("Cache HIT (extracted src) for mediaId='$mediaId' → '${track.title}'")
|
|
205
|
+
return hydratedTrack
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
Timber.w("Cache MISS for mediaId='$mediaId'")
|
|
210
|
+
return null
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Resolves multiple media IDs from cache. Throws IllegalStateException if any mediaId is not
|
|
215
|
+
* found in cache.
|
|
216
|
+
*
|
|
217
|
+
* @param mediaIds The media IDs to resolve
|
|
218
|
+
* @return List of Track objects
|
|
219
|
+
*/
|
|
220
|
+
fun resolveMediaIdsFromCache(mediaIds: List<String>): List<Track> {
|
|
221
|
+
return mediaIds.map { mediaId ->
|
|
222
|
+
Timber.d("=== Resolving from cache: mediaId='$mediaId' ===")
|
|
223
|
+
|
|
224
|
+
getCachedTrack(mediaId)?.let { cachedTrack ->
|
|
225
|
+
Timber.d("→ Found cached Track: '${cachedTrack.title}'")
|
|
226
|
+
return@map cachedTrack
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Cache miss - this indicates a bug in our caching system
|
|
230
|
+
Timber.e("→ Cache MISS for mediaId='$mediaId' - this should not happen")
|
|
231
|
+
throw IllegalStateException(
|
|
232
|
+
"MediaItem not found in cache: $mediaId. This indicates a bug in the caching system."
|
|
233
|
+
)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* **Media3/Android Auto Integration Entry Point**
|
|
239
|
+
*
|
|
240
|
+
* Resolves Media3 MediaItems for playback, with special handling for Android Auto queue
|
|
241
|
+
* expansion. Called exclusively from `MediaSessionCallback.onSetMediaItems()`.
|
|
242
|
+
*
|
|
243
|
+
* Behavior:
|
|
244
|
+
* - Single item: Attempts queue expansion (Android Auto album/playlist restoration)
|
|
245
|
+
* - Multiple items OR expansion fails: Falls back to cache resolution
|
|
246
|
+
*
|
|
247
|
+
* @param mediaItems List of Media3 MediaItems requested for playback
|
|
248
|
+
* @param startIndex Index of the item to start playing
|
|
249
|
+
* @param startPositionMs Position within the start item to begin playback
|
|
250
|
+
* @return MediaSession.MediaItemsWithStartPosition ready for Media3
|
|
251
|
+
* @throws IllegalStateException if any mediaId is not found in cache
|
|
252
|
+
*/
|
|
253
|
+
suspend fun resolveMediaItemsForPlayback(
|
|
254
|
+
mediaItems: List<MediaItem>,
|
|
255
|
+
startIndex: Int,
|
|
256
|
+
startPositionMs: Long,
|
|
257
|
+
): MediaSession.MediaItemsWithStartPosition {
|
|
258
|
+
// Android Auto queue expansion: single track → full album/playlist
|
|
259
|
+
if (mediaItems.size == 1) {
|
|
260
|
+
val mediaItem = mediaItems[0]
|
|
261
|
+
|
|
262
|
+
// Handle search query - user initiated playback from search results
|
|
263
|
+
val searchQuery = mediaItem.requestMetadata.searchQuery
|
|
264
|
+
if (searchQuery != null) {
|
|
265
|
+
Timber.d("Handling search playback request for query: $searchQuery")
|
|
266
|
+
|
|
267
|
+
// Execute search (will hit cache if already performed)
|
|
268
|
+
val searchResults = search(searchQuery)
|
|
269
|
+
val searchTracks = searchResults.children
|
|
270
|
+
|
|
271
|
+
if (searchTracks != null && searchTracks.isNotEmpty()) {
|
|
272
|
+
// Find the selected track in search results
|
|
273
|
+
val mediaId = mediaItem.mediaId
|
|
274
|
+
val selectedIndex =
|
|
275
|
+
searchTracks.indexOfFirst { track -> track.url == mediaId || track.src == mediaId }
|
|
276
|
+
|
|
277
|
+
if (selectedIndex >= 0) {
|
|
278
|
+
Timber.d(
|
|
279
|
+
"Playing search result at index $selectedIndex of ${searchTracks.size} results"
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
// Convert to Media3 MediaItems
|
|
283
|
+
val searchMediaItems = searchTracks.map { track -> TrackFactory.toMedia3(track) }
|
|
284
|
+
|
|
285
|
+
return MediaSession.MediaItemsWithStartPosition(
|
|
286
|
+
searchMediaItems,
|
|
287
|
+
selectedIndex,
|
|
288
|
+
startPositionMs,
|
|
289
|
+
)
|
|
290
|
+
} else {
|
|
291
|
+
Timber.w("Selected track not found in search results, falling back to single track")
|
|
292
|
+
}
|
|
293
|
+
} else {
|
|
294
|
+
Timber.w("Search returned no results for query: $searchQuery")
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
val mediaId = mediaItems[0].mediaId
|
|
299
|
+
|
|
300
|
+
if (BrowserPathHelper.isContextual(mediaId)) {
|
|
301
|
+
Timber.d("Attempting queue expansion for mediaId='$mediaId'")
|
|
302
|
+
|
|
303
|
+
val expanded = expandQueueFromContextualUrl(mediaId)
|
|
304
|
+
|
|
305
|
+
if (expanded != null) {
|
|
306
|
+
val (tracks, selectedIndex) = expanded
|
|
307
|
+
|
|
308
|
+
// Convert to Media3 MediaItems
|
|
309
|
+
val expandedMediaItems = tracks.map { track -> TrackFactory.toMedia3(track) }
|
|
310
|
+
|
|
311
|
+
return MediaSession.MediaItemsWithStartPosition(
|
|
312
|
+
expandedMediaItems,
|
|
313
|
+
selectedIndex,
|
|
314
|
+
startPositionMs,
|
|
315
|
+
)
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// No expansion - resolve from cache
|
|
321
|
+
val mediaIds = mediaItems.map { it.mediaId }
|
|
322
|
+
val cachedTracks = resolveMediaIdsFromCache(mediaIds)
|
|
323
|
+
|
|
324
|
+
// Convert to Media3 MediaItems
|
|
325
|
+
val resolvedMediaItems = cachedTracks.map { track -> TrackFactory.toMedia3(track) }
|
|
326
|
+
|
|
327
|
+
return MediaSession.MediaItemsWithStartPosition(resolvedMediaItems, startIndex, startPositionMs)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Validates that a track has either url or src for stable identification. Throws
|
|
332
|
+
* IllegalStateException if validation fails.
|
|
333
|
+
*/
|
|
334
|
+
private fun validateTrack(track: Track, context: String) {
|
|
335
|
+
if (track.url == null && track.src == null) {
|
|
336
|
+
throw IllegalStateException(
|
|
337
|
+
"$context must have either 'url' or 'src' property for stable identification. Track: ${track.title}"
|
|
338
|
+
)
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
suspend fun resolve(path: String, useCache: Boolean = true): ResolvedTrack {
|
|
343
|
+
Timber.d("=== RESOLVE: path='$path' (useCache=$useCache) ===")
|
|
344
|
+
|
|
345
|
+
// Strip __trackId from contextual URLs (e.g., "/library/radio?__trackId=song.mp3" →
|
|
346
|
+
// "/library/radio")
|
|
347
|
+
// This allows resolving the parent container for tracks referenced by contextual URL
|
|
348
|
+
val normalizedPath = BrowserPathHelper.stripTrackId(path)
|
|
349
|
+
if (normalizedPath != path) {
|
|
350
|
+
Timber.d("Stripped __trackId from contextual URL: '$normalizedPath'")
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Check content cache first
|
|
354
|
+
if (useCache) {
|
|
355
|
+
contentCache.get(normalizedPath)?.let { cached ->
|
|
356
|
+
Timber.d("Content cache HIT for path='$normalizedPath'")
|
|
357
|
+
// Re-hydrate favorites in case they changed since caching
|
|
358
|
+
return hydrateChildren(cached)
|
|
359
|
+
}
|
|
360
|
+
Timber.d("Content cache MISS for path='$normalizedPath'")
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
val resolvedTrack = resolveUncached(normalizedPath)
|
|
364
|
+
|
|
365
|
+
// Cache the resolved content for future navigation
|
|
366
|
+
contentCache.put(normalizedPath, resolvedTrack)
|
|
367
|
+
|
|
368
|
+
// Cache children for Media3 track lookups (getCachedTrack)
|
|
369
|
+
cacheChildren(resolvedTrack)
|
|
370
|
+
|
|
371
|
+
return hydrateChildren(resolvedTrack)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Invalidates the content cache for a specific path. Called when content at that path has changed
|
|
376
|
+
* (e.g., via notifyContentChanged).
|
|
377
|
+
*
|
|
378
|
+
* @param path The container path to invalidate (e.g., "/library/radio")
|
|
379
|
+
* @throws IllegalArgumentException if passed a contextual URL (contains __trackId)
|
|
380
|
+
*/
|
|
381
|
+
fun invalidateContentCache(path: String) {
|
|
382
|
+
require(!BrowserPathHelper.isContextual(path)) {
|
|
383
|
+
"invalidateContentCache() expects a container path, not a contextual URL: $path"
|
|
384
|
+
}
|
|
385
|
+
contentCache.remove(path)
|
|
386
|
+
Timber.d("Invalidated content cache for path='$path'")
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/** Clears all cached content. Used when artwork resolver is wired up to force re-fetch. */
|
|
390
|
+
fun clearContentCache() {
|
|
391
|
+
contentCache.evictAll()
|
|
392
|
+
Timber.d("Cleared all content cache")
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
private suspend fun resolveUncached(path: String): ResolvedTrack {
|
|
396
|
+
val routes = config.routes
|
|
397
|
+
if (routes.isNullOrEmpty()) {
|
|
398
|
+
Timber.e("No routes configured for path: $path")
|
|
399
|
+
throw ContentNotFoundException(path)
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Find best matching route
|
|
403
|
+
val (routeEntry, routeParams) =
|
|
404
|
+
findBestRouteMatch(path, routes)
|
|
405
|
+
?: run {
|
|
406
|
+
Timber.e("No route matched for path: $path")
|
|
407
|
+
throw ContentNotFoundException(path)
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
Timber.d("Matched route: ${routeEntry.path} with params: $routeParams")
|
|
411
|
+
|
|
412
|
+
// Resolve the track from the route
|
|
413
|
+
val resolvedTrack = resolveRouteEntry(routeEntry, path, routeParams)
|
|
414
|
+
|
|
415
|
+
// Get effective artwork config: per-route overrides global
|
|
416
|
+
val effectiveArtworkConfig = routeEntry.artwork ?: config.artwork
|
|
417
|
+
|
|
418
|
+
// Transform children: generate contextual URLs and transform artwork URLs
|
|
419
|
+
val transformedChildren =
|
|
420
|
+
resolvedTrack.children?.let { children ->
|
|
421
|
+
coroutineScope {
|
|
422
|
+
children
|
|
423
|
+
.mapIndexed { index, track ->
|
|
424
|
+
async {
|
|
425
|
+
// Validate that track has stable identifier
|
|
426
|
+
validateTrack(track, "Child track")
|
|
427
|
+
|
|
428
|
+
var transformedTrack = track
|
|
429
|
+
|
|
430
|
+
// Generate contextual URLs for playable tracks
|
|
431
|
+
// Always regenerate to reflect the current browsing context, not the original
|
|
432
|
+
// context
|
|
433
|
+
// (e.g., a track favorited from an album should use /favorites context when browsed
|
|
434
|
+
// there)
|
|
435
|
+
if (track.src != null) {
|
|
436
|
+
val contextualUrl = BrowserPathHelper.build(path, track.src)
|
|
437
|
+
transformedTrack = transformedTrack.copy(url = contextualUrl)
|
|
438
|
+
|
|
439
|
+
Timber.d(
|
|
440
|
+
"[$path] Child[$index] '${track.title}': Playable, contextualUrl=$contextualUrl (src=${track.src})"
|
|
441
|
+
)
|
|
442
|
+
} else {
|
|
443
|
+
Timber.d(
|
|
444
|
+
"[$path] Child[$index] '${track.title}': Browsable with url=${track.url}"
|
|
445
|
+
)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Transform artwork URL if resolver is configured
|
|
449
|
+
// At browse-time, we don't have display size info
|
|
450
|
+
val resolver = artworkUrlResolver
|
|
451
|
+
if (resolver != null) {
|
|
452
|
+
val browseContext = ImageContext(null, null)
|
|
453
|
+
transformedTrack =
|
|
454
|
+
transformArtworkUrl(
|
|
455
|
+
transformedTrack,
|
|
456
|
+
effectiveArtworkConfig,
|
|
457
|
+
resolver,
|
|
458
|
+
path,
|
|
459
|
+
index,
|
|
460
|
+
browseContext,
|
|
461
|
+
)
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
transformedTrack
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
.awaitAll()
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Return resolved track with transformed children
|
|
472
|
+
return if (transformedChildren != null) {
|
|
473
|
+
resolvedTrack.copy(children = transformedChildren.toTypedArray())
|
|
474
|
+
} else {
|
|
475
|
+
resolvedTrack
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Transforms a track's artwork using the configured resolver. Populates artworkSource with the
|
|
481
|
+
* transformed ImageSource, keeping artwork unchanged. Handles all edge cases: undefined returns,
|
|
482
|
+
* errors, missing artwork.
|
|
483
|
+
*
|
|
484
|
+
* @param imageContext Optional size context for CDN URL generation (null at browse-time)
|
|
485
|
+
*/
|
|
486
|
+
private suspend fun transformArtworkUrl(
|
|
487
|
+
track: Track,
|
|
488
|
+
artworkConfig: ArtworkRequestConfig?,
|
|
489
|
+
resolver: suspend (Track, ArtworkRequestConfig?, ImageContext?) -> ImageSource?,
|
|
490
|
+
path: String,
|
|
491
|
+
index: Int,
|
|
492
|
+
imageContext: ImageContext? = null,
|
|
493
|
+
): Track {
|
|
494
|
+
// No artwork config and no track.artwork - nothing to transform
|
|
495
|
+
if (artworkConfig == null && track.artwork == null) {
|
|
496
|
+
return track
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
return try {
|
|
500
|
+
val imageSource = resolver(track, artworkConfig, imageContext)
|
|
501
|
+
|
|
502
|
+
when {
|
|
503
|
+
// resolve returned null → no artwork source
|
|
504
|
+
imageSource == null -> {
|
|
505
|
+
Timber.d(
|
|
506
|
+
"[$path] Child[$index] '${track.title}': Artwork resolver returned null, no artworkSource"
|
|
507
|
+
)
|
|
508
|
+
track.copy(artworkSource = null)
|
|
509
|
+
}
|
|
510
|
+
// resolve returned ImageSource → set artworkSource
|
|
511
|
+
else -> {
|
|
512
|
+
Timber.d("[$path] Child[$index] '${track.title}': artworkSource set: ${imageSource.uri}")
|
|
513
|
+
track.copy(artworkSource = imageSource)
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
} catch (e: Exception) {
|
|
517
|
+
// resolve threw → log error, clear artworkSource to avoid broken images
|
|
518
|
+
Timber.e(
|
|
519
|
+
e,
|
|
520
|
+
"[$path] Child[$index] '${track.title}': Artwork transform failed, clearing artworkSource",
|
|
521
|
+
)
|
|
522
|
+
track.copy(artworkSource = null)
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Expands a contextual URL into a queue of playable tracks.
|
|
528
|
+
*
|
|
529
|
+
* Used when navigating to a track to load it with its full album/playlist context. Returns only
|
|
530
|
+
* the selected track if singleTrack is true.
|
|
531
|
+
*
|
|
532
|
+
* @param contextualUrl The contextual URL (e.g., "/album?__trackId=song.mp3")
|
|
533
|
+
* @return Pair of (tracks array, selected track index), or null if expansion fails
|
|
534
|
+
*/
|
|
535
|
+
suspend fun expandQueueFromContextualUrl(contextualUrl: String): Pair<Array<Track>, Int>? {
|
|
536
|
+
val trackId = BrowserPathHelper.extractTrackId(contextualUrl) ?: return null
|
|
537
|
+
|
|
538
|
+
Timber.d("Expanding queue from contextual URL: $contextualUrl (trackId=$trackId)")
|
|
539
|
+
|
|
540
|
+
try {
|
|
541
|
+
// Resolve the parent container to get all siblings
|
|
542
|
+
val parentPath = BrowserPathHelper.stripTrackId(contextualUrl)
|
|
543
|
+
val parentResolvedTrack = resolve(parentPath)
|
|
544
|
+
val children = parentResolvedTrack.children
|
|
545
|
+
|
|
546
|
+
if (children.isNullOrEmpty()) {
|
|
547
|
+
Timber.w("Parent has no children, cannot expand queue")
|
|
548
|
+
return null
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// Filter to only playable tracks (tracks with src)
|
|
552
|
+
val playableTracks = children.filter { track -> track.src != null }
|
|
553
|
+
|
|
554
|
+
if (playableTracks.isEmpty()) {
|
|
555
|
+
Timber.w("Parent has no playable tracks, cannot expand queue")
|
|
556
|
+
return null
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// Find the index of the selected track in the playable tracks array
|
|
560
|
+
val selectedIndex = playableTracks.indexOfFirst { track -> track.src == trackId }
|
|
561
|
+
|
|
562
|
+
if (selectedIndex < 0) {
|
|
563
|
+
Timber.w("Track with src='$trackId' not found in playable children")
|
|
564
|
+
return null
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Check singleTrack setting - if true, return only the selected track
|
|
568
|
+
if (config.singleTrack) {
|
|
569
|
+
Timber.d("singleTrack=true - returning single track at index $selectedIndex")
|
|
570
|
+
return Pair(arrayOf(playableTracks[selectedIndex]), 0)
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
Timber.d(
|
|
574
|
+
"singleTrack=false - returning ${playableTracks.size} playable tracks (from ${children.size} total), starting at index $selectedIndex"
|
|
575
|
+
)
|
|
576
|
+
return Pair(playableTracks.toTypedArray(), selectedIndex)
|
|
577
|
+
} catch (e: Exception) {
|
|
578
|
+
Timber.e(e, "Error expanding queue from contextual URL: $contextualUrl")
|
|
579
|
+
return null
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Navigate to a path and return browser content.
|
|
585
|
+
*
|
|
586
|
+
* Uses a navigation ID to prevent race conditions when multiple navigations overlap. Only the
|
|
587
|
+
* most recent navigation's result is applied.
|
|
588
|
+
*
|
|
589
|
+
* @param path The path to navigate to (e.g., "/artists/123")
|
|
590
|
+
* @return ResolvedTrack containing the navigation result
|
|
591
|
+
*/
|
|
592
|
+
suspend fun navigate(path: String): ResolvedTrack {
|
|
593
|
+
Timber.d("Navigating to path: $path")
|
|
594
|
+
|
|
595
|
+
// Increment navigation ID and capture for this navigation
|
|
596
|
+
val navigationId = ++currentNavigationId
|
|
597
|
+
|
|
598
|
+
this.path = path
|
|
599
|
+
this.content = null // Clear content immediately to show loading state
|
|
600
|
+
val content = resolve(path)
|
|
601
|
+
|
|
602
|
+
// Only apply result if this is still the current navigation
|
|
603
|
+
if (navigationId == currentNavigationId) {
|
|
604
|
+
this.content = content
|
|
605
|
+
}
|
|
606
|
+
return content
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Refresh the current path's content without changing navigation state. Used for background
|
|
611
|
+
* refreshes (e.g., when content changes via notifyContentChanged). Bypasses content cache to
|
|
612
|
+
* fetch fresh data. Errors are silently ignored.
|
|
613
|
+
*
|
|
614
|
+
* Uses navigation ID tracking to prevent race conditions.
|
|
615
|
+
*/
|
|
616
|
+
suspend fun refresh() {
|
|
617
|
+
// Increment navigation ID and capture for this refresh
|
|
618
|
+
val navigationId = ++currentNavigationId
|
|
619
|
+
|
|
620
|
+
val currentPath = path
|
|
621
|
+
Timber.d("Refreshing content for path: $currentPath")
|
|
622
|
+
|
|
623
|
+
try {
|
|
624
|
+
contentCache.remove(currentPath)
|
|
625
|
+
val content = resolve(currentPath, useCache = false)
|
|
626
|
+
|
|
627
|
+
// Only apply result if this is still the current navigation
|
|
628
|
+
if (navigationId == currentNavigationId) {
|
|
629
|
+
this.content = content
|
|
630
|
+
}
|
|
631
|
+
} catch (e: Exception) {
|
|
632
|
+
Timber.e(e, "Error refreshing content for path: $currentPath")
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Get cached search results for a query. Used by Media3 onGetSearchResult() callback to retrieve
|
|
638
|
+
* previously executed search.
|
|
639
|
+
*
|
|
640
|
+
* @param query The search query string
|
|
641
|
+
* @return Array of Track results, or null if not found
|
|
642
|
+
*/
|
|
643
|
+
fun getCachedSearchResults(query: String): Array<Track>? {
|
|
644
|
+
if (query != lastSearchQuery) return null
|
|
645
|
+
return lastSearchResults?.map { hydrateFavorite(it) }?.toTypedArray()
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Search for tracks and return playable results.
|
|
650
|
+
*
|
|
651
|
+
* @param query The search query string
|
|
652
|
+
* @return Array of playable tracks, or null if no results or search not configured
|
|
653
|
+
*/
|
|
654
|
+
suspend fun searchPlayable(query: String): Array<Track>? {
|
|
655
|
+
return searchPlayable(
|
|
656
|
+
SearchParams(
|
|
657
|
+
query = query,
|
|
658
|
+
mode = null,
|
|
659
|
+
genre = null,
|
|
660
|
+
artist = null,
|
|
661
|
+
album = null,
|
|
662
|
+
title = null,
|
|
663
|
+
playlist = null,
|
|
664
|
+
)
|
|
665
|
+
)
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Search for tracks and return playable results. If the first result is browsable, resolves it
|
|
670
|
+
* and returns its children. If the first result is playable, returns it. Used for voice search
|
|
671
|
+
* "play X" commands.
|
|
672
|
+
*
|
|
673
|
+
* @param params The structured search parameters
|
|
674
|
+
* @return Array of playable tracks, or null if no results or search not configured
|
|
675
|
+
*/
|
|
676
|
+
suspend fun searchPlayable(params: SearchParams): Array<Track>? {
|
|
677
|
+
val searchResults = search(params)
|
|
678
|
+
val tracks = searchResults.children
|
|
679
|
+
|
|
680
|
+
if (tracks.isNullOrEmpty()) {
|
|
681
|
+
return null
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
val firstResult = tracks[0]
|
|
685
|
+
|
|
686
|
+
// Check if result is browsable-only (container/route) vs playable
|
|
687
|
+
// If it's browsable but also playable (has src or playable=true), treat it as playable
|
|
688
|
+
val tracksToFilter =
|
|
689
|
+
if (firstResult.src == null) {
|
|
690
|
+
Timber.d("First search result is browsable-only, resolving: ${firstResult.url}")
|
|
691
|
+
val resolvedTrack = resolve(firstResult.url!!)
|
|
692
|
+
resolvedTrack.children
|
|
693
|
+
?.filter { it.src != null }
|
|
694
|
+
?.takeIf { it.isNotEmpty() }
|
|
695
|
+
?.toTypedArray() ?: tracks
|
|
696
|
+
} else {
|
|
697
|
+
tracks
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
return tracksToFilter.filter { it.src != null }.takeIf { it.isNotEmpty() }?.toTypedArray()
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Search for tracks using the configured search source.
|
|
705
|
+
*
|
|
706
|
+
* @param query The search query string
|
|
707
|
+
* @return ResolvedTrack containing search results as children
|
|
708
|
+
*/
|
|
709
|
+
suspend fun search(query: String): ResolvedTrack {
|
|
710
|
+
return search(
|
|
711
|
+
SearchParams(
|
|
712
|
+
query = query,
|
|
713
|
+
mode = null,
|
|
714
|
+
genre = null,
|
|
715
|
+
artist = null,
|
|
716
|
+
album = null,
|
|
717
|
+
title = null,
|
|
718
|
+
playlist = null,
|
|
719
|
+
)
|
|
720
|
+
)
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* Search for tracks using the configured search source. Returns a ResolvedTrack at the path
|
|
725
|
+
* /__search?q=query with children containing results. Always executes a fresh search and caches
|
|
726
|
+
* results for onGetSearchResult() retrieval.
|
|
727
|
+
*
|
|
728
|
+
* @param params The structured search parameters
|
|
729
|
+
* @return ResolvedTrack containing search results as children
|
|
730
|
+
*/
|
|
731
|
+
suspend fun search(params: SearchParams): ResolvedTrack {
|
|
732
|
+
Timber.d("Executing fresh search for: ${params.query} (mode=${params.mode})")
|
|
733
|
+
|
|
734
|
+
val searchPath = BrowserPathHelper.createSearchPath(params.query)
|
|
735
|
+
|
|
736
|
+
try {
|
|
737
|
+
// Execute search
|
|
738
|
+
val searchResults = resolveSearch(params)
|
|
739
|
+
|
|
740
|
+
// Create ResolvedTrack
|
|
741
|
+
val searchResolvedTrack =
|
|
742
|
+
ResolvedTrack(
|
|
743
|
+
url = searchPath,
|
|
744
|
+
title = "Search: ${params.query}",
|
|
745
|
+
children = searchResults,
|
|
746
|
+
artwork = null,
|
|
747
|
+
artworkSource = null,
|
|
748
|
+
artworkCarPlayTinted = null,
|
|
749
|
+
artist = null,
|
|
750
|
+
description = null,
|
|
751
|
+
subtitle = null,
|
|
752
|
+
album = null,
|
|
753
|
+
genre = null,
|
|
754
|
+
duration = null,
|
|
755
|
+
src = null,
|
|
756
|
+
style = null,
|
|
757
|
+
childrenStyle = null,
|
|
758
|
+
favorited = null,
|
|
759
|
+
groupTitle = null,
|
|
760
|
+
live = null,
|
|
761
|
+
)
|
|
762
|
+
|
|
763
|
+
// Cache search results for getCachedSearchResults()
|
|
764
|
+
lastSearchQuery = params.query
|
|
765
|
+
lastSearchResults = searchResults
|
|
766
|
+
|
|
767
|
+
// Cache individual tracks for Media3 lookups
|
|
768
|
+
cacheChildren(searchResolvedTrack)
|
|
769
|
+
Timber.d(
|
|
770
|
+
"Cached search results for query: ${params.query} with ${searchResults.size} results"
|
|
771
|
+
)
|
|
772
|
+
|
|
773
|
+
return searchResolvedTrack
|
|
774
|
+
} catch (e: Exception) {
|
|
775
|
+
Timber.e(e, "Error during search for query: ${params.query}")
|
|
776
|
+
|
|
777
|
+
// Return empty search result on error
|
|
778
|
+
val emptySearchResult =
|
|
779
|
+
ResolvedTrack(
|
|
780
|
+
url = searchPath,
|
|
781
|
+
title = "Search: ${params.query}",
|
|
782
|
+
children = emptyArray(),
|
|
783
|
+
artwork = null,
|
|
784
|
+
artworkSource = null,
|
|
785
|
+
artworkCarPlayTinted = null,
|
|
786
|
+
artist = null,
|
|
787
|
+
description = null,
|
|
788
|
+
subtitle = null,
|
|
789
|
+
album = null,
|
|
790
|
+
genre = null,
|
|
791
|
+
duration = null,
|
|
792
|
+
src = null,
|
|
793
|
+
style = null,
|
|
794
|
+
childrenStyle = null,
|
|
795
|
+
favorited = null,
|
|
796
|
+
groupTitle = null,
|
|
797
|
+
live = null,
|
|
798
|
+
)
|
|
799
|
+
|
|
800
|
+
return emptySearchResult
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* Get the current navigation path.
|
|
806
|
+
*
|
|
807
|
+
* @return Current path string
|
|
808
|
+
*/
|
|
809
|
+
fun getPath(): String {
|
|
810
|
+
return path
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
/**
|
|
814
|
+
* Get the current loaded content.
|
|
815
|
+
*
|
|
816
|
+
* @return Current ResolvedTrack content or null if none loaded
|
|
817
|
+
*/
|
|
818
|
+
fun getContent(): ResolvedTrack? {
|
|
819
|
+
return content
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/**
|
|
823
|
+
* Get the current cached tabs.
|
|
824
|
+
*
|
|
825
|
+
* @return Current tabs array or null if none loaded
|
|
826
|
+
*/
|
|
827
|
+
fun getTabs(): Array<Track>? {
|
|
828
|
+
return tabs
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/** Set callback for path changes. */
|
|
832
|
+
fun setOnPathChanged(callback: (String) -> Unit) {
|
|
833
|
+
onPathChanged = callback
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/** Set callback for content changes. */
|
|
837
|
+
fun setOnContentChanged(callback: (ResolvedTrack?) -> Unit) {
|
|
838
|
+
onContentChanged = callback
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
/** Set callback for tabs changes. */
|
|
842
|
+
fun setOnTabsChanged(callback: (Array<Track>) -> Unit) {
|
|
843
|
+
onTabsChanged = callback
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* Query navigation tabs from the configured tabs source. This is an async operation that resolves
|
|
848
|
+
* the tabs configuration.
|
|
849
|
+
*
|
|
850
|
+
* @return Array of Track objects representing tabs
|
|
851
|
+
*/
|
|
852
|
+
suspend fun queryTabs(): Array<Track> {
|
|
853
|
+
// Return cached tabs if available
|
|
854
|
+
this.tabs?.let {
|
|
855
|
+
return it
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
Timber.d("Getting navigation tabs")
|
|
859
|
+
|
|
860
|
+
val tabs = resolveTabs()
|
|
861
|
+
|
|
862
|
+
// Validate tabs have stable identifiers
|
|
863
|
+
tabs.forEachIndexed { index, tab ->
|
|
864
|
+
validateTrack(tab, "Tab")
|
|
865
|
+
Timber.d("[TABS] Tab[$index] '${tab.title}': url=${tab.url}")
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
this.tabs = tabs
|
|
869
|
+
return tabs
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
companion object {
|
|
873
|
+
/** Internal path used for the default/root browse source */
|
|
874
|
+
internal const val DEFAULT_ROUTE_PATH = "__default__"
|
|
875
|
+
|
|
876
|
+
/** Internal path used for navigation tabs */
|
|
877
|
+
internal const val TABS_ROUTE_PATH = "__tabs__"
|
|
878
|
+
|
|
879
|
+
/** Internal path used for search */
|
|
880
|
+
internal const val SEARCH_ROUTE_PATH = "__search__"
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* Find the best matching route entry for a path. Uses SimpleRouter for pattern matching, with
|
|
885
|
+
* __default__ as lowest priority fallback.
|
|
886
|
+
*/
|
|
887
|
+
private fun findBestRouteMatch(
|
|
888
|
+
path: String,
|
|
889
|
+
routes: Array<NativeRouteEntry>,
|
|
890
|
+
): Pair<NativeRouteEntry, Map<String, String>>? {
|
|
891
|
+
// Convert to map for router compatibility, excluding default fallback
|
|
892
|
+
val routeMap = routes.filter { it.path != DEFAULT_ROUTE_PATH }.associateBy { it.path }
|
|
893
|
+
|
|
894
|
+
// Try to find a specific route match
|
|
895
|
+
router.findBestMatch(path, routeMap)?.let { (routePattern, match) ->
|
|
896
|
+
val routeEntry = routeMap[routePattern]!!
|
|
897
|
+
return Pair(routeEntry, match.params)
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// Fall back to default route if present
|
|
901
|
+
routes
|
|
902
|
+
.find { it.path == DEFAULT_ROUTE_PATH }
|
|
903
|
+
?.let { defaultRoute ->
|
|
904
|
+
return Pair(defaultRoute, emptyMap())
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
return null
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
/**
|
|
911
|
+
* Resolve a NativeRouteEntry into a ResolvedTrack. The entry has flattened browse options:
|
|
912
|
+
* callback, config, or static.
|
|
913
|
+
*/
|
|
914
|
+
private suspend fun resolveRouteEntry(
|
|
915
|
+
entry: NativeRouteEntry,
|
|
916
|
+
path: String,
|
|
917
|
+
routeParams: Map<String, String>,
|
|
918
|
+
): ResolvedTrack {
|
|
919
|
+
// Priority: callback > config > static
|
|
920
|
+
entry.browseCallback?.let { callback ->
|
|
921
|
+
Timber.d("Resolving route via callback")
|
|
922
|
+
val param = BrowserSourceCallbackParam(path, routeParams)
|
|
923
|
+
val promise = callback.invoke(param)
|
|
924
|
+
val innerPromise = promise.await()
|
|
925
|
+
val result = innerPromise.await()
|
|
926
|
+
|
|
927
|
+
// Handle BrowseResult variant: either ResolvedTrack or BrowseError
|
|
928
|
+
return result.match(
|
|
929
|
+
first = { resolvedTrack -> resolvedTrack },
|
|
930
|
+
second = { browseError -> throw CallbackException(browseError.error) }
|
|
931
|
+
)
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
entry.browseConfig?.let { apiConfig ->
|
|
935
|
+
Timber.d("Resolving route via API config")
|
|
936
|
+
return executeApiRequest(apiConfig, path, routeParams)
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
entry.browseStatic?.let { staticTrack ->
|
|
940
|
+
Timber.d("Resolving route via static track")
|
|
941
|
+
return staticTrack
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
throw ContentNotFoundException(path)
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* Resolve search via the __search__ route entry. The entry has searchCallback or searchConfig.
|
|
949
|
+
*/
|
|
950
|
+
private suspend fun resolveSearch(params: SearchParams): Array<Track> {
|
|
951
|
+
val routes = config.routes ?: return emptyArray()
|
|
952
|
+
|
|
953
|
+
// Find the __search__ route entry
|
|
954
|
+
val searchEntry = routes.find { it.path == SEARCH_ROUTE_PATH }
|
|
955
|
+
if (searchEntry == null) {
|
|
956
|
+
Timber.w("No search route configured")
|
|
957
|
+
return emptyArray()
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
searchEntry.searchCallback?.let { callback ->
|
|
961
|
+
Timber.d("Resolving search via callback")
|
|
962
|
+
val promise = callback.invoke(params)
|
|
963
|
+
val innerPromise = promise.await()
|
|
964
|
+
return innerPromise.await()
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
searchEntry.searchConfig?.let { apiConfig ->
|
|
968
|
+
Timber.d("Resolving search via API config")
|
|
969
|
+
return executeSearchApiRequest(apiConfig, params)
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
Timber.w("Search route has no callback or config")
|
|
973
|
+
return emptyArray()
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/**
|
|
977
|
+
* Resolve tabs via the __tabs__ route entry. Returns children of the resolved track, or empty
|
|
978
|
+
* array if no tabs configured.
|
|
979
|
+
*/
|
|
980
|
+
private suspend fun resolveTabs(): Array<Track> {
|
|
981
|
+
val routes = config.routes ?: return emptyArray()
|
|
982
|
+
|
|
983
|
+
// Find the __tabs__ route entry
|
|
984
|
+
val tabsEntry = routes.find { it.path == TABS_ROUTE_PATH }
|
|
985
|
+
if (tabsEntry == null) {
|
|
986
|
+
Timber.d("No tabs route configured")
|
|
987
|
+
return emptyArray()
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
Timber.d("Resolving tabs via route entry")
|
|
991
|
+
val resolvedTrack = resolveRouteEntry(tabsEntry, TABS_ROUTE_PATH, emptyMap())
|
|
992
|
+
|
|
993
|
+
return resolvedTrack.children ?: emptyArray()
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
/**
|
|
997
|
+
* Execute an API request for browser content. Handles URL parameter substitution, config merging,
|
|
998
|
+
* and transforms.
|
|
999
|
+
*/
|
|
1000
|
+
private suspend fun executeApiRequest(
|
|
1001
|
+
apiConfig: TransformableRequestConfig,
|
|
1002
|
+
path: String,
|
|
1003
|
+
routeParams: Map<String, String>,
|
|
1004
|
+
): ResolvedTrack {
|
|
1005
|
+
return withContext(Dispatchers.IO) {
|
|
1006
|
+
// 1. Start with base config, using the navigation path as default
|
|
1007
|
+
val baseConfig =
|
|
1008
|
+
config.request?.let { req ->
|
|
1009
|
+
RequestConfigBuilder.toRequestConfig(req).copy(path = req.path ?: path)
|
|
1010
|
+
}
|
|
1011
|
+
?: RequestConfig(
|
|
1012
|
+
path = path,
|
|
1013
|
+
method = null,
|
|
1014
|
+
baseUrl = null,
|
|
1015
|
+
headers = null,
|
|
1016
|
+
query = null,
|
|
1017
|
+
body = null,
|
|
1018
|
+
contentType = null,
|
|
1019
|
+
userAgent = null,
|
|
1020
|
+
)
|
|
1021
|
+
val mergedConfig = RequestConfigBuilder.mergeConfig(baseConfig, apiConfig, routeParams)
|
|
1022
|
+
|
|
1023
|
+
// 2. Build and execute HTTP request
|
|
1024
|
+
val httpRequest = RequestConfigBuilder.buildHttpRequest(mergedConfig)
|
|
1025
|
+
val response = httpClient.request(httpRequest)
|
|
1026
|
+
|
|
1027
|
+
response.fold(
|
|
1028
|
+
onSuccess = { httpResponse ->
|
|
1029
|
+
if (httpResponse.isSuccessful) {
|
|
1030
|
+
// 3. Parse response as ResolvedTrack
|
|
1031
|
+
val jsonResolvedTrack = json.decodeFromString<JsonResolvedTrack>(httpResponse.body)
|
|
1032
|
+
jsonResolvedTrack.toNitro()
|
|
1033
|
+
} else {
|
|
1034
|
+
Timber.w(
|
|
1035
|
+
"HTTP request failed with status ${httpResponse.code} for ${httpRequest.url}: ${httpResponse.body}"
|
|
1036
|
+
)
|
|
1037
|
+
throw HttpStatusException(httpResponse.code, "Server returned ${httpResponse.code}")
|
|
1038
|
+
}
|
|
1039
|
+
},
|
|
1040
|
+
onFailure = { exception ->
|
|
1041
|
+
Timber.e(exception, "HTTP request failed")
|
|
1042
|
+
throw NetworkException("Network request failed: ${exception.message}", exception)
|
|
1043
|
+
},
|
|
1044
|
+
)
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Execute an API request for search results. Automatically adds search parameters to request
|
|
1050
|
+
* query:
|
|
1051
|
+
* - q: The search query string (always included)
|
|
1052
|
+
* - mode: The search mode (any, genre, artist, album, song, playlist) - omitted for unstructured
|
|
1053
|
+
* search
|
|
1054
|
+
* - genre, artist, album, title, playlist: Included only when non-null
|
|
1055
|
+
*
|
|
1056
|
+
* Transform callbacks can access and modify all parameters as needed.
|
|
1057
|
+
*/
|
|
1058
|
+
private suspend fun executeSearchApiRequest(
|
|
1059
|
+
apiConfig: TransformableRequestConfig,
|
|
1060
|
+
params: SearchParams,
|
|
1061
|
+
): Array<Track> {
|
|
1062
|
+
return withContext(Dispatchers.IO) {
|
|
1063
|
+
try {
|
|
1064
|
+
// 1. Start with base config
|
|
1065
|
+
val baseConfig =
|
|
1066
|
+
config.request?.let { RequestConfigBuilder.toRequestConfig(it) }
|
|
1067
|
+
?: RequestConfig(
|
|
1068
|
+
method = null,
|
|
1069
|
+
path = null,
|
|
1070
|
+
baseUrl = null,
|
|
1071
|
+
headers = null,
|
|
1072
|
+
query = null,
|
|
1073
|
+
body = null,
|
|
1074
|
+
contentType = null,
|
|
1075
|
+
userAgent = null,
|
|
1076
|
+
)
|
|
1077
|
+
|
|
1078
|
+
// 2. Build query parameters from SearchParams
|
|
1079
|
+
val searchQueryParams = buildMap {
|
|
1080
|
+
put("q", params.query)
|
|
1081
|
+
params.mode?.let { put("mode", it.toString().lowercase()) }
|
|
1082
|
+
params.genre?.let { put("genre", it) }
|
|
1083
|
+
params.artist?.let { put("artist", it) }
|
|
1084
|
+
params.album?.let { put("album", it) }
|
|
1085
|
+
params.title?.let { put("title", it) }
|
|
1086
|
+
params.playlist?.let { put("playlist", it) }
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
// 3. Create a copy of API config with added search parameters
|
|
1090
|
+
val searchConfig =
|
|
1091
|
+
TransformableRequestConfig(
|
|
1092
|
+
transform = apiConfig.transform,
|
|
1093
|
+
method = apiConfig.method,
|
|
1094
|
+
path = apiConfig.path,
|
|
1095
|
+
baseUrl = apiConfig.baseUrl,
|
|
1096
|
+
headers = apiConfig.headers,
|
|
1097
|
+
query = (apiConfig.query ?: emptyMap()) + searchQueryParams,
|
|
1098
|
+
body = apiConfig.body,
|
|
1099
|
+
contentType = apiConfig.contentType,
|
|
1100
|
+
userAgent = apiConfig.userAgent,
|
|
1101
|
+
)
|
|
1102
|
+
|
|
1103
|
+
// 3. Merge configs and apply transform if provided
|
|
1104
|
+
var mergedConfig = RequestConfigBuilder.mergeConfig(baseConfig, searchConfig, emptyMap())
|
|
1105
|
+
|
|
1106
|
+
// 4. Build and execute HTTP request
|
|
1107
|
+
val httpRequest = RequestConfigBuilder.buildHttpRequest(mergedConfig)
|
|
1108
|
+
val response = httpClient.request(httpRequest)
|
|
1109
|
+
|
|
1110
|
+
response.fold(
|
|
1111
|
+
onSuccess = { httpResponse ->
|
|
1112
|
+
if (httpResponse.isSuccessful) {
|
|
1113
|
+
// 4. Parse response as Track array
|
|
1114
|
+
val jsonTracks = json.decodeFromString<List<JsonTrack>>(httpResponse.body)
|
|
1115
|
+
jsonTracks.map { it.toNitro() }.toTypedArray()
|
|
1116
|
+
} else {
|
|
1117
|
+
Timber.w(
|
|
1118
|
+
"Search HTTP request failed with status ${httpResponse.code}: ${httpResponse.body}"
|
|
1119
|
+
)
|
|
1120
|
+
emptyArray()
|
|
1121
|
+
}
|
|
1122
|
+
},
|
|
1123
|
+
onFailure = { exception ->
|
|
1124
|
+
Timber.e(exception, "Search HTTP request failed")
|
|
1125
|
+
emptyArray()
|
|
1126
|
+
},
|
|
1127
|
+
)
|
|
1128
|
+
} catch (e: Exception) {
|
|
1129
|
+
Timber.e(e, "Error executing search API request")
|
|
1130
|
+
emptyArray()
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
/** Exception thrown when no content is configured for a requested path. */
|
|
1137
|
+
class ContentNotFoundException(val path: String) : Exception("Content not found")
|
|
1138
|
+
|
|
1139
|
+
/** Exception thrown when an HTTP request fails with a non-2xx status code. */
|
|
1140
|
+
class HttpStatusException(val statusCode: Int, message: String) : Exception(message)
|
|
1141
|
+
|
|
1142
|
+
/** Exception thrown when a network request fails (connection error, timeout, etc). */
|
|
1143
|
+
class NetworkException(message: String, cause: Throwable? = null) : Exception(message, cause)
|
|
1144
|
+
|
|
1145
|
+
/** Exception thrown when a browse callback returns an error message. */
|
|
1146
|
+
class CallbackException(message: String) : Exception(message)
|
|
1147
|
+
|
|
1148
|
+
/**
|
|
1149
|
+
* Configuration object that holds all browser settings. Uses flattened structure matching
|
|
1150
|
+
* NativeBrowserConfiguration from JS.
|
|
1151
|
+
*/
|
|
1152
|
+
data class BrowserConfig(
|
|
1153
|
+
val request: TransformableRequestConfig? = null,
|
|
1154
|
+
val media: MediaRequestConfig? = null,
|
|
1155
|
+
val artwork: ArtworkRequestConfig? = null,
|
|
1156
|
+
// Routes as array with flattened entries (includes __tabs__, __search__, and __default__ special
|
|
1157
|
+
// routes)
|
|
1158
|
+
val routes: Array<NativeRouteEntry>? = null,
|
|
1159
|
+
// Behavior
|
|
1160
|
+
val singleTrack: Boolean = false,
|
|
1161
|
+
val androidControllerOfflineError: Boolean = true,
|
|
1162
|
+
) {
|
|
1163
|
+
/** Returns true if search functionality is configured (either callback or config). */
|
|
1164
|
+
val hasSearch: Boolean
|
|
1165
|
+
get() {
|
|
1166
|
+
val searchEntry = routes?.find { it.path == BrowserManager.SEARCH_ROUTE_PATH }
|
|
1167
|
+
return searchEntry?.searchCallback != null || searchEntry?.searchConfig != null
|
|
1168
|
+
}
|
|
1169
|
+
}
|