react-native-nitro-player 0.5.8 → 0.5.9-alpha.1
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/android/src/main/cpp/cpp-adapter.cpp +5 -1
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridPlayerQueue.kt +2 -2
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerCore.kt +119 -59
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadDatabase.kt +3 -1
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadManagerCore.kt +19 -8
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadWorker.kt +2 -1
- package/android/src/main/java/com/margelo/nitro/nitroplayer/equalizer/EqualizerCore.kt +14 -2
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaSessionManager.kt +29 -30
- package/android/src/main/java/com/margelo/nitro/nitroplayer/playlist/PlaylistManager.kt +10 -31
- package/android/src/main/java/com/margelo/nitro/nitroplayer/queue/Queue.kt +1 -1
- package/ios/core/TrackPlayerCore.swift +328 -84
- package/ios/download/DownloadDatabase.swift +8 -2
- package/ios/download/DownloadFileManager.swift +11 -2
- package/ios/download/DownloadManagerCore.swift +84 -25
- package/ios/equalizer/EqualizerCore.swift +83 -42
- package/ios/media/MediaSessionManager.swift +5 -5
- package/ios/playlist/PlaylistModel.swift +1 -1
- package/ios/queue/HybridPlayerQueue.swift +2 -0
- package/ios/storage/NitroPlayerStorage.swift +4 -2
- package/lib/hooks/usePlaylist.js +25 -4
- package/nitrogen/generated/android/NitroPlayer+autolinking.cmake +1 -1
- package/nitrogen/generated/android/NitroPlayer+autolinking.gradle +1 -1
- package/nitrogen/generated/android/NitroPlayerOnLoad.cpp +76 -73
- package/nitrogen/generated/android/NitroPlayerOnLoad.hpp +14 -5
- package/nitrogen/generated/android/c++/JCurrentPlayingType.hpp +5 -6
- package/nitrogen/generated/android/c++/JDownloadConfig.hpp +1 -1
- package/nitrogen/generated/android/c++/JDownloadError.hpp +1 -1
- package/nitrogen/generated/android/c++/JDownloadErrorReason.hpp +8 -9
- package/nitrogen/generated/android/c++/JDownloadProgress.hpp +1 -1
- package/nitrogen/generated/android/c++/JDownloadQueueStatus.hpp +1 -1
- package/nitrogen/generated/android/c++/JDownloadState.hpp +7 -8
- package/nitrogen/generated/android/c++/JDownloadStorageInfo.hpp +1 -1
- package/nitrogen/generated/android/c++/JDownloadTask.hpp +1 -1
- package/nitrogen/generated/android/c++/JDownloadedPlaylist.hpp +1 -1
- package/nitrogen/generated/android/c++/JDownloadedTrack.hpp +1 -1
- package/nitrogen/generated/android/c++/JEqualizerBand.hpp +1 -1
- package/nitrogen/generated/android/c++/JEqualizerPreset.hpp +1 -1
- package/nitrogen/generated/android/c++/JEqualizerState.hpp +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_DownloadProgress.hpp +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_DownloadedTrack.hpp +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_TrackItem_std__optional_Reason_.hpp +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_TrackPlayerState_std__optional_Reason_.hpp +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_double_double.hpp +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_double_double_std__optional_bool_.hpp +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_std__variant_nitro__NullType__std__string__.hpp +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_std__string_Playlist_std__optional_QueueOperation_.hpp +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_std__string_std__string_DownloadState_std__optional_DownloadError_.hpp +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_EqualizerBand_.hpp +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_Playlist__std__optional_QueueOperation_.hpp +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_TrackItem__double.hpp +1 -1
- package/nitrogen/generated/android/c++/JGainRange.hpp +1 -1
- package/nitrogen/generated/android/c++/JHybridAndroidAutoMediaLibrarySpec.cpp +8 -1
- package/nitrogen/generated/android/c++/JHybridAndroidAutoMediaLibrarySpec.hpp +2 -1
- package/nitrogen/generated/android/c++/JHybridAudioDevicesSpec.cpp +8 -1
- package/nitrogen/generated/android/c++/JHybridAudioDevicesSpec.hpp +2 -1
- package/nitrogen/generated/android/c++/JHybridDownloadManagerSpec.cpp +9 -1
- package/nitrogen/generated/android/c++/JHybridDownloadManagerSpec.hpp +2 -1
- package/nitrogen/generated/android/c++/JHybridEqualizerSpec.cpp +8 -1
- package/nitrogen/generated/android/c++/JHybridEqualizerSpec.hpp +2 -1
- package/nitrogen/generated/android/c++/JHybridPlayerQueueSpec.cpp +8 -1
- package/nitrogen/generated/android/c++/JHybridPlayerQueueSpec.hpp +2 -1
- package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.cpp +9 -1
- package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.hpp +2 -1
- package/nitrogen/generated/android/c++/JPlaybackSource.hpp +4 -5
- package/nitrogen/generated/android/c++/JPlayerConfig.hpp +1 -1
- package/nitrogen/generated/android/c++/JPlayerState.hpp +1 -1
- package/nitrogen/generated/android/c++/JPlaylist.hpp +1 -1
- package/nitrogen/generated/android/c++/JPresetType.hpp +3 -4
- package/nitrogen/generated/android/c++/JQueueOperation.hpp +5 -6
- package/nitrogen/generated/android/c++/JReason.hpp +6 -7
- package/nitrogen/generated/android/c++/JRepeatMode.hpp +4 -5
- package/nitrogen/generated/android/c++/JStorageLocation.hpp +3 -4
- package/nitrogen/generated/android/c++/JTAudioDevice.hpp +1 -1
- package/nitrogen/generated/android/c++/JTrackItem.hpp +1 -1
- package/nitrogen/generated/android/c++/JTrackPlayerState.hpp +4 -5
- package/nitrogen/generated/android/c++/JVariant_NullType_Double.cpp +1 -1
- package/nitrogen/generated/android/c++/JVariant_NullType_Double.hpp +3 -3
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadError.cpp +1 -1
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadError.hpp +3 -3
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadTask.cpp +1 -1
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadTask.hpp +3 -3
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadedPlaylist.cpp +1 -1
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadedPlaylist.hpp +3 -3
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadedTrack.cpp +1 -1
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadedTrack.hpp +3 -3
- package/nitrogen/generated/android/c++/JVariant_NullType_Playlist.cpp +1 -1
- package/nitrogen/generated/android/c++/JVariant_NullType_Playlist.hpp +3 -3
- package/nitrogen/generated/android/c++/JVariant_NullType_String.cpp +1 -1
- package/nitrogen/generated/android/c++/JVariant_NullType_String.hpp +3 -3
- package/nitrogen/generated/android/c++/JVariant_NullType_TrackItem.cpp +1 -1
- package/nitrogen/generated/android/c++/JVariant_NullType_TrackItem.hpp +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/CurrentPlayingType.kt +3 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadConfig.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadError.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadErrorReason.kt +3 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadProgress.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadQueueStatus.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadState.kt +3 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadStorageInfo.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadTask.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadedPlaylist.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadedTrack.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/EqualizerBand.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/EqualizerPreset.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/EqualizerState.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_DownloadProgress.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_DownloadedTrack.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_TrackItem_std__optional_Reason_.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_TrackPlayerState_std__optional_Reason_.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_bool.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_double_double.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_double_double_std__optional_bool_.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__optional_std__variant_nitro__NullType__std__string__.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__string_Playlist_std__optional_QueueOperation_.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__string_std__string_DownloadState_std__optional_DownloadError_.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__vector_EqualizerBand_.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__vector_Playlist__std__optional_QueueOperation_.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__vector_TrackItem__double.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/GainRange.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridAndroidAutoMediaLibrarySpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridAudioDevicesSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridDownloadManagerSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridEqualizerSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridPlayerQueueSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridTrackPlayerSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/NitroPlayerOnLoad.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/PlaybackSource.kt +3 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/PlayerConfig.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/PlayerState.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Playlist.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/PresetType.kt +3 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/QueueOperation.kt +3 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Reason.kt +3 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/RepeatMode.kt +3 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/StorageLocation.kt +3 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/TAudioDevice.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/TrackItem.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/TrackPlayerState.kt +3 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Variant_NullType_Double.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Variant_NullType_DownloadError.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Variant_NullType_DownloadTask.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Variant_NullType_DownloadedPlaylist.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Variant_NullType_DownloadedTrack.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Variant_NullType_Playlist.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Variant_NullType_String.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Variant_NullType_TrackItem.kt +1 -1
- package/nitrogen/generated/ios/NitroPlayer+autolinking.rb +2 -2
- package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.cpp +1 -1
- package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.hpp +21 -21
- package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Umbrella.hpp +1 -1
- package/nitrogen/generated/ios/NitroPlayerAutolinking.mm +1 -1
- package/nitrogen/generated/ios/NitroPlayerAutolinking.swift +25 -36
- package/nitrogen/generated/ios/c++/HybridAudioRoutePickerSpecSwift.cpp +1 -1
- package/nitrogen/generated/ios/c++/HybridAudioRoutePickerSpecSwift.hpp +7 -1
- package/nitrogen/generated/ios/c++/HybridDownloadManagerSpecSwift.cpp +1 -1
- package/nitrogen/generated/ios/c++/HybridDownloadManagerSpecSwift.hpp +7 -1
- package/nitrogen/generated/ios/c++/HybridEqualizerSpecSwift.cpp +1 -1
- package/nitrogen/generated/ios/c++/HybridEqualizerSpecSwift.hpp +7 -1
- package/nitrogen/generated/ios/c++/HybridPlayerQueueSpecSwift.cpp +1 -1
- package/nitrogen/generated/ios/c++/HybridPlayerQueueSpecSwift.hpp +7 -1
- package/nitrogen/generated/ios/c++/HybridTrackPlayerSpecSwift.cpp +1 -1
- package/nitrogen/generated/ios/c++/HybridTrackPlayerSpecSwift.hpp +7 -1
- package/nitrogen/generated/ios/swift/CurrentPlayingType.swift +1 -1
- package/nitrogen/generated/ios/swift/DownloadConfig.swift +78 -168
- package/nitrogen/generated/ios/swift/DownloadError.swift +9 -34
- package/nitrogen/generated/ios/swift/DownloadErrorReason.swift +1 -1
- package/nitrogen/generated/ios/swift/DownloadProgress.swift +13 -50
- package/nitrogen/generated/ios/swift/DownloadQueueStatus.swift +15 -58
- package/nitrogen/generated/ios/swift/DownloadState.swift +1 -1
- package/nitrogen/generated/ios/swift/DownloadStorageInfo.swift +11 -42
- package/nitrogen/generated/ios/swift/DownloadTask.swift +97 -210
- package/nitrogen/generated/ios/swift/DownloadedPlaylist.swift +13 -56
- package/nitrogen/generated/ios/swift/DownloadedTrack.swift +34 -90
- package/nitrogen/generated/ios/swift/EqualizerBand.swift +9 -34
- package/nitrogen/generated/ios/swift/EqualizerPreset.swift +7 -32
- package/nitrogen/generated/ios/swift/EqualizerState.swift +26 -64
- package/nitrogen/generated/ios/swift/Func_void.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_DownloadProgress.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_DownloadStorageInfo.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_DownloadedTrack.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_PlayerState.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_TrackItem_std__optional_Reason_.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_TrackPlayerState_std__optional_Reason_.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_bool.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_double.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_double_double.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_double_double_std__optional_bool_.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_std__optional_std__variant_nitro__NullType__std__string__.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_std__string.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_std__string_Playlist_std__optional_QueueOperation_.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_std__string_std__string_DownloadState_std__optional_DownloadError_.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_std__vector_EqualizerBand_.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_std__vector_Playlist__std__optional_QueueOperation_.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_std__vector_TrackItem_.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_std__vector_TrackItem__double.swift +1 -2
- package/nitrogen/generated/ios/swift/Func_void_std__vector_std__string_.swift +1 -2
- package/nitrogen/generated/ios/swift/GainRange.swift +5 -18
- package/nitrogen/generated/ios/swift/HybridAudioRoutePickerSpec.swift +3 -4
- package/nitrogen/generated/ios/swift/HybridAudioRoutePickerSpec_cxx.swift +9 -2
- package/nitrogen/generated/ios/swift/HybridDownloadManagerSpec.swift +3 -4
- package/nitrogen/generated/ios/swift/HybridDownloadManagerSpec_cxx.swift +9 -2
- package/nitrogen/generated/ios/swift/HybridEqualizerSpec.swift +3 -4
- package/nitrogen/generated/ios/swift/HybridEqualizerSpec_cxx.swift +9 -2
- package/nitrogen/generated/ios/swift/HybridPlayerQueueSpec.swift +3 -4
- package/nitrogen/generated/ios/swift/HybridPlayerQueueSpec_cxx.swift +25 -4
- package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec.swift +3 -4
- package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec_cxx.swift +9 -2
- package/nitrogen/generated/ios/swift/PlaybackSource.swift +1 -1
- package/nitrogen/generated/ios/swift/PlayerConfig.swift +37 -79
- package/nitrogen/generated/ios/swift/PlayerState.swift +53 -122
- package/nitrogen/generated/ios/swift/Playlist.swift +49 -112
- package/nitrogen/generated/ios/swift/PresetType.swift +1 -1
- package/nitrogen/generated/ios/swift/QueueOperation.swift +1 -1
- package/nitrogen/generated/ios/swift/Reason.swift +1 -1
- package/nitrogen/generated/ios/swift/RepeatMode.swift +1 -1
- package/nitrogen/generated/ios/swift/StorageLocation.swift +1 -1
- package/nitrogen/generated/ios/swift/TrackItem.swift +43 -111
- package/nitrogen/generated/ios/swift/TrackPlayerState.swift +1 -1
- package/nitrogen/generated/ios/swift/Variant_NullType_Double.swift +1 -1
- package/nitrogen/generated/ios/swift/Variant_NullType_DownloadError.swift +1 -1
- package/nitrogen/generated/ios/swift/Variant_NullType_DownloadTask.swift +1 -1
- package/nitrogen/generated/ios/swift/Variant_NullType_DownloadedPlaylist.swift +1 -1
- package/nitrogen/generated/ios/swift/Variant_NullType_DownloadedTrack.swift +1 -1
- package/nitrogen/generated/ios/swift/Variant_NullType_Playlist.swift +1 -1
- package/nitrogen/generated/ios/swift/Variant_NullType_String.swift +1 -1
- package/nitrogen/generated/ios/swift/Variant_NullType_TrackItem.swift +1 -1
- package/nitrogen/generated/shared/c++/CurrentPlayingType.hpp +1 -1
- package/nitrogen/generated/shared/c++/DownloadConfig.hpp +34 -26
- package/nitrogen/generated/shared/c++/DownloadError.hpp +22 -14
- package/nitrogen/generated/shared/c++/DownloadErrorReason.hpp +1 -1
- package/nitrogen/generated/shared/c++/DownloadProgress.hpp +28 -20
- package/nitrogen/generated/shared/c++/DownloadQueueStatus.hpp +31 -23
- package/nitrogen/generated/shared/c++/DownloadState.hpp +1 -1
- package/nitrogen/generated/shared/c++/DownloadStorageInfo.hpp +25 -17
- package/nitrogen/generated/shared/c++/DownloadTask.hpp +40 -32
- package/nitrogen/generated/shared/c++/DownloadedPlaylist.hpp +28 -20
- package/nitrogen/generated/shared/c++/DownloadedTrack.hpp +31 -23
- package/nitrogen/generated/shared/c++/EqualizerBand.hpp +22 -14
- package/nitrogen/generated/shared/c++/EqualizerPreset.hpp +19 -11
- package/nitrogen/generated/shared/c++/EqualizerState.hpp +19 -11
- package/nitrogen/generated/shared/c++/GainRange.hpp +16 -8
- package/nitrogen/generated/shared/c++/HybridAndroidAutoMediaLibrarySpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridAndroidAutoMediaLibrarySpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridAudioDevicesSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridAudioDevicesSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridAudioRoutePickerSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridAudioRoutePickerSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridDownloadManagerSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridDownloadManagerSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridEqualizerSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridEqualizerSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridPlayerQueueSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridPlayerQueueSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/PlaybackSource.hpp +1 -1
- package/nitrogen/generated/shared/c++/PlayerConfig.hpp +22 -14
- package/nitrogen/generated/shared/c++/PlayerState.hpp +31 -23
- package/nitrogen/generated/shared/c++/Playlist.hpp +25 -17
- package/nitrogen/generated/shared/c++/PresetType.hpp +1 -1
- package/nitrogen/generated/shared/c++/QueueOperation.hpp +1 -1
- package/nitrogen/generated/shared/c++/Reason.hpp +1 -1
- package/nitrogen/generated/shared/c++/RepeatMode.hpp +1 -1
- package/nitrogen/generated/shared/c++/StorageLocation.hpp +1 -1
- package/nitrogen/generated/shared/c++/TAudioDevice.hpp +22 -14
- package/nitrogen/generated/shared/c++/TrackItem.hpp +34 -26
- package/nitrogen/generated/shared/c++/TrackPlayerState.hpp +1 -1
- package/package.json +3 -3
- package/src/hooks/usePlaylist.ts +26 -4
|
@@ -82,6 +82,12 @@ final class DownloadDatabase {
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
private func _isTrackDownloadedUnsafe(trackId: String) -> Bool {
|
|
86
|
+
guard let record = downloadedTracks[trackId] else { return false }
|
|
87
|
+
let absolutePath = resolveAbsolutePath(for: record)
|
|
88
|
+
return FileManager.default.fileExists(atPath: absolutePath)
|
|
89
|
+
}
|
|
90
|
+
|
|
85
91
|
func isPlaylistDownloaded(playlistId: String) -> Bool {
|
|
86
92
|
return queue.sync {
|
|
87
93
|
guard let trackIds = playlistTracks[playlistId], !trackIds.isEmpty else { return false }
|
|
@@ -93,7 +99,7 @@ final class DownloadDatabase {
|
|
|
93
99
|
|
|
94
100
|
// Check if all tracks are downloaded
|
|
95
101
|
for track in playlistModel.tracks {
|
|
96
|
-
if !
|
|
102
|
+
if !_isTrackDownloadedUnsafe(trackId: track.id) {
|
|
97
103
|
return false
|
|
98
104
|
}
|
|
99
105
|
}
|
|
@@ -108,7 +114,7 @@ final class DownloadDatabase {
|
|
|
108
114
|
|
|
109
115
|
// Check if at least one track is downloaded
|
|
110
116
|
for trackId in trackIds {
|
|
111
|
-
if
|
|
117
|
+
if _isTrackDownloadedUnsafe(trackId: trackId) {
|
|
112
118
|
return true
|
|
113
119
|
}
|
|
114
120
|
}
|
|
@@ -304,8 +304,18 @@ final class DownloadFileManager {
|
|
|
304
304
|
return bytesFreed
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
+
private static let commonAudioExtensions = ["mp3", "m4a", "aac", "wav", "flac", "ogg", "opus", "mp4"]
|
|
308
|
+
|
|
307
309
|
func getLocalPath(for trackId: String) -> String? {
|
|
308
|
-
//
|
|
310
|
+
// Try common extensions first (fast O(1) path)
|
|
311
|
+
for ext in Self.commonAudioExtensions {
|
|
312
|
+
let privatePath = privateDownloadsDirectory.appendingPathComponent("\(trackId).\(ext)").path
|
|
313
|
+
if fileManager.fileExists(atPath: privatePath) { return privatePath }
|
|
314
|
+
let publicPath = publicDownloadsDirectory.appendingPathComponent("\(trackId).\(ext)").path
|
|
315
|
+
if fileManager.fileExists(atPath: publicPath) { return publicPath }
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Fallback to directory enumeration for uncommon extensions
|
|
309
319
|
let privateFiles =
|
|
310
320
|
(try? fileManager.contentsOfDirectory(
|
|
311
321
|
at: privateDownloadsDirectory, includingPropertiesForKeys: nil)) ?? []
|
|
@@ -315,7 +325,6 @@ final class DownloadFileManager {
|
|
|
315
325
|
}
|
|
316
326
|
}
|
|
317
327
|
|
|
318
|
-
// Check public directory
|
|
319
328
|
let publicFiles =
|
|
320
329
|
(try? fileManager.contentsOfDirectory(
|
|
321
330
|
at: publicDownloadsDirectory, includingPropertiesForKeys: nil)) ?? []
|
|
@@ -58,6 +58,9 @@ final class DownloadManagerCore: NSObject {
|
|
|
58
58
|
/// Playlist associations (downloadId -> playlistId)
|
|
59
59
|
private var playlistAssociations: [String: String] = [:]
|
|
60
60
|
|
|
61
|
+
/// Cached parsed (downloadId, trackId) tuples per task description to avoid repeated string splitting
|
|
62
|
+
private var parsedDescriptionCache: [String: (downloadId: String, trackId: String)] = [:]
|
|
63
|
+
|
|
61
64
|
/// Background completion handler from AppDelegate
|
|
62
65
|
var backgroundCompletionHandler: (() -> Void)?
|
|
63
66
|
|
|
@@ -258,10 +261,50 @@ final class DownloadManagerCore: NSObject {
|
|
|
258
261
|
}
|
|
259
262
|
}
|
|
260
263
|
|
|
264
|
+
private func _pauseDownloadUnsafe(downloadId: String) {
|
|
265
|
+
guard let task = self.activeTasks[downloadId] else { return }
|
|
266
|
+
task.cancel(byProducingResumeData: { resumeData in
|
|
267
|
+
self.taskMetadata[downloadId]?.resumeData = resumeData
|
|
268
|
+
})
|
|
269
|
+
self.taskMetadata[downloadId]?.state = .paused
|
|
270
|
+
if let trackId = self.taskMetadata[downloadId]?.trackId {
|
|
271
|
+
self.notifyStateChange(downloadId: downloadId, trackId: trackId, state: .paused, error: nil)
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
private func _resumeDownloadUnsafe(downloadId: String) {
|
|
276
|
+
guard let metadata = self.taskMetadata[downloadId] else { return }
|
|
277
|
+
var task: URLSessionDownloadTask
|
|
278
|
+
if let resumeData = metadata.resumeData {
|
|
279
|
+
task = self.backgroundSession.downloadTask(withResumeData: resumeData)
|
|
280
|
+
} else if let track = self.trackMetadata[metadata.trackId],
|
|
281
|
+
let url = URL(string: track.url) {
|
|
282
|
+
task = self.backgroundSession.downloadTask(with: url)
|
|
283
|
+
} else { return }
|
|
284
|
+
task.taskDescription = "\(downloadId)|\(metadata.trackId)"
|
|
285
|
+
self.activeTasks[downloadId] = task
|
|
286
|
+
self.taskMetadata[downloadId]?.state = .downloading
|
|
287
|
+
self.taskMetadata[downloadId]?.resumeData = nil
|
|
288
|
+
task.resume()
|
|
289
|
+
self.notifyStateChange(downloadId: downloadId, trackId: metadata.trackId, state: .downloading, error: nil)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private func _cancelDownloadUnsafe(downloadId: String) {
|
|
293
|
+
guard let task = self.activeTasks[downloadId] else { return }
|
|
294
|
+
task.cancel()
|
|
295
|
+
if let trackId = self.taskMetadata[downloadId]?.trackId {
|
|
296
|
+
self.taskMetadata[downloadId]?.state = .cancelled
|
|
297
|
+
self.notifyStateChange(downloadId: downloadId, trackId: trackId, state: .cancelled, error: nil)
|
|
298
|
+
self.cleanupPersistedMetadata(trackId: trackId, downloadId: downloadId)
|
|
299
|
+
}
|
|
300
|
+
self.activeTasks.removeValue(forKey: downloadId)
|
|
301
|
+
self.taskMetadata.removeValue(forKey: downloadId)
|
|
302
|
+
}
|
|
303
|
+
|
|
261
304
|
func pauseAllDownloads() {
|
|
262
305
|
queue.async(flags: .barrier) {
|
|
263
306
|
for downloadId in self.activeTasks.keys {
|
|
264
|
-
self.
|
|
307
|
+
self._pauseDownloadUnsafe(downloadId: downloadId)
|
|
265
308
|
}
|
|
266
309
|
}
|
|
267
310
|
}
|
|
@@ -270,7 +313,7 @@ final class DownloadManagerCore: NSObject {
|
|
|
270
313
|
queue.async(flags: .barrier) {
|
|
271
314
|
for downloadId in self.taskMetadata.keys where self.taskMetadata[downloadId]?.state == .paused
|
|
272
315
|
{
|
|
273
|
-
self.
|
|
316
|
+
self._resumeDownloadUnsafe(downloadId: downloadId)
|
|
274
317
|
}
|
|
275
318
|
}
|
|
276
319
|
}
|
|
@@ -278,7 +321,7 @@ final class DownloadManagerCore: NSObject {
|
|
|
278
321
|
func cancelAllDownloads() {
|
|
279
322
|
queue.async(flags: .barrier) {
|
|
280
323
|
for downloadId in self.activeTasks.keys {
|
|
281
|
-
self.
|
|
324
|
+
self._cancelDownloadUnsafe(downloadId: downloadId)
|
|
282
325
|
}
|
|
283
326
|
}
|
|
284
327
|
}
|
|
@@ -302,15 +345,24 @@ final class DownloadManagerCore: NSObject {
|
|
|
302
345
|
|
|
303
346
|
func getQueueStatus() -> DownloadQueueStatus {
|
|
304
347
|
return queue.sync {
|
|
305
|
-
|
|
348
|
+
var pendingCount = 0
|
|
349
|
+
var activeCount = 0
|
|
350
|
+
var failedCount = 0
|
|
351
|
+
var totalBytes = 0.0
|
|
352
|
+
var downloadedBytes = 0.0
|
|
353
|
+
|
|
354
|
+
for m in taskMetadata.values {
|
|
355
|
+
switch m.state {
|
|
356
|
+
case .pending: pendingCount += 1
|
|
357
|
+
case .downloading: activeCount += 1
|
|
358
|
+
case .failed: failedCount += 1
|
|
359
|
+
default: break
|
|
360
|
+
}
|
|
361
|
+
totalBytes += m.totalBytes ?? 0
|
|
362
|
+
downloadedBytes += m.bytesDownloaded
|
|
363
|
+
}
|
|
306
364
|
|
|
307
|
-
let pendingCount = metadata.filter { $0.state == .pending }.count
|
|
308
|
-
let activeCount = metadata.filter { $0.state == .downloading }.count
|
|
309
365
|
let completedCount = DownloadDatabase.shared.getAllDownloadedTracks().count
|
|
310
|
-
let failedCount = metadata.filter { $0.state == .failed }.count
|
|
311
|
-
|
|
312
|
-
let totalBytes = metadata.reduce(0.0) { $0 + ($1.totalBytes ?? 0) }
|
|
313
|
-
let downloadedBytes = metadata.reduce(0.0) { $0 + $1.bytesDownloaded }
|
|
314
366
|
|
|
315
367
|
return DownloadQueueStatus(
|
|
316
368
|
pendingCount: Double(pendingCount),
|
|
@@ -601,6 +653,17 @@ final class DownloadManagerCore: NSObject {
|
|
|
601
653
|
savePersistedMetadata()
|
|
602
654
|
}
|
|
603
655
|
|
|
656
|
+
private func parseTaskDescription(_ description: String) -> (downloadId: String, trackId: String)? {
|
|
657
|
+
if let cached = parsedDescriptionCache[description] {
|
|
658
|
+
return cached
|
|
659
|
+
}
|
|
660
|
+
let parts = description.split(separator: "|")
|
|
661
|
+
guard parts.count == 2 else { return nil }
|
|
662
|
+
let result = (downloadId: String(parts[0]), trackId: String(parts[1]))
|
|
663
|
+
parsedDescriptionCache[description] = result
|
|
664
|
+
return result
|
|
665
|
+
}
|
|
666
|
+
|
|
604
667
|
// MARK: - TrackItem Serialization
|
|
605
668
|
|
|
606
669
|
private func trackItemToRecord(_ track: TrackItem) -> TrackItemRecord {
|
|
@@ -725,14 +788,13 @@ extension DownloadManagerCore: URLSessionDownloadDelegate {
|
|
|
725
788
|
NitroPlayerLogger.log("DownloadManagerCore", "❌ No task description")
|
|
726
789
|
return
|
|
727
790
|
}
|
|
728
|
-
let
|
|
729
|
-
guard parts.count == 2 else {
|
|
791
|
+
guard let parsed = parseTaskDescription(description) else {
|
|
730
792
|
NitroPlayerLogger.log("DownloadManagerCore", "❌ Invalid task description format: \(description)")
|
|
731
793
|
return
|
|
732
794
|
}
|
|
733
795
|
|
|
734
|
-
let downloadId =
|
|
735
|
-
let trackId =
|
|
796
|
+
let downloadId = parsed.downloadId
|
|
797
|
+
let trackId = parsed.trackId
|
|
736
798
|
|
|
737
799
|
NitroPlayerLogger.log("DownloadManagerCore", "🎯 Processing completion for downloadId=\(downloadId), trackId=\(trackId)")
|
|
738
800
|
|
|
@@ -834,12 +896,11 @@ extension DownloadManagerCore: URLSessionDownloadDelegate {
|
|
|
834
896
|
_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64,
|
|
835
897
|
totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64
|
|
836
898
|
) {
|
|
837
|
-
guard let description = downloadTask.taskDescription
|
|
838
|
-
|
|
839
|
-
guard parts.count == 2 else { return }
|
|
899
|
+
guard let description = downloadTask.taskDescription,
|
|
900
|
+
let parsed = parseTaskDescription(description) else { return }
|
|
840
901
|
|
|
841
|
-
let downloadId =
|
|
842
|
-
let trackId =
|
|
902
|
+
let downloadId = parsed.downloadId
|
|
903
|
+
let trackId = parsed.trackId
|
|
843
904
|
|
|
844
905
|
queue.async(flags: .barrier) {
|
|
845
906
|
self.taskMetadata[downloadId]?.bytesDownloaded = Double(totalBytesWritten)
|
|
@@ -862,14 +923,12 @@ extension DownloadManagerCore: URLSessionDownloadDelegate {
|
|
|
862
923
|
|
|
863
924
|
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
|
|
864
925
|
guard let downloadTask = task as? URLSessionDownloadTask,
|
|
865
|
-
let description = downloadTask.taskDescription
|
|
926
|
+
let description = downloadTask.taskDescription,
|
|
927
|
+
let parsed = parseTaskDescription(description)
|
|
866
928
|
else { return }
|
|
867
929
|
|
|
868
|
-
let
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
let downloadId = String(parts[0])
|
|
872
|
-
let trackId = String(parts[1])
|
|
930
|
+
let downloadId = parsed.downloadId
|
|
931
|
+
let trackId = parsed.trackId
|
|
873
932
|
|
|
874
933
|
guard let error = error else { return } // Success case handled in didFinishDownloadingTo
|
|
875
934
|
|
|
@@ -28,6 +28,8 @@ class EqualizerCore {
|
|
|
28
28
|
|
|
29
29
|
// Current gains storage - internal so TapContext can access
|
|
30
30
|
private(set) var currentGains: [Double] = [0, 0, 0, 0, 0]
|
|
31
|
+
private var cachedBands: [EqualizerBand]?
|
|
32
|
+
private var cachedCustomPresets: [EqualizerPreset]?
|
|
31
33
|
|
|
32
34
|
// Dirty flag: set when gains change so TapContext only recalculates when needed
|
|
33
35
|
var gainsDirty: Bool = true
|
|
@@ -89,11 +91,35 @@ class EqualizerCore {
|
|
|
89
91
|
|
|
90
92
|
// MARK: - Audio Mix Creation for AVPlayerItem
|
|
91
93
|
|
|
92
|
-
/// Applies an AVAudioMix with equalizer processing for the given AVPlayerItem
|
|
94
|
+
/// Applies an AVAudioMix with equalizer processing for the given AVPlayerItem.
|
|
95
|
+
/// No-ops when the equalizer is disabled so that AVPlayerItems remain tap-free,
|
|
96
|
+
/// keeping the audio pipeline configuration identical across all queued items
|
|
97
|
+
/// and allowing AVQueuePlayer to perform seamless gapless transitions.
|
|
98
|
+
///
|
|
99
|
+
/// When the asset's "tracks" key is already loaded (e.g. from preloading),
|
|
100
|
+
/// the mix is applied **synchronously** so the item enters AVQueuePlayer with
|
|
101
|
+
/// the correct tap from the start — avoiding a pipeline reconfiguration that
|
|
102
|
+
/// causes an audible gap at the transition.
|
|
93
103
|
func applyAudioMix(to playerItem: AVPlayerItem) {
|
|
104
|
+
guard isEqualizerEnabled else {
|
|
105
|
+
// Ensure no stale tap remains from a previous enable/disable cycle
|
|
106
|
+
if playerItem.audioMix != nil {
|
|
107
|
+
playerItem.audioMix = nil
|
|
108
|
+
}
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
|
|
94
112
|
let asset = playerItem.asset
|
|
95
113
|
|
|
96
|
-
//
|
|
114
|
+
// Fast path: "tracks" already loaded (from preloadUpcomingTracks) — apply synchronously.
|
|
115
|
+
var keyError: NSError?
|
|
116
|
+
if asset.statusOfValue(forKey: "tracks", error: &keyError) == .loaded {
|
|
117
|
+
buildAndApplyAudioMix(to: playerItem, asset: asset)
|
|
118
|
+
NitroPlayerLogger.log("EqualizerCore", "✅ Applied audio mix with EQ tap to player item (sync — preloaded)")
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Slow path: load "tracks" key asynchronously to avoid blocking
|
|
97
123
|
asset.loadValuesAsynchronously(forKeys: ["tracks"]) { [weak self] in
|
|
98
124
|
guard let self = self else { return }
|
|
99
125
|
|
|
@@ -111,50 +137,55 @@ class EqualizerCore {
|
|
|
111
137
|
return
|
|
112
138
|
}
|
|
113
139
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
140
|
+
// Apply directly — audioMix is thread-safe and applying on the
|
|
141
|
+
// loadValues completion queue avoids a main-thread hop that would
|
|
142
|
+
// delay tap attachment and risk a pipeline mismatch at pre-roll time.
|
|
143
|
+
self.buildAndApplyAudioMix(to: playerItem, asset: asset)
|
|
144
|
+
NitroPlayerLogger.log("EqualizerCore", "✅ Applied audio mix with EQ tap to player item (async)")
|
|
145
|
+
}
|
|
146
|
+
}
|
|
118
147
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
init: tapInitCallback,
|
|
127
|
-
finalize: tapFinalizeCallback,
|
|
128
|
-
prepare: tapPrepareCallback,
|
|
129
|
-
unprepare: tapUnprepareCallback,
|
|
130
|
-
process: tapProcessCallback
|
|
131
|
-
)
|
|
148
|
+
/// Creates an MTAudioProcessingTap-backed AVAudioMix and sets it on the player item.
|
|
149
|
+
/// Must be called when the asset's "tracks" key is already loaded.
|
|
150
|
+
private func buildAndApplyAudioMix(to playerItem: AVPlayerItem, asset: AVAsset) {
|
|
151
|
+
guard let audioTrack = asset.tracks(withMediaType: .audio).first else {
|
|
152
|
+
NitroPlayerLogger.log("EqualizerCore", "⚠️ No audio track found in asset")
|
|
153
|
+
return
|
|
154
|
+
}
|
|
132
155
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
)
|
|
156
|
+
// Create audio mix input parameters
|
|
157
|
+
let inputParams = AVMutableAudioMixInputParameters(track: audioTrack)
|
|
158
|
+
|
|
159
|
+
// Create the audio processing tap
|
|
160
|
+
var callbacks = MTAudioProcessingTapCallbacks(
|
|
161
|
+
version: kMTAudioProcessingTapCallbacksVersion_0,
|
|
162
|
+
clientInfo: UnsafeMutableRawPointer(Unmanaged.passRetained(self).toOpaque()),
|
|
163
|
+
init: tapInitCallback,
|
|
164
|
+
finalize: tapFinalizeCallback,
|
|
165
|
+
prepare: tapPrepareCallback,
|
|
166
|
+
unprepare: tapUnprepareCallback,
|
|
167
|
+
process: tapProcessCallback
|
|
168
|
+
)
|
|
140
169
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
170
|
+
var tap: MTAudioProcessingTap?
|
|
171
|
+
let createStatus = MTAudioProcessingTapCreate(
|
|
172
|
+
kCFAllocatorDefault,
|
|
173
|
+
&callbacks,
|
|
174
|
+
kMTAudioProcessingTapCreationFlag_PreEffects,
|
|
175
|
+
&tap
|
|
176
|
+
)
|
|
145
177
|
|
|
146
|
-
|
|
178
|
+
guard createStatus == noErr, let audioTap = tap else {
|
|
179
|
+
NitroPlayerLogger.log("EqualizerCore", "❌ Failed to create audio processing tap, status: \(createStatus)")
|
|
180
|
+
return
|
|
181
|
+
}
|
|
147
182
|
|
|
148
|
-
|
|
149
|
-
let audioMix = AVMutableAudioMix()
|
|
150
|
-
audioMix.inputParameters = [inputParams]
|
|
183
|
+
inputParams.audioTapProcessor = audioTap
|
|
151
184
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
}
|
|
185
|
+
// Create and apply audio mix
|
|
186
|
+
let audioMix = AVMutableAudioMix()
|
|
187
|
+
audioMix.inputParameters = [inputParams]
|
|
188
|
+
playerItem.audioMix = audioMix
|
|
158
189
|
}
|
|
159
190
|
|
|
160
191
|
// MARK: - Public Methods
|
|
@@ -174,7 +205,8 @@ class EqualizerCore {
|
|
|
174
205
|
}
|
|
175
206
|
|
|
176
207
|
func getBands() -> [EqualizerBand] {
|
|
177
|
-
|
|
208
|
+
if let cached = cachedBands { return cached }
|
|
209
|
+
let bands = (0..<5).map { i in
|
|
178
210
|
EqualizerBand(
|
|
179
211
|
index: Double(i),
|
|
180
212
|
centerFrequency: Double(frequencies[i]),
|
|
@@ -182,6 +214,8 @@ class EqualizerCore {
|
|
|
182
214
|
frequencyLabel: frequencyLabels[i]
|
|
183
215
|
)
|
|
184
216
|
}
|
|
217
|
+
cachedBands = bands
|
|
218
|
+
return bands
|
|
185
219
|
}
|
|
186
220
|
|
|
187
221
|
func setBandGain(bandIndex: Int, gainDb: Double) -> Bool {
|
|
@@ -189,6 +223,7 @@ class EqualizerCore {
|
|
|
189
223
|
|
|
190
224
|
let clampedGain = max(-12.0, min(12.0, gainDb))
|
|
191
225
|
currentGains[bandIndex] = clampedGain
|
|
226
|
+
cachedBands = nil
|
|
192
227
|
gainsDirty = true
|
|
193
228
|
|
|
194
229
|
currentPresetName = nil
|
|
@@ -207,6 +242,7 @@ class EqualizerCore {
|
|
|
207
242
|
for i in 0..<5 {
|
|
208
243
|
currentGains[i] = max(-12.0, min(12.0, gains[i]))
|
|
209
244
|
}
|
|
245
|
+
cachedBands = nil
|
|
210
246
|
gainsDirty = true
|
|
211
247
|
|
|
212
248
|
notifyBandChange(getBands())
|
|
@@ -231,15 +267,18 @@ class EqualizerCore {
|
|
|
231
267
|
}
|
|
232
268
|
|
|
233
269
|
func getCustomPresets() -> [EqualizerPreset] {
|
|
270
|
+
if let cached = cachedCustomPresets { return cached }
|
|
234
271
|
guard let data = UserDefaults.standard.data(forKey: customPresetsKey),
|
|
235
272
|
let presets = try? JSONDecoder().decode([String: [Double]].self, from: data)
|
|
236
273
|
else {
|
|
237
274
|
return []
|
|
238
275
|
}
|
|
239
276
|
|
|
240
|
-
|
|
277
|
+
let result = presets.map { name, gains in
|
|
241
278
|
EqualizerPreset(name: name, gains: gains, type: .custom)
|
|
242
279
|
}
|
|
280
|
+
cachedCustomPresets = result
|
|
281
|
+
return result
|
|
243
282
|
}
|
|
244
283
|
|
|
245
284
|
func applyPreset(_ presetName: String) -> Bool {
|
|
@@ -292,6 +331,7 @@ class EqualizerCore {
|
|
|
292
331
|
|
|
293
332
|
if let data = try? JSONEncoder().encode(presets) {
|
|
294
333
|
UserDefaults.standard.set(data, forKey: customPresetsKey)
|
|
334
|
+
cachedCustomPresets = nil
|
|
295
335
|
currentPresetName = name
|
|
296
336
|
notifyPresetChange(name)
|
|
297
337
|
saveCurrentPreset(name)
|
|
@@ -321,6 +361,7 @@ class EqualizerCore {
|
|
|
321
361
|
|
|
322
362
|
if let data = try? JSONEncoder().encode(presets) {
|
|
323
363
|
UserDefaults.standard.set(data, forKey: customPresetsKey)
|
|
364
|
+
cachedCustomPresets = nil
|
|
324
365
|
|
|
325
366
|
if currentPresetName == name {
|
|
326
367
|
currentPresetName = nil
|
|
@@ -21,7 +21,7 @@ class MediaSessionManager {
|
|
|
21
21
|
// MARK: - Properties
|
|
22
22
|
|
|
23
23
|
private var trackPlayerCore: TrackPlayerCore?
|
|
24
|
-
private
|
|
24
|
+
private let artworkCache = NSCache<NSString, UIImage>()
|
|
25
25
|
|
|
26
26
|
private var showInNotification: Bool = true
|
|
27
27
|
|
|
@@ -135,7 +135,7 @@ class MediaSessionManager {
|
|
|
135
135
|
// Artwork: use cache synchronously when available, otherwise kick off async load
|
|
136
136
|
if let artwork = track.artwork, case .second(let artworkUrl) = artwork {
|
|
137
137
|
lastArtworkUrl = artworkUrl
|
|
138
|
-
if let cachedImage = artworkCache
|
|
138
|
+
if let cachedImage = artworkCache.object(forKey: artworkUrl as NSString) {
|
|
139
139
|
nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(
|
|
140
140
|
boundsSize: CGSize(width: Constants.artworkSize, height: Constants.artworkSize),
|
|
141
141
|
requestHandler: { _ in cachedImage }
|
|
@@ -285,7 +285,7 @@ class MediaSessionManager {
|
|
|
285
285
|
}
|
|
286
286
|
|
|
287
287
|
private func loadArtwork(url: String, completion: @escaping (UIImage?) -> Void) {
|
|
288
|
-
if let cached = artworkCache
|
|
288
|
+
if let cached = artworkCache.object(forKey: url as NSString) {
|
|
289
289
|
completion(cached)
|
|
290
290
|
return
|
|
291
291
|
}
|
|
@@ -301,7 +301,7 @@ class MediaSessionManager {
|
|
|
301
301
|
return
|
|
302
302
|
}
|
|
303
303
|
DispatchQueue.main.async {
|
|
304
|
-
self?.artworkCache
|
|
304
|
+
self?.artworkCache.setObject(image, forKey: url as NSString)
|
|
305
305
|
completion(image)
|
|
306
306
|
}
|
|
307
307
|
}.resume()
|
|
@@ -310,6 +310,6 @@ class MediaSessionManager {
|
|
|
310
310
|
func release() {
|
|
311
311
|
clearNowPlayingInfo()
|
|
312
312
|
disableAllCommands()
|
|
313
|
-
artworkCache.
|
|
313
|
+
artworkCache.removeAllObjects()
|
|
314
314
|
}
|
|
315
315
|
}
|
|
@@ -77,6 +77,7 @@ final class HybridPlayerQueue: HybridPlayerQueueSpec {
|
|
|
77
77
|
|
|
78
78
|
func onPlaylistsChanged(callback: @escaping ([Playlist], QueueOperation?) -> Void) throws {
|
|
79
79
|
// Store callback in static storage so it persists across HybridPlayerQueue instances
|
|
80
|
+
HybridPlayerQueue.playlistsChangeCallbacks.removeAll()
|
|
80
81
|
HybridPlayerQueue.playlistsChangeCallbacks.append(callback)
|
|
81
82
|
|
|
82
83
|
// Register a single listener with PlaylistManager that dispatches to all callbacks
|
|
@@ -94,6 +95,7 @@ final class HybridPlayerQueue: HybridPlayerQueueSpec {
|
|
|
94
95
|
|
|
95
96
|
func onPlaylistChanged(callback: @escaping (String, Playlist, QueueOperation?) -> Void) throws {
|
|
96
97
|
// Store callback in static storage so it persists across HybridPlayerQueue instances
|
|
98
|
+
HybridPlayerQueue.playlistChangeCallbacks.removeAll()
|
|
97
99
|
HybridPlayerQueue.playlistChangeCallbacks.append(callback)
|
|
98
100
|
|
|
99
101
|
// Register listeners for all existing playlists (only once per playlist)
|
|
@@ -35,10 +35,12 @@ enum NitroPlayerStorage {
|
|
|
35
35
|
/// Uses `FileManager` APIs — never hardcodes the UUID-based container path
|
|
36
36
|
/// so this resolves correctly regardless of which device or simulator the
|
|
37
37
|
/// app runs on.
|
|
38
|
-
private static
|
|
38
|
+
private static let storageDir: URL = {
|
|
39
39
|
let appSupport = FileManager.default.urls(
|
|
40
40
|
for: .applicationSupportDirectory, in: .userDomainMask
|
|
41
41
|
).first!
|
|
42
42
|
return appSupport.appendingPathComponent("NitroPlayer", isDirectory: true)
|
|
43
|
-
}
|
|
43
|
+
}()
|
|
44
|
+
|
|
45
|
+
private static func storageDirectory() -> URL { storageDir }
|
|
44
46
|
}
|
package/lib/hooks/usePlaylist.js
CHANGED
|
@@ -41,6 +41,9 @@ export function usePlaylist() {
|
|
|
41
41
|
const [isLoading, setIsLoading] = useState(true);
|
|
42
42
|
const isMounted = useRef(true);
|
|
43
43
|
const hasSubscribed = useRef(false);
|
|
44
|
+
// Tracks the last fetched playlist ID so track-change events can skip
|
|
45
|
+
// a full refresh when the playlist itself hasn't changed.
|
|
46
|
+
const lastPlaylistIdRef = useRef(undefined);
|
|
44
47
|
const refreshPlaylists = useCallback(() => {
|
|
45
48
|
if (!isMounted.current)
|
|
46
49
|
return;
|
|
@@ -49,6 +52,7 @@ export function usePlaylist() {
|
|
|
49
52
|
const playlistId = PlayerQueue.getCurrentPlaylistId();
|
|
50
53
|
if (!isMounted.current)
|
|
51
54
|
return;
|
|
55
|
+
lastPlaylistIdRef.current = playlistId;
|
|
52
56
|
setCurrentPlaylistId(playlistId);
|
|
53
57
|
// Get current playlist details
|
|
54
58
|
if (playlistId) {
|
|
@@ -88,6 +92,24 @@ export function usePlaylist() {
|
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
94
|
}, []);
|
|
95
|
+
// Lightweight track-change handler: only does a full refresh when the
|
|
96
|
+
// active playlist ID has actually changed (e.g. cross-playlist navigation).
|
|
97
|
+
// Within-playlist track changes — the common case — are skipped with a
|
|
98
|
+
// single bridge call instead of three.
|
|
99
|
+
const refreshOnTrackChange = useCallback(() => {
|
|
100
|
+
if (!isMounted.current)
|
|
101
|
+
return;
|
|
102
|
+
try {
|
|
103
|
+
const newPlaylistId = PlayerQueue.getCurrentPlaylistId();
|
|
104
|
+
if (newPlaylistId === lastPlaylistIdRef.current)
|
|
105
|
+
return;
|
|
106
|
+
lastPlaylistIdRef.current = newPlaylistId;
|
|
107
|
+
refreshPlaylists();
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
console.error('[usePlaylist] Error checking playlist ID on track change:', error);
|
|
111
|
+
}
|
|
112
|
+
}, [refreshPlaylists]);
|
|
91
113
|
// Initialize and setup mounted ref
|
|
92
114
|
useEffect(() => {
|
|
93
115
|
isMounted.current = true;
|
|
@@ -113,18 +135,17 @@ export function usePlaylist() {
|
|
|
113
135
|
console.error('[usePlaylist] Error setting up playlist listener:', error);
|
|
114
136
|
}
|
|
115
137
|
}, [refreshPlaylists]);
|
|
116
|
-
//
|
|
138
|
+
// Refresh on track change only if the active playlist ID changed.
|
|
117
139
|
useEffect(() => {
|
|
118
140
|
const unsubscribe = callbackManager.subscribeToTrackChange(() => {
|
|
119
|
-
// Refresh to update currentPlaylistId when track changes
|
|
120
141
|
if (isMounted.current) {
|
|
121
|
-
|
|
142
|
+
refreshOnTrackChange();
|
|
122
143
|
}
|
|
123
144
|
});
|
|
124
145
|
return () => {
|
|
125
146
|
unsubscribe();
|
|
126
147
|
};
|
|
127
|
-
}, [
|
|
148
|
+
}, [refreshOnTrackChange]);
|
|
128
149
|
return {
|
|
129
150
|
currentPlaylist,
|
|
130
151
|
currentPlaylistId,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# NitroPlayer+autolinking.cmake
|
|
3
3
|
# This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
# https://github.com/mrousavy/nitro
|
|
5
|
-
# Copyright ©
|
|
5
|
+
# Copyright © Marc Rousavy @ Margelo
|
|
6
6
|
#
|
|
7
7
|
|
|
8
8
|
# This is a CMake file that adds all files generated by Nitrogen
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// NitroPlayer+autolinking.gradle
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
/// This is a Gradle file that adds all files generated by Nitrogen
|