react-native-nitro-player 0.5.8 → 0.5.9-alpha.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/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 +112 -55
- 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 +142 -41
- 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 +14 -2
- 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/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
|
@@ -11,6 +11,7 @@ import android.graphics.BitmapFactory
|
|
|
11
11
|
import android.net.Uri
|
|
12
12
|
import android.os.Build
|
|
13
13
|
import android.util.Log
|
|
14
|
+
import android.util.LruCache
|
|
14
15
|
import androidx.core.app.NotificationCompat
|
|
15
16
|
import androidx.media3.common.MediaItem
|
|
16
17
|
import androidx.media3.common.MediaMetadata
|
|
@@ -49,7 +50,9 @@ class MediaSessionManager(
|
|
|
49
50
|
private set
|
|
50
51
|
private var notificationManager: NotificationManager? = null
|
|
51
52
|
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
|
52
|
-
private val artworkCache =
|
|
53
|
+
private val artworkCache = object : LruCache<String, Bitmap>(20) {
|
|
54
|
+
override fun sizeOf(key: String, value: Bitmap): Int = 1
|
|
55
|
+
}
|
|
53
56
|
|
|
54
57
|
private var androidAutoEnabled: Boolean = false
|
|
55
58
|
private var carPlayEnabled: Boolean = false
|
|
@@ -115,7 +118,7 @@ class MediaSessionManager(
|
|
|
115
118
|
mediaItems: MutableList<MediaItem>,
|
|
116
119
|
): ListenableFuture<MutableList<MediaItem>> {
|
|
117
120
|
// This is called when Android Auto requests to play a track
|
|
118
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
121
|
+
NitroPlayerLogger.log("MediaSessionManager") { "🎵 MediaSessionManager: onAddMediaItems called with ${mediaItems.size} items" }
|
|
119
122
|
|
|
120
123
|
if (mediaItems.isEmpty()) {
|
|
121
124
|
return Futures.immediateFuture(mutableListOf())
|
|
@@ -129,7 +132,7 @@ class MediaSessionManager(
|
|
|
129
132
|
requestedMediaItem.requestMetadata.mediaUri?.toString()
|
|
130
133
|
?: requestedMediaItem.mediaId
|
|
131
134
|
|
|
132
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
135
|
+
NitroPlayerLogger.log("MediaSessionManager") { "🎵 MediaSessionManager: Processing mediaId: $mediaId" }
|
|
133
136
|
|
|
134
137
|
try {
|
|
135
138
|
// Parse mediaId format: "playlistId:trackId"
|
|
@@ -138,7 +141,7 @@ class MediaSessionManager(
|
|
|
138
141
|
val playlistId = mediaId.substring(0, colonIndex)
|
|
139
142
|
val trackId = mediaId.substring(colonIndex + 1)
|
|
140
143
|
|
|
141
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
144
|
+
NitroPlayerLogger.log("MediaSessionManager") { "🎵 MediaSessionManager: Parsed playlistId: $playlistId, trackId: $trackId" }
|
|
142
145
|
|
|
143
146
|
// Get the playlist and track
|
|
144
147
|
val playlist = playlistManager.getPlaylist(playlistId)
|
|
@@ -148,27 +151,27 @@ class MediaSessionManager(
|
|
|
148
151
|
// Create a proper MediaItem with all metadata
|
|
149
152
|
val resolvedMediaItem = createMediaItem(track, mediaId)
|
|
150
153
|
updatedMediaItems.add(resolvedMediaItem)
|
|
151
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
154
|
+
NitroPlayerLogger.log("MediaSessionManager") { "✅ MediaSessionManager: Resolved track: ${track.title}" }
|
|
152
155
|
} else {
|
|
153
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
156
|
+
NitroPlayerLogger.log("MediaSessionManager") { "⚠️ MediaSessionManager: Track $trackId not found in playlist" }
|
|
154
157
|
updatedMediaItems.add(requestedMediaItem)
|
|
155
158
|
}
|
|
156
159
|
} else {
|
|
157
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
160
|
+
NitroPlayerLogger.log("MediaSessionManager") { "⚠️ MediaSessionManager: Playlist $playlistId not found" }
|
|
158
161
|
updatedMediaItems.add(requestedMediaItem)
|
|
159
162
|
}
|
|
160
163
|
} else {
|
|
161
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
164
|
+
NitroPlayerLogger.log("MediaSessionManager") { "⚠️ MediaSessionManager: Invalid mediaId format: $mediaId" }
|
|
162
165
|
updatedMediaItems.add(requestedMediaItem)
|
|
163
166
|
}
|
|
164
167
|
} catch (e: Exception) {
|
|
165
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
168
|
+
NitroPlayerLogger.log("MediaSessionManager") { "❌ MediaSessionManager: Error processing mediaId - ${e.message}" }
|
|
166
169
|
e.printStackTrace()
|
|
167
170
|
updatedMediaItems.add(requestedMediaItem)
|
|
168
171
|
}
|
|
169
172
|
}
|
|
170
173
|
|
|
171
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
174
|
+
NitroPlayerLogger.log("MediaSessionManager") { "🎵 MediaSessionManager: Returning ${updatedMediaItems.size} resolved media items" }
|
|
172
175
|
return Futures.immediateFuture(updatedMediaItems)
|
|
173
176
|
}
|
|
174
177
|
|
|
@@ -180,7 +183,7 @@ class MediaSessionManager(
|
|
|
180
183
|
startPositionMs: Long,
|
|
181
184
|
): ListenableFuture<MediaSession.MediaItemsWithStartPosition> {
|
|
182
185
|
// This is called when Android Auto wants to set and play media items
|
|
183
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
186
|
+
NitroPlayerLogger.log("MediaSessionManager") { "🎵 MediaSessionManager: onSetMediaItems called with ${mediaItems.size} items, startIndex: $startIndex" }
|
|
184
187
|
|
|
185
188
|
if (mediaItems.isEmpty()) {
|
|
186
189
|
return Futures.immediateFuture(
|
|
@@ -195,7 +198,7 @@ class MediaSessionManager(
|
|
|
195
198
|
try {
|
|
196
199
|
// Get the first item's mediaId to determine the playlist
|
|
197
200
|
val firstMediaId = mediaItems[0].mediaId
|
|
198
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
201
|
+
NitroPlayerLogger.log("MediaSessionManager") { "🎵 MediaSessionManager: First mediaId: $firstMediaId" }
|
|
199
202
|
|
|
200
203
|
// Parse mediaId format: "playlistId:trackId"
|
|
201
204
|
if (firstMediaId.contains(':')) {
|
|
@@ -203,7 +206,7 @@ class MediaSessionManager(
|
|
|
203
206
|
val playlistId = firstMediaId.substring(0, colonIndex)
|
|
204
207
|
val trackId = firstMediaId.substring(colonIndex + 1)
|
|
205
208
|
|
|
206
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
209
|
+
NitroPlayerLogger.log("MediaSessionManager") { "🎵 MediaSessionManager: Loading full playlist: $playlistId, starting at track: $trackId" }
|
|
207
210
|
|
|
208
211
|
// Get the full playlist
|
|
209
212
|
val playlist = playlistManager.getPlaylist(playlistId)
|
|
@@ -223,7 +226,7 @@ class MediaSessionManager(
|
|
|
223
226
|
createMediaItem(track, trackMediaId)
|
|
224
227
|
}.toMutableList()
|
|
225
228
|
|
|
226
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
229
|
+
NitroPlayerLogger.log("MediaSessionManager") { "✅ MediaSessionManager: Loaded ${playlistMediaItems.size} tracks, starting at index $trackIndex" }
|
|
227
230
|
|
|
228
231
|
// Return the full playlist with the correct start index
|
|
229
232
|
return Futures.immediateFuture(
|
|
@@ -241,7 +244,7 @@ class MediaSessionManager(
|
|
|
241
244
|
}
|
|
242
245
|
}
|
|
243
246
|
} catch (e: Exception) {
|
|
244
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
247
|
+
NitroPlayerLogger.log("MediaSessionManager") { "❌ MediaSessionManager: Error in onSetMediaItems - ${e.message}" }
|
|
245
248
|
e.printStackTrace()
|
|
246
249
|
}
|
|
247
250
|
|
|
@@ -283,7 +286,7 @@ class MediaSessionManager(
|
|
|
283
286
|
if (artworkUrl.isNullOrEmpty()) return null
|
|
284
287
|
|
|
285
288
|
// Check cache first
|
|
286
|
-
artworkCache
|
|
289
|
+
artworkCache.get(artworkUrl)?.let { return it }
|
|
287
290
|
|
|
288
291
|
return try {
|
|
289
292
|
val bitmap =
|
|
@@ -293,7 +296,7 @@ class MediaSessionManager(
|
|
|
293
296
|
}
|
|
294
297
|
// Cache the bitmap
|
|
295
298
|
if (bitmap != null) {
|
|
296
|
-
artworkCache
|
|
299
|
+
artworkCache.put(artworkUrl, bitmap)
|
|
297
300
|
}
|
|
298
301
|
bitmap
|
|
299
302
|
} catch (e: Exception) {
|
|
@@ -302,12 +305,6 @@ class MediaSessionManager(
|
|
|
302
305
|
}
|
|
303
306
|
}
|
|
304
307
|
|
|
305
|
-
private fun bitmapToByteArray(bitmap: Bitmap): ByteArray {
|
|
306
|
-
val stream = java.io.ByteArrayOutputStream()
|
|
307
|
-
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
|
|
308
|
-
return stream.toByteArray()
|
|
309
|
-
}
|
|
310
|
-
|
|
311
308
|
private fun createNotificationChannel() {
|
|
312
309
|
notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
313
310
|
|
|
@@ -342,10 +339,12 @@ class MediaSessionManager(
|
|
|
342
339
|
// Find track in current playlist or all playlists
|
|
343
340
|
return trackPlayerCore?.getCurrentPlaylistId()?.let { playlistId ->
|
|
344
341
|
playlistManager.getPlaylist(playlistId)?.tracks?.find { it.id == trackId }
|
|
345
|
-
} ?:
|
|
346
|
-
.getAllPlaylists()
|
|
347
|
-
|
|
348
|
-
|
|
342
|
+
} ?: run {
|
|
343
|
+
for (playlist in playlistManager.getAllPlaylists()) {
|
|
344
|
+
playlist.tracks.find { it.id == trackId }?.let { return it }
|
|
345
|
+
}
|
|
346
|
+
null
|
|
347
|
+
}
|
|
349
348
|
}
|
|
350
349
|
|
|
351
350
|
private fun updateNotification() {
|
|
@@ -392,7 +391,7 @@ class MediaSessionManager(
|
|
|
392
391
|
.setShowActionsInCompactView(0, 1, 2),
|
|
393
392
|
)
|
|
394
393
|
} catch (e: Exception) {
|
|
395
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
394
|
+
NitroPlayerLogger.log("MediaSessionManager") { "Failed to set media session token: ${e.message}" }
|
|
396
395
|
}
|
|
397
396
|
|
|
398
397
|
// Add action buttons
|
|
@@ -483,7 +482,7 @@ class MediaSessionManager(
|
|
|
483
482
|
hideNotification()
|
|
484
483
|
mediaSession?.release()
|
|
485
484
|
mediaSession = null
|
|
486
|
-
artworkCache.
|
|
485
|
+
artworkCache.evictAll()
|
|
487
486
|
}
|
|
488
487
|
|
|
489
488
|
private fun createMediaItem(
|
|
@@ -501,7 +500,7 @@ class MediaSessionManager(
|
|
|
501
500
|
try {
|
|
502
501
|
metadataBuilder.setArtworkUri(Uri.parse(artworkUrl))
|
|
503
502
|
} catch (e: Exception) {
|
|
504
|
-
NitroPlayerLogger.log("MediaSessionManager"
|
|
503
|
+
NitroPlayerLogger.log("MediaSessionManager") { "⚠️ MediaSessionManager: Invalid artwork URI: $artworkUrl" }
|
|
505
504
|
}
|
|
506
505
|
}
|
|
507
506
|
|
|
@@ -112,12 +112,8 @@ class PlaylistManager private constructor(
|
|
|
112
112
|
description: String? = null,
|
|
113
113
|
artwork: String? = null,
|
|
114
114
|
): Boolean {
|
|
115
|
-
val playlist =
|
|
116
|
-
synchronized(playlists) {
|
|
117
|
-
playlists[playlistId]
|
|
118
|
-
} ?: return false
|
|
119
|
-
|
|
120
115
|
synchronized(playlists) {
|
|
116
|
+
val playlist = playlists[playlistId] ?: return false
|
|
121
117
|
playlists[playlistId] =
|
|
122
118
|
playlist.copy(
|
|
123
119
|
name = name ?: playlist.name,
|
|
@@ -161,12 +157,8 @@ class PlaylistManager private constructor(
|
|
|
161
157
|
track: TrackItem,
|
|
162
158
|
index: Int? = null,
|
|
163
159
|
): Boolean {
|
|
164
|
-
val playlist =
|
|
165
|
-
synchronized(playlists) {
|
|
166
|
-
playlists[playlistId]
|
|
167
|
-
} ?: return false
|
|
168
|
-
|
|
169
160
|
synchronized(playlists) {
|
|
161
|
+
val playlist = playlists[playlistId] ?: return false
|
|
170
162
|
val tracks = playlist.tracks.toMutableList()
|
|
171
163
|
if (index != null && index >= 0 && index <= tracks.size) {
|
|
172
164
|
tracks.add(index, track)
|
|
@@ -199,12 +191,8 @@ class PlaylistManager private constructor(
|
|
|
199
191
|
tracks: List<TrackItem>,
|
|
200
192
|
index: Int? = null,
|
|
201
193
|
): Boolean {
|
|
202
|
-
val playlist =
|
|
203
|
-
synchronized(playlists) {
|
|
204
|
-
playlists[playlistId]
|
|
205
|
-
} ?: return false
|
|
206
|
-
|
|
207
194
|
synchronized(playlists) {
|
|
195
|
+
val playlist = playlists[playlistId] ?: return false
|
|
208
196
|
val currentTracks = playlist.tracks.toMutableList()
|
|
209
197
|
if (index != null && index >= 0 && index <= currentTracks.size) {
|
|
210
198
|
currentTracks.addAll(index, tracks)
|
|
@@ -236,13 +224,9 @@ class PlaylistManager private constructor(
|
|
|
236
224
|
playlistId: String,
|
|
237
225
|
trackId: String,
|
|
238
226
|
): Boolean {
|
|
239
|
-
val playlist =
|
|
240
|
-
synchronized(playlists) {
|
|
241
|
-
playlists[playlistId]
|
|
242
|
-
} ?: return false
|
|
243
|
-
|
|
244
227
|
val removed =
|
|
245
228
|
synchronized(playlists) {
|
|
229
|
+
val playlist = playlists[playlistId] ?: return false
|
|
246
230
|
val tracks = playlist.tracks.toMutableList()
|
|
247
231
|
val removed = tracks.removeAll { it.id == trackId }
|
|
248
232
|
if (removed) {
|
|
@@ -273,18 +257,13 @@ class PlaylistManager private constructor(
|
|
|
273
257
|
trackId: String,
|
|
274
258
|
newIndex: Int,
|
|
275
259
|
): Boolean {
|
|
276
|
-
val playlist =
|
|
277
|
-
synchronized(playlists) {
|
|
278
|
-
playlists[playlistId]
|
|
279
|
-
} ?: return false
|
|
280
|
-
|
|
281
|
-
val tracks = playlist.tracks.toMutableList()
|
|
282
|
-
val oldIndex = tracks.indexOfFirst { it.id == trackId }
|
|
283
|
-
if (oldIndex < 0 || newIndex < 0 || newIndex >= tracks.size) {
|
|
284
|
-
return false
|
|
285
|
-
}
|
|
286
|
-
|
|
287
260
|
synchronized(playlists) {
|
|
261
|
+
val playlist = playlists[playlistId] ?: return false
|
|
262
|
+
val tracks = playlist.tracks.toMutableList()
|
|
263
|
+
val oldIndex = tracks.indexOfFirst { it.id == trackId }
|
|
264
|
+
if (oldIndex < 0 || newIndex < 0 || newIndex >= tracks.size) {
|
|
265
|
+
return false
|
|
266
|
+
}
|
|
288
267
|
val track = tracks.removeAt(oldIndex)
|
|
289
268
|
tracks.add(newIndex, track)
|
|
290
269
|
playlists[playlistId] = playlist.copy(tracks = tracks)
|
|
@@ -229,6 +229,7 @@ class TrackPlayerCore: NSObject {
|
|
|
229
229
|
|
|
230
230
|
// Create boundary times at each interval
|
|
231
231
|
var boundaryTimes: [NSValue] = []
|
|
232
|
+
boundaryTimes.reserveCapacity(Int(duration / interval) + 1)
|
|
232
233
|
var time: Double = 0
|
|
233
234
|
while time <= duration {
|
|
234
235
|
let cmTime = CMTime(seconds: time, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
|
|
@@ -423,6 +424,7 @@ class TrackPlayerCore: NSObject {
|
|
|
423
424
|
return
|
|
424
425
|
}
|
|
425
426
|
|
|
427
|
+
#if DEBUG
|
|
426
428
|
NitroPlayerLogger.log("TrackPlayerCore", "\n" + String(repeating: "▶", count: Constants.separatorLineLength))
|
|
427
429
|
NitroPlayerLogger.log("TrackPlayerCore", "🔄 CURRENT ITEM CHANGED")
|
|
428
430
|
NitroPlayerLogger.log("TrackPlayerCore", String(repeating: "▶", count: Constants.separatorLineLength))
|
|
@@ -449,6 +451,7 @@ class TrackPlayerCore: NSObject {
|
|
|
449
451
|
}
|
|
450
452
|
|
|
451
453
|
NitroPlayerLogger.log("TrackPlayerCore", String(repeating: "▶", count: Constants.separatorLineLength) + "\n")
|
|
454
|
+
#endif
|
|
452
455
|
|
|
453
456
|
// Log item status
|
|
454
457
|
NitroPlayerLogger.log("TrackPlayerCore", "📱 Item status: \(currentItem.status.rawValue)")
|
|
@@ -510,10 +513,12 @@ class TrackPlayerCore: NSObject {
|
|
|
510
513
|
}
|
|
511
514
|
} else {
|
|
512
515
|
NitroPlayerLogger.log("TrackPlayerCore", " ⚠️ Track ID '\(trackId)' NOT FOUND in currentTracks!")
|
|
516
|
+
#if DEBUG
|
|
513
517
|
NitroPlayerLogger.log("TrackPlayerCore", " Current tracks:")
|
|
514
518
|
for (idx, track) in currentTracks.enumerated() {
|
|
515
519
|
NitroPlayerLogger.log("TrackPlayerCore", " [\(idx)] \(track.id) - \(track.title)")
|
|
516
520
|
}
|
|
521
|
+
#endif
|
|
517
522
|
}
|
|
518
523
|
}
|
|
519
524
|
|
|
@@ -811,7 +816,8 @@ class TrackPlayerCore: NSObject {
|
|
|
811
816
|
|
|
812
817
|
/// Clears preloaded assets that are no longer needed
|
|
813
818
|
private func cleanupPreloadedAssets(keepingFrom currentIndex: Int) {
|
|
814
|
-
|
|
819
|
+
// Must run on main thread — preloadedAssets is only mutated on main
|
|
820
|
+
DispatchQueue.main.async { [weak self] in
|
|
815
821
|
guard let self = self else { return }
|
|
816
822
|
|
|
817
823
|
// Keep assets for current track and upcoming tracks within preload range
|
|
@@ -991,6 +997,25 @@ class TrackPlayerCore: NSObject {
|
|
|
991
997
|
// Clear old preloaded assets when loading new queue
|
|
992
998
|
preloadedAssets.removeAll()
|
|
993
999
|
|
|
1000
|
+
// Replace current queue (player should always exist after setupPlayer)
|
|
1001
|
+
guard let existingPlayer = self.player else {
|
|
1002
|
+
NitroPlayerLogger.log("TrackPlayerCore", "❌ No player available")
|
|
1003
|
+
return
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
// Always clear old items so a stale playlist doesn't keep playing.
|
|
1007
|
+
NitroPlayerLogger.log("TrackPlayerCore", "🔄 Removing \(existingPlayer.items().count) old items from player")
|
|
1008
|
+
existingPlayer.removeAllItems()
|
|
1009
|
+
|
|
1010
|
+
// Lazy-load mode: if any track has no URL yet, don't populate AVQueuePlayer items now.
|
|
1011
|
+
// Adding downloaded tracks at incorrect positions would cause the wrong track to play.
|
|
1012
|
+
// updateTracks will rebuild from the correct currentTrackIndex once URLs are resolved.
|
|
1013
|
+
let isLazyLoad = tracks.contains { $0.url.isEmpty }
|
|
1014
|
+
if isLazyLoad {
|
|
1015
|
+
NitroPlayerLogger.log("TrackPlayerCore", "⏳ Lazy-load mode — player cleared, awaiting URL resolution")
|
|
1016
|
+
return
|
|
1017
|
+
}
|
|
1018
|
+
|
|
994
1019
|
// Create gapless-optimized AVPlayerItems from tracks
|
|
995
1020
|
let items = tracks.enumerated().compactMap { (index, track) -> AVPlayerItem? in
|
|
996
1021
|
let isPreload = index < Constants.gaplessPreloadCount
|
|
@@ -1004,16 +1029,7 @@ class TrackPlayerCore: NSObject {
|
|
|
1004
1029
|
return
|
|
1005
1030
|
}
|
|
1006
1031
|
|
|
1007
|
-
|
|
1008
|
-
guard let existingPlayer = self.player else {
|
|
1009
|
-
NitroPlayerLogger.log("TrackPlayerCore", "❌ No player available - this should never happen!")
|
|
1010
|
-
return
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
NitroPlayerLogger.log("TrackPlayerCore", "🔄 Updating queue - removing \(existingPlayer.items().count) items, adding \(items.count) new items")
|
|
1014
|
-
|
|
1015
|
-
// Remove all existing items
|
|
1016
|
-
existingPlayer.removeAllItems()
|
|
1032
|
+
NitroPlayerLogger.log("TrackPlayerCore", "🔄 Adding \(items.count) new items to player")
|
|
1017
1033
|
|
|
1018
1034
|
// Add new items IN ORDER
|
|
1019
1035
|
// IMPORTANT: insert(after: nil) puts item at the start
|
|
@@ -1023,9 +1039,11 @@ class TrackPlayerCore: NSObject {
|
|
|
1023
1039
|
existingPlayer.insert(item, after: lastItem)
|
|
1024
1040
|
lastItem = item
|
|
1025
1041
|
|
|
1042
|
+
#if DEBUG
|
|
1026
1043
|
if let trackId = item.trackId, let track = tracks.first(where: { $0.id == trackId }) {
|
|
1027
1044
|
NitroPlayerLogger.log("TrackPlayerCore", " ➕ Added to player queue [\(index + 1)]: \(track.title)")
|
|
1028
1045
|
}
|
|
1046
|
+
#endif
|
|
1029
1047
|
}
|
|
1030
1048
|
|
|
1031
1049
|
#if DEBUG
|
|
@@ -1296,6 +1314,18 @@ class TrackPlayerCore: NSObject {
|
|
|
1296
1314
|
private func skipToNextInternal() {
|
|
1297
1315
|
guard let queuePlayer = self.player else { return }
|
|
1298
1316
|
|
|
1317
|
+
// Lazy-load: AVQueuePlayer is empty because updatePlayerQueue deferred population.
|
|
1318
|
+
// Delegate to playFromIndexInternal which handles both the has-URL (rebuild queue)
|
|
1319
|
+
// and no-URL (defer + emit) cases correctly.
|
|
1320
|
+
if queuePlayer.items().isEmpty && !currentTracks.isEmpty {
|
|
1321
|
+
let nextIndex = currentTrackIndex + 1
|
|
1322
|
+
if nextIndex < currentTracks.count {
|
|
1323
|
+
_ = skipToIndexInternal(index: nextIndex)
|
|
1324
|
+
}
|
|
1325
|
+
checkUpcomingTracksForUrls(lookahead: lookaheadCount)
|
|
1326
|
+
return
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1299
1329
|
// Remove current temp track from its list before advancing
|
|
1300
1330
|
if let trackId = queuePlayer.currentItem?.trackId {
|
|
1301
1331
|
if currentTemporaryType == .playNext {
|
|
@@ -1352,11 +1382,11 @@ class TrackPlayerCore: NSObject {
|
|
|
1352
1382
|
}
|
|
1353
1383
|
}
|
|
1354
1384
|
// Go to current original track position (skip back from temp)
|
|
1355
|
-
self.
|
|
1385
|
+
self.rebuildQueueFromPlaylistIndex(index: self.currentTrackIndex)
|
|
1356
1386
|
} else if self.currentTrackIndex > 0 {
|
|
1357
1387
|
// Go to previous track in original playlist
|
|
1358
1388
|
let previousIndex = self.currentTrackIndex - 1
|
|
1359
|
-
self.
|
|
1389
|
+
self.rebuildQueueFromPlaylistIndex(index: previousIndex)
|
|
1360
1390
|
} else {
|
|
1361
1391
|
// Already at first track, restart it
|
|
1362
1392
|
queuePlayer.seek(to: .zero)
|
|
@@ -1533,10 +1563,10 @@ class TrackPlayerCore: NSObject {
|
|
|
1533
1563
|
|
|
1534
1564
|
func playFromIndex(index: Int) {
|
|
1535
1565
|
if Thread.isMainThread {
|
|
1536
|
-
|
|
1566
|
+
rebuildQueueFromPlaylistIndex(index: index)
|
|
1537
1567
|
} else {
|
|
1538
1568
|
DispatchQueue.main.async { [weak self] in
|
|
1539
|
-
self?.
|
|
1569
|
+
self?.rebuildQueueFromPlaylistIndex(index: index)
|
|
1540
1570
|
}
|
|
1541
1571
|
}
|
|
1542
1572
|
}
|
|
@@ -1580,9 +1610,9 @@ class TrackPlayerCore: NSObject {
|
|
|
1580
1610
|
let upNextEnd = upNextStart + effectiveUpNextSize
|
|
1581
1611
|
let originalRemainingStart = upNextEnd
|
|
1582
1612
|
|
|
1583
|
-
// Case 1: Target is before current -
|
|
1613
|
+
// Case 1: Target is before current - rebuild from that playlist index
|
|
1584
1614
|
if index < currentPos {
|
|
1585
|
-
|
|
1615
|
+
rebuildQueueFromPlaylistIndex(index: index)
|
|
1586
1616
|
return true
|
|
1587
1617
|
}
|
|
1588
1618
|
|
|
@@ -1645,7 +1675,7 @@ class TrackPlayerCore: NSObject {
|
|
|
1645
1675
|
upNextQueue.removeAll()
|
|
1646
1676
|
currentTemporaryType = .none
|
|
1647
1677
|
|
|
1648
|
-
let result =
|
|
1678
|
+
let result = rebuildQueueFromPlaylistIndex(index: originalIndex)
|
|
1649
1679
|
|
|
1650
1680
|
// Check if upcoming tracks need URLs
|
|
1651
1681
|
checkUpcomingTracksForUrls(lookahead: lookaheadCount)
|
|
@@ -1659,20 +1689,23 @@ class TrackPlayerCore: NSObject {
|
|
|
1659
1689
|
return false
|
|
1660
1690
|
}
|
|
1661
1691
|
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
private func playFromIndexInternalWithResult(index: Int) -> Bool {
|
|
1692
|
+
/// Clears temporary tracks, rebuilds AVQueuePlayer from `index` in the original playlist,
|
|
1693
|
+
/// and resumes playback only if the player was already playing (preserves paused state).
|
|
1694
|
+
@discardableResult
|
|
1695
|
+
private func rebuildQueueFromPlaylistIndex(index: Int) -> Bool {
|
|
1667
1696
|
guard index >= 0 && index < self.currentTracks.count else {
|
|
1668
|
-
NitroPlayerLogger.log("TrackPlayerCore", "❌
|
|
1697
|
+
NitroPlayerLogger.log("TrackPlayerCore", "❌ rebuildQueueFromPlaylistIndex - invalid index \(index), currentTracks.count = \(self.currentTracks.count)")
|
|
1669
1698
|
return false
|
|
1670
1699
|
}
|
|
1671
1700
|
|
|
1672
|
-
NitroPlayerLogger.log("TrackPlayerCore", "\n🎯
|
|
1701
|
+
NitroPlayerLogger.log("TrackPlayerCore", "\n🎯 REBUILD QUEUE FROM PLAYLIST INDEX \(index)")
|
|
1673
1702
|
NitroPlayerLogger.log("TrackPlayerCore", " Total tracks in playlist: \(self.currentTracks.count)")
|
|
1674
1703
|
NitroPlayerLogger.log("TrackPlayerCore", " Current index: \(self.currentTrackIndex), target index: \(index)")
|
|
1675
1704
|
|
|
1705
|
+
// Preserve playback state — only resume if already playing.
|
|
1706
|
+
// This prevents auto-starting when called during queue setup (e.g. loadPlaylist → skipToIndex).
|
|
1707
|
+
let wasPlaying = self.player?.rate ?? 0 > 0
|
|
1708
|
+
|
|
1676
1709
|
// Clear temporary tracks when jumping to specific index
|
|
1677
1710
|
self.playNextStack.removeAll()
|
|
1678
1711
|
self.upNextQueue.removeAll()
|
|
@@ -1685,6 +1718,22 @@ class TrackPlayerCore: NSObject {
|
|
|
1685
1718
|
// Update currentTrackIndex BEFORE updating queue
|
|
1686
1719
|
self.currentTrackIndex = index
|
|
1687
1720
|
|
|
1721
|
+
// Lazy-load guard: if the target track itself has no URL yet, the queue can't be built.
|
|
1722
|
+
// Emit the track change now (so UI reflects the navigation) and defer queue population
|
|
1723
|
+
// to updateTracks once URL resolution completes.
|
|
1724
|
+
// Only check the target — other unresolved tracks elsewhere in the playlist shouldn't
|
|
1725
|
+
// block a skip to a track that is already playable.
|
|
1726
|
+
let isLazyLoad = fullPlaylist[index].url.isEmpty
|
|
1727
|
+
if isLazyLoad {
|
|
1728
|
+
NitroPlayerLogger.log("TrackPlayerCore", " ⏳ Lazy-load — deferring AVQueuePlayer setup; emitting track change for index \(index)")
|
|
1729
|
+
self.currentTracks = fullPlaylist
|
|
1730
|
+
if let track = self.currentTracks[safe: index] {
|
|
1731
|
+
notifyTrackChange(track, .skip)
|
|
1732
|
+
self.mediaSessionManager?.onTrackChanged()
|
|
1733
|
+
}
|
|
1734
|
+
return true
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1688
1737
|
// Recreate the queue starting from the target index
|
|
1689
1738
|
// This ensures all remaining tracks are in the queue
|
|
1690
1739
|
let tracksToPlay = Array(fullPlaylist[index...])
|
|
@@ -1732,7 +1781,12 @@ class TrackPlayerCore: NSObject {
|
|
|
1732
1781
|
// Start preloading upcoming tracks for gapless playback
|
|
1733
1782
|
self.preloadUpcomingTracks(from: index + 1)
|
|
1734
1783
|
|
|
1735
|
-
player
|
|
1784
|
+
// Only resume playback if the player was already playing before we rebuilt
|
|
1785
|
+
// the loaded playlist. This prevents auto-starting when called during queue setup
|
|
1786
|
+
// (e.g. loadPlaylist → skipToIndex).
|
|
1787
|
+
if wasPlaying {
|
|
1788
|
+
player.play()
|
|
1789
|
+
}
|
|
1736
1790
|
return true
|
|
1737
1791
|
}
|
|
1738
1792
|
|
|
@@ -1813,7 +1867,7 @@ class TrackPlayerCore: NSObject {
|
|
|
1813
1867
|
// Add playNext stack (LIFO - most recently added plays first)
|
|
1814
1868
|
// Skip index 0 if current track is from playNext (it's already playing)
|
|
1815
1869
|
if currentTemporaryType == .playNext && playNextStack.count > 1 {
|
|
1816
|
-
newQueueTracks.append(contentsOf:
|
|
1870
|
+
newQueueTracks.append(contentsOf: playNextStack.dropFirst())
|
|
1817
1871
|
} else if currentTemporaryType != .playNext {
|
|
1818
1872
|
newQueueTracks.append(contentsOf: playNextStack)
|
|
1819
1873
|
}
|
|
@@ -1821,15 +1875,14 @@ class TrackPlayerCore: NSObject {
|
|
|
1821
1875
|
// Add upNext queue (in order, FIFO)
|
|
1822
1876
|
// Skip index 0 if current track is from upNext (it's already playing)
|
|
1823
1877
|
if currentTemporaryType == .upNext && upNextQueue.count > 1 {
|
|
1824
|
-
newQueueTracks.append(contentsOf:
|
|
1878
|
+
newQueueTracks.append(contentsOf: upNextQueue.dropFirst())
|
|
1825
1879
|
} else if currentTemporaryType != .upNext {
|
|
1826
1880
|
newQueueTracks.append(contentsOf: upNextQueue)
|
|
1827
1881
|
}
|
|
1828
1882
|
|
|
1829
1883
|
// Add remaining original tracks
|
|
1830
1884
|
if currentTrackIndex + 1 < currentTracks.count {
|
|
1831
|
-
|
|
1832
|
-
newQueueTracks.append(contentsOf: remainingOriginal)
|
|
1885
|
+
newQueueTracks.append(contentsOf: currentTracks[(currentTrackIndex + 1)...])
|
|
1833
1886
|
}
|
|
1834
1887
|
|
|
1835
1888
|
// Remove all items from player EXCEPT the currently playing one
|
|
@@ -1904,17 +1957,26 @@ class TrackPlayerCore: NSObject {
|
|
|
1904
1957
|
|
|
1905
1958
|
NitroPlayerLogger.log("TrackPlayerCore", "🔄 updateTracks: \(tracks.count) updates")
|
|
1906
1959
|
|
|
1907
|
-
// Get current track
|
|
1908
|
-
let
|
|
1960
|
+
// Get current track to decide how to handle it
|
|
1961
|
+
let currentTrack = self.getCurrentTrack()
|
|
1962
|
+
let currentTrackId = currentTrack?.id
|
|
1963
|
+
let currentTrackIsEmpty = currentTrack?.url.isEmpty ?? false
|
|
1909
1964
|
|
|
1910
1965
|
// Filter out current track and validate
|
|
1911
1966
|
let safeTracks = tracks.filter { track in
|
|
1912
1967
|
switch true {
|
|
1913
|
-
case track.id == currentTrackId:
|
|
1968
|
+
case track.id == currentTrackId && !currentTrackIsEmpty:
|
|
1969
|
+
// Has a real URL already — skip to preserve gapless playback
|
|
1914
1970
|
NitroPlayerLogger.log(
|
|
1915
1971
|
"TrackPlayerCore",
|
|
1916
1972
|
"⚠️ Skipping update for currently playing track: \(track.id) (preserves gapless)")
|
|
1917
1973
|
return false
|
|
1974
|
+
case track.id == currentTrackId && currentTrackIsEmpty:
|
|
1975
|
+
// Empty URL — must not be playing, allow the update (only if the new URL is real)
|
|
1976
|
+
NitroPlayerLogger.log(
|
|
1977
|
+
"TrackPlayerCore",
|
|
1978
|
+
"🔄 Updating current track with no URL: \(track.id)")
|
|
1979
|
+
return !track.url.isEmpty
|
|
1918
1980
|
case track.url.isEmpty:
|
|
1919
1981
|
NitroPlayerLogger.log(
|
|
1920
1982
|
"TrackPlayerCore", "⚠️ Skipping track with empty URL: \(track.id)")
|
|
@@ -1943,7 +2005,16 @@ class TrackPlayerCore: NSObject {
|
|
|
1943
2005
|
// Update in PlaylistManager
|
|
1944
2006
|
let affectedPlaylists = self.playlistManager.updateTracks(tracks: safeTracks)
|
|
1945
2007
|
|
|
1946
|
-
//
|
|
2008
|
+
// If the current track had no URL and now has one, replace the current AVPlayerItem
|
|
2009
|
+
if let update = currentTrack, currentTrackIsEmpty, !update.url.isEmpty {
|
|
2010
|
+
NitroPlayerLogger.log(
|
|
2011
|
+
"TrackPlayerCore", "🔄 Replacing current AVPlayerItem for track with resolved URL: \(update.id)")
|
|
2012
|
+
if let newItem = self.createGaplessPlayerItem(for: update, isPreload: false) {
|
|
2013
|
+
self.player?.replaceCurrentItem(with: newItem)
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
// Rebuild queue if current playlist was affected
|
|
1947
2018
|
if let currentId = self.currentPlaylistId,
|
|
1948
2019
|
let updateCount = affectedPlaylists[currentId]
|
|
1949
2020
|
{
|
|
@@ -1951,12 +2022,36 @@ class TrackPlayerCore: NSObject {
|
|
|
1951
2022
|
"TrackPlayerCore",
|
|
1952
2023
|
"🔄 Rebuilding queue - \(updateCount) tracks updated in current playlist")
|
|
1953
2024
|
|
|
1954
|
-
//
|
|
1955
|
-
self.
|
|
2025
|
+
// Sync currentTracks from the freshly-updated PlaylistManager so rebuilds use resolved URLs
|
|
2026
|
+
if let updatedPlaylist = self.playlistManager.getPlaylist(playlistId: currentId) {
|
|
2027
|
+
self.currentTracks = updatedPlaylist.tracks
|
|
2028
|
+
NitroPlayerLogger.log("TrackPlayerCore", "📥 Synced currentTracks from PlaylistManager (\(self.currentTracks.count) tracks)")
|
|
2029
|
+
}
|
|
1956
2030
|
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
2031
|
+
if self.player?.currentItem == nil, let player = self.player {
|
|
2032
|
+
// No AVPlayerItem exists yet — lazy-load mode: URLs were empty when the queue first
|
|
2033
|
+
// loaded. Rebuild the full queue from currentTrackIndex now that URLs are resolved.
|
|
2034
|
+
NitroPlayerLogger.log(
|
|
2035
|
+
"TrackPlayerCore",
|
|
2036
|
+
"🔄 No current item — full queue rebuild from currentTrackIndex \(self.currentTrackIndex)")
|
|
2037
|
+
player.removeAllItems()
|
|
2038
|
+
var lastItem: AVPlayerItem? = nil
|
|
2039
|
+
for (offset, track) in self.currentTracks[self.currentTrackIndex...].enumerated() {
|
|
2040
|
+
let isPreload = offset < Constants.gaplessPreloadCount
|
|
2041
|
+
if let newItem = self.createGaplessPlayerItem(for: track, isPreload: isPreload) {
|
|
2042
|
+
player.insert(newItem, after: lastItem)
|
|
2043
|
+
lastItem = newItem
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
player.play()
|
|
2047
|
+
self.preloadUpcomingTracks(from: self.currentTrackIndex + 1)
|
|
2048
|
+
} else {
|
|
2049
|
+
// A current AVPlayerItem already exists — preserve it and only rebuild upcoming items.
|
|
2050
|
+
self.rebuildAVQueueFromCurrentPosition()
|
|
2051
|
+
// Re-preload upcoming tracks for gapless playback
|
|
2052
|
+
// CRITICAL: This restores gapless buffering after queue rebuild
|
|
2053
|
+
self.preloadUpcomingTracks(from: self.currentTrackIndex + 1)
|
|
2054
|
+
}
|
|
1960
2055
|
|
|
1961
2056
|
NitroPlayerLogger.log("TrackPlayerCore", "✅ Queue rebuilt, gapless playback preserved")
|
|
1962
2057
|
}
|
|
@@ -2099,8 +2194,14 @@ class TrackPlayerCore: NSObject {
|
|
|
2099
2194
|
* Call this in playerItemDidPlayToEndTime or after skip operations
|
|
2100
2195
|
*/
|
|
2101
2196
|
private func checkUpcomingTracksForUrls(lookahead: Int = 5) {
|
|
2102
|
-
let
|
|
2103
|
-
|
|
2197
|
+
let upcomingTracks = getNextTracksInternal(count: lookahead)
|
|
2198
|
+
|
|
2199
|
+
// Always include the current track if it has no URL — it can't play without one
|
|
2200
|
+
let currentTrack = getCurrentTrack()
|
|
2201
|
+
let currentNeedsUrl = currentTrack.map { $0.url.isEmpty } ?? false
|
|
2202
|
+
let candidateTracks = currentNeedsUrl ? [currentTrack!] + upcomingTracks : upcomingTracks
|
|
2203
|
+
|
|
2204
|
+
let tracksNeedingUrls = candidateTracks.filter { $0.url.isEmpty }
|
|
2104
2205
|
|
|
2105
2206
|
if !tracksNeedingUrls.isEmpty {
|
|
2106
2207
|
NitroPlayerLogger.log(
|