react-native-nitro-player 0.7.0 → 0.7.1-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.
Files changed (107) hide show
  1. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridAndroidAutoMediaLibrary.kt +9 -13
  2. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridAudioDevices.kt +45 -90
  3. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridDownloadManager.kt +48 -182
  4. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridEqualizer.kt +21 -77
  5. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridPlayerQueue.kt +55 -104
  6. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridTrackPlayer.kt +113 -123
  7. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/ExoPlayerCore.kt +82 -0
  8. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/ListenerRegistry.kt +48 -0
  9. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerAndroidAuto.kt +62 -0
  10. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerCore.kt +153 -1887
  11. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerListener.kt +122 -0
  12. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerNotify.kt +44 -0
  13. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerPlayback.kt +162 -0
  14. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerQueue.kt +165 -0
  15. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerQueueBuild.kt +161 -0
  16. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerSetup.kt +28 -0
  17. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerTempQueue.kt +121 -0
  18. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerUrlLoader.kt +98 -0
  19. package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadDatabase.kt +27 -18
  20. package/android/src/main/java/com/margelo/nitro/nitroplayer/equalizer/EqualizerCore.kt +11 -58
  21. package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaSessionManager.kt +13 -30
  22. package/android/src/main/java/com/margelo/nitro/nitroplayer/playlist/PlaylistManager.kt +102 -162
  23. package/ios/HybridDownloadManager.swift +32 -26
  24. package/ios/HybridEqualizer.swift +48 -35
  25. package/ios/HybridTrackPlayer.swift +127 -102
  26. package/ios/core/ListenerRegistry.swift +60 -0
  27. package/ios/core/TrackPlayerCore.swift +130 -2356
  28. package/ios/core/TrackPlayerListener.swift +395 -0
  29. package/ios/core/TrackPlayerNotify.swift +52 -0
  30. package/ios/core/TrackPlayerPlayback.swift +274 -0
  31. package/ios/core/TrackPlayerQueue.swift +212 -0
  32. package/ios/core/TrackPlayerQueueBuild.swift +482 -0
  33. package/ios/core/TrackPlayerTempQueue.swift +167 -0
  34. package/ios/core/TrackPlayerUrlLoader.swift +169 -0
  35. package/ios/equalizer/EqualizerCore.swift +24 -89
  36. package/ios/media/MediaSessionManager.swift +32 -49
  37. package/ios/playlist/PlaylistManager.swift +2 -9
  38. package/ios/queue/HybridPlayerQueue.swift +69 -66
  39. package/lib/hooks/useDownloadedTracks.js +16 -13
  40. package/lib/hooks/useEqualizer.d.ts +4 -4
  41. package/lib/hooks/useEqualizer.js +12 -12
  42. package/lib/hooks/useEqualizerPresets.d.ts +3 -3
  43. package/lib/hooks/useEqualizerPresets.js +12 -18
  44. package/lib/specs/AndroidAutoMediaLibrary.nitro.d.ts +2 -2
  45. package/lib/specs/AudioDevices.nitro.d.ts +2 -2
  46. package/lib/specs/DownloadManager.nitro.d.ts +10 -10
  47. package/lib/specs/Equalizer.nitro.d.ts +9 -9
  48. package/lib/specs/TrackPlayer.nitro.d.ts +38 -16
  49. package/nitrogen/generated/android/NitroPlayerOnLoad.cpp +2 -0
  50. package/nitrogen/generated/android/c++/JFunc_void_std__vector_TrackItem__std__vector_TrackItem_.hpp +122 -0
  51. package/nitrogen/generated/android/c++/JHybridAndroidAutoMediaLibrarySpec.cpp +31 -6
  52. package/nitrogen/generated/android/c++/JHybridAndroidAutoMediaLibrarySpec.hpp +2 -2
  53. package/nitrogen/generated/android/c++/JHybridAudioDevicesSpec.cpp +16 -3
  54. package/nitrogen/generated/android/c++/JHybridAudioDevicesSpec.hpp +1 -1
  55. package/nitrogen/generated/android/c++/JHybridDownloadManagerSpec.cpp +154 -44
  56. package/nitrogen/generated/android/c++/JHybridDownloadManagerSpec.hpp +10 -10
  57. package/nitrogen/generated/android/c++/JHybridEqualizerSpec.cpp +130 -34
  58. package/nitrogen/generated/android/c++/JHybridEqualizerSpec.hpp +9 -9
  59. package/nitrogen/generated/android/c++/JHybridPlayerQueueSpec.cpp +115 -24
  60. package/nitrogen/generated/android/c++/JHybridPlayerQueueSpec.hpp +8 -8
  61. package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.cpp +243 -24
  62. package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.hpp +16 -8
  63. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__vector_TrackItem__std__vector_TrackItem_.kt +80 -0
  64. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridAndroidAutoMediaLibrarySpec.kt +3 -2
  65. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridAudioDevicesSpec.kt +2 -1
  66. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridDownloadManagerSpec.kt +10 -10
  67. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridEqualizerSpec.kt +10 -9
  68. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridPlayerQueueSpec.kt +9 -8
  69. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridTrackPlayerSpec.kt +45 -8
  70. package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.cpp +74 -18
  71. package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.hpp +380 -151
  72. package/nitrogen/generated/ios/c++/HybridDownloadManagerSpecSwift.hpp +10 -10
  73. package/nitrogen/generated/ios/c++/HybridEqualizerSpecSwift.hpp +12 -9
  74. package/nitrogen/generated/ios/c++/HybridPlayerQueueSpecSwift.hpp +23 -8
  75. package/nitrogen/generated/ios/c++/HybridTrackPlayerSpecSwift.hpp +82 -8
  76. package/nitrogen/generated/ios/swift/Func_void_EqualizerState.swift +46 -0
  77. package/nitrogen/generated/ios/swift/Func_void_std__variant_nitro__NullType__DownloadedPlaylist_.swift +58 -0
  78. package/nitrogen/generated/ios/swift/Func_void_std__variant_nitro__NullType__DownloadedTrack_.swift +58 -0
  79. package/nitrogen/generated/ios/swift/Func_void_std__variant_nitro__NullType__std__string_.swift +58 -0
  80. package/nitrogen/generated/ios/swift/Func_void_std__vector_DownloadedPlaylist_.swift +46 -0
  81. package/nitrogen/generated/ios/swift/Func_void_std__vector_DownloadedTrack_.swift +46 -0
  82. package/nitrogen/generated/ios/swift/Func_void_std__vector_EqualizerBand_.swift +5 -5
  83. package/nitrogen/generated/ios/swift/Func_void_std__vector_TrackItem__std__vector_TrackItem_.swift +46 -0
  84. package/nitrogen/generated/ios/swift/HybridDownloadManagerSpec.swift +10 -10
  85. package/nitrogen/generated/ios/swift/HybridDownloadManagerSpec_cxx.swift +141 -71
  86. package/nitrogen/generated/ios/swift/HybridEqualizerSpec.swift +9 -9
  87. package/nitrogen/generated/ios/swift/HybridEqualizerSpec_cxx.swift +105 -41
  88. package/nitrogen/generated/ios/swift/HybridPlayerQueueSpec.swift +8 -8
  89. package/nitrogen/generated/ios/swift/HybridPlayerQueueSpec_cxx.swift +95 -32
  90. package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec.swift +16 -8
  91. package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec_cxx.swift +267 -32
  92. package/nitrogen/generated/shared/c++/HybridAndroidAutoMediaLibrarySpec.hpp +3 -2
  93. package/nitrogen/generated/shared/c++/HybridAudioDevicesSpec.hpp +2 -1
  94. package/nitrogen/generated/shared/c++/HybridDownloadManagerSpec.hpp +10 -10
  95. package/nitrogen/generated/shared/c++/HybridEqualizerSpec.hpp +10 -9
  96. package/nitrogen/generated/shared/c++/HybridPlayerQueueSpec.hpp +9 -8
  97. package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.cpp +8 -0
  98. package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.hpp +16 -8
  99. package/package.json +1 -1
  100. package/src/hooks/useDownloadedTracks.ts +17 -13
  101. package/src/hooks/useEqualizer.ts +16 -16
  102. package/src/hooks/useEqualizerPresets.ts +15 -21
  103. package/src/specs/AndroidAutoMediaLibrary.nitro.ts +2 -2
  104. package/src/specs/AudioDevices.nitro.ts +2 -2
  105. package/src/specs/DownloadManager.nitro.ts +10 -10
  106. package/src/specs/Equalizer.nitro.ts +9 -9
  107. package/src/specs/TrackPlayer.nitro.ts +52 -16
