react-native-nitro-player 0.5.3 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridAudioDevices.kt +5 -3
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridTrackPlayer.kt +4 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/connection/AndroidAutoConnectionDetector.kt +14 -13
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/NitroPlayerLogger.kt +31 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerCore.kt +142 -95
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadDatabase.kt +7 -6
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadManagerCore.kt +2 -1
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadWorker.kt +1 -2
- package/android/src/main/java/com/margelo/nitro/nitroplayer/equalizer/EqualizerCore.kt +3 -2
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaBrowserService.kt +25 -24
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaLibraryManager.kt +3 -2
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaSessionManager.kt +20 -19
- package/android/src/main/java/com/margelo/nitro/nitroplayer/playlist/PlaylistManager.kt +16 -9
- package/ios/HybridAudioRoutePicker.swift +1 -1
- package/ios/HybridDownloadManager.swift +3 -3
- package/ios/HybridEqualizer.swift +3 -3
- package/ios/HybridTrackPlayer.swift +8 -4
- package/ios/core/NitroPlayerLogger.swift +22 -0
- package/ios/core/TrackPlayerCore.swift +195 -256
- package/ios/download/DownloadDatabase.swift +35 -39
- package/ios/download/DownloadFileManager.swift +17 -17
- package/ios/download/DownloadManagerCore.swift +29 -33
- package/ios/equalizer/EqualizerCore.swift +25 -20
- package/ios/playlist/PlaylistManager.swift +19 -9
- package/ios/queue/QueueManager.swift +1 -1
- package/lib/specs/TrackPlayer.nitro.d.ts +1 -0
- package/lib/types/PlayerQueue.d.ts +1 -1
- package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.cpp +5 -0
- package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.hpp +1 -0
- package/nitrogen/generated/android/c++/JReason.hpp +3 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridTrackPlayerSpec.kt +4 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Reason.kt +2 -1
- package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.hpp +12 -0
- package/nitrogen/generated/ios/c++/HybridTrackPlayerSpecSwift.hpp +8 -0
- package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec.swift +1 -0
- package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec_cxx.swift +12 -0
- package/nitrogen/generated/ios/swift/Reason.swift +4 -0
- package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.hpp +1 -0
- package/nitrogen/generated/shared/c++/Reason.hpp +4 -0
- package/package.json +1 -1
- package/src/specs/TrackPlayer.nitro.ts +1 -0
- package/src/types/PlayerQueue.ts +1 -1
|
@@ -5,6 +5,7 @@ import android.content.SharedPreferences
|
|
|
5
5
|
import android.util.Log
|
|
6
6
|
import com.margelo.nitro.core.NullType
|
|
7
7
|
import com.margelo.nitro.nitroplayer.*
|
|
8
|
+
import com.margelo.nitro.nitroplayer.core.NitroPlayerLogger
|
|
8
9
|
import com.margelo.nitro.nitroplayer.playlist.PlaylistManager
|
|
9
10
|
import org.json.JSONArray
|
|
10
11
|
import org.json.JSONObject
|
|
@@ -253,13 +254,13 @@ class DownloadDatabase private constructor(
|
|
|
253
254
|
/** Validates all downloads and removes records for missing files */
|
|
254
255
|
fun syncDownloads(): Int {
|
|
255
256
|
synchronized(this) {
|
|
256
|
-
|
|
257
|
+
NitroPlayerLogger.log("DownloadDatabase", "syncDownloads called")
|
|
257
258
|
|
|
258
259
|
val trackIdsToRemove = mutableListOf<String>()
|
|
259
260
|
|
|
260
261
|
for ((trackId, record) in downloadedTracks) {
|
|
261
262
|
if (!File(record.localPath).exists()) {
|
|
262
|
-
|
|
263
|
+
NitroPlayerLogger.log("DownloadDatabase", "Missing file for track $trackId: ${record.localPath}")
|
|
263
264
|
trackIdsToRemove.add(trackId)
|
|
264
265
|
}
|
|
265
266
|
}
|
|
@@ -282,9 +283,9 @@ class DownloadDatabase private constructor(
|
|
|
282
283
|
|
|
283
284
|
if (trackIdsToRemove.isNotEmpty()) {
|
|
284
285
|
saveToDisk()
|
|
285
|
-
|
|
286
|
+
NitroPlayerLogger.log("DownloadDatabase", "Cleaned up ${trackIdsToRemove.size} orphaned records")
|
|
286
287
|
} else {
|
|
287
|
-
|
|
288
|
+
NitroPlayerLogger.log("DownloadDatabase", "All downloads are valid")
|
|
288
289
|
}
|
|
289
290
|
|
|
290
291
|
return trackIdsToRemove.size
|
|
@@ -432,7 +433,7 @@ internal data class DownloadedTrackRecord(
|
|
|
432
433
|
trackId = json.getString("trackId"),
|
|
433
434
|
originalTrack = TrackItemRecord.fromJson(json.getJSONObject("originalTrack")),
|
|
434
435
|
localPath = json.getString("localPath"),
|
|
435
|
-
localArtworkPath = json.
|
|
436
|
+
localArtworkPath = if (json.isNull("localArtworkPath")) null else json.getString("localArtworkPath"),
|
|
436
437
|
downloadedAt = json.getDouble("downloadedAt"),
|
|
437
438
|
fileSize = json.getDouble("fileSize"),
|
|
438
439
|
storageLocation = json.getString("storageLocation"),
|
|
@@ -469,7 +470,7 @@ internal data class TrackItemRecord(
|
|
|
469
470
|
album = json.getString("album"),
|
|
470
471
|
duration = json.getDouble("duration"),
|
|
471
472
|
url = json.getString("url"),
|
|
472
|
-
artwork = json.
|
|
473
|
+
artwork = if (json.isNull("artwork")) null else json.getString("artwork"),
|
|
473
474
|
)
|
|
474
475
|
}
|
|
475
476
|
}
|
|
@@ -7,6 +7,7 @@ import android.util.Log
|
|
|
7
7
|
import androidx.work.*
|
|
8
8
|
import com.margelo.nitro.core.NullType
|
|
9
9
|
import com.margelo.nitro.nitroplayer.*
|
|
10
|
+
import com.margelo.nitro.nitroplayer.core.NitroPlayerLogger
|
|
10
11
|
import java.util.*
|
|
11
12
|
import java.util.concurrent.ConcurrentHashMap
|
|
12
13
|
import java.util.concurrent.CopyOnWriteArrayList
|
|
@@ -289,7 +290,7 @@ class DownloadManagerCore private constructor(
|
|
|
289
290
|
fun syncDownloads(): Int {
|
|
290
291
|
val removedCount = database.syncDownloads()
|
|
291
292
|
val bytesFreed = fileManager.cleanupOrphanedFiles(database.getAllDownloadedTracks().map { it.trackId }.toSet())
|
|
292
|
-
|
|
293
|
+
NitroPlayerLogger.log("DownloadManagerCore", "syncDownloads: removed $removedCount orphaned records, freed $bytesFreed bytes")
|
|
293
294
|
return removedCount
|
|
294
295
|
}
|
|
295
296
|
|
|
@@ -4,11 +4,11 @@ import android.app.NotificationChannel
|
|
|
4
4
|
import android.app.NotificationManager
|
|
5
5
|
import android.content.Context
|
|
6
6
|
import android.os.Build
|
|
7
|
+
import android.webkit.MimeTypeMap
|
|
7
8
|
import androidx.core.app.NotificationCompat
|
|
8
9
|
import androidx.work.CoroutineWorker
|
|
9
10
|
import androidx.work.ForegroundInfo
|
|
10
11
|
import androidx.work.WorkerParameters
|
|
11
|
-
import android.webkit.MimeTypeMap
|
|
12
12
|
import com.margelo.nitro.nitroplayer.*
|
|
13
13
|
import kotlinx.coroutines.Dispatchers
|
|
14
14
|
import kotlinx.coroutines.withContext
|
|
@@ -149,7 +149,6 @@ class DownloadWorker(
|
|
|
149
149
|
|
|
150
150
|
val finalExtension = if (extension.isNullOrEmpty()) "mp3" else extension
|
|
151
151
|
|
|
152
|
-
|
|
153
152
|
// Create destination file
|
|
154
153
|
val destinationFile = fileManager.createDownloadFile(trackId, storageLocation, finalExtension)
|
|
155
154
|
|
|
@@ -11,6 +11,7 @@ import com.margelo.nitro.nitroplayer.EqualizerState
|
|
|
11
11
|
import com.margelo.nitro.nitroplayer.GainRange
|
|
12
12
|
import com.margelo.nitro.nitroplayer.PresetType
|
|
13
13
|
import com.margelo.nitro.nitroplayer.Variant_NullType_String
|
|
14
|
+
import com.margelo.nitro.nitroplayer.core.NitroPlayerLogger
|
|
14
15
|
import org.json.JSONArray
|
|
15
16
|
import org.json.JSONObject
|
|
16
17
|
import java.lang.ref.WeakReference
|
|
@@ -99,7 +100,7 @@ class EqualizerCore private constructor(
|
|
|
99
100
|
setupBandMapping()
|
|
100
101
|
restoreSettings()
|
|
101
102
|
} catch (e: Exception) {
|
|
102
|
-
|
|
103
|
+
NitroPlayerLogger.log("EqualizerCore", "Failed to initialize equalizer: ${e.message}")
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
|
|
@@ -144,7 +145,7 @@ class EqualizerCore private constructor(
|
|
|
144
145
|
saveEnabled(enabled)
|
|
145
146
|
true
|
|
146
147
|
} catch (e: Exception) {
|
|
147
|
-
|
|
148
|
+
NitroPlayerLogger.log("EqualizerCore", "Failed to set enabled: ${e.message}")
|
|
148
149
|
false
|
|
149
150
|
}
|
|
150
151
|
}
|
|
@@ -10,6 +10,7 @@ import android.support.v4.media.MediaDescriptionCompat
|
|
|
10
10
|
import androidx.media.MediaBrowserServiceCompat
|
|
11
11
|
import androidx.media.utils.MediaConstants
|
|
12
12
|
import com.margelo.nitro.nitroplayer.TrackItem
|
|
13
|
+
import com.margelo.nitro.nitroplayer.core.NitroPlayerLogger
|
|
13
14
|
import com.margelo.nitro.nitroplayer.core.TrackPlayerCore
|
|
14
15
|
import com.margelo.nitro.nitroplayer.playlist.Playlist
|
|
15
16
|
import kotlinx.coroutines.CoroutineScope
|
|
@@ -53,23 +54,23 @@ class NitroPlayerMediaBrowserService : MediaBrowserServiceCompat() {
|
|
|
53
54
|
sessionToken =
|
|
54
55
|
android.support.v4.media.session.MediaSessionCompat.Token
|
|
55
56
|
.fromToken(session.platformToken)
|
|
56
|
-
|
|
57
|
+
NitroPlayerLogger.log("MediaBrowserService", "🎵 NitroPlayerMediaBrowserService: MediaSession token set successfully")
|
|
57
58
|
} else {
|
|
58
|
-
|
|
59
|
+
NitroPlayerLogger.log("MediaBrowserService", "⚠️ NitroPlayerMediaBrowserService: MediaSession not available yet")
|
|
59
60
|
}
|
|
60
61
|
} catch (e: Exception) {
|
|
61
|
-
|
|
62
|
+
NitroPlayerLogger.log("MediaBrowserService", "❌ NitroPlayerMediaBrowserService: Error setting session token - ${e.message}")
|
|
62
63
|
e.printStackTrace()
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
NitroPlayerLogger.log("MediaBrowserService", "🚀 NitroPlayerMediaBrowserService: Service created")
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
override fun onDestroy() {
|
|
69
70
|
super.onDestroy()
|
|
70
71
|
instance = null
|
|
71
72
|
serviceScope.cancel()
|
|
72
|
-
|
|
73
|
+
NitroPlayerLogger.log("MediaBrowserService", "🛑 NitroPlayerMediaBrowserService: Service destroyed")
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
override fun onGetRoot(
|
|
@@ -77,11 +78,11 @@ class NitroPlayerMediaBrowserService : MediaBrowserServiceCompat() {
|
|
|
77
78
|
clientUid: Int,
|
|
78
79
|
rootHints: Bundle?,
|
|
79
80
|
): BrowserRoot? {
|
|
80
|
-
|
|
81
|
+
NitroPlayerLogger.log("MediaBrowserService", "📂 NitroPlayerMediaBrowserService: onGetRoot called from $clientPackageName")
|
|
81
82
|
|
|
82
83
|
// Check if Android Auto is enabled
|
|
83
84
|
if (!isAndroidAutoEnabled) {
|
|
84
|
-
|
|
85
|
+
NitroPlayerLogger.log("MediaBrowserService", "⚠️ NitroPlayerMediaBrowserService: Android Auto not enabled")
|
|
85
86
|
return BrowserRoot(EMPTY_ROOT_ID, null)
|
|
86
87
|
}
|
|
87
88
|
|
|
@@ -94,7 +95,7 @@ class NitroPlayerMediaBrowserService : MediaBrowserServiceCompat() {
|
|
|
94
95
|
MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM,
|
|
95
96
|
)
|
|
96
97
|
}
|
|
97
|
-
|
|
98
|
+
NitroPlayerLogger.log("MediaBrowserService", "✅ NitroPlayerMediaBrowserService: Allowing connection from $clientPackageName with grid layout")
|
|
98
99
|
return BrowserRoot(ROOT_ID, extras)
|
|
99
100
|
}
|
|
100
101
|
|
|
@@ -102,10 +103,10 @@ class NitroPlayerMediaBrowserService : MediaBrowserServiceCompat() {
|
|
|
102
103
|
parentId: String,
|
|
103
104
|
result: Result<MutableList<MediaBrowserCompat.MediaItem>>,
|
|
104
105
|
) {
|
|
105
|
-
|
|
106
|
+
NitroPlayerLogger.log("MediaBrowserService", "📂 NitroPlayerMediaBrowserService: onLoadChildren called for parentId: $parentId")
|
|
106
107
|
|
|
107
108
|
if (!isAndroidAutoEnabled) {
|
|
108
|
-
|
|
109
|
+
NitroPlayerLogger.log("MediaBrowserService", "⚠️ NitroPlayerMediaBrowserService: Android Auto not enabled, returning empty")
|
|
109
110
|
result.sendResult(mutableListOf())
|
|
110
111
|
return
|
|
111
112
|
}
|
|
@@ -121,7 +122,7 @@ class NitroPlayerMediaBrowserService : MediaBrowserServiceCompat() {
|
|
|
121
122
|
|
|
122
123
|
if (library == null) {
|
|
123
124
|
// Fallback: show playlists if no media library is set
|
|
124
|
-
|
|
125
|
+
NitroPlayerLogger.log("MediaBrowserService", "⚠️ NitroPlayerMediaBrowserService: No media library set, using fallback playlists")
|
|
125
126
|
val mediaItems = loadFallbackPlaylists()
|
|
126
127
|
result.sendResult(mediaItems)
|
|
127
128
|
return@launch
|
|
@@ -133,10 +134,10 @@ class NitroPlayerMediaBrowserService : MediaBrowserServiceCompat() {
|
|
|
133
134
|
mediaItems.add(convertToMediaBrowserItem(item, library.layoutType))
|
|
134
135
|
}
|
|
135
136
|
|
|
136
|
-
|
|
137
|
+
NitroPlayerLogger.log("MediaBrowserService", "✅ NitroPlayerMediaBrowserService: Returning ${mediaItems.size} root items")
|
|
137
138
|
result.sendResult(mediaItems)
|
|
138
139
|
} catch (e: Exception) {
|
|
139
|
-
|
|
140
|
+
NitroPlayerLogger.log("MediaBrowserService", "❌ NitroPlayerMediaBrowserService: Error loading root items - ${e.message}")
|
|
140
141
|
e.printStackTrace()
|
|
141
142
|
result.sendResult(mutableListOf())
|
|
142
143
|
}
|
|
@@ -154,7 +155,7 @@ class NitroPlayerMediaBrowserService : MediaBrowserServiceCompat() {
|
|
|
154
155
|
val playlist = trackPlayerCore?.getPlaylistManager()?.getPlaylist(playlistId)
|
|
155
156
|
|
|
156
157
|
if (playlist == null) {
|
|
157
|
-
|
|
158
|
+
NitroPlayerLogger.log("MediaBrowserService", "⚠️ NitroPlayerMediaBrowserService: Playlist '$playlistId' not found")
|
|
158
159
|
result.sendResult(mutableListOf())
|
|
159
160
|
return@launch
|
|
160
161
|
}
|
|
@@ -188,10 +189,10 @@ class NitroPlayerMediaBrowserService : MediaBrowserServiceCompat() {
|
|
|
188
189
|
)
|
|
189
190
|
}
|
|
190
191
|
|
|
191
|
-
|
|
192
|
+
NitroPlayerLogger.log("MediaBrowserService", "✅ NitroPlayerMediaBrowserService: Returning ${mediaItems.size} tracks from playlist '$playlistId'")
|
|
192
193
|
result.sendResult(mediaItems)
|
|
193
194
|
} catch (e: Exception) {
|
|
194
|
-
|
|
195
|
+
NitroPlayerLogger.log("MediaBrowserService", "❌ NitroPlayerMediaBrowserService: Error loading playlist tracks - ${e.message}")
|
|
195
196
|
e.printStackTrace()
|
|
196
197
|
result.sendResult(mutableListOf())
|
|
197
198
|
}
|
|
@@ -211,7 +212,7 @@ class NitroPlayerMediaBrowserService : MediaBrowserServiceCompat() {
|
|
|
211
212
|
val children = mediaLibraryManager.getChildrenById(parentId)
|
|
212
213
|
|
|
213
214
|
if (children == null) {
|
|
214
|
-
|
|
215
|
+
NitroPlayerLogger.log("MediaBrowserService", "⚠️ NitroPlayerMediaBrowserService: No children found for parentId: $parentId")
|
|
215
216
|
result.sendResult(mutableListOf())
|
|
216
217
|
return@launch
|
|
217
218
|
}
|
|
@@ -224,10 +225,10 @@ class NitroPlayerMediaBrowserService : MediaBrowserServiceCompat() {
|
|
|
224
225
|
convertToMediaBrowserItem(item, defaultLayout)
|
|
225
226
|
}.toMutableList()
|
|
226
227
|
|
|
227
|
-
|
|
228
|
+
NitroPlayerLogger.log("MediaBrowserService", "✅ NitroPlayerMediaBrowserService: Returning ${mediaItems.size} items for parentId: $parentId")
|
|
228
229
|
result.sendResult(mediaItems)
|
|
229
230
|
} catch (e: Exception) {
|
|
230
|
-
|
|
231
|
+
NitroPlayerLogger.log("MediaBrowserService", "❌ NitroPlayerMediaBrowserService: Error loading children - ${e.message}")
|
|
231
232
|
e.printStackTrace()
|
|
232
233
|
result.sendResult(mutableListOf())
|
|
233
234
|
}
|
|
@@ -239,18 +240,18 @@ class NitroPlayerMediaBrowserService : MediaBrowserServiceCompat() {
|
|
|
239
240
|
fun onPlaylistsUpdated() {
|
|
240
241
|
try {
|
|
241
242
|
notifyChildrenChanged(ROOT_ID)
|
|
242
|
-
|
|
243
|
+
NitroPlayerLogger.log("MediaBrowserService", "📢 NitroPlayerMediaBrowserService: Notified Android Auto of playlist update")
|
|
243
244
|
} catch (e: Exception) {
|
|
244
|
-
|
|
245
|
+
NitroPlayerLogger.log("MediaBrowserService", "⚠️ NitroPlayerMediaBrowserService: Error notifying children changed: ${e.message}")
|
|
245
246
|
}
|
|
246
247
|
}
|
|
247
248
|
|
|
248
249
|
fun onPlaylistUpdated(playlistId: String) {
|
|
249
250
|
try {
|
|
250
251
|
notifyChildrenChanged("$PLAYLIST_PREFIX$playlistId")
|
|
251
|
-
|
|
252
|
+
NitroPlayerLogger.log("MediaBrowserService", "📢 NitroPlayerMediaBrowserService: Notified Android Auto of playlist '$playlistId' update")
|
|
252
253
|
} catch (e: Exception) {
|
|
253
|
-
|
|
254
|
+
NitroPlayerLogger.log("MediaBrowserService", "⚠️ NitroPlayerMediaBrowserService: Error notifying playlist changed: ${e.message}")
|
|
254
255
|
}
|
|
255
256
|
}
|
|
256
257
|
|
|
@@ -348,7 +349,7 @@ class NitroPlayerMediaBrowserService : MediaBrowserServiceCompat() {
|
|
|
348
349
|
)
|
|
349
350
|
}
|
|
350
351
|
|
|
351
|
-
|
|
352
|
+
NitroPlayerLogger.log("MediaBrowserService", "✅ NitroPlayerMediaBrowserService: Loaded ${mediaItems.size} playlists as fallback")
|
|
352
353
|
return mediaItems
|
|
353
354
|
}
|
|
354
355
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package com.margelo.nitro.nitroplayer.media
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
+
import com.margelo.nitro.nitroplayer.core.NitroPlayerLogger
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Manages the Android Auto media library structure
|
|
@@ -27,7 +28,7 @@ class MediaLibraryManager private constructor(
|
|
|
27
28
|
*/
|
|
28
29
|
fun setMediaLibrary(library: MediaLibrary) {
|
|
29
30
|
mediaLibrary = library
|
|
30
|
-
|
|
31
|
+
NitroPlayerLogger.log("MediaLibraryManager", "📚 MediaLibraryManager: Media library set with ${library.rootItems.size} root items")
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/**
|
|
@@ -72,6 +73,6 @@ class MediaLibraryManager private constructor(
|
|
|
72
73
|
*/
|
|
73
74
|
fun clear() {
|
|
74
75
|
mediaLibrary = null
|
|
75
|
-
|
|
76
|
+
NitroPlayerLogger.log("MediaLibraryManager", "📚 MediaLibraryManager: Media library cleared")
|
|
76
77
|
}
|
|
77
78
|
}
|
|
@@ -23,6 +23,7 @@ import androidx.media3.session.SessionResult
|
|
|
23
23
|
import com.google.common.util.concurrent.Futures
|
|
24
24
|
import com.google.common.util.concurrent.ListenableFuture
|
|
25
25
|
import com.margelo.nitro.nitroplayer.TrackItem
|
|
26
|
+
import com.margelo.nitro.nitroplayer.core.NitroPlayerLogger
|
|
26
27
|
import com.margelo.nitro.nitroplayer.core.TrackPlayerCore
|
|
27
28
|
import com.margelo.nitro.nitroplayer.media.NitroPlayerMediaBrowserService
|
|
28
29
|
import com.margelo.nitro.nitroplayer.playlist.PlaylistManager
|
|
@@ -114,7 +115,7 @@ class MediaSessionManager(
|
|
|
114
115
|
mediaItems: MutableList<MediaItem>,
|
|
115
116
|
): ListenableFuture<MutableList<MediaItem>> {
|
|
116
117
|
// This is called when Android Auto requests to play a track
|
|
117
|
-
|
|
118
|
+
NitroPlayerLogger.log("MediaSessionManager", "🎵 MediaSessionManager: onAddMediaItems called with ${mediaItems.size} items")
|
|
118
119
|
|
|
119
120
|
if (mediaItems.isEmpty()) {
|
|
120
121
|
return Futures.immediateFuture(mutableListOf())
|
|
@@ -128,7 +129,7 @@ class MediaSessionManager(
|
|
|
128
129
|
requestedMediaItem.requestMetadata.mediaUri?.toString()
|
|
129
130
|
?: requestedMediaItem.mediaId
|
|
130
131
|
|
|
131
|
-
|
|
132
|
+
NitroPlayerLogger.log("MediaSessionManager", "🎵 MediaSessionManager: Processing mediaId: $mediaId")
|
|
132
133
|
|
|
133
134
|
try {
|
|
134
135
|
// Parse mediaId format: "playlistId:trackId"
|
|
@@ -137,7 +138,7 @@ class MediaSessionManager(
|
|
|
137
138
|
val playlistId = mediaId.substring(0, colonIndex)
|
|
138
139
|
val trackId = mediaId.substring(colonIndex + 1)
|
|
139
140
|
|
|
140
|
-
|
|
141
|
+
NitroPlayerLogger.log("MediaSessionManager", "🎵 MediaSessionManager: Parsed playlistId: $playlistId, trackId: $trackId")
|
|
141
142
|
|
|
142
143
|
// Get the playlist and track
|
|
143
144
|
val playlist = playlistManager.getPlaylist(playlistId)
|
|
@@ -147,27 +148,27 @@ class MediaSessionManager(
|
|
|
147
148
|
// Create a proper MediaItem with all metadata
|
|
148
149
|
val resolvedMediaItem = createMediaItem(track, mediaId)
|
|
149
150
|
updatedMediaItems.add(resolvedMediaItem)
|
|
150
|
-
|
|
151
|
+
NitroPlayerLogger.log("MediaSessionManager", "✅ MediaSessionManager: Resolved track: ${track.title}")
|
|
151
152
|
} else {
|
|
152
|
-
|
|
153
|
+
NitroPlayerLogger.log("MediaSessionManager", "⚠️ MediaSessionManager: Track $trackId not found in playlist")
|
|
153
154
|
updatedMediaItems.add(requestedMediaItem)
|
|
154
155
|
}
|
|
155
156
|
} else {
|
|
156
|
-
|
|
157
|
+
NitroPlayerLogger.log("MediaSessionManager", "⚠️ MediaSessionManager: Playlist $playlistId not found")
|
|
157
158
|
updatedMediaItems.add(requestedMediaItem)
|
|
158
159
|
}
|
|
159
160
|
} else {
|
|
160
|
-
|
|
161
|
+
NitroPlayerLogger.log("MediaSessionManager", "⚠️ MediaSessionManager: Invalid mediaId format: $mediaId")
|
|
161
162
|
updatedMediaItems.add(requestedMediaItem)
|
|
162
163
|
}
|
|
163
164
|
} catch (e: Exception) {
|
|
164
|
-
|
|
165
|
+
NitroPlayerLogger.log("MediaSessionManager", "❌ MediaSessionManager: Error processing mediaId - ${e.message}")
|
|
165
166
|
e.printStackTrace()
|
|
166
167
|
updatedMediaItems.add(requestedMediaItem)
|
|
167
168
|
}
|
|
168
169
|
}
|
|
169
170
|
|
|
170
|
-
|
|
171
|
+
NitroPlayerLogger.log("MediaSessionManager", "🎵 MediaSessionManager: Returning ${updatedMediaItems.size} resolved media items")
|
|
171
172
|
return Futures.immediateFuture(updatedMediaItems)
|
|
172
173
|
}
|
|
173
174
|
|
|
@@ -179,7 +180,7 @@ class MediaSessionManager(
|
|
|
179
180
|
startPositionMs: Long,
|
|
180
181
|
): ListenableFuture<MediaSession.MediaItemsWithStartPosition> {
|
|
181
182
|
// This is called when Android Auto wants to set and play media items
|
|
182
|
-
|
|
183
|
+
NitroPlayerLogger.log("MediaSessionManager", "🎵 MediaSessionManager: onSetMediaItems called with ${mediaItems.size} items, startIndex: $startIndex")
|
|
183
184
|
|
|
184
185
|
if (mediaItems.isEmpty()) {
|
|
185
186
|
return Futures.immediateFuture(
|
|
@@ -194,7 +195,7 @@ class MediaSessionManager(
|
|
|
194
195
|
try {
|
|
195
196
|
// Get the first item's mediaId to determine the playlist
|
|
196
197
|
val firstMediaId = mediaItems[0].mediaId
|
|
197
|
-
|
|
198
|
+
NitroPlayerLogger.log("MediaSessionManager", "🎵 MediaSessionManager: First mediaId: $firstMediaId")
|
|
198
199
|
|
|
199
200
|
// Parse mediaId format: "playlistId:trackId"
|
|
200
201
|
if (firstMediaId.contains(':')) {
|
|
@@ -202,7 +203,7 @@ class MediaSessionManager(
|
|
|
202
203
|
val playlistId = firstMediaId.substring(0, colonIndex)
|
|
203
204
|
val trackId = firstMediaId.substring(colonIndex + 1)
|
|
204
205
|
|
|
205
|
-
|
|
206
|
+
NitroPlayerLogger.log("MediaSessionManager", "🎵 MediaSessionManager: Loading full playlist: $playlistId, starting at track: $trackId")
|
|
206
207
|
|
|
207
208
|
// Get the full playlist
|
|
208
209
|
val playlist = playlistManager.getPlaylist(playlistId)
|
|
@@ -222,7 +223,7 @@ class MediaSessionManager(
|
|
|
222
223
|
createMediaItem(track, trackMediaId)
|
|
223
224
|
}.toMutableList()
|
|
224
225
|
|
|
225
|
-
|
|
226
|
+
NitroPlayerLogger.log("MediaSessionManager", "✅ MediaSessionManager: Loaded ${playlistMediaItems.size} tracks, starting at index $trackIndex")
|
|
226
227
|
|
|
227
228
|
// Return the full playlist with the correct start index
|
|
228
229
|
return Futures.immediateFuture(
|
|
@@ -233,19 +234,19 @@ class MediaSessionManager(
|
|
|
233
234
|
),
|
|
234
235
|
)
|
|
235
236
|
} else {
|
|
236
|
-
|
|
237
|
+
NitroPlayerLogger.log("MediaSessionManager", "⚠️ MediaSessionManager: Track not found in playlist")
|
|
237
238
|
}
|
|
238
239
|
} else {
|
|
239
|
-
|
|
240
|
+
NitroPlayerLogger.log("MediaSessionManager", "⚠️ MediaSessionManager: Playlist not found")
|
|
240
241
|
}
|
|
241
242
|
}
|
|
242
243
|
} catch (e: Exception) {
|
|
243
|
-
|
|
244
|
+
NitroPlayerLogger.log("MediaSessionManager", "❌ MediaSessionManager: Error in onSetMediaItems - ${e.message}")
|
|
244
245
|
e.printStackTrace()
|
|
245
246
|
}
|
|
246
247
|
|
|
247
248
|
// Fallback: use the provided media items
|
|
248
|
-
|
|
249
|
+
NitroPlayerLogger.log("MediaSessionManager", "🎵 MediaSessionManager: Using fallback - provided media items")
|
|
249
250
|
return Futures.immediateFuture(
|
|
250
251
|
MediaSession.MediaItemsWithStartPosition(
|
|
251
252
|
mediaItems,
|
|
@@ -391,7 +392,7 @@ class MediaSessionManager(
|
|
|
391
392
|
.setShowActionsInCompactView(0, 1, 2),
|
|
392
393
|
)
|
|
393
394
|
} catch (e: Exception) {
|
|
394
|
-
|
|
395
|
+
NitroPlayerLogger.log("MediaSessionManager", "Failed to set media session token: ${e.message}")
|
|
395
396
|
}
|
|
396
397
|
|
|
397
398
|
// Add action buttons
|
|
@@ -500,7 +501,7 @@ class MediaSessionManager(
|
|
|
500
501
|
try {
|
|
501
502
|
metadataBuilder.setArtworkUri(Uri.parse(artworkUrl))
|
|
502
503
|
} catch (e: Exception) {
|
|
503
|
-
|
|
504
|
+
NitroPlayerLogger.log("MediaSessionManager", "⚠️ MediaSessionManager: Invalid artwork URI: $artworkUrl")
|
|
504
505
|
}
|
|
505
506
|
}
|
|
506
507
|
|
|
@@ -2,6 +2,7 @@ package com.margelo.nitro.nitroplayer.playlist
|
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import android.content.SharedPreferences
|
|
5
|
+
import com.margelo.nitro.core.AnyMap
|
|
5
6
|
import com.margelo.nitro.core.NullType
|
|
6
7
|
import com.margelo.nitro.nitroplayer.QueueOperation
|
|
7
8
|
import com.margelo.nitro.nitroplayer.TrackItem
|
|
@@ -13,8 +14,6 @@ import org.json.JSONObject
|
|
|
13
14
|
import java.util.UUID
|
|
14
15
|
import java.util.concurrent.CopyOnWriteArrayList
|
|
15
16
|
|
|
16
|
-
import com.margelo.nitro.core.AnyMap
|
|
17
|
-
|
|
18
17
|
/**
|
|
19
18
|
* Manages multiple playlists using ExoPlayer's native playlist functionality
|
|
20
19
|
* Based on: https://developer.android.com/media/media3/exoplayer/playlists
|
|
@@ -30,6 +29,14 @@ class PlaylistManager private constructor(
|
|
|
30
29
|
private val sharedPreferences: SharedPreferences =
|
|
31
30
|
context.getSharedPreferences("NitroPlayerPlaylists", Context.MODE_PRIVATE)
|
|
32
31
|
|
|
32
|
+
private val saveHandler = android.os.Handler(android.os.Looper.getMainLooper())
|
|
33
|
+
private val saveRunnable = Runnable { savePlaylistsToPreferences() }
|
|
34
|
+
|
|
35
|
+
private fun scheduleSave() {
|
|
36
|
+
saveHandler.removeCallbacks(saveRunnable)
|
|
37
|
+
saveHandler.postDelayed(saveRunnable, 300)
|
|
38
|
+
}
|
|
39
|
+
|
|
33
40
|
companion object {
|
|
34
41
|
@Volatile
|
|
35
42
|
@Suppress("ktlint:standard:property-naming")
|
|
@@ -63,7 +70,7 @@ class PlaylistManager private constructor(
|
|
|
63
70
|
|
|
64
71
|
// Only cache for Android Auto if connected
|
|
65
72
|
if (NitroPlayerMediaBrowserService.isAndroidAutoConnected) {
|
|
66
|
-
|
|
73
|
+
scheduleSave()
|
|
67
74
|
}
|
|
68
75
|
notifyPlaylistsChanged(QueueOperation.ADD)
|
|
69
76
|
NitroPlayerMediaBrowserService.getInstance()?.onPlaylistsUpdated()
|
|
@@ -87,7 +94,7 @@ class PlaylistManager private constructor(
|
|
|
87
94
|
playlistListeners.remove(playlistId)
|
|
88
95
|
// Only cache for Android Auto if connected
|
|
89
96
|
if (NitroPlayerMediaBrowserService.isAndroidAutoConnected) {
|
|
90
|
-
|
|
97
|
+
scheduleSave()
|
|
91
98
|
}
|
|
92
99
|
notifyPlaylistsChanged(QueueOperation.REMOVE)
|
|
93
100
|
NitroPlayerMediaBrowserService.getInstance()?.onPlaylistsUpdated()
|
|
@@ -122,7 +129,7 @@ class PlaylistManager private constructor(
|
|
|
122
129
|
|
|
123
130
|
// Only cache for Android Auto if connected
|
|
124
131
|
if (NitroPlayerMediaBrowserService.isAndroidAutoConnected) {
|
|
125
|
-
|
|
132
|
+
scheduleSave()
|
|
126
133
|
}
|
|
127
134
|
notifyPlaylistChanged(playlistId, QueueOperation.UPDATE)
|
|
128
135
|
notifyPlaylistsChanged(QueueOperation.UPDATE)
|
|
@@ -172,7 +179,7 @@ class PlaylistManager private constructor(
|
|
|
172
179
|
|
|
173
180
|
// Only cache for Android Auto if connected
|
|
174
181
|
if (NitroPlayerMediaBrowserService.isAndroidAutoConnected) {
|
|
175
|
-
|
|
182
|
+
scheduleSave()
|
|
176
183
|
}
|
|
177
184
|
notifyPlaylistChanged(playlistId, QueueOperation.ADD)
|
|
178
185
|
NitroPlayerMediaBrowserService.getInstance()?.onPlaylistUpdated(playlistId)
|
|
@@ -210,7 +217,7 @@ class PlaylistManager private constructor(
|
|
|
210
217
|
|
|
211
218
|
// Only cache for Android Auto if connected
|
|
212
219
|
if (NitroPlayerMediaBrowserService.isAndroidAutoConnected) {
|
|
213
|
-
|
|
220
|
+
scheduleSave()
|
|
214
221
|
}
|
|
215
222
|
notifyPlaylistChanged(playlistId, QueueOperation.ADD)
|
|
216
223
|
NitroPlayerMediaBrowserService.getInstance()?.onPlaylistUpdated(playlistId)
|
|
@@ -246,7 +253,7 @@ class PlaylistManager private constructor(
|
|
|
246
253
|
}
|
|
247
254
|
|
|
248
255
|
if (removed) {
|
|
249
|
-
|
|
256
|
+
scheduleSave()
|
|
250
257
|
notifyPlaylistChanged(playlistId, QueueOperation.REMOVE)
|
|
251
258
|
NitroPlayerMediaBrowserService.getInstance()?.onPlaylistUpdated(playlistId)
|
|
252
259
|
|
|
@@ -284,7 +291,7 @@ class PlaylistManager private constructor(
|
|
|
284
291
|
playlists[playlistId] = playlist.copy(tracks = tracks)
|
|
285
292
|
}
|
|
286
293
|
|
|
287
|
-
|
|
294
|
+
scheduleSave()
|
|
288
295
|
notifyPlaylistChanged(playlistId, QueueOperation.UPDATE)
|
|
289
296
|
NitroPlayerMediaBrowserService.getInstance()?.onPlaylistUpdated(playlistId)
|
|
290
297
|
|
|
@@ -30,7 +30,7 @@ class HybridAudioRoutePicker: HybridAudioRoutePickerSpec {
|
|
|
30
30
|
.flatMap({ $0.windows })
|
|
31
31
|
.first(where: { $0.isKeyWindow })
|
|
32
32
|
else {
|
|
33
|
-
|
|
33
|
+
NitroPlayerLogger.log("HybridAudioRoutePicker", "Could not find key window")
|
|
34
34
|
return
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -208,19 +208,19 @@ final class HybridDownloadManager: HybridDownloadManagerSpec {
|
|
|
208
208
|
// MARK: - Event Callbacks
|
|
209
209
|
|
|
210
210
|
func onDownloadProgress(callback: @escaping (DownloadProgress) -> Void) throws {
|
|
211
|
-
|
|
211
|
+
NitroPlayerLogger.log("HybridDownloadManager", "onDownloadProgress callback registered")
|
|
212
212
|
core.addProgressCallback(callback)
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
func onDownloadStateChange(
|
|
216
216
|
callback: @escaping (String, String, DownloadState, DownloadError?) -> Void
|
|
217
217
|
) throws {
|
|
218
|
-
|
|
218
|
+
NitroPlayerLogger.log("HybridDownloadManager", "onDownloadStateChange callback registered")
|
|
219
219
|
core.addStateChangeCallback(callback)
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
func onDownloadComplete(callback: @escaping (DownloadedTrack) -> Void) throws {
|
|
223
|
-
|
|
223
|
+
NitroPlayerLogger.log("HybridDownloadManager", "onDownloadComplete callback registered")
|
|
224
224
|
core.addCompleteCallback(callback)
|
|
225
225
|
}
|
|
226
226
|
}
|
|
@@ -95,17 +95,17 @@ final class HybridEqualizer: HybridEqualizerSpec {
|
|
|
95
95
|
// MARK: - Event Callbacks
|
|
96
96
|
|
|
97
97
|
func onEnabledChange(callback: @escaping (Bool) -> Void) throws {
|
|
98
|
-
|
|
98
|
+
NitroPlayerLogger.log("HybridEqualizer", "onEnabledChange callback registered")
|
|
99
99
|
core.addOnEnabledChangeListener(owner: self, callback)
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
func onBandChange(callback: @escaping ([EqualizerBand]) -> Void) throws {
|
|
103
|
-
|
|
103
|
+
NitroPlayerLogger.log("HybridEqualizer", "onBandChange callback registered")
|
|
104
104
|
core.addOnBandChangeListener(owner: self, callback)
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
func onPresetChange(callback: @escaping (Variant_NullType_String?) -> Void) throws {
|
|
108
|
-
|
|
108
|
+
NitroPlayerLogger.log("HybridEqualizer", "onPresetChange callback registered")
|
|
109
109
|
core.addOnPresetChangeListener(owner: self, callback)
|
|
110
110
|
}
|
|
111
111
|
}
|