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.
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerCore.kt +89 -115
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadFileManager.kt +10 -7
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadWorker.kt +30 -3
- package/ios/core/TrackPlayerCore.swift +101 -113
- package/ios/download/DownloadFileManager.swift +12 -4
- package/ios/download/DownloadManagerCore.swift +6 -1
- package/ios/media/MediaSessionManager.swift +181 -108
- package/lib/hooks/callbackManager.d.ts +18 -0
- package/lib/hooks/callbackManager.js +66 -0
- package/lib/hooks/useNowPlaying.js +30 -18
- package/lib/hooks/useOnPlaybackProgressChange.js +2 -2
- package/package.json +2 -2
- package/src/hooks/callbackManager.ts +87 -0
- package/src/hooks/useNowPlaying.ts +31 -19
- package/src/hooks/useOnPlaybackProgressChange.ts +2 -2
|
@@ -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
|
|
54
|
+
const fetchFullState = useCallback(async () => {
|
|
55
55
|
if (!isMounted.current) return
|
|
56
56
|
|
|
57
57
|
try {
|
|
58
58
|
const newState = await TrackPlayer.getState()
|
|
59
|
-
|
|
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
|
-
|
|
70
|
+
fetchFullState()
|
|
69
71
|
|
|
70
72
|
return () => {
|
|
71
73
|
isMounted.current = false
|
|
72
74
|
}
|
|
73
|
-
}, [
|
|
75
|
+
}, [fetchFullState])
|
|
74
76
|
|
|
75
|
-
// Subscribe to track changes
|
|
77
|
+
// Subscribe to track changes — full refresh
|
|
76
78
|
useEffect(() => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
return callbackManager.subscribeToTrackChange(() => {
|
|
80
|
+
fetchFullState()
|
|
79
81
|
})
|
|
82
|
+
}, [fetchFullState])
|
|
80
83
|
|
|
81
|
-
|
|
82
|
-
unsubscribe()
|
|
83
|
-
}
|
|
84
|
-
}, [updateState])
|
|
85
|
-
|
|
86
|
-
// Subscribe to playback state changes
|
|
84
|
+
// Subscribe to playback state changes — full refresh
|
|
87
85
|
useEffect(() => {
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
return callbackManager.subscribeToPlaybackState(() => {
|
|
87
|
+
fetchFullState()
|
|
90
88
|
})
|
|
89
|
+
}, [fetchFullState])
|
|
91
90
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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 {
|
|
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
|
-
|
|
20
|
+
return callbackManager.subscribeToPlaybackProgressChange(
|
|
21
21
|
(newPosition, newTotalDuration, newIsManuallySeeked) => {
|
|
22
22
|
setPosition(newPosition)
|
|
23
23
|
setTotalDuration(newTotalDuration)
|