@@ -5,13 +5,19 @@ import com.margelo.nitro.core.AnyMap
5
5
  import com.margelo.nitro.nitroplayer.QueueOperation
6
6
  import com.margelo.nitro.nitroplayer.TrackItem
7
7
  import com.margelo.nitro.nitroplayer.Variant_NullType_String
8
- import com.margelo.nitro.nitroplayer.core.TrackPlayerCore
9
8
  import com.margelo.nitro.nitroplayer.media.NitroPlayerMediaBrowserService
10
9
  import com.margelo.nitro.nitroplayer.storage.NitroPlayerStorage
11
10
  import org.json.JSONArray
12
11
  import org.json.JSONObject
13
12
  import java.util.UUID
13
+ import java.util.concurrent.ConcurrentHashMap
14
14
  import java.util.concurrent.CopyOnWriteArrayList
15
+ import kotlinx.coroutines.CoroutineScope
16
+ import kotlinx.coroutines.Dispatchers
17
+ import kotlinx.coroutines.Job
18
+ import kotlinx.coroutines.SupervisorJob
19
+ import kotlinx.coroutines.delay
20
+ import kotlinx.coroutines.launch
15
21
 
16
22
  /**
17
23
  * Manages multiple playlists using ExoPlayer's native playlist functionality
@@ -20,17 +26,20 @@ import java.util.concurrent.CopyOnWriteArrayList
20
26
  class PlaylistManager private constructor(
21
27
  private val context: Context,
22
28
  ) {
23
- private val playlists: MutableMap<String, Playlist> = mutableMapOf()
29
+ private val playlists = ConcurrentHashMap<String, Playlist>()
24
30
  private val listeners = CopyOnWriteArrayList<(List<Playlist>, QueueOperation?) -> Unit>()
25
31
  private val playlistListeners = mutableMapOf<String, CopyOnWriteArrayList<(Playlist, QueueOperation?) -> Unit>>()
26
32
  private var currentPlaylistId: String? = null
27
33
 
28
- private val saveHandler = android.os.Handler(android.os.Looper.getMainLooper())
29
- private val saveRunnable = Runnable { saveToFile() }
34
+ private val saveScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
35
+ private var saveJob: Job? = null
30
36
 
31
37
  private fun scheduleSave() {
32
- saveHandler.removeCallbacks(saveRunnable)
33
- saveHandler.postDelayed(saveRunnable, 300)
38
+ saveJob?.cancel()
39
+ saveJob = saveScope.launch {
40
+ delay(300)
41
+ saveToFile()
42
+ }
34
43
  }
35
44
 
36
45
  companion object {
@@ -63,9 +72,7 @@ class PlaylistManager private constructor(
63
72
  val id = UUID.randomUUID().toString()
64
73
  val playlist = Playlist(id, name, description, artwork)
65
74
 
66
- synchronized(playlists) {
67
- playlists[id] = playlist
68
- }
75
+ playlists[id] = playlist
69
76
 
70
77
  // Only cache for Android Auto if connected
71
78
  if (NitroPlayerMediaBrowserService.isAndroidAutoConnected) {
@@ -81,10 +88,7 @@ class PlaylistManager private constructor(
81
88
  * Delete a playlist
82
89
  */
