react-native-nitro-player 0.4.0 → 0.5.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.
@@ -3,6 +3,12 @@ import type { TrackItem, TrackPlayerState, Reason } from '../types/PlayerQueue'
3
3
 
4
4
  type PlaybackStateCallback = (state: TrackPlayerState, reason?: Reason) => void
5
5
  type TrackChangeCallback = (track: TrackItem, reason?: Reason) => void
6
+ type PlaybackProgressCallback = (
7
+ position: number,
8
+ totalDuration: number,
9
+ isManuallySeeked?: boolean
10
+ ) => void
11
+ type SeekCallback = (position: number, totalDuration: number) => void
6
12
 
7
13
  /**
8
14
  * Internal subscription manager that allows multiple hooks to subscribe
@@ -12,8 +18,12 @@ type TrackChangeCallback = (track: TrackItem, reason?: Reason) => void
12
18
  class CallbackSubscriptionManager {
13
19
  private playbackStateSubscribers = new Set<PlaybackStateCallback>()
14
20
  private trackChangeSubscribers = new Set<TrackChangeCallback>()
21
+ private playbackProgressSubscribers = new Set<PlaybackProgressCallback>()
22
+ private seekSubscribers = new Set<SeekCallback>()
15
23
  private isPlaybackStateRegistered = false
16
24
  private isTrackChangeRegistered = false
25
+ private isPlaybackProgressRegistered = false
26
+ private isSeekRegistered = false
17
27
 
18
28
  /**
19
29
  * Subscribe to playback state changes
@@ -90,6 +100,83 @@ class CallbackSubscriptionManager {
90
100
  )
91
101
  }
92
102
  }
103
+
104
+ /**
105
+ * Subscribe to playback progress changes
106
+ * @returns Unsubscribe function
107
+ */
108
+ subscribeToPlaybackProgressChange(
109
+ callback: PlaybackProgressCallback
110
+ ): () => void {
111
+ this.playbackProgressSubscribers.add(callback)
112
+ this.ensurePlaybackProgressRegistered()
113
+
114
+ return () => {
115
+ this.playbackProgressSubscribers.delete(callback)
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Subscribe to seek events
121
+ * @returns Unsubscribe function
122
+ */
123
+ subscribeToSeek(callback: SeekCallback): () => void {
124
+ this.seekSubscribers.add(callback)
125
+ this.ensureSeekRegistered()
126
+
127
+ return () => {
128
+ this.seekSubscribers.delete(callback)
129
+ }
130
+ }
131
+
132
+ private ensurePlaybackProgressRegistered(): void {
133
+ if (this.isPlaybackProgressRegistered) return
134
+
135
+ try {
136
+ TrackPlayer.onPlaybackProgressChange(
137
+ (position, totalDuration, isManuallySeeked) => {
138
+ this.playbackProgressSubscribers.forEach((subscriber) => {
139
+ try {
140
+ subscriber(position, totalDuration, isManuallySeeked)
141
+ } catch (error) {
142
+ console.error(
143
+ '[CallbackManager] Error in playback progress subscriber:',
144
+ error
145
+ )
146
+ }
147
+ })
148
+ }
149
+ )
150
+ this.isPlaybackProgressRegistered = true
151
+ } catch (error) {
152
+ console.error(
153
+ '[CallbackManager] Failed to register playback progress callback:',
154
+ error
155
+ )
156
+ }
157
+ }
158
+
159
+ private ensureSeekRegistered(): void {
160
+ if (this.isSeekRegistered) return
161
+
162
+ try {
163
+ TrackPlayer.onSeek((position, totalDuration) => {
164
+ this.seekSubscribers.forEach((subscriber) => {
165
+ try {
166
+ subscriber(position, totalDuration)
167
+ } catch (error) {
168
+ console.error('[CallbackManager] Error in seek subscriber:', error)
169
+ }
170
+ })
171
+ })
172
+ this.isSeekRegistered = true
173
+ } catch (error) {
174
+ console.error(
175
+ '[CallbackManager] Failed to register seek callback:',
176
+ error
177
+ )
178
+ }
179
+ }
93
180
  }
94
181
 
95
182
  // Export singleton instance
@@ -51,12 +51,14 @@ export function useNowPlaying(): PlayerState {
51
51
  const [state, setState] = useState<PlayerState>(DEFAULT_STATE)
52
52
  const isMounted = useRef(true)
53
53
 
54
- const updateState = useCallback(async () => {
54
+ const fetchFullState = useCallback(async () => {
55
55
  if (!isMounted.current) return
56
56
 
57
57
  try {
58
58
  const newState = await TrackPlayer.getState()
59
- setState(newState)
59
+ if (isMounted.current) {
60
+ setState(newState)
61
+ }
60
62
  } catch (error) {
61
63
  console.error('[useNowPlaying] Error updating player state:', error)
62
64
  }
@@ -65,34 +67,44 @@ export function useNowPlaying(): PlayerState {
65
67
  // Initialize with current state
66
68
  useEffect(() => {
67
69
  isMounted.current = true
68
- updateState()
70
+ fetchFullState()
69
71
 
70
72
  return () => {
71
73
  isMounted.current = false
72
74
  }
73
- }, [updateState])
75
+ }, [fetchFullState])
74
76
 
75
- // Subscribe to track changes
77
+ // Subscribe to track changes — full refresh
76
78
  useEffect(() => {
77
- const unsubscribe = callbackManager.subscribeToTrackChange(() => {
78
- updateState()
79
+ return callbackManager.subscribeToTrackChange(() => {
80
+ fetchFullState()
79
81
  })
82
+ }, [fetchFullState])
80
83
 
81
- return () => {
82
- unsubscribe()
83
- }
84
- }, [updateState])
85
-
86
- // Subscribe to playback state changes
84
+ // Subscribe to playback state changes — full refresh
87
85
  useEffect(() => {
88
- const unsubscribe = callbackManager.subscribeToPlaybackState(() => {
89
- updateState()
86
+ return callbackManager.subscribeToPlaybackState(() => {
87
+ fetchFullState()
90
88
  })
89
+ }, [fetchFullState])
91
90
 
92
- return () => {
93
- unsubscribe()
94
- }
95
- }, [updateState])
91
+ // Subscribe to progress changes — lightweight position/duration update
92
+ useEffect(() => {
93
+ return callbackManager.subscribeToPlaybackProgressChange(
94
+ (currentPosition, totalDuration) => {
95
+ if (!isMounted.current) return
96
+ setState((prev) => ({ ...prev, currentPosition, totalDuration }))
97
+ }
98
+ )
99
+ }, [])
100
+
101
+ // Subscribe to seek events — lightweight position/duration update
102
+ useEffect(() => {
103
+ return callbackManager.subscribeToSeek((currentPosition, totalDuration) => {
104
+ if (!isMounted.current) return
105
+ setState((prev) => ({ ...prev, currentPosition, totalDuration }))
106
+ })
107
+ }, [])
96
108
 
97
109
  return state
98
110
  }
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useState } from 'react'
2
- import { TrackPlayer } from '../index'
2
+ import { callbackManager } from './callbackManager'
3
3
 
4
4
  /**
5
5
  * Hook to get the current playback progress
@@ -17,7 +17,7 @@ export function useOnPlaybackProgressChange(): {
17
17
  )
18
18
 
19
19
  useEffect(() => {
20
- TrackPlayer.onPlaybackProgressChange(
20
+ return callbackManager.subscribeToPlaybackProgressChange(
21
21
  (newPosition, newTotalDuration, newIsManuallySeeked) => {
22
22
  setPosition(newPosition)
23
23
  setTotalDuration(newTotalDuration)