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,475 @@
|
|
|
1
|
+
package com.margelo.nitro.nitroplayer.download
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.SharedPreferences
|
|
5
|
+
import android.util.Log
|
|
6
|
+
import com.margelo.nitro.core.NullType
|
|
7
|
+
import com.margelo.nitro.nitroplayer.*
|
|
8
|
+
import com.margelo.nitro.nitroplayer.playlist.PlaylistManager
|
|
9
|
+
import org.json.JSONArray
|
|
10
|
+
import org.json.JSONObject
|
|
11
|
+
import java.io.File
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Manages persistence of downloaded track metadata using SharedPreferences
|
|
15
|
+
*/
|
|
16
|
+
class DownloadDatabase private constructor(
|
|
17
|
+
private val context: Context,
|
|
18
|
+
) {
|
|
19
|
+
companion object {
|
|
20
|
+
private const val TAG = "DownloadDatabase"
|
|
21
|
+
private const val PREFS_NAME = "NitroPlayerDownloads"
|
|
22
|
+
private const val KEY_DOWNLOADED_TRACKS = "downloaded_tracks"
|
|
23
|
+
private const val KEY_PLAYLIST_TRACKS = "playlist_tracks"
|
|
24
|
+
|
|
25
|
+
@Volatile
|
|
26
|
+
private var instance: DownloadDatabase? = null
|
|
27
|
+
|
|
28
|
+
fun getInstance(context: Context): DownloadDatabase =
|
|
29
|
+
instance ?: synchronized(this) {
|
|
30
|
+
instance ?: DownloadDatabase(context.applicationContext).also { instance = it }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private val prefs: SharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
35
|
+
private val downloadedTracks = mutableMapOf<String, DownloadedTrackRecord>()
|
|
36
|
+
private val playlistTracks = mutableMapOf<String, MutableSet<String>>()
|
|
37
|
+
private val fileManager = DownloadFileManager.getInstance(context)
|
|
38
|
+
|
|
39
|
+
init {
|
|
40
|
+
loadFromDisk()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Save Operations
|
|
44
|
+
fun saveDownloadedTrack(
|
|
45
|
+
track: DownloadedTrack,
|
|
46
|
+
playlistId: String?,
|
|
47
|
+
) {
|
|
48
|
+
synchronized(this) {
|
|
49
|
+
val record =
|
|
50
|
+
DownloadedTrackRecord(
|
|
51
|
+
trackId = track.trackId,
|
|
52
|
+
originalTrack = trackItemToRecord(track.originalTrack),
|
|
53
|
+
localPath = track.localPath,
|
|
54
|
+
localArtworkPath = track.localArtworkPath?.asSecondOrNull(),
|
|
55
|
+
downloadedAt = track.downloadedAt,
|
|
56
|
+
fileSize = track.fileSize,
|
|
57
|
+
storageLocation = track.storageLocation.name,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
downloadedTracks[track.trackId] = record
|
|
61
|
+
|
|
62
|
+
// Associate with playlist if provided
|
|
63
|
+
playlistId?.let {
|
|
64
|
+
if (playlistTracks[it] == null) {
|
|
65
|
+
playlistTracks[it] = mutableSetOf()
|
|
66
|
+
}
|
|
67
|
+
playlistTracks[it]?.add(track.trackId)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
saveToDisk()
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Query Operations
|
|
75
|
+
fun isTrackDownloaded(trackId: String): Boolean {
|
|
76
|
+
synchronized(this) {
|
|
77
|
+
val record = downloadedTracks[trackId] ?: return false
|
|
78
|
+
// Verify file still exists
|
|
79
|
+
return File(record.localPath).exists()
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
fun isPlaylistDownloaded(playlistId: String): Boolean {
|
|
84
|
+
synchronized(this) {
|
|
85
|
+
val trackIds = playlistTracks[playlistId] ?: return false
|
|
86
|
+
if (trackIds.isEmpty()) return false
|
|
87
|
+
|
|
88
|
+
// Get original playlist to check all tracks
|
|
89
|
+
val playlist = PlaylistManager.getInstance(context).getPlaylist(playlistId) ?: return false
|
|
90
|
+
|
|
91
|
+
// Check if all tracks are downloaded
|
|
92
|
+
return playlist.tracks.all { track ->
|
|
93
|
+
isTrackDownloaded(track.id)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
fun isPlaylistPartiallyDownloaded(playlistId: String): Boolean {
|
|
99
|
+
synchronized(this) {
|
|
100
|
+
val trackIds = playlistTracks[playlistId] ?: return false
|
|
101
|
+
if (trackIds.isEmpty()) return false
|
|
102
|
+
|
|
103
|
+
// Check if at least one track is downloaded
|
|
104
|
+
return trackIds.any { trackId ->
|
|
105
|
+
isTrackDownloaded(trackId)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
fun getDownloadedTrack(trackId: String): DownloadedTrack? {
|
|
111
|
+
synchronized(this) {
|
|
112
|
+
val record = downloadedTracks[trackId] ?: return null
|
|
113
|
+
|
|
114
|
+
// Verify file still exists
|
|
115
|
+
if (!File(record.localPath).exists()) {
|
|
116
|
+
// File was deleted externally, clean up record
|
|
117
|
+
downloadedTracks.remove(trackId)
|
|
118
|
+
saveToDisk()
|
|
119
|
+
return null
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return recordToDownloadedTrack(record)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
fun getAllDownloadedTracks(): List<DownloadedTrack> {
|
|
127
|
+
synchronized(this) {
|
|
128
|
+
val validTracks = mutableListOf<DownloadedTrack>()
|
|
129
|
+
val invalidTrackIds = mutableListOf<String>()
|
|
130
|
+
|
|
131
|
+
for ((trackId, record) in downloadedTracks) {
|
|
132
|
+
if (File(record.localPath).exists()) {
|
|
133
|
+
validTracks.add(recordToDownloadedTrack(record))
|
|
134
|
+
} else {
|
|
135
|
+
invalidTrackIds.add(trackId)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Clean up invalid records
|
|
140
|
+
if (invalidTrackIds.isNotEmpty()) {
|
|
141
|
+
invalidTrackIds.forEach { downloadedTracks.remove(it) }
|
|
142
|
+
saveToDisk()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return validTracks
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
fun getDownloadedPlaylist(playlistId: String): DownloadedPlaylist? {
|
|
150
|
+
synchronized(this) {
|
|
151
|
+
val trackIds = playlistTracks[playlistId] ?: return null
|
|
152
|
+
if (trackIds.isEmpty()) return null
|
|
153
|
+
|
|
154
|
+
val playlist = PlaylistManager.getInstance(context).getPlaylist(playlistId) ?: return null
|
|
155
|
+
|
|
156
|
+
val downloadedTracksList = mutableListOf<DownloadedTrack>()
|
|
157
|
+
var totalSize = 0.0
|
|
158
|
+
|
|
159
|
+
for (trackId in trackIds) {
|
|
160
|
+
getDownloadedTrack(trackId)?.let { track ->
|
|
161
|
+
downloadedTracksList.add(track)
|
|
162
|
+
totalSize += track.fileSize
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (downloadedTracksList.isEmpty()) return null
|
|
167
|
+
|
|
168
|
+
val isComplete = downloadedTracksList.size == playlist.tracks.size
|
|
169
|
+
|
|
170
|
+
return DownloadedPlaylist(
|
|
171
|
+
playlistId = playlistId,
|
|
172
|
+
originalPlaylist = convertPlaylistManagerToNitro(playlist),
|
|
173
|
+
downloadedTracks = downloadedTracksList.toTypedArray(),
|
|
174
|
+
totalSize = totalSize,
|
|
175
|
+
downloadedAt = downloadedTracksList.minOfOrNull { it.downloadedAt } ?: System.currentTimeMillis().toDouble(),
|
|
176
|
+
isComplete = isComplete,
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
fun getAllDownloadedPlaylists(): List<DownloadedPlaylist> {
|
|
182
|
+
synchronized(this) {
|
|
183
|
+
return playlistTracks.keys.mapNotNull { playlistId ->
|
|
184
|
+
getDownloadedPlaylist(playlistId)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Delete Operations
|
|
190
|
+
fun deleteDownloadedTrack(trackId: String) {
|
|
191
|
+
synchronized(this) {
|
|
192
|
+
downloadedTracks[trackId]?.let { record ->
|
|
193
|
+
// Delete the file
|
|
194
|
+
fileManager.deleteFile(record.localPath)
|
|
195
|
+
|
|
196
|
+
// Delete artwork if exists
|
|
197
|
+
record.localArtworkPath?.let { artworkPath ->
|
|
198
|
+
fileManager.deleteFile(artworkPath)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Remove from records
|
|
203
|
+
downloadedTracks.remove(trackId)
|
|
204
|
+
|
|
205
|
+
// Remove from all playlist associations
|
|
206
|
+
playlistTracks.forEach { (playlistId, trackIds) ->
|
|
207
|
+
trackIds.remove(trackId)
|
|
208
|
+
if (trackIds.isEmpty()) {
|
|
209
|
+
playlistTracks.remove(playlistId)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
saveToDisk()
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
fun deleteDownloadedPlaylist(playlistId: String) {
|
|
218
|
+
synchronized(this) {
|
|
219
|
+
val trackIds = playlistTracks[playlistId]?.toList() ?: return
|
|
220
|
+
|
|
221
|
+
// Delete all tracks in the playlist
|
|
222
|
+
for (trackId in trackIds) {
|
|
223
|
+
downloadedTracks[trackId]?.let { record ->
|
|
224
|
+
fileManager.deleteFile(record.localPath)
|
|
225
|
+
record.localArtworkPath?.let { fileManager.deleteFile(it) }
|
|
226
|
+
}
|
|
227
|
+
downloadedTracks.remove(trackId)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Remove playlist association
|
|
231
|
+
playlistTracks.remove(playlistId)
|
|
232
|
+
|
|
233
|
+
saveToDisk()
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
fun deleteAllDownloads() {
|
|
238
|
+
synchronized(this) {
|
|
239
|
+
// Delete all files
|
|
240
|
+
for (record in downloadedTracks.values) {
|
|
241
|
+
fileManager.deleteFile(record.localPath)
|
|
242
|
+
record.localArtworkPath?.let { fileManager.deleteFile(it) }
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Clear all records
|
|
246
|
+
downloadedTracks.clear()
|
|
247
|
+
playlistTracks.clear()
|
|
248
|
+
|
|
249
|
+
saveToDisk()
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** Validates all downloads and removes records for missing files */
|
|
254
|
+
fun syncDownloads(): Int {
|
|
255
|
+
synchronized(this) {
|
|
256
|
+
Log.d(TAG, "syncDownloads called")
|
|
257
|
+
|
|
258
|
+
val trackIdsToRemove = mutableListOf<String>()
|
|
259
|
+
|
|
260
|
+
for ((trackId, record) in downloadedTracks) {
|
|
261
|
+
if (!File(record.localPath).exists()) {
|
|
262
|
+
Log.d(TAG, "Missing file for track $trackId: ${record.localPath}")
|
|
263
|
+
trackIdsToRemove.add(trackId)
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Remove invalid records
|
|
268
|
+
for (trackId in trackIdsToRemove) {
|
|
269
|
+
downloadedTracks.remove(trackId)
|
|
270
|
+
|
|
271
|
+
// Also remove from playlist associations
|
|
272
|
+
val playlistsToClean = mutableListOf<String>()
|
|
273
|
+
for ((playlistId, trackIds) in playlistTracks) {
|
|
274
|
+
if (trackIds.remove(trackId)) {
|
|
275
|
+
if (trackIds.isEmpty()) {
|
|
276
|
+
playlistsToClean.add(playlistId)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
playlistsToClean.forEach { playlistTracks.remove(it) }
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (trackIdsToRemove.isNotEmpty()) {
|
|
284
|
+
saveToDisk()
|
|
285
|
+
Log.d(TAG, "Cleaned up ${trackIdsToRemove.size} orphaned records")
|
|
286
|
+
} else {
|
|
287
|
+
Log.d(TAG, "All downloads are valid")
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return trackIdsToRemove.size
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Persistence
|
|
295
|
+
private fun saveToDisk() {
|
|
296
|
+
try {
|
|
297
|
+
// Save downloaded tracks
|
|
298
|
+
val tracksJson = JSONObject()
|
|
299
|
+
for ((trackId, record) in downloadedTracks) {
|
|
300
|
+
tracksJson.put(trackId, record.toJson())
|
|
301
|
+
}
|
|
302
|
+
prefs.edit().putString(KEY_DOWNLOADED_TRACKS, tracksJson.toString()).apply()
|
|
303
|
+
|
|
304
|
+
// Save playlist associations
|
|
305
|
+
val playlistJson = JSONObject()
|
|
306
|
+
for ((playlistId, trackIds) in playlistTracks) {
|
|
307
|
+
playlistJson.put(playlistId, JSONArray(trackIds.toList()))
|
|
308
|
+
}
|
|
309
|
+
prefs.edit().putString(KEY_PLAYLIST_TRACKS, playlistJson.toString()).apply()
|
|
310
|
+
} catch (e: Exception) {
|
|
311
|
+
e.printStackTrace()
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
private fun loadFromDisk() {
|
|
316
|
+
try {
|
|
317
|
+
// Load downloaded tracks
|
|
318
|
+
val tracksString = prefs.getString(KEY_DOWNLOADED_TRACKS, null)
|
|
319
|
+
if (tracksString != null) {
|
|
320
|
+
val tracksJson = JSONObject(tracksString)
|
|
321
|
+
for (trackId in tracksJson.keys()) {
|
|
322
|
+
val record = DownloadedTrackRecord.fromJson(tracksJson.getJSONObject(trackId))
|
|
323
|
+
downloadedTracks[trackId] = record
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Load playlist associations
|
|
328
|
+
val playlistString = prefs.getString(KEY_PLAYLIST_TRACKS, null)
|
|
329
|
+
if (playlistString != null) {
|
|
330
|
+
val playlistJson = JSONObject(playlistString)
|
|
331
|
+
for (playlistId in playlistJson.keys()) {
|
|
332
|
+
val trackIdsArray = playlistJson.getJSONArray(playlistId)
|
|
333
|
+
val trackIds = mutableSetOf<String>()
|
|
334
|
+
for (i in 0 until trackIdsArray.length()) {
|
|
335
|
+
trackIds.add(trackIdsArray.getString(i))
|
|
336
|
+
}
|
|
337
|
+
playlistTracks[playlistId] = trackIds
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
} catch (e: Exception) {
|
|
341
|
+
e.printStackTrace()
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Conversion Helpers
|
|
346
|
+
private fun trackItemToRecord(track: TrackItem): TrackItemRecord =
|
|
347
|
+
TrackItemRecord(
|
|
348
|
+
id = track.id,
|
|
349
|
+
title = track.title,
|
|
350
|
+
artist = track.artist,
|
|
351
|
+
album = track.album,
|
|
352
|
+
duration = track.duration,
|
|
353
|
+
url = track.url,
|
|
354
|
+
artwork = track.artwork?.asSecondOrNull(),
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
private fun recordToTrackItem(record: TrackItemRecord): TrackItem {
|
|
358
|
+
val artworkVariant =
|
|
359
|
+
if (record.artwork != null) {
|
|
360
|
+
Variant_NullType_String.create(record.artwork)
|
|
361
|
+
} else {
|
|
362
|
+
null
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return TrackItem(
|
|
366
|
+
id = record.id,
|
|
367
|
+
title = record.title,
|
|
368
|
+
artist = record.artist,
|
|
369
|
+
album = record.album,
|
|
370
|
+
duration = record.duration,
|
|
371
|
+
url = record.url,
|
|
372
|
+
artwork = artworkVariant,
|
|
373
|
+
extraPayload = null,
|
|
374
|
+
)
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
private fun recordToDownloadedTrack(record: DownloadedTrackRecord): DownloadedTrack {
|
|
378
|
+
val localArtworkVariant =
|
|
379
|
+
if (record.localArtworkPath != null) {
|
|
380
|
+
Variant_NullType_String.create(record.localArtworkPath)
|
|
381
|
+
} else {
|
|
382
|
+
null
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return DownloadedTrack(
|
|
386
|
+
trackId = record.trackId,
|
|
387
|
+
originalTrack = recordToTrackItem(record.originalTrack),
|
|
388
|
+
localPath = record.localPath,
|
|
389
|
+
localArtworkPath = localArtworkVariant,
|
|
390
|
+
downloadedAt = record.downloadedAt,
|
|
391
|
+
fileSize = record.fileSize,
|
|
392
|
+
storageLocation = StorageLocation.valueOf(record.storageLocation),
|
|
393
|
+
)
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
private fun convertPlaylistManagerToNitro(playlist: com.margelo.nitro.nitroplayer.playlist.Playlist): Playlist {
|
|
397
|
+
// PlaylistManager already uses TrackItem from generated code with proper Variant types
|
|
398
|
+
return Playlist(
|
|
399
|
+
id = playlist.id,
|
|
400
|
+
name = playlist.name,
|
|
401
|
+
description = null, // PlaylistManager doesn't have description in Nitro Playlist
|
|
402
|
+
artwork = null, // PlaylistManager doesn't have artwork in Nitro Playlist
|
|
403
|
+
tracks = playlist.tracks.toTypedArray(),
|
|
404
|
+
)
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Internal record classes
|
|
409
|
+
internal data class DownloadedTrackRecord(
|
|
410
|
+
val trackId: String,
|
|
411
|
+
val originalTrack: TrackItemRecord,
|
|
412
|
+
val localPath: String,
|
|
413
|
+
val localArtworkPath: String?,
|
|
414
|
+
val downloadedAt: Double,
|
|
415
|
+
val fileSize: Double,
|
|
416
|
+
val storageLocation: String,
|
|
417
|
+
) {
|
|
418
|
+
fun toJson(): JSONObject =
|
|
419
|
+
JSONObject().apply {
|
|
420
|
+
put("trackId", trackId)
|
|
421
|
+
put("originalTrack", originalTrack.toJson())
|
|
422
|
+
put("localPath", localPath)
|
|
423
|
+
put("localArtworkPath", localArtworkPath)
|
|
424
|
+
put("downloadedAt", downloadedAt)
|
|
425
|
+
put("fileSize", fileSize)
|
|
426
|
+
put("storageLocation", storageLocation)
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
companion object {
|
|
430
|
+
fun fromJson(json: JSONObject): DownloadedTrackRecord =
|
|
431
|
+
DownloadedTrackRecord(
|
|
432
|
+
trackId = json.getString("trackId"),
|
|
433
|
+
originalTrack = TrackItemRecord.fromJson(json.getJSONObject("originalTrack")),
|
|
434
|
+
localPath = json.getString("localPath"),
|
|
435
|
+
localArtworkPath = json.optString("localArtworkPath", null),
|
|
436
|
+
downloadedAt = json.getDouble("downloadedAt"),
|
|
437
|
+
fileSize = json.getDouble("fileSize"),
|
|
438
|
+
storageLocation = json.getString("storageLocation"),
|
|
439
|
+
)
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
internal data class TrackItemRecord(
|
|
444
|
+
val id: String,
|
|
445
|
+
val title: String,
|
|
446
|
+
val artist: String,
|
|
447
|
+
val album: String,
|
|
448
|
+
val duration: Double,
|
|
449
|
+
val url: String,
|
|
450
|
+
val artwork: String?,
|
|
451
|
+
) {
|
|
452
|
+
fun toJson(): JSONObject =
|
|
453
|
+
JSONObject().apply {
|
|
454
|
+
put("id", id)
|
|
455
|
+
put("title", title)
|
|
456
|
+
put("artist", artist)
|
|
457
|
+
put("album", album)
|
|
458
|
+
put("duration", duration)
|
|
459
|
+
put("url", url)
|
|
460
|
+
put("artwork", artwork)
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
companion object {
|
|
464
|
+
fun fromJson(json: JSONObject): TrackItemRecord =
|
|
465
|
+
TrackItemRecord(
|
|
466
|
+
id = json.getString("id"),
|
|
467
|
+
title = json.getString("title"),
|
|
468
|
+
artist = json.getString("artist"),
|
|
469
|
+
album = json.getString("album"),
|
|
470
|
+
duration = json.getDouble("duration"),
|
|
471
|
+
url = json.getString("url"),
|
|
472
|
+
artwork = json.optString("artwork", null),
|
|
473
|
+
)
|
|
474
|
+
}
|
|
475
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
package com.margelo.nitro.nitroplayer.download
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.os.Environment
|
|
5
|
+
import android.os.StatFs
|
|
6
|
+
import com.margelo.nitro.nitroplayer.DownloadStorageInfo
|
|
7
|
+
import com.margelo.nitro.nitroplayer.StorageLocation
|
|
8
|
+
import java.io.File
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Manages file operations for downloaded tracks
|
|
12
|
+
*/
|
|
13
|
+
class DownloadFileManager private constructor(
|
|
14
|
+
private val context: Context,
|
|
15
|
+
) {
|
|
16
|
+
companion object {
|
|
17
|
+
private const val PRIVATE_DOWNLOADS_FOLDER = "NitroPlayerDownloads"
|
|
18
|
+
private const val PUBLIC_DOWNLOADS_FOLDER = "NitroPlayerMusic"
|
|
19
|
+
|
|
20
|
+
@Volatile
|
|
21
|
+
private var instance: DownloadFileManager? = null
|
|
22
|
+
|
|
23
|
+
fun getInstance(context: Context): DownloadFileManager =
|
|
24
|
+
instance ?: synchronized(this) {
|
|
25
|
+
instance ?: DownloadFileManager(context.applicationContext).also { instance = it }
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private val privateDownloadsDir: File by lazy {
|
|
30
|
+
File(context.filesDir, PRIVATE_DOWNLOADS_FOLDER).apply {
|
|
31
|
+
if (!exists()) mkdirs()
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private val publicDownloadsDir: File by lazy {
|
|
36
|
+
val publicDir =
|
|
37
|
+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
|
|
38
|
+
// On Android 10+, use app-specific external storage
|
|
39
|
+
File(context.getExternalFilesDir(Environment.DIRECTORY_MUSIC), PUBLIC_DOWNLOADS_FOLDER)
|
|
40
|
+
} else {
|
|
41
|
+
// On older versions, use public Downloads directory
|
|
42
|
+
@Suppress("DEPRECATION")
|
|
43
|
+
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC), PUBLIC_DOWNLOADS_FOLDER)
|
|
44
|
+
}
|
|
45
|
+
publicDir.apply {
|
|
46
|
+
if (!exists()) mkdirs()
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
fun createDownloadFile(
|
|
51
|
+
trackId: String,
|
|
52
|
+
storageLocation: StorageLocation,
|
|
53
|
+
): File {
|
|
54
|
+
val destinationDir =
|
|
55
|
+
when (storageLocation) {
|
|
56
|
+
StorageLocation.PRIVATE -> privateDownloadsDir
|
|
57
|
+
StorageLocation.PUBLIC -> publicDownloadsDir
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Create unique filename based on trackId
|
|
61
|
+
val fileName = "$trackId.mp3"
|
|
62
|
+
return File(destinationDir, fileName)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
fun deleteFile(path: String) {
|
|
66
|
+
try {
|
|
67
|
+
val file = File(path)
|
|
68
|
+
if (file.exists()) {
|
|
69
|
+
file.delete()
|
|
70
|
+
}
|
|
71
|
+
} catch (e: Exception) {
|
|
72
|
+
e.printStackTrace()
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fun getFileSize(path: String): Long =
|
|
77
|
+
try {
|
|
78
|
+
File(path).length()
|
|
79
|
+
} catch (e: Exception) {
|
|
80
|
+
0L
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
fun getStorageInfo(): DownloadStorageInfo {
|
|
84
|
+
var totalDownloadedSize = 0L
|
|
85
|
+
var trackCount = 0
|
|
86
|
+
|
|
87
|
+
// Count files in private directory
|
|
88
|
+
privateDownloadsDir.listFiles()?.forEach { file ->
|
|
89
|
+
if (file.isFile) {
|
|
90
|
+
totalDownloadedSize += file.length()
|
|
91
|
+
trackCount++
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Count files in public directory
|
|
96
|
+
publicDownloadsDir.listFiles()?.forEach { file ->
|
|
97
|
+
if (file.isFile) {
|
|
98
|
+
totalDownloadedSize += file.length()
|
|
99
|
+
trackCount++
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Get device storage info
|
|
104
|
+
val stat = StatFs(context.filesDir.path)
|
|
105
|
+
val availableSpace = stat.availableBytes
|
|
106
|
+
val totalSpace = stat.totalBytes
|
|
107
|
+
|
|
108
|
+
// Get playlist count from database
|
|
109
|
+
val playlistCount = DownloadDatabase.getInstance(context).getAllDownloadedPlaylists().size
|
|
110
|
+
|
|
111
|
+
return DownloadStorageInfo(
|
|
112
|
+
totalDownloadedSize = totalDownloadedSize.toDouble(),
|
|
113
|
+
trackCount = trackCount.toDouble(),
|
|
114
|
+
playlistCount = playlistCount.toDouble(),
|
|
115
|
+
availableSpace = availableSpace.toDouble(),
|
|
116
|
+
totalSpace = totalSpace.toDouble(),
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
fun getLocalPath(trackId: String): String? {
|
|
121
|
+
// Check private directory first
|
|
122
|
+
val privateFile = File(privateDownloadsDir, "$trackId.mp3")
|
|
123
|
+
if (privateFile.exists()) {
|
|
124
|
+
return privateFile.absolutePath
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Check public directory
|
|
128
|
+
val publicFile = File(publicDownloadsDir, "$trackId.mp3")
|
|
129
|
+
if (publicFile.exists()) {
|
|
130
|
+
return publicFile.absolutePath
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return null
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
fun cleanupOrphanedFiles(validTrackIds: Set<String>): Long {
|
|
137
|
+
var bytesFreed = 0L
|
|
138
|
+
|
|
139
|
+
// Clean private directory
|
|
140
|
+
privateDownloadsDir.listFiles()?.forEach { file ->
|
|
141
|
+
val trackId = file.nameWithoutExtension
|
|
142
|
+
if (trackId !in validTrackIds) {
|
|
143
|
+
bytesFreed += file.length()
|
|
144
|
+
file.delete()
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Clean public directory
|
|
149
|
+
publicDownloadsDir.listFiles()?.forEach { file ->
|
|
150
|
+
val trackId = file.nameWithoutExtension
|
|
151
|
+
if (trackId !in validTrackIds) {
|
|
152
|
+
bytesFreed += file.length()
|
|
153
|
+
file.delete()
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return bytesFreed
|
|
158
|
+
}
|
|
159
|
+
}
|