83
90
  fun deletePlaylist(playlistId: String): Boolean {
84
- val removed =
85
- synchronized(playlists) {
86
- playlists.remove(playlistId)
87
- }
91
+ val removed = playlists.remove(playlistId)
88
92
 
89
93
  if (removed != null) {
90
94
  if (currentPlaylistId == playlistId) {
@@ -112,15 +116,13 @@ class PlaylistManager private constructor(
112
116
  description: String? = null,
113
117
  artwork: String? = null,
114
118
  ): Boolean {
115
- synchronized(playlists) {
116
- val playlist = playlists[playlistId] ?: return false
117
- playlists[playlistId] =
118
- playlist.copy(
119
- name = name ?: playlist.name,
120
- description = description ?: playlist.description,
121
- artwork = artwork ?: playlist.artwork,
122
- )
123
- }
119
+ val playlist = playlists[playlistId] ?: return false
120
+ playlists[playlistId] =
121
+ playlist.copy(
122
+ name = name ?: playlist.name,
123
+ description = description ?: playlist.description,
124
+ artwork = artwork ?: playlist.artwork,
125
+ )
124
126
 
125
127
  // Only cache for Android Auto if connected
126
128
  if (NitroPlayerMediaBrowserService.isAndroidAutoConnected) {
@@ -136,18 +138,12 @@ class PlaylistManager private constructor(
136
138
  /**
137
139
  * Get a playlist by ID
138
140
  */
139
- fun getPlaylist(playlistId: String): Playlist? =
140
- synchronized(playlists) {
141
- playlists[playlistId]
142
- }
141
+ fun getPlaylist(playlistId: String): Playlist? = playlists[playlistId]
143
142
 
144
143
  /**
145
144
  * Get all playlists
146
145
  */
147
- fun getAllPlaylists(): List<Playlist> =
148
- synchronized(playlists) {
149
- playlists.values.toList()
150
- }
146
+ fun getAllPlaylists(): List<Playlist> = playlists.values.toList()
151
147
 
152
148
  /**
153
149
  * Add a track to a playlist
@@ -157,16 +153,14 @@ class PlaylistManager private constructor(
157
153
  track: TrackItem,
158
154
  index: Int? = null,
159
155
  ): Boolean {
160
- synchronized(playlists) {
161
- val playlist = playlists[playlistId] ?: return false
162
- val tracks = playlist.tracks.toMutableList()
163
- if (index != null && index >= 0 && index <= tracks.size) {
164
- tracks.add(index, track)
165
- } else {
166
- tracks.add(track)
167
- }
168
- playlists[playlistId] = playlist.copy(tracks = tracks)
156
+ val playlist = playlists[playlistId] ?: return false
157
+ val tracks = playlist.tracks.toMutableList()
158
+ if (index != null && index >= 0 && index <= tracks.size) {
159
+ tracks.add(index, track)
160
+ } else {
161
+ tracks.add(track)
169
162
  }
163
+ playlists[playlistId] = playlist.copy(tracks = tracks)
170
164
 
171
165
  // Only cache for Android Auto if connected
172
166
  if (NitroPlayerMediaBrowserService.isAndroidAutoConnected) {
@@ -174,12 +168,6 @@ class PlaylistManager private constructor(
174
168
  }
175
169
  notifyPlaylistChanged(playlistId, QueueOperation.ADD)
176
170
  NitroPlayerMediaBrowserService.getInstance()?.onPlaylistUpdated(playlistId)
177
-
178
- // Update ExoPlayer if this is the current playlist
179
- if (currentPlaylistId == playlistId) {
180
- TrackPlayerCore.getInstance(context)?.updatePlaylist(playlistId)
181
- }
182
-
183
171
  return true
184
172
  }
185
173
 
@@ -191,16 +179,14 @@ class PlaylistManager private constructor(
191
179
  tracks: List<TrackItem>,
192
180
  index: Int? = null,
193
181
  ): Boolean {
194
- synchronized(playlists) {
195
- val playlist = playlists[playlistId] ?: return false
196
- val currentTracks = playlist.tracks.toMutableList()
197
- if (index != null && index >= 0 && index <= currentTracks.size) {
198
- currentTracks.addAll(index, tracks)
199
- } else {
200
- currentTracks.addAll(tracks)
201
- }
202
- playlists[playlistId] = playlist.copy(tracks = currentTracks)
182
+ val playlist = playlists[playlistId] ?: return false
183
+ val currentTracks = playlist.tracks.toMutableList()
184
+ if (index != null && index >= 0 && index <= currentTracks.size) {
185
+ currentTracks.addAll(index, tracks)
186
+ } else {
187
+ currentTracks.addAll(tracks)
203
188
  }
189
+ playlists[playlistId] = playlist.copy(tracks = currentTracks)
204
190
 
205
191
  // Only cache for Android Auto if connected
206
192
  if (NitroPlayerMediaBrowserService.isAndroidAutoConnected) {
@@ -208,12 +194,6 @@ class PlaylistManager private constructor(
208
194
  }
209
195
  notifyPlaylistChanged(playlistId, QueueOperation.ADD)
210
196
  NitroPlayerMediaBrowserService.getInstance()?.onPlaylistUpdated(playlistId)
211
-
212
- // Update ExoPlayer if this is the current playlist
213
- if (currentPlaylistId == playlistId) {
214
- TrackPlayerCore.getInstance(context)?.updatePlaylist(playlistId)
215
- }
216
-
217
197
  return true
218
198
  }
219
199
 
@@ -224,26 +204,17 @@ class PlaylistManager private constructor(
224
204
  playlistId: String,
225
205
  trackId: String,
226
206
  ): Boolean {
227
- val removed =
228
- synchronized(playlists) {
229
- val playlist = playlists[playlistId] ?: return false
230
- val tracks = playlist.tracks.toMutableList()
231
- val removed = tracks.removeAll { it.id == trackId }
232
- if (removed) {
233
- playlists[playlistId] = playlist.copy(tracks = tracks)
234
- }
235
- removed
236
- }
207
+ val playlist = playlists[playlistId] ?: return false
208
+ val tracks = playlist.tracks.toMutableList()
209
+ val removed = tracks.removeAll { it.id == trackId }
210
+ if (removed) {
211
+ playlists[playlistId] = playlist.copy(tracks = tracks)
212
+ }
237
213
 
238
214
  if (removed) {
239
215
  scheduleSave()
240
216
  notifyPlaylistChanged(playlistId, QueueOperation.REMOVE)
241
217
  NitroPlayerMediaBrowserService.getInstance()?.onPlaylistUpdated(playlistId)
242
-
243
- // Update ExoPlayer if this is the current playlist
244
- if (currentPlaylistId == playlistId) {
245
- TrackPlayerCore.getInstance(context)?.updatePlaylist(playlistId)
246
- }
247
218
  }
248
219
 
249
220
  return removed
@@ -257,27 +228,19 @@ class PlaylistManager private constructor(
257
228
  trackId: String,
258
229
  newIndex: Int,
259
230
  ): Boolean {
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
- }
267
- val track = tracks.removeAt(oldIndex)
268
- tracks.add(newIndex, track)
269
- playlists[playlistId] = playlist.copy(tracks = tracks)
231
+ val playlist = playlists[playlistId] ?: return false
232
+ val tracks = playlist.tracks.toMutableList()
233
+ val oldIndex = tracks.indexOfFirst { it.id == trackId }
234
+ if (oldIndex < 0 || newIndex < 0 || newIndex >= tracks.size) {
235
+ return false
270
236
  }
237
+ val track = tracks.removeAt(oldIndex)
238
+ tracks.add(newIndex, track)
239
+ playlists[playlistId] = playlist.copy(tracks = tracks)
271
240
 
272
241
  scheduleSave()
273
242
  notifyPlaylistChanged(playlistId, QueueOperation.UPDATE)
274
243
  NitroPlayerMediaBrowserService.getInstance()?.onPlaylistUpdated(playlistId)
275
-
276
- // Update ExoPlayer if this is the current playlist
277
- if (currentPlaylistId == playlistId) {
278
- TrackPlayerCore.getInstance(context)?.updatePlaylist(playlistId)
279
- }
280
-
281
244
  return true
282
245
  }
283
246
 
@@ -291,19 +254,17 @@ class PlaylistManager private constructor(
291
254
  val tracksMap = tracks.associateBy { it.id }
292
255
  val affectedPlaylists = mutableMapOf<String, Int>()
293
256
 
294
- synchronized(playlists) {
295
- playlists.forEach { (playlistId, playlist) ->
296
- var updateCount = 0
297
- val newTracks =
298
- playlist.tracks
299
- .map { track ->
300
- tracksMap[track.id]?.also { updateCount++ } ?: track
301
- }.toMutableList()
302
-
303
- if (updateCount > 0) {
304
- affectedPlaylists[playlistId] = updateCount
305
- playlists[playlistId] = playlist.copy(tracks = newTracks)
306
- }
257
+ playlists.forEach { (playlistId, playlist) ->
258
+ var updateCount = 0
259
+ val newTracks =
260
+ playlist.tracks
261
+ .map { track ->
262
+ tracksMap[track.id]?.also { updateCount++ } ?: track
263
+ }.toMutableList()
264
+
265
+ if (updateCount > 0) {
266
+ affectedPlaylists[playlistId] = updateCount
267
+ playlists[playlistId] = playlist.copy(tracks = newTracks)
307
268
  }
308
269
  }
309
270
 
@@ -327,12 +288,10 @@ class PlaylistManager private constructor(
327
288
  val trackIdSet = trackIds.toSet()
328
289
  val foundTracks = mutableMapOf<String, TrackItem>()
329
290
 
330
- synchronized(playlists) {
331
- playlists.values.forEach { playlist ->
332
- playlist.tracks.forEach { track ->
333
- if (trackIdSet.contains(track.id) && !foundTracks.containsKey(track.id)) {
334
- foundTracks[track.id] = track
335
- }
291
+ playlists.values.forEach { playlist ->
292
+ playlist.tracks.forEach { track ->
293
+ if (trackIdSet.contains(track.id) && !foundTracks.containsKey(track.id)) {
294
+ foundTracks[track.id] = track
336
295
  }
337
296
  }
338
297
  }
@@ -345,14 +304,8 @@ class PlaylistManager private constructor(
345
304
  * Load a playlist for playback (sets it as current)
346
305
  */
347
306
  fun loadPlaylist(playlistId: String): Boolean {
348
- val playlist =
349
- synchronized(playlists) {
350
- playlists[playlistId]
351
- } ?: return false
352
-
307
+ if (playlists[playlistId] == null) return false
353
308
  currentPlaylistId = playlistId
354
- TrackPlayerCore.getInstance(context)?.loadPlaylist(playlistId)
355
-
356
309
  return true
357
310
  }
358
311
 
@@ -364,7 +317,7 @@ class PlaylistManager private constructor(
364
317
  /**
365
318
  * Get the current playlist
366
319
  */
367
- fun getCurrentPlaylist(): Playlist? = currentPlaylistId?.let { synchronized(playlists) { playlists[it] } }
320
+ fun getCurrentPlaylist(): Playlist? = currentPlaylistId?.let { playlists[it] }
368
321
 
369
322
  /**
370
323
  * Add a listener for playlist changes
@@ -387,22 +340,14 @@ class PlaylistManager private constructor(
387
340
  }
388
341
 
389
342
  private fun notifyPlaylistsChanged(operation: QueueOperation?) {
390
- val allPlaylists =
391
- synchronized(playlists) {
392
- playlists.values.toList()
393
- }
394
- listeners.forEach { it(allPlaylists, operation) }
343
+ listeners.forEach { it(playlists.values.toList(), operation) }
395
344
  }
396
345
 
397
346
  private fun notifyPlaylistChanged(
398
347
  playlistId: String,
399
348
  operation: QueueOperation?,
400
349
  ) {
401
- val playlist =
402
- synchronized(playlists) {
403
- playlists[playlistId]
404
- } ?: return
405
-
350
+ val playlist = playlists[playlistId] ?: return
406
351
  playlistListeners[playlistId]?.forEach { it(playlist, operation) }
407
352
  }
408
353
 
@@ -411,37 +356,34 @@ class PlaylistManager private constructor(
411
356
  private fun saveToFile() {
412
357
  try {
413
358
  val jsonArray = JSONArray()
414
- synchronized(playlists) {
415
- playlists.values.forEach { playlist ->
416
- val jsonObject =
417
- JSONObject().apply {
418
- put("id", playlist.id)
419
- put("name", playlist.name)
420
- put("description", playlist.description ?: "")
421
- put("artwork", playlist.artwork ?: "")
422
- val tracksArray = JSONArray()
423
- playlist.tracks.forEach { track ->
424
- tracksArray.put(
425
- JSONObject().apply {
426
- put("id", track.id)
427
- put("title", track.title)
428
- put("artist", track.artist)
429
- put("album", track.album)
430
- put("duration", track.duration)
431
- put("url", track.url)
432
- track.artwork?.let { put("artwork", it) }
433
- track.extraPayload?.let { payload ->
434
- val extraPayloadMap = payload.toHashMap()
435
- val extraPayloadJson = JSONObject(extraPayloadMap)
436
- put("extraPayload", extraPayloadJson)
437
- }
438
- },
439
- )
440
- }
441
- put("tracks", tracksArray)
442
- }
443
- jsonArray.put(jsonObject)
359
+ playlists.values.forEach { playlist ->
360
+ val jsonObject = JSONObject().apply {
361
+ put("id", playlist.id)
362
+ put("name", playlist.name)
363
+ put("description", playlist.description ?: "")
364
+ put("artwork", playlist.artwork ?: "")
365
+ val tracksArray = JSONArray()
366
+ playlist.tracks.forEach { track ->
367
+ tracksArray.put(
368
+ JSONObject().apply {
369
+ put("id", track.id)
370
+ put("title", track.title)
371
+ put("artist", track.artist)
372
+ put("album", track.album)
373
+ put("duration", track.duration)
374
+ put("url", track.url)
375
+ track.artwork?.let { put("artwork", it) }
376
+ track.extraPayload?.let { payload ->
377
+ val extraPayloadMap = payload.toHashMap()
378
+ val extraPayloadJson = JSONObject(extraPayloadMap)
379
+ put("extraPayload", extraPayloadJson)
380
+ }
381
+ },
382
+ )
383
+ }
384
+ put("tracks", tracksArray)
444
385
  }
386
+ jsonArray.put(jsonObject)
445
387
  }
446
388
 
447
389
  val wrapper =
@@ -501,9 +443,8 @@ class PlaylistManager private constructor(
501
443
  }
502
444
 
503
445
  private fun parseAndLoadPlaylists(jsonArray: JSONArray) {
504
- synchronized(playlists) {
505
- playlists.clear()
506
- for (i in 0 until jsonArray.length()) {
446
+ playlists.clear()
447
+ for (i in 0 until jsonArray.length()) {
507
448
  val jsonObject = jsonArray.getJSONObject(i)
508
449
  val tracks = mutableListOf<TrackItem>()
509
450
  val tracksArray = jsonObject.getJSONArray("tracks")
@@ -557,7 +498,6 @@ class PlaylistManager private constructor(
557
498
  tracks = tracks,
558
499
  )
559
500
  playlists[playlist.id] = playlist
560
- }
561
501
  }
562
502
  }
563
503
  }
@@ -118,45 +118,51 @@ final class HybridDownloadManager: HybridDownloadManagerSpec {
118
118
 
119
119
  // MARK: - Downloaded Content Queries
120
120
 
121
- func isTrackDownloaded(trackId: String) throws -> Bool {
122
- return core.isTrackDownloaded(trackId: trackId)
121
+ func isTrackDownloaded(trackId: String) throws -> Promise<Bool> {
122
+ Promise.async { self.core.isTrackDownloaded(trackId: trackId) }
123
123
  }
124
124
 
125
- func isPlaylistDownloaded(playlistId: String) throws -> Bool {
126
- return core.isPlaylistDownloaded(playlistId: playlistId)
125
+ func isPlaylistDownloaded(playlistId: String) throws -> Promise<Bool> {
126
+ Promise.async { self.core.isPlaylistDownloaded(playlistId: playlistId) }
127
127
  }
128
128
 
129
- func isPlaylistPartiallyDownloaded(playlistId: String) throws -> Bool {
130
- return core.isPlaylistPartiallyDownloaded(playlistId: playlistId)
129
+ func isPlaylistPartiallyDownloaded(playlistId: String) throws -> Promise<Bool> {
130
+ Promise.async { self.core.isPlaylistPartiallyDownloaded(playlistId: playlistId) }
131
131
  }
132
132
 
133
- func getDownloadedTrack(trackId: String) throws -> Variant_NullType_DownloadedTrack {
134
- if let track = core.getDownloadedTrack(trackId: trackId) {
135
- return Variant_NullType_DownloadedTrack.second(track)
133
+ func getDownloadedTrack(trackId: String) throws -> Promise<Variant_NullType_DownloadedTrack> {
134
+ Promise.async {
135
+ if let track = self.core.getDownloadedTrack(trackId: trackId) {
136
+ return Variant_NullType_DownloadedTrack.second(track)
137
+ }
138
+ return Variant_NullType_DownloadedTrack.first(NullType.null)
136
139
  }
137
- return Variant_NullType_DownloadedTrack.first(NullType.null)
138
140
  }
139
141
 
140
- func getAllDownloadedTracks() throws -> [DownloadedTrack] {
141
- return core.getAllDownloadedTracks()
142
+ func getAllDownloadedTracks() throws -> Promise<[DownloadedTrack]> {
143
+ Promise.async { self.core.getAllDownloadedTracks() }
142
144
  }
143
145
 
144
- func getDownloadedPlaylist(playlistId: String) throws -> Variant_NullType_DownloadedPlaylist {
145
- if let playlist = core.getDownloadedPlaylist(playlistId: playlistId) {
146
- return Variant_NullType_DownloadedPlaylist.second(playlist)
146
+ func getDownloadedPlaylist(playlistId: String) throws -> Promise<Variant_NullType_DownloadedPlaylist> {
147
+ Promise.async {
148
+ if let playlist = self.core.getDownloadedPlaylist(playlistId: playlistId) {
149
+ return Variant_NullType_DownloadedPlaylist.second(playlist)
150
+ }
151
+ return Variant_NullType_DownloadedPlaylist.first(NullType.null)
147
152
  }
148
- return Variant_NullType_DownloadedPlaylist.first(NullType.null)
149
153
  }
150
154
 
151
- func getAllDownloadedPlaylists() throws -> [DownloadedPlaylist] {
152
- return core.getAllDownloadedPlaylists()
155
+ func getAllDownloadedPlaylists() throws -> Promise<[DownloadedPlaylist]> {
156
+ Promise.async { self.core.getAllDownloadedPlaylists() }
153
157
  }
154
158
 
155
- func getLocalPath(trackId: String) throws -> Variant_NullType_String {
156
- if let path = core.getLocalPath(trackId: trackId) {
157
- return Variant_NullType_String.second(path)
159
+ func getLocalPath(trackId: String) throws -> Promise<Variant_NullType_String> {
160
+ Promise.async {
161
+ if let path = self.core.getLocalPath(trackId: trackId) {
162
+ return Variant_NullType_String.second(path)
163
+ }
164
+ return Variant_NullType_String.first(NullType.null)
158
165
  }
159
- return Variant_NullType_String.first(NullType.null)
160
166
  }
161
167
 
162
168
  // MARK: - Deletion
@@ -187,8 +193,8 @@ final class HybridDownloadManager: HybridDownloadManagerSpec {
187
193
  }
188
194
  }
189
195
 
190
- func syncDownloads() throws -> Double {
191
- return Double(core.syncDownloads())
196
+ func syncDownloads() throws -> Promise<Double> {
197
+ Promise.async { Double(self.core.syncDownloads()) }
192
198
  }
193
199
 
194
200
  // MARK: - Playback Source Preference
@@ -201,8 +207,8 @@ final class HybridDownloadManager: HybridDownloadManagerSpec {
201
207
  return core.getPlaybackSourcePreference()
202
208
  }
203
209
 
204
- func getEffectiveUrl(track: TrackItem) throws -> String {
205
- return core.getEffectiveUrl(track: track)
210
+ func getEffectiveUrl(track: TrackItem) throws -> Promise<String> {
211
+ Promise.async { self.core.getEffectiveUrl(track: track) }
206
212
  }
207
213
 
208
214
  // MARK: - Event Callbacks