react-native-nitro-player 0.5.5 → 0.5.7

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 (36) hide show
  1. package/README.md +2 -0
  2. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridTrackPlayer.kt +43 -0
  3. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/NitroPlayerLogger.kt +8 -2
  4. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerCore.kt +345 -4
  5. package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadDatabase.kt +43 -10
  6. package/android/src/main/java/com/margelo/nitro/nitroplayer/playlist/PlaylistManager.kt +76 -7
  7. package/android/src/main/java/com/margelo/nitro/nitroplayer/storage/NitroPlayerStorage.kt +9 -2
  8. package/ios/HybridTrackPlayer.swift +54 -1
  9. package/ios/core/TrackPlayerCore.swift +254 -2
  10. package/ios/download/DownloadDatabase.swift +79 -2
  11. package/ios/download/DownloadManagerCore.swift +81 -2
  12. package/ios/playlist/PlaylistManager.swift +68 -0
  13. package/lib/specs/TrackPlayer.nitro.d.ts +47 -0
  14. package/lib/types/PlayerQueue.d.ts +5 -0
  15. package/nitrogen/generated/android/NitroPlayerOnLoad.cpp +2 -0
  16. package/nitrogen/generated/android/c++/JFunc_void_std__vector_TrackItem__double.hpp +104 -0
  17. package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.cpp +160 -0
  18. package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.hpp +8 -0
  19. package/nitrogen/generated/android/c++/JPlayerConfig.hpp +7 -3
  20. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__vector_TrackItem__double.kt +80 -0
  21. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridTrackPlayerSpec.kt +37 -0
  22. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/PlayerConfig.kt +6 -3
  23. package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.cpp +16 -0
  24. package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.hpp +65 -0
  25. package/nitrogen/generated/ios/c++/HybridTrackPlayerSpecSwift.hpp +62 -0
  26. package/nitrogen/generated/ios/swift/Func_void_double.swift +47 -0
  27. package/nitrogen/generated/ios/swift/Func_void_std__vector_TrackItem__double.swift +47 -0
  28. package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec.swift +8 -0
  29. package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec_cxx.swift +173 -0
  30. package/nitrogen/generated/ios/swift/PlayerConfig.swift +24 -1
  31. package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.cpp +8 -0
  32. package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.hpp +8 -0
  33. package/nitrogen/generated/shared/c++/PlayerConfig.hpp +6 -2
  34. package/package.json +1 -1
  35. package/src/specs/TrackPlayer.nitro.ts +57 -0
  36. package/src/types/PlayerQueue.ts +5 -0
@@ -613,6 +613,12 @@ final class DownloadManagerCore: NSObject {
613
613
  artworkString = value
614
614
  }
615
615
  }
616
+
617
+ var extraPayloadDict: [String: Any]? = nil
618
+ if let extraPayload = track.extraPayload {
619
+ extraPayloadDict = extraPayload.toDictionary()
620
+ }
621
+
616
622
  return TrackItemRecord(
617
623
  id: track.id,
618
624
  title: track.title,
@@ -620,12 +626,30 @@ final class DownloadManagerCore: NSObject {
620
626
  album: track.album,
621
627
  duration: track.duration,
622
628
  url: track.url,
623
- artwork: artworkString
629
+ artwork: artworkString,
630
+ extraPayload: extraPayloadDict
624
631
  )
625
632
  }
626
633
 
