react-native-nitro-player 0.3.0-alpha.9 → 0.4.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/README.md +444 -4
- package/android/build.gradle +4 -1
- package/android/src/main/AndroidManifest.xml +16 -1
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridAndroidAutoMediaLibrary.kt +2 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridAudioDevices.kt +8 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridDownloadManager.kt +225 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridEqualizer.kt +105 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridPlayerQueue.kt +6 -6
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridTrackPlayer.kt +37 -12
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerCore.kt +970 -213
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadDatabase.kt +475 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadFileManager.kt +159 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadManagerCore.kt +489 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadWorker.kt +209 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/equalizer/EqualizerCore.kt +486 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaBrowserService.kt +3 -1
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaSessionManager.kt +14 -6
- package/android/src/main/java/com/margelo/nitro/nitroplayer/playlist/PlaylistManager.kt +27 -0
- package/ios/HybridDownloadManager.swift +226 -0
- package/ios/HybridEqualizer.swift +111 -0
- package/ios/HybridTrackPlayer.swift +36 -8
- package/ios/core/TrackPlayerCore.swift +998 -276
- package/ios/download/DownloadDatabase.swift +493 -0
- package/ios/download/DownloadFileManager.swift +241 -0
- package/ios/download/DownloadManagerCore.swift +923 -0
- package/ios/equalizer/EqualizerCore.swift +685 -0
- package/ios/media/MediaSessionManager.swift +40 -28
- package/ios/playlist/PlaylistManager.swift +40 -9
- package/ios/queue/HybridPlayerQueue.swift +33 -13
- package/lib/hooks/downloadCallbackManager.d.ts +36 -0
- package/lib/hooks/downloadCallbackManager.js +108 -0
- package/lib/hooks/equalizerCallbackManager.d.ts +37 -0
- package/lib/hooks/equalizerCallbackManager.js +109 -0
- package/lib/hooks/index.d.ts +16 -0
- package/lib/hooks/index.js +10 -0
- package/lib/hooks/useActualQueue.d.ts +48 -0
- package/lib/hooks/useActualQueue.js +98 -0
- package/lib/hooks/useDownloadActions.d.ts +26 -0
- package/lib/hooks/useDownloadActions.js +117 -0
- package/lib/hooks/useDownloadProgress.d.ts +25 -0
- package/lib/hooks/useDownloadProgress.js +79 -0
- package/lib/hooks/useDownloadStorage.d.ts +19 -0
- package/lib/hooks/useDownloadStorage.js +60 -0
- package/lib/hooks/useDownloadedTracks.d.ts +25 -0
- package/lib/hooks/useDownloadedTracks.js +69 -0
- package/lib/hooks/useEqualizer.d.ts +25 -0
- package/lib/hooks/useEqualizer.js +124 -0
- package/lib/hooks/useEqualizerPresets.d.ts +22 -0
- package/lib/hooks/useEqualizerPresets.js +96 -0
- package/lib/hooks/useNowPlaying.js +3 -2
- package/lib/hooks/useOnChangeTrack.js +15 -12
- package/lib/hooks/useOnPlaybackStateChange.js +16 -13
- package/lib/hooks/usePlaylist.d.ts +48 -0
- package/lib/hooks/usePlaylist.js +136 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +6 -0
- package/lib/specs/DownloadManager.nitro.d.ts +152 -0
- package/lib/specs/DownloadManager.nitro.js +1 -0
- package/lib/specs/Equalizer.nitro.d.ts +43 -0
- package/lib/specs/Equalizer.nitro.js +1 -0
- package/lib/specs/TrackPlayer.nitro.d.ts +6 -2
- package/lib/types/DownloadTypes.d.ts +110 -0
- package/lib/types/DownloadTypes.js +1 -0
- package/lib/types/EqualizerTypes.d.ts +52 -0
- package/lib/types/EqualizerTypes.js +1 -0
- package/lib/types/PlayerQueue.d.ts +4 -0
- package/nitro.json +8 -0
- package/nitrogen/generated/android/NitroPlayer+autolinking.cmake +10 -1
- package/nitrogen/generated/android/NitroPlayerOnLoad.cpp +32 -2
- package/nitrogen/generated/android/c++/JCurrentPlayingType.hpp +65 -0
- package/nitrogen/generated/android/c++/JDownloadConfig.hpp +92 -0
- package/nitrogen/generated/android/c++/JDownloadError.hpp +71 -0
- package/nitrogen/generated/android/c++/JDownloadErrorReason.hpp +74 -0
- package/nitrogen/generated/android/c++/JDownloadProgress.hpp +79 -0
- package/nitrogen/generated/android/c++/JDownloadQueueStatus.hpp +81 -0
- package/nitrogen/generated/android/c++/JDownloadState.hpp +71 -0
- package/nitrogen/generated/android/c++/JDownloadStorageInfo.hpp +73 -0
- package/nitrogen/generated/android/c++/JDownloadTask.hpp +108 -0
- package/nitrogen/generated/android/c++/JDownloadedPlaylist.hpp +111 -0
- package/nitrogen/generated/android/c++/JDownloadedTrack.hpp +92 -0
- package/nitrogen/generated/android/c++/JEqualizerBand.hpp +69 -0
- package/nitrogen/generated/android/c++/JEqualizerPreset.hpp +78 -0
- package/nitrogen/generated/android/c++/JEqualizerState.hpp +91 -0
- package/nitrogen/generated/android/c++/JFunc_void_DownloadProgress.hpp +80 -0
- package/nitrogen/generated/android/c++/JFunc_void_DownloadedTrack.hpp +89 -0
- package/nitrogen/generated/android/c++/JFunc_void_TrackItem_std__optional_Reason_.hpp +2 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_std__variant_nitro__NullType__std__string__.hpp +81 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__string_Playlist_std__optional_QueueOperation_.hpp +2 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__string_std__string_DownloadState_std__optional_DownloadError_.hpp +83 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_EqualizerBand_.hpp +97 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_Playlist__std__optional_QueueOperation_.hpp +2 -0
- package/nitrogen/generated/android/c++/JGainRange.hpp +61 -0
- package/nitrogen/generated/android/c++/JHybridDownloadManagerSpec.cpp +470 -0
- package/nitrogen/generated/android/c++/JHybridDownloadManagerSpec.hpp +99 -0
- package/nitrogen/generated/android/c++/JHybridEqualizerSpec.cpp +204 -0
- package/nitrogen/generated/android/c++/JHybridEqualizerSpec.hpp +82 -0
- package/nitrogen/generated/android/c++/JHybridPlayerQueueSpec.cpp +2 -0
- package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.cpp +117 -15
- package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.hpp +6 -2
- package/nitrogen/generated/android/c++/JPlaybackSource.hpp +62 -0
- package/nitrogen/generated/android/c++/JPlayerState.hpp +11 -3
- package/nitrogen/generated/android/c++/JPlaylist.hpp +2 -0
- package/nitrogen/generated/android/c++/JPresetType.hpp +59 -0
- package/nitrogen/generated/android/c++/JStorageLocation.hpp +59 -0
- package/nitrogen/generated/android/c++/JTrackItem.hpp +9 -3
- package/nitrogen/generated/android/c++/JTrackPlayerState.hpp +3 -3
- package/nitrogen/generated/android/c++/JVariant_NullType_Double.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_Double.hpp +69 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadError.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadError.hpp +74 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadTask.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadTask.hpp +84 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadedPlaylist.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadedPlaylist.hpp +85 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadedTrack.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_DownloadedTrack.hpp +80 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_Playlist.hpp +2 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_TrackItem.hpp +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/CurrentPlayingType.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadConfig.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadError.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadErrorReason.kt +26 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadProgress.kt +53 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadQueueStatus.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadState.kt +25 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadStorageInfo.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadTask.kt +65 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadedPlaylist.kt +53 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/DownloadedTrack.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/EqualizerBand.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/EqualizerPreset.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/EqualizerState.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_DownloadProgress.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_DownloadedTrack.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__optional_std__variant_nitro__NullType__std__string__.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__string_std__string_DownloadState_std__optional_DownloadError_.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__vector_EqualizerBand_.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/GainRange.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridDownloadManagerSpec.kt +210 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridEqualizerSpec.kt +141 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridTrackPlayerSpec.kt +19 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/PlaybackSource.kt +22 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/PlayerState.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/PresetType.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/StorageLocation.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/TrackItem.kt +7 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/TrackPlayerState.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Variant_NullType_Double.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Variant_NullType_DownloadError.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Variant_NullType_DownloadTask.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Variant_NullType_DownloadedPlaylist.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Variant_NullType_DownloadedTrack.kt +59 -0
- package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.cpp +138 -8
- package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.hpp +1046 -121
- package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Umbrella.hpp +66 -0
- package/nitrogen/generated/ios/NitroPlayerAutolinking.mm +16 -0
- package/nitrogen/generated/ios/NitroPlayerAutolinking.swift +30 -0
- package/nitrogen/generated/ios/c++/HybridDownloadManagerSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridDownloadManagerSpecSwift.hpp +386 -0
- package/nitrogen/generated/ios/c++/HybridEqualizerSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridEqualizerSpecSwift.hpp +223 -0
- package/nitrogen/generated/ios/c++/HybridPlayerQueueSpecSwift.hpp +1 -0
- package/nitrogen/generated/ios/c++/HybridTrackPlayerSpecSwift.hpp +46 -6
- package/nitrogen/generated/ios/swift/CurrentPlayingType.swift +48 -0
- package/nitrogen/generated/ios/swift/DownloadConfig.swift +270 -0
- package/nitrogen/generated/ios/swift/DownloadError.swift +69 -0
- package/nitrogen/generated/ios/swift/DownloadErrorReason.swift +60 -0
- package/nitrogen/generated/ios/swift/DownloadProgress.swift +91 -0
- package/nitrogen/generated/ios/swift/DownloadQueueStatus.swift +102 -0
- package/nitrogen/generated/ios/swift/DownloadState.swift +56 -0
- package/nitrogen/generated/ios/swift/DownloadStorageInfo.swift +80 -0
- package/nitrogen/generated/ios/swift/DownloadTask.swift +315 -0
- package/nitrogen/generated/ios/swift/DownloadedPlaylist.swift +103 -0
- package/nitrogen/generated/ios/swift/DownloadedTrack.swift +147 -0
- package/nitrogen/generated/ios/swift/EqualizerBand.swift +69 -0
- package/nitrogen/generated/ios/swift/EqualizerPreset.swift +70 -0
- package/nitrogen/generated/ios/swift/EqualizerState.swift +115 -0
- package/nitrogen/generated/ios/swift/Func_void.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_DownloadProgress.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_DownloadStorageInfo.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_DownloadedTrack.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_PlayerState.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_bool.swift +5 -5
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__optional_std__variant_nitro__NullType__std__string__.swift +66 -0
- package/nitrogen/generated/ios/swift/Func_void_std__string.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__string_std__string_DownloadState_std__optional_DownloadError_.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__vector_EqualizerBand_.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__vector_TrackItem_.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__vector_std__string_.swift +47 -0
- package/nitrogen/generated/ios/swift/GainRange.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridDownloadManagerSpec.swift +90 -0
- package/nitrogen/generated/ios/swift/HybridDownloadManagerSpec_cxx.swift +705 -0
- package/nitrogen/generated/ios/swift/HybridEqualizerSpec.swift +73 -0
- package/nitrogen/generated/ios/swift/HybridEqualizerSpec_cxx.swift +396 -0
- package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec.swift +6 -2
- package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec_cxx.swift +105 -8
- package/nitrogen/generated/ios/swift/PlaybackSource.swift +44 -0
- package/nitrogen/generated/ios/swift/PlayerState.swift +13 -2
- package/nitrogen/generated/ios/swift/PresetType.swift +40 -0
- package/nitrogen/generated/ios/swift/StorageLocation.swift +40 -0
- package/nitrogen/generated/ios/swift/TrackItem.swift +31 -1
- package/nitrogen/generated/ios/swift/TrackPlayerState.swift +4 -4
- package/nitrogen/generated/ios/swift/Variant_NullType_Double.swift +18 -0
- package/nitrogen/generated/ios/swift/Variant_NullType_DownloadError.swift +18 -0
- package/nitrogen/generated/ios/swift/Variant_NullType_DownloadTask.swift +18 -0
- package/nitrogen/generated/ios/swift/Variant_NullType_DownloadedPlaylist.swift +18 -0
- package/nitrogen/generated/ios/swift/Variant_NullType_DownloadedTrack.swift +18 -0
- package/nitrogen/generated/shared/c++/CurrentPlayingType.hpp +84 -0
- package/nitrogen/generated/shared/c++/DownloadConfig.hpp +108 -0
- package/nitrogen/generated/shared/c++/DownloadError.hpp +89 -0
- package/nitrogen/generated/shared/c++/DownloadErrorReason.hpp +96 -0
- package/nitrogen/generated/shared/c++/DownloadProgress.hpp +97 -0
- package/nitrogen/generated/shared/c++/DownloadQueueStatus.hpp +99 -0
- package/nitrogen/generated/shared/c++/DownloadState.hpp +92 -0
- package/nitrogen/generated/shared/c++/DownloadStorageInfo.hpp +91 -0
- package/nitrogen/generated/shared/c++/DownloadTask.hpp +122 -0
- package/nitrogen/generated/shared/c++/DownloadedPlaylist.hpp +101 -0
- package/nitrogen/generated/shared/c++/DownloadedTrack.hpp +107 -0
- package/nitrogen/generated/shared/c++/EqualizerBand.hpp +87 -0
- package/nitrogen/generated/shared/c++/EqualizerPreset.hpp +86 -0
- package/nitrogen/generated/shared/c++/EqualizerState.hpp +89 -0
- package/nitrogen/generated/shared/c++/GainRange.hpp +79 -0
- package/nitrogen/generated/shared/c++/HybridDownloadManagerSpec.cpp +55 -0
- package/nitrogen/generated/shared/c++/HybridDownloadManagerSpec.hpp +134 -0
- package/nitrogen/generated/shared/c++/HybridEqualizerSpec.cpp +38 -0
- package/nitrogen/generated/shared/c++/HybridEqualizerSpec.hpp +95 -0
- package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.cpp +4 -0
- package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.hpp +11 -5
- package/nitrogen/generated/shared/c++/PlaybackSource.hpp +80 -0
- package/nitrogen/generated/shared/c++/PlayerState.hpp +9 -2
- package/nitrogen/generated/shared/c++/PresetType.hpp +76 -0
- package/nitrogen/generated/shared/c++/StorageLocation.hpp +76 -0
- package/nitrogen/generated/shared/c++/TrackItem.hpp +7 -2
- package/nitrogen/generated/shared/c++/TrackPlayerState.hpp +5 -5
- package/package.json +1 -1
- package/src/hooks/downloadCallbackManager.ts +149 -0
- package/src/hooks/equalizerCallbackManager.ts +138 -0
- package/src/hooks/index.ts +23 -0
- package/src/hooks/useActualQueue.ts +116 -0
- package/src/hooks/useDownloadActions.ts +179 -0
- package/src/hooks/useDownloadProgress.ts +126 -0
- package/src/hooks/useDownloadStorage.ts +84 -0
- package/src/hooks/useDownloadedTracks.ts +138 -0
- package/src/hooks/useEqualizer.ts +173 -0
- package/src/hooks/useEqualizerPresets.ts +140 -0
- package/src/hooks/useNowPlaying.ts +3 -2
- package/src/hooks/useOnChangeTrack.ts +15 -11
- package/src/hooks/useOnPlaybackStateChange.ts +19 -15
- package/src/hooks/usePlaylist.ts +161 -0
- package/src/index.ts +12 -0
- package/src/specs/DownloadManager.nitro.ts +203 -0
- package/src/specs/Equalizer.nitro.ts +69 -0
- package/src/specs/TrackPlayer.nitro.ts +6 -2
- package/src/types/DownloadTypes.ts +135 -0
- package/src/types/EqualizerTypes.ts +72 -0
- package/src/types/PlayerQueue.ts +9 -0
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
//
|
|
2
|
+
// DownloadDatabase.swift
|
|
3
|
+
// NitroPlayer
|
|
4
|
+
//
|
|
5
|
+
// Created by Ritesh Shukla on 2026-01-23..
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
import NitroModules
|
|
10
|
+
|
|
11
|
+
/// Manages persistence of downloaded track metadata using UserDefaults
|
|
12
|
+
final class DownloadDatabase {
|
|
13
|
+
|
|
14
|
+
// MARK: - Singleton
|
|
15
|
+
|
|
16
|
+
static let shared = DownloadDatabase()
|
|
17
|
+
|
|
18
|
+
// MARK: - Constants
|
|
19
|
+
|
|
20
|
+
private static let downloadedTracksKey = "NitroPlayerDownloadedTracks"
|
|
21
|
+
private static let playlistTracksKey = "NitroPlayerPlaylistTracks"
|
|
22
|
+
|
|
23
|
+
// MARK: - Properties
|
|
24
|
+
|
|
25
|
+
private var downloadedTracks: [String: DownloadedTrackRecord] = [:]
|
|
26
|
+
private var playlistTracks: [String: Set<String>] = [:] // playlistId -> Set of trackIds
|
|
27
|
+
|
|
28
|
+
private let queue = DispatchQueue(
|
|
29
|
+
label: "com.nitroplayer.downloadDatabase", attributes: .concurrent)
|
|
30
|
+
|
|
31
|
+
// MARK: - Initialization
|
|
32
|
+
|
|
33
|
+
private init() {
|
|
34
|
+
loadFromDisk()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// MARK: - Save Operations
|
|
38
|
+
|
|
39
|
+
func saveDownloadedTrack(_ track: DownloadedTrack, playlistId: String?) {
|
|
40
|
+
queue.async(flags: .barrier) {
|
|
41
|
+
let record = DownloadedTrackRecord(
|
|
42
|
+
trackId: track.trackId,
|
|
43
|
+
originalTrack: self.trackItemToRecord(track.originalTrack),
|
|
44
|
+
localPath: track.localPath,
|
|
45
|
+
localArtworkPath: self.variantToString(track.localArtworkPath),
|
|
46
|
+
downloadedAt: track.downloadedAt,
|
|
47
|
+
fileSize: track.fileSize,
|
|
48
|
+
storageLocation: track.storageLocation == .private ? "private" : "public"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
self.downloadedTracks[track.trackId] = record
|
|
52
|
+
|
|
53
|
+
// Associate with playlist if provided
|
|
54
|
+
if let playlistId = playlistId {
|
|
55
|
+
if self.playlistTracks[playlistId] == nil {
|
|
56
|
+
self.playlistTracks[playlistId] = Set()
|
|
57
|
+
}
|
|
58
|
+
self.playlistTracks[playlistId]?.insert(track.trackId)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
self.saveToDisk()
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// MARK: - Query Operations
|
|
66
|
+
|
|
67
|
+
func isTrackDownloaded(trackId: String) -> Bool {
|
|
68
|
+
return queue.sync {
|
|
69
|
+
guard let record = downloadedTracks[trackId] else {
|
|
70
|
+
print("🔍 DownloadDatabase: Track \(trackId) NOT found in database")
|
|
71
|
+
return false
|
|
72
|
+
}
|
|
73
|
+
// Verify file still exists
|
|
74
|
+
let exists = FileManager.default.fileExists(atPath: record.localPath)
|
|
75
|
+
if exists {
|
|
76
|
+
print("✅ DownloadDatabase: Track \(trackId) IS downloaded at \(record.localPath)")
|
|
77
|
+
} else {
|
|
78
|
+
print(
|
|
79
|
+
"❌ DownloadDatabase: Track \(trackId) record exists but file NOT found at \(record.localPath)"
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
return exists
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
func isPlaylistDownloaded(playlistId: String) -> Bool {
|
|
87
|
+
return queue.sync {
|
|
88
|
+
guard let trackIds = playlistTracks[playlistId], !trackIds.isEmpty else { return false }
|
|
89
|
+
|
|
90
|
+
// Get original playlist to check all tracks
|
|
91
|
+
guard let playlistModel = PlaylistManager.shared.getPlaylist(playlistId: playlistId) else {
|
|
92
|
+
return false
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Check if all tracks are downloaded
|
|
96
|
+
for track in playlistModel.tracks {
|
|
97
|
+
if !isTrackDownloaded(trackId: track.id) {
|
|
98
|
+
return false
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return true
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
func isPlaylistPartiallyDownloaded(playlistId: String) -> Bool {
|
|
107
|
+
return queue.sync {
|
|
108
|
+
guard let trackIds = playlistTracks[playlistId], !trackIds.isEmpty else { return false }
|
|
109
|
+
|
|
110
|
+
// Check if at least one track is downloaded
|
|
111
|
+
for trackId in trackIds {
|
|
112
|
+
if isTrackDownloaded(trackId: trackId) {
|
|
113
|
+
return true
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return false
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
func getDownloadedTrack(trackId: String) -> DownloadedTrack? {
|
|
122
|
+
return queue.sync {
|
|
123
|
+
print("🔍 DownloadDatabase.getDownloadedTrack() for trackId: \(trackId)")
|
|
124
|
+
print(" Total records in memory: \(downloadedTracks.count)")
|
|
125
|
+
print(" Available trackIds: \(Array(downloadedTracks.keys))")
|
|
126
|
+
|
|
127
|
+
guard let record = downloadedTracks[trackId] else {
|
|
128
|
+
print(" ❌ No record found for trackId: \(trackId)")
|
|
129
|
+
return nil
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
print(" Found record, checking file at: \(record.localPath)")
|
|
133
|
+
|
|
134
|
+
// Verify file still exists
|
|
135
|
+
guard FileManager.default.fileExists(atPath: record.localPath) else {
|
|
136
|
+
print(" ❌ File does NOT exist, cleaning up record")
|
|
137
|
+
// File was deleted externally, clean up record
|
|
138
|
+
queue.async(flags: .barrier) {
|
|
139
|
+
self.downloadedTracks.removeValue(forKey: trackId)
|
|
140
|
+
self.saveToDisk()
|
|
141
|
+
}
|
|
142
|
+
return nil
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
print(" ✅ File exists, returning track")
|
|
146
|
+
return recordToDownloadedTrack(record)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
func getAllDownloadedTracks() -> [DownloadedTrack] {
|
|
151
|
+
return queue.sync {
|
|
152
|
+
print(
|
|
153
|
+
"🎯 DownloadDatabase: getAllDownloadedTracks called, have \(downloadedTracks.count) records")
|
|
154
|
+
|
|
155
|
+
var validTracks: [DownloadedTrack] = []
|
|
156
|
+
var invalidTrackIds: [String] = []
|
|
157
|
+
|
|
158
|
+
for (trackId, record) in downloadedTracks {
|
|
159
|
+
print(" Checking track \(trackId) at path: \(record.localPath)")
|
|
160
|
+
if FileManager.default.fileExists(atPath: record.localPath) {
|
|
161
|
+
print(" ✅ File exists")
|
|
162
|
+
validTracks.append(recordToDownloadedTrack(record))
|
|
163
|
+
} else {
|
|
164
|
+
print(" ❌ File NOT found")
|
|
165
|
+
invalidTrackIds.append(trackId)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Clean up invalid records
|
|
170
|
+
if !invalidTrackIds.isEmpty {
|
|
171
|
+
print(" Cleaning up \(invalidTrackIds.count) invalid records")
|
|
172
|
+
queue.async(flags: .barrier) {
|
|
173
|
+
for trackId in invalidTrackIds {
|
|
174
|
+
self.downloadedTracks.removeValue(forKey: trackId)
|
|
175
|
+
}
|
|
176
|
+
self.saveToDisk()
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
print("🎯 DownloadDatabase: Returning \(validTracks.count) valid tracks")
|
|
181
|
+
return validTracks
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
func getDownloadedPlaylist(playlistId: String) -> DownloadedPlaylist? {
|
|
186
|
+
return queue.sync { () -> DownloadedPlaylist? in
|
|
187
|
+
guard let trackIds = playlistTracks[playlistId], !trackIds.isEmpty else { return nil }
|
|
188
|
+
guard let playlistModel = PlaylistManager.shared.getPlaylist(playlistId: playlistId) else {
|
|
189
|
+
return nil
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
var downloadedTracks: [DownloadedTrack] = []
|
|
193
|
+
var totalSize: Double = 0
|
|
194
|
+
|
|
195
|
+
for trackId in trackIds {
|
|
196
|
+
if let track = getDownloadedTrack(trackId: trackId) {
|
|
197
|
+
downloadedTracks.append(track)
|
|
198
|
+
totalSize += track.fileSize
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
guard !downloadedTracks.isEmpty else { return nil }
|
|
203
|
+
|
|
204
|
+
let isComplete = downloadedTracks.count == playlistModel.tracks.count
|
|
205
|
+
|
|
206
|
+
return DownloadedPlaylist(
|
|
207
|
+
playlistId: playlistId,
|
|
208
|
+
originalPlaylist: playlistModel.toGeneratedPlaylist(),
|
|
209
|
+
downloadedTracks: downloadedTracks,
|
|
210
|
+
totalSize: totalSize,
|
|
211
|
+
downloadedAt: downloadedTracks.map { $0.downloadedAt }.min()
|
|
212
|
+
?? Date().timeIntervalSince1970,
|
|
213
|
+
isComplete: isComplete
|
|
214
|
+
)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
func getAllDownloadedPlaylists() -> [DownloadedPlaylist] {
|
|
219
|
+
return queue.sync {
|
|
220
|
+
var playlists: [DownloadedPlaylist] = []
|
|
221
|
+
|
|
222
|
+
for playlistId in playlistTracks.keys {
|
|
223
|
+
if let playlist = getDownloadedPlaylist(playlistId: playlistId) {
|
|
224
|
+
playlists.append(playlist)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return playlists
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// MARK: - Sync Operations
|
|
233
|
+
|
|
234
|
+
/// Validates all downloads and removes records for missing files
|
|
235
|
+
/// Returns the number of orphaned records that were cleaned up
|
|
236
|
+
func syncDownloads() -> Int {
|
|
237
|
+
return queue.sync(flags: .barrier) {
|
|
238
|
+
print("🔄 DownloadDatabase: syncDownloads called")
|
|
239
|
+
|
|
240
|
+
var removedCount = 0
|
|
241
|
+
var trackIdsToRemove: [String] = []
|
|
242
|
+
|
|
243
|
+
for (trackId, record) in downloadedTracks {
|
|
244
|
+
if !FileManager.default.fileExists(atPath: record.localPath) {
|
|
245
|
+
print(" ❌ Missing file for track \(trackId): \(record.localPath)")
|
|
246
|
+
trackIdsToRemove.append(trackId)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Remove invalid records
|
|
251
|
+
for trackId in trackIdsToRemove {
|
|
252
|
+
downloadedTracks.removeValue(forKey: trackId)
|
|
253
|
+
|
|
254
|
+
// Also remove from playlist associations
|
|
255
|
+
for (playlistId, var trackIds) in playlistTracks {
|
|
256
|
+
if trackIds.remove(trackId) != nil {
|
|
257
|
+
if trackIds.isEmpty {
|
|
258
|
+
playlistTracks.removeValue(forKey: playlistId)
|
|
259
|
+
} else {
|
|
260
|
+
playlistTracks[playlistId] = trackIds
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
removedCount += 1
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if removedCount > 0 {
|
|
269
|
+
saveToDisk()
|
|
270
|
+
print(" ✅ Cleaned up \(removedCount) orphaned records")
|
|
271
|
+
} else {
|
|
272
|
+
print(" ✅ All downloads are valid")
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return removedCount
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// MARK: - Delete Operations
|
|
280
|
+
|
|
281
|
+
func deleteDownloadedTrack(trackId: String) {
|
|
282
|
+
queue.async(flags: .barrier) {
|
|
283
|
+
guard let record = self.downloadedTracks[trackId] else { return }
|
|
284
|
+
|
|
285
|
+
// Delete the file
|
|
286
|
+
DownloadFileManager.shared.deleteFile(at: record.localPath)
|
|
287
|
+
|
|
288
|
+
// Delete artwork if exists
|
|
289
|
+
if let artworkPath = record.localArtworkPath {
|
|
290
|
+
DownloadFileManager.shared.deleteFile(at: artworkPath)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Remove from records
|
|
294
|
+
self.downloadedTracks.removeValue(forKey: trackId)
|
|
295
|
+
|
|
296
|
+
// Remove from all playlist associations
|
|
297
|
+
for (playlistId, var trackIds) in self.playlistTracks {
|
|
298
|
+
trackIds.remove(trackId)
|
|
299
|
+
if trackIds.isEmpty {
|
|
300
|
+
self.playlistTracks.removeValue(forKey: playlistId)
|
|
301
|
+
} else {
|
|
302
|
+
self.playlistTracks[playlistId] = trackIds
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
self.saveToDisk()
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
func deleteDownloadedPlaylist(playlistId: String) {
|
|
311
|
+
queue.async(flags: .barrier) {
|
|
312
|
+
guard let trackIds = self.playlistTracks[playlistId] else { return }
|
|
313
|
+
|
|
314
|
+
// Delete all tracks in the playlist
|
|
315
|
+
for trackId in trackIds {
|
|
316
|
+
if let record = self.downloadedTracks[trackId] {
|
|
317
|
+
DownloadFileManager.shared.deleteFile(at: record.localPath)
|
|
318
|
+
if let artworkPath = record.localArtworkPath {
|
|
319
|
+
DownloadFileManager.shared.deleteFile(at: artworkPath)
|
|
320
|
+
}
|
|
321
|
+
self.downloadedTracks.removeValue(forKey: trackId)
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Remove playlist association
|
|
326
|
+
self.playlistTracks.removeValue(forKey: playlistId)
|
|
327
|
+
|
|
328
|
+
self.saveToDisk()
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
func deleteAllDownloads() {
|
|
333
|
+
queue.async(flags: .barrier) {
|
|
334
|
+
// Delete all files
|
|
335
|
+
for record in self.downloadedTracks.values {
|
|
336
|
+
DownloadFileManager.shared.deleteFile(at: record.localPath)
|
|
337
|
+
if let artworkPath = record.localArtworkPath {
|
|
338
|
+
DownloadFileManager.shared.deleteFile(at: artworkPath)
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Clear all records
|
|
343
|
+
self.downloadedTracks.removeAll()
|
|
344
|
+
self.playlistTracks.removeAll()
|
|
345
|
+
|
|
346
|
+
self.saveToDisk()
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// MARK: - Persistence
|
|
351
|
+
|
|
352
|
+
private func saveToDisk() {
|
|
353
|
+
do {
|
|
354
|
+
let tracksData = try JSONEncoder().encode(downloadedTracks)
|
|
355
|
+
UserDefaults.standard.set(tracksData, forKey: Self.downloadedTracksKey)
|
|
356
|
+
|
|
357
|
+
// Convert Set to Array for encoding
|
|
358
|
+
let playlistTracksDict = playlistTracks.mapValues { Array($0) }
|
|
359
|
+
let playlistData = try JSONEncoder().encode(playlistTracksDict)
|
|
360
|
+
UserDefaults.standard.set(playlistData, forKey: Self.playlistTracksKey)
|
|
361
|
+
} catch {
|
|
362
|
+
print("[DownloadDatabase] Failed to save to disk: \(error)")
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
private func loadFromDisk() {
|
|
367
|
+
print("\n" + String(repeating: "📀", count: 40))
|
|
368
|
+
print("📀 DownloadDatabase: LOADING FROM DISK")
|
|
369
|
+
print(String(repeating: "📀", count: 40))
|
|
370
|
+
|
|
371
|
+
// Load synchronously to ensure data is available immediately
|
|
372
|
+
// Load downloaded tracks
|
|
373
|
+
if let tracksData = UserDefaults.standard.data(forKey: Self.downloadedTracksKey) {
|
|
374
|
+
do {
|
|
375
|
+
self.downloadedTracks = try JSONDecoder().decode(
|
|
376
|
+
[String: DownloadedTrackRecord].self, from: tracksData)
|
|
377
|
+
print("✅ DownloadDatabase: Loaded \(self.downloadedTracks.count) tracks from disk")
|
|
378
|
+
|
|
379
|
+
// Log each downloaded track
|
|
380
|
+
for (trackId, record) in self.downloadedTracks {
|
|
381
|
+
print(" 📥 \(trackId)")
|
|
382
|
+
print(" Title: \(record.originalTrack.title)")
|
|
383
|
+
print(" Path: \(record.localPath)")
|
|
384
|
+
print(" Exists: \(FileManager.default.fileExists(atPath: record.localPath))")
|
|
385
|
+
}
|
|
386
|
+
} catch {
|
|
387
|
+
print("❌ DownloadDatabase: Failed to load tracks from disk: \(error)")
|
|
388
|
+
}
|
|
389
|
+
} else {
|
|
390
|
+
print("⚠️ DownloadDatabase: No saved tracks found in UserDefaults")
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Load playlist associations
|
|
394
|
+
if let playlistData = UserDefaults.standard.data(forKey: Self.playlistTracksKey) {
|
|
395
|
+
do {
|
|
396
|
+
let playlistTracksDict = try JSONDecoder().decode(
|
|
397
|
+
[String: [String]].self, from: playlistData)
|
|
398
|
+
self.playlistTracks = playlistTracksDict.mapValues { Set($0) }
|
|
399
|
+
print(
|
|
400
|
+
"✅ DownloadDatabase: Loaded \(self.playlistTracks.count) playlist associations from disk")
|
|
401
|
+
|
|
402
|
+
// Log playlist associations
|
|
403
|
+
for (playlistId, trackIds) in self.playlistTracks {
|
|
404
|
+
print(" 📋 Playlist \(playlistId): \(trackIds.count) tracks")
|
|
405
|
+
}
|
|
406
|
+
} catch {
|
|
407
|
+
print("❌ DownloadDatabase: Failed to load playlist tracks from disk: \(error)")
|
|
408
|
+
}
|
|
409
|
+
} else {
|
|
410
|
+
print("⚠️ DownloadDatabase: No playlist associations found")
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
print(String(repeating: "📀", count: 40) + "\n")
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// MARK: - Conversion Helpers
|
|
417
|
+
|
|
418
|
+
/// Convert Variant_NullType_String? to String?
|
|
419
|
+
private func variantToString(_ variant: Variant_NullType_String?) -> String? {
|
|
420
|
+
guard let variant = variant else { return nil }
|
|
421
|
+
switch variant {
|
|
422
|
+
case .first(_):
|
|
423
|
+
return nil
|
|
424
|
+
case .second(let value):
|
|
425
|
+
return value
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/// Convert String? to Variant_NullType_String?
|
|
430
|
+
private func stringToVariant(_ string: String?) -> Variant_NullType_String? {
|
|
431
|
+
guard let string = string else { return nil }
|
|
432
|
+
return .second(string)
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
private func trackItemToRecord(_ track: TrackItem) -> TrackItemRecord {
|
|
436
|
+
return TrackItemRecord(
|
|
437
|
+
id: track.id,
|
|
438
|
+
title: track.title,
|
|
439
|
+
artist: track.artist,
|
|
440
|
+
album: track.album,
|
|
441
|
+
duration: track.duration,
|
|
442
|
+
url: track.url,
|
|
443
|
+
artwork: variantToString(track.artwork)
|
|
444
|
+
)
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
private func recordToTrackItem(_ record: TrackItemRecord) -> TrackItem {
|
|
448
|
+
return TrackItem(
|
|
449
|
+
id: record.id,
|
|
450
|
+
title: record.title,
|
|
451
|
+
artist: record.artist,
|
|
452
|
+
album: record.album,
|
|
453
|
+
duration: record.duration,
|
|
454
|
+
url: record.url,
|
|
455
|
+
artwork: stringToVariant(record.artwork),
|
|
456
|
+
extraPayload: nil
|
|
457
|
+
)
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
private func recordToDownloadedTrack(_ record: DownloadedTrackRecord) -> DownloadedTrack {
|
|
461
|
+
return DownloadedTrack(
|
|
462
|
+
trackId: record.trackId,
|
|
463
|
+
originalTrack: recordToTrackItem(record.originalTrack),
|
|
464
|
+
localPath: record.localPath,
|
|
465
|
+
localArtworkPath: stringToVariant(record.localArtworkPath),
|
|
466
|
+
downloadedAt: record.downloadedAt,
|
|
467
|
+
fileSize: record.fileSize,
|
|
468
|
+
storageLocation: record.storageLocation == "private" ? .private : .public
|
|
469
|
+
)
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// MARK: - Codable Records
|
|
474
|
+
|
|
475
|
+
private struct DownloadedTrackRecord: Codable {
|
|
476
|
+
let trackId: String
|
|
477
|
+
let originalTrack: TrackItemRecord
|
|
478
|
+
let localPath: String
|
|
479
|
+
let localArtworkPath: String?
|
|
480
|
+
let downloadedAt: Double
|
|
481
|
+
let fileSize: Double
|
|
482
|
+
let storageLocation: String
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
private struct TrackItemRecord: Codable {
|
|
486
|
+
let id: String
|
|
487
|
+
let title: String
|
|
488
|
+
let artist: String
|
|
489
|
+
let album: String
|
|
490
|
+
let duration: Double
|
|
491
|
+
let url: String
|
|
492
|
+
let artwork: String?
|
|
493
|
+
}
|