expo-gliph-player 1.3.15 → 1.3.17

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.
@@ -20,12 +20,16 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
20
20
  private var playerItems: [AVPlayerItem] = []
21
21
  private var queue: [[String: Any]] = []
22
22
  private var currentIndex: Int = -1
23
- private var repeatMode: Int = 0
23
+ private var repeatMode: Int = 0 // 0=off, 1=track, 2=queue
24
24
  private var isSetup = false
25
25
  private var progressTimer: Timer?
26
26
  private var progressInterval: TimeInterval = 1.0
27
27
  private var options: [String: Any] = [:]
28
28
 
29
+ // ✅ AVPlayerLooper для повтора трека
30
+ private var playerLooper: AVPlayerLooper?
31
+ private var templateItem: AVPlayerItem?
32
+
29
33
  private let eventEmitter: EventEmitter
30
34
  private var timeObserver: Any?
31
35
  private var playerObservations: [NSKeyValueObservation] = []
@@ -260,6 +264,12 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
260
264
 
261
265
  @objc public func reset(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
262
266
  player?.pause()
267
+
268
+ // ✅ Уничтожаем looper
269
+ playerLooper?.disableLooping()
270
+ playerLooper = nil
271
+ templateItem = nil
272
+
263
273
  player?.removeAllItems()
264
274
  queue.removeAll()
265
275
  playerItems.removeAll()
@@ -304,8 +314,23 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
304
314
 
305
315
  @objc public func getRate() -> Float { return player?.rate ?? 1.0 }
306
316
 
317
+ // ✅ ИСПРАВЛЕНО: пересоздаём очередь при смене режима
307
318
  @objc public func setRepeatMode(_ mode: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
319
+ let oldMode = repeatMode
308
320
  repeatMode = mode
321
+
322
+ // ✅ Пересоздаём очередь с учётом нового режима
323
+ if oldMode != mode {
324
+ let wasPlaying = player?.timeControlStatus == .playing
325
+ rebuildPlayerQueue()
326
+ if wasPlaying {
327
+ player?.play()
328
+ }
329
+ }
330
+
331
+ // ✅ Отправляем событие
332
+ eventEmitter("playback-repeat-mode-changed", ["mode": mode])
333
+
309
334
  resolve(nil)
310
335
  }
311
336
 
@@ -420,12 +445,40 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
420
445
  ])
421
446
  }
422
447
 
448
+ // ✅ ИСПРАВЛЕНО: добавлен AVPlayerLooper для повторения трека
423
449
  private func rebuildPlayerQueue() {
424
450
  guard let player = player else { return }
451
+
452
+ // ✅ Уничтожаем старый looper
453
+ playerLooper?.disableLooping()
454
+ playerLooper = nil
455
+ templateItem = nil
456
+
425
457
  player.removeAllItems()
426
458
  playerItems.removeAll()
427
459
 
428
460
  let startIndex = max(0, currentIndex)
461
+
462
+ // ✅ РЕЖИМ ПОВТОРА ТРЕКА (RepeatMode.Track = 1)
463
+ if repeatMode == 1 && startIndex < queue.count {
464
+ let track = queue[startIndex]
465
+ guard let urlString = track["url"] as? String,
466
+ let url = URL(string: urlString) else { return }
467
+
468
+ // ✅ Создаём template item
469
+ let item = AVPlayerItem(url: url)
470
+ templateItem = item
471
+ playerItems.append(item)
472
+
473
+ // ✅ Создаём looper для бесконечного повтора
474
+ playerLooper = AVPlayerLooper(player: player, templateItem: item)
475
+
476
+ currentIndex = startIndex
477
+ updateNowPlayingInfo()
478
+ return
479
+ }
480
+
481
+ // ✅ ОБЫЧНАЯ ОЧЕРЕДЬ (RepeatMode.Off / RepeatMode.Queue)
429
482
  for i in startIndex..<queue.count {
430
483
  let track = queue[i]
431
484
  guard let urlString = track["url"] as? String,
@@ -632,10 +685,16 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
632
685
  }
633
686
  }
634
687
 