627
634
  private func recordToTrackItem(_ record: TrackItemRecord) -> TrackItem {
628
635
  let artwork: Variant_NullType_String? = record.artwork.map { .second($0) }
636
+
637
+ var extraPayload: AnyMap? = nil
638
+ if let extraPayloadDict = record.extraPayload {
639
+ extraPayload = AnyMap()
640
+ for (key, value) in extraPayloadDict {
641
+ if let stringValue = value as? String {
642
+ extraPayload?.setString(key: key, value: stringValue)
643
+ } else if let doubleValue = value as? Double {
644
+ extraPayload?.setDouble(key: key, value: doubleValue)
645
+ } else if let intValue = value as? Int {
646
+ extraPayload?.setDouble(key: key, value: Double(intValue))
647
+ } else if let boolValue = value as? Bool {
648
+ extraPayload?.setBoolean(key: key, value: boolValue)
649
+ }
650
+ }
651
+ }
652
+
629
653
  return TrackItem(
630
654
  id: record.id,
631
655
  title: record.title,
@@ -634,7 +658,7 @@ final class DownloadManagerCore: NSObject {
634
658
  duration: record.duration,
635
659
  url: record.url,
636
660
  artwork: artwork,
637
- extraPayload: nil
661
+ extraPayload: extraPayload
638
662
  )
639
663
  }
640
664
 
@@ -963,4 +987,59 @@ private struct TrackItemRecord: Codable {
963
987
  let duration: Double
964
988
  let url: String
965
989
  let artwork: String?
990
+ let extraPayload: [String: Any]?
991
+
992
+ enum CodingKeys: String, CodingKey {
993
+ case id, title, artist, album, duration, url, artwork, extraPayload
994
+ }
995
+
996
+ // Manual encoding to handle [String: Any]
997
+ func encode(to encoder: Encoder) throws {
998
+ var container = encoder.container(keyedBy: CodingKeys.self)
999
+ try container.encode(id, forKey: .id)
1000
+ try container.encode(title, forKey: .title)
1001
+ try container.encode(artist, forKey: .artist)
1002
+ try container.encode(album, forKey: .album)
1003
+ try container.encode(duration, forKey: .duration)
1004
+ try container.encode(url, forKey: .url)
1005
+ try container.encodeIfPresent(artwork, forKey: .artwork)
1006
+
1007
+ if let extraPayload = extraPayload {
1008
+ let jsonData = try JSONSerialization.data(withJSONObject: extraPayload)
1009
+ if let jsonString = String(data: jsonData, encoding: .utf8) {
1010
+ try container.encode(jsonString, forKey: .extraPayload)
1011
+ }
1012
+ }
1013
+ }
1014
+
1015
+ // Manual decoding to handle [String: Any]
1016
+ init(from decoder: Decoder) throws {
1017
+ let container = try decoder.container(keyedBy: CodingKeys.self)
1018
+ id = try container.decode(String.self, forKey: .id)
1019
+ title = try container.decode(String.self, forKey: .title)
1020
+ artist = try container.decode(String.self, forKey: .artist)
1021
+ album = try container.decode(String.self, forKey: .album)
1022
+ duration = try container.decode(Double.self, forKey: .duration)
1023
+ url = try container.decode(String.self, forKey: .url)
1024
+ artwork = try container.decodeIfPresent(String.self, forKey: .artwork)
1025
+
1026
+ if let jsonString = try? container.decodeIfPresent(String.self, forKey: .extraPayload),
1027
+ let jsonData = jsonString.data(using: .utf8) {
1028
+ extraPayload = try? JSONSerialization.jsonObject(with: jsonData) as? [String: Any]
1029
+ } else {
1030
+ extraPayload = nil
1031
+ }
1032
+ }
1033
+
1034
+ // Initializer for code creation
1035
+ init(id: String, title: String, artist: String, album: String, duration: Double, url: String, artwork: String?, extraPayload: [String: Any]?) {
1036
+ self.id = id
1037
+ self.title = title
1038
+ self.artist = artist
1039
+ self.album = album
1040
+ self.duration = duration
1041
+ self.url = url
1042
+ self.artwork = artwork
1043
+ self.extraPayload = extraPayload
1044
+ }
966
1045
  }
@@ -274,6 +274,74 @@ class PlaylistManager {
274
274
  return true
275
275
  }
276
276
 
277
+ /**
278
+ * Update entire track objects across all playlists
279
+ * Matches by track.id and replaces the entire track object
280
+ * @param tracks Array of full TrackItem objects to update
281
+ * @return Dictionary of playlistId -> count of tracks updated
282
+ */
283
+ func updateTracks(tracks: [TrackItem]) -> [String: Int] {
284
+ let tracksMap = Dictionary(uniqueKeysWithValues: tracks.map { ($0.id, $0) })
285
+ var affectedPlaylists: [String: Int] = [:]
286
+
287
+ queue.sync {
288
+ for (playlistId, playlist) in playlists {
289
+ var updateCount = 0
290
+ let newTracks = playlist.tracks.map { track -> TrackItem in
291
+ if let updatedTrack = tracksMap[track.id] {
292
+ updateCount += 1
293
+ return updatedTrack
294
+ }
295
+ return track
296
+ }
297
+
298
+ if updateCount > 0 {
299
+ affectedPlaylists[playlistId] = updateCount
300
+ playlists[playlistId] = PlaylistModel(
301
+ id: playlist.id,
302
+ name: playlist.name,
303
+ description: playlist.description,
304
+ artwork: playlist.artwork,
305
+ tracks: newTracks
306
+ )
307
+ }
308
+ }
309
+ }
310
+
311
+ if !affectedPlaylists.isEmpty {
312
+ scheduleSave()
313
+ affectedPlaylists.keys.forEach { playlistId in
314
+ notifyPlaylistChanged(playlistId, .update)
315
+ }
316
+ notifyPlaylistsChanged(.update)
317
+ }
318
+
319
+ return affectedPlaylists
320
+ }
321
+
322
+ /**
323
+ * Get tracks by IDs from all playlists
324
+ * @param trackIds Array of track IDs to fetch
325
+ * @return Array of matching TrackItem objects
326
+ */
327
+ func getTracksById(trackIds: [String]) -> [TrackItem] {
328
+ let trackIdSet = Set(trackIds)
329
+ var foundTracks: [String: TrackItem] = [:]
330
+
331
+ queue.sync {
332
+ for playlist in playlists.values {
333
+ for track in playlist.tracks {
334
+ if trackIdSet.contains(track.id) && foundTracks[track.id] == nil {
335
+ foundTracks[track.id] = track
336
+ }
337
+ }
338
+ }
339
+ }
340
+
341
+ // Return in same order as requested
342
+ return trackIds.compactMap { foundTracks[$0] }
343
+ }
344
+
277
345
  /**
278
346
  * Get the current playlist ID
279
347
  */
@@ -44,4 +44,51 @@ export interface TrackPlayer extends HybridObject<{
44
44
  onAndroidAutoConnectionChange(callback: (connected: boolean) => void): void;
45
45
  isAndroidAutoConnected(): boolean;
46
46
  setVolume(volume: number): boolean;
47
+ /**
48
+ * Update entire track objects across all playlists
49
+ * Matches by track.id and updates all properties (url, artwork, title, etc.)
50
+ * Note: Empty string "" is valid for TrackItem.url to support lazy loading
51
+ * @param tracks Array of full TrackItem objects to update
52
+ * @returns Promise that resolves when updates complete
53
+ */
54
+ updateTracks(tracks: TrackItem[]): Promise<void>;
55
+ /**
56
+ * Get tracks by IDs from all playlists
57
+ * @param trackIds Array of track IDs to fetch
58
+ * @returns Promise resolving to array of matching tracks
59
+ */
60
+ getTracksById(trackIds: string[]): Promise<TrackItem[]>;
61
+ /**
62
+ * Get tracks with missing/empty URLs from current playlist
63
+ * @returns Promise resolving to array of tracks needing URLs
64
+ */
65
+ getTracksNeedingUrls(): Promise<TrackItem[]>;
66
+ /**
67
+ * Get next N tracks from current position in playlist
68
+ * Useful for preloading URLs before they're needed
69
+ * @param count Number of upcoming tracks to return
70
+ * @returns Promise resolving to array of next tracks
71
+ */
72
+ getNextTracks(count: number): Promise<TrackItem[]>;
73
+ /**
74
+ * Get current track index in the active playlist
75
+ * @returns Promise resolving to 0-based index, or -1 if no track playing
76
+ */
77
+ getCurrentTrackIndex(): Promise<number>;
78
+ /**
79
+ * Register callback that fires when tracks will be needed soon
80
+ * Useful for proactive URL resolution in Android Auto/CarPlay
81
+ * @param callback Function called with tracks needing URLs and lookahead count
82
+ */
83
+ onTracksNeedUpdate(callback: (tracks: TrackItem[], lookahead: number) => void): void;
84
+ /**
85
+ * Get the current track index in the active playlist
86
+ * @returns Promise resolving to 0-based index, or -1 if no track playing
87
+ */
88
+ setPlaybackSpeed(speed: number): Promise<void>;
89
+ /**
90
+ * Get the current playback speed
91
+ * @returns Promise resolving to playback speed
92
+ */
93
+ getPlaybackSpeed(): Promise<number>;
47
94
  }
@@ -33,4 +33,9 @@ export interface PlayerConfig {
33
33
  androidAutoEnabled?: boolean;
34
34
  carPlayEnabled?: boolean;
35
35
  showInNotification?: boolean;
36
+ /**
37
+ * Number of upcoming tracks to preload URLs for (default: 5)
38
+ * Higher values = more proactive loading, but more network requests
39
+ */
40
+ lookaheadCount?: number;
36
41
  }
@@ -33,6 +33,7 @@
33
33
  #include "JFunc_void_TrackPlayerState_std__optional_Reason_.hpp"
34
34
  #include "JFunc_void_double_double.hpp"
35
35
  #include "JFunc_void_double_double_std__optional_bool_.hpp"
36
+ #include "JFunc_void_std__vector_TrackItem__double.hpp"
36
37
  #include <NitroModules/DefaultConstructableObject.hpp>
37
38
 
38
39
  namespace margelo::nitro::nitroplayer {
@@ -62,6 +63,7 @@ int initialize(JavaVM* vm) {
62
63
  margelo::nitro::nitroplayer::JFunc_void_TrackPlayerState_std__optional_Reason__cxx::registerNatives();
63
64
  margelo::nitro::nitroplayer::JFunc_void_double_double_cxx::registerNatives();
64
65
  margelo::nitro::nitroplayer::JFunc_void_double_double_std__optional_bool__cxx::registerNatives();
66
+ margelo::nitro::nitroplayer::JFunc_void_std__vector_TrackItem__double_cxx::registerNatives();
65
67
 
66
68
  // Register Nitro Hybrid Objects
67
69
  HybridObjectRegistry::registerHybridObjectConstructor(
@@ -0,0 +1,104 @@
1
+ ///
2
+ /// JFunc_void_std__vector_TrackItem__double.hpp
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © 2026 Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ #pragma once
9
+
10
+ #include <fbjni/fbjni.h>
11
+ #include <functional>
12
+
13
+ #include "TrackItem.hpp"
14
+ #include <vector>
15
+ #include <functional>
16
+ #include <NitroModules/JNICallable.hpp>
17
+ #include "JTrackItem.hpp"
18
+ #include <string>
19
+ #include <NitroModules/Null.hpp>
20
+ #include <variant>
21
+ #include <optional>
22
+ #include "JVariant_NullType_String.hpp"
23
+ #include <NitroModules/JNull.hpp>
24
+ #include <NitroModules/AnyMap.hpp>
25
+ #include <NitroModules/JAnyMap.hpp>
26
+
27
+ namespace margelo::nitro::nitroplayer {
28
+
29
+ using namespace facebook;
30
+
31
+ /**
32
+ * Represents the Java/Kotlin callback `(tracks: Array<TrackItem>, lookahead: Double) -> Unit`.
33
+ * This can be passed around between C++ and Java/Kotlin.
34
+ */
35
+ struct JFunc_void_std__vector_TrackItem__double: public jni::JavaClass<JFunc_void_std__vector_TrackItem__double> {
36
+ public:
37
+ static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/nitroplayer/Func_void_std__vector_TrackItem__double;";
38
+
39
+ public:
40
+ /**
41
+ * Invokes the function this `JFunc_void_std__vector_TrackItem__double` instance holds through JNI.
42
+ */
43
+ void invoke(const std::vector<TrackItem>& tracks, double lookahead) const {
44
+ static const auto method = javaClassStatic()->getMethod<void(jni::alias_ref<jni::JArrayClass<JTrackItem>> /* tracks */, double /* lookahead */)>("invoke");
45
+ method(self(), [&]() {
46
+ size_t __size = tracks.size();
47
+ jni::local_ref<jni::JArrayClass<JTrackItem>> __array = jni::JArrayClass<JTrackItem>::newArray(__size);
48
+ for (size_t __i = 0; __i < __size; __i++) {
49
+ const auto& __element = tracks[__i];
50
+ auto __elementJni = JTrackItem::fromCpp(__element);
51
+ __array->setElement(__i, *__elementJni);
52
+ }
53
+ return __array;
54
+ }(), lookahead);
55
+ }
56
+ };
57
+
58
+ /**
59
+ * An implementation of Func_void_std__vector_TrackItem__double that is backed by a C++ implementation (using `std::function<...>`)
60
+ */
61
+ class JFunc_void_std__vector_TrackItem__double_cxx final: public jni::HybridClass<JFunc_void_std__vector_TrackItem__double_cxx, JFunc_void_std__vector_TrackItem__double> {
62
+ public:
63
+ static jni::local_ref<JFunc_void_std__vector_TrackItem__double::javaobject> fromCpp(const std::function<void(const std::vector<TrackItem>& /* tracks */, double /* lookahead */)>& func) {
64
+ return JFunc_void_std__vector_TrackItem__double_cxx::newObjectCxxArgs(func);
65
+ }
66
+
67
+ public:
68
+ /**
69
+ * Invokes the C++ `std::function<...>` this `JFunc_void_std__vector_TrackItem__double_cxx` instance holds.
70
+ */
71
+ void invoke_cxx(jni::alias_ref<jni::JArrayClass<JTrackItem>> tracks, double lookahead) {
72
+ _func([&]() {
73
+ size_t __size = tracks->size();
74
+ std::vector<TrackItem> __vector;
75
+ __vector.reserve(__size);
76
+ for (size_t __i = 0; __i < __size; __i++) {
77
+ auto __element = tracks->getElement(__i);
78
+ __vector.push_back(__element->toCpp());
79
+ }
80
+ return __vector;
81
+ }(), lookahead);
82
+ }
83
+
84
+ public:
85
+ [[nodiscard]]
86
+ inline const std::function<void(const std::vector<TrackItem>& /* tracks */, double /* lookahead */)>& getFunction() const {
87
+ return _func;
88
+ }
89
+
90
+ public:
91
+ static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/nitroplayer/Func_void_std__vector_TrackItem__double_cxx;";
92
+ static void registerNatives() {
93
+ registerHybrid({makeNativeMethod("invoke_cxx", JFunc_void_std__vector_TrackItem__double_cxx::invoke_cxx)});
94
+ }
95
+
96
+ private:
97
+ explicit JFunc_void_std__vector_TrackItem__double_cxx(const std::function<void(const std::vector<TrackItem>& /* tracks */, double /* lookahead */)>& func): _func(func) { }
98
+
99
+ private:
100
+ friend HybridBase;
101
+ std::function<void(const std::vector<TrackItem>& /* tracks */, double /* lookahead */)> _func;
102
+ };
103
+
104
+ } // namespace margelo::nitro::nitroplayer
@@ -55,6 +55,7 @@ namespace margelo::nitro::nitroplayer { enum class Reason; }
55
55
  #include "JFunc_void_double_double.hpp"
56
56
  #include "JFunc_void_double_double_std__optional_bool_.hpp"
57
57
  #include "JFunc_void_bool.hpp"
58
+ #include "JFunc_void_std__vector_TrackItem__double.hpp"
58
59
 
59
60
  namespace margelo::nitro::nitroplayer {
60
61
 
@@ -254,5 +255,164 @@ namespace margelo::nitro::nitroplayer {
254
255
  auto __result = method(_javaPart, volume);
255
256
  return static_cast<bool>(__result);
256
257
  }
258
+ std::shared_ptr<Promise<void>> JHybridTrackPlayerSpec::updateTracks(const std::vector<TrackItem>& tracks) {
259
+ static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>(jni::alias_ref<jni::JArrayClass<JTrackItem>> /* tracks */)>("updateTracks");
260
+ auto __result = method(_javaPart, [&]() {
261
+ size_t __size = tracks.size();
262
+ jni::local_ref<jni::JArrayClass<JTrackItem>> __array = jni::JArrayClass<JTrackItem>::newArray(__size);
263
+ for (size_t __i = 0; __i < __size; __i++) {
264
+ const auto& __element = tracks[__i];
265
+ auto __elementJni = JTrackItem::fromCpp(__element);
266
+ __array->setElement(__i, *__elementJni);
267
+ }
268
+ return __array;
269
+ }());
270
+ return [&]() {
271
+ auto __promise = Promise<void>::create();
272
+ __result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& /* unit */) {
273
+ __promise->resolve();
274
+ });
275
+ __result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
276
+ jni::JniException __jniError(__throwable);
277
+ __promise->reject(std::make_exception_ptr(__jniError));
278
+ });
279
+ return __promise;
280
+ }();
281
+ }
282
+ std::shared_ptr<Promise<std::vector<TrackItem>>> JHybridTrackPlayerSpec::getTracksById(const std::vector<std::string>& trackIds) {
283
+ static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>(jni::alias_ref<jni::JArrayClass<jni::JString>> /* trackIds */)>("getTracksById");
284
+ auto __result = method(_javaPart, [&]() {
285
+ size_t __size = trackIds.size();
286
+ jni::local_ref<jni::JArrayClass<jni::JString>> __array = jni::JArrayClass<jni::JString>::newArray(__size);
287
+ for (size_t __i = 0; __i < __size; __i++) {
288
+ const auto& __element = trackIds[__i];
289
+ auto __elementJni = jni::make_jstring(__element);
290
+ __array->setElement(__i, *__elementJni);
291
+ }
292
+ return __array;
293
+ }());
294
+ return [&]() {
295
+ auto __promise = Promise<std::vector<TrackItem>>::create();
296
+ __result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
297
+ auto __result = jni::static_ref_cast<jni::JArrayClass<JTrackItem>>(__boxedResult);
298
+ __promise->resolve([&]() {
299
+ size_t __size = __result->size();
300
+ std::vector<TrackItem> __vector;
301
+ __vector.reserve(__size);
302
+ for (size_t __i = 0; __i < __size; __i++) {
303
+ auto __element = __result->getElement(__i);
304
+ __vector.push_back(__element->toCpp());
305
+ }
306
+ return __vector;
307
+ }());
308
+ });
309
+ __result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
310
+ jni::JniException __jniError(__throwable);
311
+ __promise->reject(std::make_exception_ptr(__jniError));
312
+ });
313
+ return __promise;
314
+ }();
315
+ }
316
+ std::shared_ptr<Promise<std::vector<TrackItem>>> JHybridTrackPlayerSpec::getTracksNeedingUrls() {
317
+ static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>()>("getTracksNeedingUrls");
318
+ auto __result = method(_javaPart);
319
+ return [&]() {
320
+ auto __promise = Promise<std::vector<TrackItem>>::create();
321
+ __result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
322
+ auto __result = jni::static_ref_cast<jni::JArrayClass<JTrackItem>>(__boxedResult);
323
+ __promise->resolve([&]() {
324
+ size_t __size = __result->size();
325
+ std::vector<TrackItem> __vector;
326
+ __vector.reserve(__size);
327
+ for (size_t __i = 0; __i < __size; __i++) {
328
+ auto __element = __result->getElement(__i);
329
+ __vector.push_back(__element->toCpp());
330
+ }
331
+ return __vector;
332
+ }());
333
+ });
334
+ __result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
335
+ jni::JniException __jniError(__throwable);
336
+ __promise->reject(std::make_exception_ptr(__jniError));
337
+ });
338
+ return __promise;
339
+ }();
340
+ }
341
+ std::shared_ptr<Promise<std::vector<TrackItem>>> JHybridTrackPlayerSpec::getNextTracks(double count) {
342
+ static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>(double /* count */)>("getNextTracks");
343
+ auto __result = method(_javaPart, count);
344
+ return [&]() {
345
+ auto __promise = Promise<std::vector<TrackItem>>::create();
346
+ __result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
347
+ auto __result = jni::static_ref_cast<jni::JArrayClass<JTrackItem>>(__boxedResult);
348
+ __promise->resolve([&]() {
349
+ size_t __size = __result->size();
350
+ std::vector<TrackItem> __vector;
351
+ __vector.reserve(__size);
352
+ for (size_t __i = 0; __i < __size; __i++) {
353
+ auto __element = __result->getElement(__i);
354
+ __vector.push_back(__element->toCpp());
355
+ }
356
+ return __vector;
357
+ }());
358
+ });
359
+ __result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
360
+ jni::JniException __jniError(__throwable);
361
+ __promise->reject(std::make_exception_ptr(__jniError));
362
+ });
363
+ return __promise;
364
+ }();
365
+ }
366
+ std::shared_ptr<Promise<double>> JHybridTrackPlayerSpec::getCurrentTrackIndex() {
367
+ static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>()>("getCurrentTrackIndex");
368
+ auto __result = method(_javaPart);
369
+ return [&]() {
370
+ auto __promise = Promise<double>::create();
371
+ __result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
372
+ auto __result = jni::static_ref_cast<jni::JDouble>(__boxedResult);
373
+ __promise->resolve(__result->value());
374
+ });
375
+ __result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
376
+ jni::JniException __jniError(__throwable);
377
+ __promise->reject(std::make_exception_ptr(__jniError));
378
+ });
379
+ return __promise;
380
+ }();
381
+ }
382
+ void JHybridTrackPlayerSpec::onTracksNeedUpdate(const std::function<void(const std::vector<TrackItem>& /* tracks */, double /* lookahead */)>& callback) {
383
+ static const auto method = javaClassStatic()->getMethod<void(jni::alias_ref<JFunc_void_std__vector_TrackItem__double::javaobject> /* callback */)>("onTracksNeedUpdate_cxx");
384
+ method(_javaPart, JFunc_void_std__vector_TrackItem__double_cxx::fromCpp(callback));
385
+ }
386
+ std::shared_ptr<Promise<void>> JHybridTrackPlayerSpec::setPlaybackSpeed(double speed) {
387
+ static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>(double /* speed */)>("setPlaybackSpeed");
388
+ auto __result = method(_javaPart, speed);
389
+ return [&]() {
390
+ auto __promise = Promise<void>::create();
391
+ __result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& /* unit */) {
392
+ __promise->resolve();
393
+ });
394
+ __result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
395
+ jni::JniException __jniError(__throwable);
396
+ __promise->reject(std::make_exception_ptr(__jniError));
397
+ });
398
+ return __promise;
399
+ }();
400
+ }
401
+ std::shared_ptr<Promise<double>> JHybridTrackPlayerSpec::getPlaybackSpeed() {
402
+ static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>()>("getPlaybackSpeed");
403
+ auto __result = method(_javaPart);
404
+ return [&]() {
405
+ auto __promise = Promise<double>::create();
406
+ __result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
407
+ auto __result = jni::static_ref_cast<jni::JDouble>(__boxedResult);
408
+ __promise->resolve(__result->value());
409
+ });
410
+ __result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
411
+ jni::JniException __jniError(__throwable);
412
+ __promise->reject(std::make_exception_ptr(__jniError));
413
+ });
414
+ return __promise;
415
+ }();
416
+ }
257
417
 