688
+ // ✅ ИСПРАВЛЕНО: AVPlayerLooper сам обрабатывает повтор трека
635
689
  @objc private func playerItemDidFinish(_ notification: Notification) {
636
690
  guard let finishedItem = notification.object as? AVPlayerItem,
637
691
  finishedItem === player?.currentItem else { return }
638
692
 
693
+ // ✅ Если режим повтора трека - AVPlayerLooper сам обрабатывает, выходим
694
+ if repeatMode == 1 {
695
+ return
696
+ }
697
+
639
698
  let nextIndex = currentIndex + 1
640
699
  let currentPosition = CMTimeGetSeconds(player?.currentTime() ?? .zero)
641
700
 
@@ -644,12 +703,6 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
644
703
  "position": currentPosition
645
704
  ])
646
705
 
647
- if repeatMode == 1 {
648
- player?.seek(to: .zero)
649
- player?.play()
650
- return
651
- }
652
-
653
706
  if nextIndex < queue.count {
654
707
  currentIndex = nextIndex
655
708
  updateNowPlayingInfo()
@@ -660,6 +713,7 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
660
713
  "lastPosition": 0.0,
661
714
  ])
662
715
  } else if repeatMode == 2 {
716
+ // ✅ ПОВТОР ВСЕЙ ОЧЕРЕДИ
663
717
  currentIndex = 0
664
718
  rebuildPlayerQueue()
665
719
  player?.play()
@@ -22,7 +22,7 @@ RCT_EXPORT_MODULE(RNGliphPlayer)
22
22
  if (self = [super init]) {
23
23
  __weak GliphPlayerModule *weakSelf = self;
24
24
  _player = [[GliphAudioPlayer alloc] initWithEventEmitter:^(NSString *event, NSDictionary *data) {
25
- [weakSelf sendEventWithName:event body:data];
25
+ [weakSelf safeSendEventWithName:event body:data];
26
26
  }];
27
27
  }
28
28
  return self;
@@ -41,6 +41,7 @@ RCT_EXPORT_MODULE(RNGliphPlayer)
41
41
  @"playback-queue-ended",
42
42
  @"playback-progress-updated",
43
43
  @"playback-metadata-received",
44
+ @"playback-repeat-mode-changed",
44
45
  @"remote-play",
45
46
  @"remote-pause",
46
47
  @"remote-stop",
@@ -61,6 +62,13 @@ RCT_EXPORT_MODULE(RNGliphPlayer)
61
62
  - (void)startObserving { _hasListeners = YES; }
62
63
  - (void)stopObserving { _hasListeners = NO; }
63
64
 
65
+ - (void)safeSendEventWithName:(NSString *)eventName body:(id)body {
66
+ if (!_hasListeners) {
67
+ return;
68
+ }
69
+ [self sendEventWithName:eventName body:body];
70
+ }
71
+
64
72
  RCT_EXPORT_METHOD(setupPlayer:(NSDictionary *)options
65
73
  resolve:(RCTPromiseResolveBlock)resolve
66
74
  reject:(RCTPromiseRejectBlock)reject) {
@@ -245,8 +253,6 @@ RCT_EXPORT_METHOD(updateOptions:(NSDictionary *)options
245
253
  [_player updateOptions:options resolve:resolve reject:reject];
246
254
  }
247
255
 
248
- // ── New Architecture (TurboModule) ────────────────────────────────────────────
249
-
250
256
  #ifdef RCT_NEW_ARCH_ENABLED
251
257
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
252
258
  (const facebook::react::ObjCTurboModule::InitParams &)params {
@@ -15,291 +15,298 @@ import { State } from './types';
15
15
 
16
16
  let _emitter = null;
17
17
  function getEmitter() {
18
- if (!NativeGliphPlayer) {
19
- throw new Error('[RNGliphPlayer] Native module not found. Is it linked correctly?');
20
- }
21
- if (!_emitter) {
22
- _emitter = new NativeEventEmitter(NativeGliphPlayer);
23
- }
24
- return _emitter;
18
+ if (!NativeGliphPlayer) {
19
+ throw new Error('[RNGliphPlayer] Native module not found. Is it linked correctly?');
20
+ }
21
+ if (!_emitter) {
22
+ _emitter = new NativeEventEmitter(NativeGliphPlayer);
23
+ }
24
+ return _emitter;
25
25
  }
26
26
 
27
27
  /** Resolve a require()'d asset to a URI string the native side can consume */
28
28
  function resolveAssetSource(source) {
29
- if (typeof source === 'number') {
30
- const {
31
- Image
32
- } = require('react-native');
33
- return Image.resolveAssetSource(source).uri;
34
- }
35
- return source;
29
+ if (typeof source === 'number') {
30
+ const {
31
+ Image
32
+ } = require('react-native');
33
+ return Image.resolveAssetSource(source).uri;
34
+ }
35
+ return source;
36
36
  }
37
37
 
38
38
  /** Serialize a Track to a plain object safe for the TurboModule bridge */
39
39
  function serializeTrack(track) {
40
- return {
41
- id: track.id ?? `track_${Date.now()}_${Math.random().toString(36).slice(2)}`,
42
- url: resolveAssetSource(track.url),
43
- title: track.title,
44
- artist: track.artist,
45
- album: track.album ?? '',
46
- artwork: track.artwork != null ? resolveAssetSource(track.artwork) : '',
47
- duration: track.duration ?? -1,
48
- genre: track.genre ?? '',
49
- date: track.date ?? '',
50
- description: track.description ?? '',
51
- rating: track.rating ?? 0,
52
- isLiveStream: track.isLiveStream ?? false,
53
- headers: track.headers ?? {},
54
- pitchAlgorithm: track.pitchAlgorithm ?? 0,
55
- userAgent: track.userAgent ?? ''
56
- };
40
+ return {
41
+ id: track.id ?? `track_${Date.now()}_${Math.random().toString(36).slice(2)}`,
42
+ url: resolveAssetSource(track.url),
43
+ title: track.title,
44
+ artist: track.artist,
45
+ album: track.album ?? '',
46
+ artwork: track.artwork != null ? resolveAssetSource(track.artwork) : '',
47
+ duration: track.duration ?? -1,
48
+ genre: track.genre ?? '',
49
+ date: track.date ?? '',
50
+ description: track.description ?? '',
51
+ rating: track.rating ?? 0,
52
+ isLiveStream: track.isLiveStream ?? false,
53
+ headers: track.headers ?? {},
54
+ pitchAlgorithm: track.pitchAlgorithm ?? 0,
55
+ userAgent: track.userAgent ?? ''
56
+ };
57
57
  }
58
58
  function checkModule() {
59
- if (!NativeGliphPlayer) {
60
- throw new Error('[RNGliphPlayer] Native module not found. ' + 'Ensure you have rebuilt the app after installing the library and ' + 'that you are not calling player methods before the JSI bridge is ready.');
61
- }
62
- return NativeGliphPlayer;
59
+ if (!NativeGliphPlayer) {
60
+ throw new Error('[RNGliphPlayer] Native module not found. ' + 'Ensure you have rebuilt the app after installing the library and ' + 'that you are not calling player methods before the JSI bridge is ready.');
61
+ }
62
+ return NativeGliphPlayer;
63
63
  }
64
64
 
65
65
  // ─── GliphPlayer API ─────────────────────────────────────────────────────────
66
66
 
67
67
  const GliphPlayer = {
68
- // ── Setup ──────────────────────────────────────────────────────────────────
68
+ // ── Setup ──────────────────────────────────────────────────────────────────
69
69
 
70
- /**
71
- * Initialize the player. Must be called once before any other method.
72
- * Safe to call multiple times — subsequent calls are no-ops.
73
- */
74
- async setupPlayer(options = {}) {
75
- if (!NativeGliphPlayer) {
76
- throw new Error('[RNGliphPlayer] Native module not ready. Ensure setup is called after app initialization.');
77
- }
78
- const opts = {
79
- minBuffer: options.minBuffer ?? 15,
80
- maxBuffer: options.maxBuffer ?? 50,
81
- playBuffer: options.playBuffer ?? 2.5,
82
- backBuffer: options.backBuffer ?? 0,
83
- maxCacheSize: options.maxCacheSize ?? 0,
84
- iosCategory: options.iosCategory ?? 'playback',
85
- iosCategoryMode: options.iosCategoryMode ?? 'default',
86
- iosCategoryOptions: options.iosCategoryOptions ?? [],
87
- waitForBuffer: options.waitForBuffer ?? true,
88
- autoHandleInterruptions: options.autoHandleInterruptions ?? false,
89
- autoUpdateMetadata: options.autoUpdateMetadata ?? true,
90
- progressUpdateEventInterval: options.progressUpdateEventInterval ?? 1.0,
91
- android: options.android ?? {}
92
- };
93
- return NativeGliphPlayer.setupPlayer(opts);
94
- },
95
- /**
96
- * Destroy the player and release all resources.
97
- */
98
- destroy() {
99
- checkModule().destroy();
100
- _emitter = null;
101
- },
102
- /**
103
- * Returns true if the background service is running (Android).
104
- */
105
- async isServiceRunning() {
106
- if (Platform.OS !== 'android') {
107
- return true;
108
- }
109
- return checkModule().isServiceRunning();
110
- },
111
- // ── Queue management ───────────────────────────────────────────────────────
70
+ /**
71
+ * Initialize the player. Must be called once before any other method.
72
+ * Safe to call multiple times — subsequent calls are no-ops.
73
+ */
74
+ async setupPlayer(options = {}) {
75
+ if (!NativeGliphPlayer) {
76
+ throw new Error('[RNGliphPlayer] Native module not ready. Ensure setup is called after app initialization.');
77
+ }
78
+ const opts = {
79
+ minBuffer: options.minBuffer ?? 15,
80
+ maxBuffer: options.maxBuffer ?? 50,
81
+ playBuffer: options.playBuffer ?? 2.5,
82
+ backBuffer: options.backBuffer ?? 0,
83
+ maxCacheSize: options.maxCacheSize ?? 0,
84
+ iosCategory: options.iosCategory ?? 'playback',
85
+ iosCategoryMode: options.iosCategoryMode ?? 'default',
86
+ iosCategoryOptions: options.iosCategoryOptions ?? [],
87
+ waitForBuffer: options.waitForBuffer ?? true,
88
+ autoHandleInterruptions: options.autoHandleInterruptions ?? false,
89
+ autoUpdateMetadata: options.autoUpdateMetadata ?? true,
90
+ progressUpdateEventInterval: options.progressUpdateEventInterval ?? 1.0,
91
+ android: options.android ?? {}
92
+ };
93
+ return NativeGliphPlayer.setupPlayer(opts);
94
+ },
95
+ /**
96
+ * Destroy the player and release all resources.
97
+ */
98
+ destroy() {
99
+ checkModule().destroy();
100
+ _emitter = null;
101
+ },
102
+ /**
103
+ * Returns true if the background service is running (Android).
104
+ */
105
+ async isServiceRunning() {
106
+ if (Platform.OS !== 'android') {
107
+ return true;
108
+ }
109
+ return checkModule().isServiceRunning();
110
+ },
111
+ // ── Queue management ───────────────────────────────────────────────────────
112
112
 
113
- /**
114
- * Add one or more tracks to the queue.
115
- * @param tracks Single track or array of tracks.
116
- * @param insertBeforeIndex Insert position. Defaults to end of queue.
117
- * @returns The index of the first inserted track.
118
- */
119
- async add(tracks, insertBeforeIndex) {
120
- const arr = Array.isArray(tracks) ? tracks : [tracks];
121
- const serialized = arr.map(serializeTrack);
122
- // Pass -1 as sentinel for "append to end" — Codegen doesn't support optional number params
123
- const result = await checkModule().add(serialized, insertBeforeIndex ?? -1);
124
- return result;
125
- },
126
- /**
127
- * Remove tracks by their IDs.
128
- */
129
- async remove(trackIds) {
130
- const ids = Array.isArray(trackIds) ? trackIds : [trackIds];
131
- return checkModule().remove(ids);
132
- },
133
- /**
134
- * Remove all tracks after the current one.
135
- */
136
- async removeUpcomingTracks() {
137
- return checkModule().removeUpcomingTracks();
138
- },
139
- /**
140
- * Skip to a specific queue index.
141
- */
142
- async skip(index, initialPosition) {
143
- return checkModule().skip(index, initialPosition ?? -1);
144
- },
145
- /**
146
- * Skip to the next track.
147
- */
148
- async skipToNext(initialPosition) {
149
- return checkModule().skipToNext(initialPosition ?? -1);
150
- },
151
- /**
152
- * Skip to the previous track.
153
- */
154
- async skipToPrevious(initialPosition) {
155
- return checkModule().skipToPrevious(initialPosition ?? -1);
156
- },
157
- /**
158
- * Move a track from one index to another.
159
- */
160
- async move(fromIndex, toIndex) {
161
- return checkModule().move(fromIndex, toIndex);
162
- },
163
- // ── Playback control ───────────────────────────────────────────────────────
113
+ /**
114
+ * Add one or more tracks to the queue.
115
+ * @param tracks Single track or array of tracks.
116
+ * @param insertBeforeIndex Insert position. Defaults to end of queue.
117
+ * @returns The index of the first inserted track.
118
+ */
119
+ async add(tracks, insertBeforeIndex) {
120
+ const arr = Array.isArray(tracks) ? tracks : [tracks];
121
+ const serialized = arr.map(serializeTrack);
122
+ // Pass -1 as sentinel for "append to end" — Codegen doesn't support optional number params
123
+ const result = await checkModule().add(serialized, insertBeforeIndex ?? -1);
124
+ return result;
125
+ },
126
+ /**
127
+ * Remove tracks by their IDs.
128
+ */
129
+ async remove(trackIds) {
130
+ const ids = Array.isArray(trackIds) ? trackIds : [trackIds];
131
+ return checkModule().remove(ids);
132
+ },
133
+ /**
134
+ * Remove all tracks after the current one.
135
+ */
136
+ async removeUpcomingTracks() {
137
+ return checkModule().removeUpcomingTracks();
138
+ },
139
+ /**
140
+ * Skip to a specific queue index.
141
+ * @param index - Index of the track to skip to
142
+ * @param initialPosition - Position in seconds to start from (default: -1 = start)
143
+ * @param autoPlay - Whether to automatically start playback (default: true)
144
+ */
145
+ async skip(index, initialPosition, autoPlay = true) {
146
+ return checkModule().skip(index, initialPosition ?? -1, autoPlay);
147
+ },
148
+ /**
149
+ * Skip to the next track.
150
+ * @param initialPosition - Position in seconds to start from (default: -1 = start)
151
+ * @param autoPlay - Whether to automatically start playback (default: true)
152
+ */
153
+ async skipToNext(initialPosition, autoPlay = true) {
154
+ return checkModule().skipToNext(initialPosition ?? -1, autoPlay);
155
+ },
156
+ /**
157
+ * Skip to the previous track.
158
+ * @param initialPosition - Position in seconds to start from (default: -1 = start)
159
+ * @param autoPlay - Whether to automatically start playback (default: true)
160
+ */
161
+ async skipToPrevious(initialPosition, autoPlay = true) {
162
+ return checkModule().skipToPrevious(initialPosition ?? -1, autoPlay);
163
+ },
164
+ /**
165
+ * Move a track from one index to another.
166
+ */
167
+ async move(fromIndex, toIndex) {
168
+ return checkModule().move(fromIndex, toIndex);
169
+ },
170
+ // ── Playback control ───────────────────────────────────────────────────────
164
171
 
165
- async play() {
166
- return checkModule().play();
167
- },
168
- async pause() {
169
- return checkModule().pause();
170
- },
171
- async stop() {
172
- return checkModule().stop();
173
- },
174
- /**
175
- * Stop playback and clear the queue.
176
- */
177
- async reset() {
178
- return checkModule().reset();
179
- },
180
- /**
181
- * Seek to an absolute position in seconds.
182
- */
183
- async seekTo(position) {
184
- return checkModule().seekTo(position);
185
- },
186
- /**
187
- * Seek by a relative offset in seconds (positive = forward, negative = back).
188
- */
189
- async seekBy(offset) {
190
- return checkModule().seekBy(offset);
191
- },
192
- /**
193
- * Set volume (0.0 – 1.0).
194
- */
195
- async setVolume(volume) {
196
- if (volume < 0 || volume > 1) {
197
- throw new Error('Volume must be between 0 and 1');
198
- }
199
- return checkModule().setVolume(volume);
200
- },
201
- async getVolume() {
202
- return checkModule().getVolume();
203
- },
204
- /**
205
- * Set playback rate (1.0 = normal speed).
206
- */
207
- async setRate(rate) {
208
- return checkModule().setRate(rate);
209
- },
210
- async getRate() {
211
- return checkModule().getRate();
212
- },
213
- async setRepeatMode(mode) {
214
- return checkModule().setRepeatMode(mode);
215
- },
216
- async getRepeatMode() {
217
- const mode = await checkModule().getRepeatMode();
218
- return mode;
219
- },
220
- // ── Queue getters ──────────────────────────────────────────────────────────
172
+ async play() {
173
+ return checkModule().play();
174
+ },
175
+ async pause() {
176
+ return checkModule().pause();
177
+ },
178
+ async stop() {
179
+ return checkModule().stop();
180
+ },
181
+ /**
182
+ * Stop playback and clear the queue.
183
+ */
184
+ async reset() {
185
+ return checkModule().reset();
186
+ },
187
+ /**
188
+ * Seek to an absolute position in seconds.
189
+ */
190
+ async seekTo(position) {
191
+ return checkModule().seekTo(position);
192
+ },
193
+ /**
194
+ * Seek by a relative offset in seconds (positive = forward, negative = back).
195
+ */
196
+ async seekBy(offset) {
197
+ return checkModule().seekBy(offset);
198
+ },
199
+ /**
200
+ * Set volume (0.0 – 1.0).
201
+ */
202
+ async setVolume(volume) {
203
+ if (volume < 0 || volume > 1) {
204
+ throw new Error('Volume must be between 0 and 1');
205
+ }
206
+ return checkModule().setVolume(volume);
207
+ },
208
+ async getVolume() {
209
+ return checkModule().getVolume();
210
+ },
211
+ /**
212
+ * Set playback rate (1.0 = normal speed).
213
+ */
214
+ async setRate(rate) {
215
+ return checkModule().setRate(rate);
216
+ },
217
+ async getRate() {
218
+ return checkModule().getRate();
219
+ },
220
+ async setRepeatMode(mode) {
221
+ return checkModule().setRepeatMode(mode);
222
+ },
223
+ async getRepeatMode() {
224
+ const mode = await checkModule().getRepeatMode();
225
+ return mode;
226
+ },
227
+ // ── Queue getters ──────────────────────────────────────────────────────────
221
228
 
222
- async getQueue() {
223
- const queue = await checkModule().getQueue();
224
- return queue;
225
- },
226
- async getActiveTrackIndex() {
227
- const idx = await checkModule().getActiveTrackIndex();
228
- // Native returns -1 as sentinel when no track is active
229
- return idx < 0 ? null : idx;
230
- },
231
- async getActiveTrack() {
232
- const track = await checkModule().getActiveTrack();
233
- return track;
234
- },
235
- async getTrack(index) {
236
- const track = await checkModule().getTrack(index);
237
- return track;
238
- },
239
- async getQueueSize() {
240
- return checkModule().getQueueSize();
241
- },
242
- // ── State / progress ───────────────────────────────────────────────────────
229
+ async getQueue() {
230
+ const queue = await checkModule().getQueue();
231
+ return queue;
232
+ },
233
+ async getActiveTrackIndex() {
234
+ const idx = await checkModule().getActiveTrackIndex();
235
+ // Native returns -1 as sentinel when no track is active
236
+ return idx < 0 ? null : idx;
237
+ },
238
+ async getActiveTrack() {
239
+ const track = await checkModule().getActiveTrack();
240
+ return track;
241
+ },
242
+ async getTrack(index) {
243
+ const track = await checkModule().getTrack(index);
244
+ return track;
245
+ },
246
+ async getQueueSize() {
247
+ return checkModule().getQueueSize();
248
+ },
249
+ // ── State / progress ───────────────────────────────────────────────────────
243
250
 
244
- async getPlaybackState() {
245
- const state = await checkModule().getPlaybackState();
246
- return state;
247
- },
248
- async getProgress() {
249
- const progress = await checkModule().getProgress();
250
- return progress;
251
- },
252
- // ── Metadata ───────────────────────────────────────────────────────────────
251
+ async getPlaybackState() {
252
+ const state = await checkModule().getPlaybackState();
253
+ return state;
254
+ },
255
+ async getProgress() {
256
+ const progress = await checkModule().getProgress();
257
+ return progress;
258
+ },
259
+ // ── Metadata ───────────────────────────────────────────────────────────────
253
260
 
254
- async updateMetadataForTrack(index, metadata) {
255
- return checkModule().updateMetadataForTrack(index, metadata);
256
- },
257
- async clearNowPlayingMetadata() {
258
- return checkModule().clearNowPlayingMetadata();
259
- },
260
- async updateNowPlayingMetadata(metadata) {
261
- return checkModule().updateNowPlayingMetadata(metadata);
262
- },
263
- // ── Options / notification ─────────────────────────────────────────────────
261
+ async updateMetadataForTrack(index, metadata) {
262
+ return checkModule().updateMetadataForTrack(index, metadata);
263
+ },
264
+ async clearNowPlayingMetadata() {
265
+ return checkModule().clearNowPlayingMetadata();
266
+ },
267
+ async updateNowPlayingMetadata(metadata) {
268
+ return checkModule().updateNowPlayingMetadata(metadata);
269
+ },
270
+ // ── Options / notification ─────────────────────────────────────────────────
264
271
 
265
- /**
266
- * Configure notification capabilities, jump intervals, etc.
267
- */
268
- async updateOptions(options) {
269
- return checkModule().updateOptions(options);
270
- },
271
- // ── Event subscription ─────────────────────────────────────────────────────
272
+ /**
273
+ * Configure notification capabilities, jump intervals, etc.
274
+ */
275
+ async updateOptions(options) {
276
+ return checkModule().updateOptions(options);
277
+ },
278
+ // ── Event subscription ─────────────────────────────────────────────────────
272
279
 
273
- /**
274
- * Subscribe to a player event.
275
- * Returns an unsubscribe function — call it to remove the listener.
276
- *
277
- * @example
278
- * const unsub = GliphPlayer.addEventListener(Event.PlaybackState, ({ state }) => {
279
- * console.log('State:', state);
280
- * });
281
- * // later:
282
- * unsub();
283
- */
284
- addEventListener(event, listener) {
285
- const subscription = getEmitter().addListener(event, listener);
286
- return () => subscription.remove();
287
- }
280
+ /**
281
+ * Subscribe to a player event.
282
+ * Returns an unsubscribe function — call it to remove the listener.
283
+ *
284
+ * @example
285
+ * const unsub = GliphPlayer.addEventListener(Event.PlaybackState, ({ state }) => {
286
+ * console.log('State:', state);
287
+ * });
288
+ * // later:
289
+ * unsub();
290
+ */
291
+ addEventListener(event, listener) {
292
+ const subscription = getEmitter().addListener(event, listener);
293
+ return () => subscription.remove();
294
+ }
288
295
  };
289
296
  export default GliphPlayer;
290
297
 
291
298
  // ─── Convenience state helpers ────────────────────────────────────────────────
292
299
 
293
300
  export function isPlaying(state) {
294
- return state === State.Playing;
301
+ return state === State.Playing;
295
302
  }
296
303
  export function isPaused(state) {
297
- return state === State.Paused;
304
+ return state === State.Paused;
298
305
  }
299
306
  export function isBuffering(state) {
300
- return state === State.Buffering || state === State.Loading;
307
+ return state === State.Buffering || state === State.Loading;
301
308
  }
302
309
  export function isStopped(state) {
303
- return state === State.Stopped || state === State.None;
310
+ return state === State.Stopped || state === State.None;
304
311
  }
305
312
  //# sourceMappingURL=GliphPlayer.js.map
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "name": "Aleksey Ostrikov",
5
5
  "email": "alex303606@gmail.com"
6
6
  },
7
- "version": "1.3.15",
7
+ "version": "1.3.17",
8
8
  "description": "Fixed version of react-native-gliph-player with Expo compatibility",
9
9
  "main": "app.plugin.js",
10
10
  "module": "lib/module/index.js",