258
418
  } // namespace margelo::nitro::nitroplayer
@@ -75,6 +75,14 @@ namespace margelo::nitro::nitroplayer {
75
75
  void onAndroidAutoConnectionChange(const std::function<void(bool /* connected */)>& callback) override;
76
76
  bool isAndroidAutoConnected() override;
77
77
  bool setVolume(double volume) override;
78
+ std::shared_ptr<Promise<void>> updateTracks(const std::vector<TrackItem>& tracks) override;
79
+ std::shared_ptr<Promise<std::vector<TrackItem>>> getTracksById(const std::vector<std::string>& trackIds) override;
80
+ std::shared_ptr<Promise<std::vector<TrackItem>>> getTracksNeedingUrls() override;
81
+ std::shared_ptr<Promise<std::vector<TrackItem>>> getNextTracks(double count) override;
82
+ std::shared_ptr<Promise<double>> getCurrentTrackIndex() override;
83
+ void onTracksNeedUpdate(const std::function<void(const std::vector<TrackItem>& /* tracks */, double /* lookahead */)>& callback) override;
84
+ std::shared_ptr<Promise<void>> setPlaybackSpeed(double speed) override;
85
+ std::shared_ptr<Promise<double>> getPlaybackSpeed() override;
78
86
 
79
87
  private:
80
88
  friend HybridBase;
@@ -37,10 +37,13 @@ namespace margelo::nitro::nitroplayer {
37
37
  jni::local_ref<jni::JBoolean> carPlayEnabled = this->getFieldValue(fieldCarPlayEnabled);
38
38
  static const auto fieldShowInNotification = clazz->getField<jni::JBoolean>("showInNotification");
39
39
  jni::local_ref<jni::JBoolean> showInNotification = this->getFieldValue(fieldShowInNotification);
40
+ static const auto fieldLookaheadCount = clazz->getField<jni::JDouble>("lookaheadCount");
41
+ jni::local_ref<jni::JDouble> lookaheadCount = this->getFieldValue(fieldLookaheadCount);
40
42
  return PlayerConfig(
41
43
  androidAutoEnabled != nullptr ? std::make_optional(static_cast<bool>(androidAutoEnabled->value())) : std::nullopt,
42
44
  carPlayEnabled != nullptr ? std::make_optional(static_cast<bool>(carPlayEnabled->value())) : std::nullopt,
43
- showInNotification != nullptr ? std::make_optional(static_cast<bool>(showInNotification->value())) : std::nullopt
45
+ showInNotification != nullptr ? std::make_optional(static_cast<bool>(showInNotification->value())) : std::nullopt,
46
+ lookaheadCount != nullptr ? std::make_optional(lookaheadCount->value()) : std::nullopt
44
47
  );
45
48
  }
46
49
 
@@ -50,14 +53,15 @@ namespace margelo::nitro::nitroplayer {
50
53
  */
51
54
  [[maybe_unused]]
52
55
  static jni::local_ref<JPlayerConfig::javaobject> fromCpp(const PlayerConfig& value) {
53
- using JSignature = JPlayerConfig(jni::alias_ref<jni::JBoolean>, jni::alias_ref<jni::JBoolean>, jni::alias_ref<jni::JBoolean>);
56
+ using JSignature = JPlayerConfig(jni::alias_ref<jni::JBoolean>, jni::alias_ref<jni::JBoolean>, jni::alias_ref<jni::JBoolean>, jni::alias_ref<jni::JDouble>);
54
57
  static const auto clazz = javaClassStatic();
55
58
  static const auto create = clazz->getStaticMethod<JSignature>("fromCpp");
56
59
  return create(
57
60
  clazz,
58
61
  value.androidAutoEnabled.has_value() ? jni::JBoolean::valueOf(value.androidAutoEnabled.value()) : nullptr,
59
62
  value.carPlayEnabled.has_value() ? jni::JBoolean::valueOf(value.carPlayEnabled.value()) : nullptr,
60
- value.showInNotification.has_value() ? jni::JBoolean::valueOf(value.showInNotification.value()) : nullptr
63
+ value.showInNotification.has_value() ? jni::JBoolean::valueOf(value.showInNotification.value()) : nullptr,
64
+ value.lookaheadCount.has_value() ? jni::JDouble::valueOf(value.lookaheadCount.value()) : nullptr
61
65
  );
62
66
  }
63
67
  };
@@ -0,0 +1,80 @@
1
+ ///
2
+ /// Func_void_std__vector_TrackItem__double.kt
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © 2026 Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ package com.margelo.nitro.nitroplayer
9
+
10
+ import androidx.annotation.Keep
11
+ import com.facebook.jni.HybridData
12
+ import com.facebook.proguard.annotations.DoNotStrip
13
+ import dalvik.annotation.optimization.FastNative
14
+
15
+
16
+ /**
17
+ * Represents the JavaScript callback `(tracks: array, lookahead: number) => void`.
18
+ * This can be either implemented in C++ (in which case it might be a callback coming from JS),
19
+ * or in Kotlin/Java (in which case it is a native callback).
20
+ */
21
+ @DoNotStrip
22
+ @Keep
23
+ @Suppress("ClassName", "RedundantUnitReturnType")
24
+ fun interface Func_void_std__vector_TrackItem__double: (Array<TrackItem>, Double) -> Unit {
25
+ /**
26
+ * Call the given JS callback.
27
+ * @throws Throwable if the JS function itself throws an error, or if the JS function/runtime has already been deleted.
28
+ */
29
+ @DoNotStrip
30
+ @Keep
31
+ override fun invoke(tracks: Array<TrackItem>, lookahead: Double): Unit
32
+ }
33
+
34
+ /**
35
+ * Represents the JavaScript callback `(tracks: array, lookahead: number) => void`.
36
+ * This is implemented in C++, via a `std::function<...>`.
37
+ * The callback might be coming from JS.
38
+ */
39
+ @DoNotStrip
40
+ @Keep
41
+ @Suppress(
42
+ "KotlinJniMissingFunction", "unused",
43
+ "RedundantSuppression", "RedundantUnitReturnType", "FunctionName",
44
+ "ConvertSecondaryConstructorToPrimary", "ClassName", "LocalVariableName",
45
+ )
46
+ class Func_void_std__vector_TrackItem__double_cxx: Func_void_std__vector_TrackItem__double {
47
+ @DoNotStrip
48
+ @Keep
49
+ private val mHybridData: HybridData
50
+
51
+ @DoNotStrip
52
+ @Keep
53
+ private constructor(hybridData: HybridData) {
54
+ mHybridData = hybridData
55
+ }
56
+
57
+ @DoNotStrip
58
+ @Keep
59
+ override fun invoke(tracks: Array<TrackItem>, lookahead: Double): Unit
60
+ = invoke_cxx(tracks,lookahead)
61
+
62
+ @FastNative
63
+ private external fun invoke_cxx(tracks: Array<TrackItem>, lookahead: Double): Unit
64
+ }
65
+
66
+ /**
67
+ * Represents the JavaScript callback `(tracks: array, lookahead: number) => void`.
68
+ * This is implemented in Java/Kotlin, via a `(Array<TrackItem>, Double) -> Unit`.
69
+ * The callback is always coming from native.
70
+ */
71
+ @DoNotStrip
72
+ @Keep
73
+ @Suppress("ClassName", "RedundantUnitReturnType", "unused")
74
+ class Func_void_std__vector_TrackItem__double_java(private val function: (Array<TrackItem>, Double) -> Unit): Func_void_std__vector_TrackItem__double {
75
+ @DoNotStrip
76
+ @Keep
77
+ override fun invoke(tracks: Array<TrackItem>, lookahead: Double): Unit {
78
+ return this.function(tracks, lookahead)
79
+ }
80
+ }