@5stones/react-native-audio-browser 0.1.4 → 0.1.5
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/audiobrowser/player/MediaFactory.kt +11 -71
- package/android/src/main/java/com/audiobrowser/player/TransformingDataSource.kt +125 -0
- package/ios/Browser/BrowserManager.swift +17 -2
- package/ios/TrackPlayer.swift +150 -31
- package/lib/commonjs/features/browser.js.map +1 -1
- package/lib/commonjs/features/equalizer.js.map +1 -1
- package/lib/commonjs/features/errors.js.map +1 -1
- package/lib/commonjs/features/favorites.js.map +1 -1
- package/lib/commonjs/features/metadata.js.map +1 -1
- package/lib/commonjs/features/nowPlaying.js.map +1 -1
- package/lib/commonjs/features/output.js.map +1 -1
- package/lib/commonjs/features/playback/state.js.map +1 -1
- package/lib/commonjs/features/player/options.js.map +1 -1
- package/lib/commonjs/features/queue/activeTrack.js.map +1 -1
- package/lib/commonjs/features/queue/queue.js +1 -1
- package/lib/commonjs/features/queue/queue.js.map +1 -1
- package/lib/commonjs/features/remoteControls.js.map +1 -1
- package/lib/commonjs/utils/useDebug.js.map +1 -1
- package/lib/commonjs/utils/validation.js +23 -0
- package/lib/commonjs/utils/validation.js.map +1 -0
- package/lib/commonjs/web/NativeAudioBrowser.js +53 -15
- package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
- package/lib/commonjs/web/SimpleRouter.js +5 -4
- package/lib/commonjs/web/SimpleRouter.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/Player.js +49 -24
- package/lib/commonjs/web/TrackPlayer/Player.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/PlaylistPlayer.js +54 -45
- package/lib/commonjs/web/TrackPlayer/PlaylistPlayer.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/State.js.map +1 -1
- package/lib/commonjs/web/browser/BrowserManager.js +10 -17
- package/lib/commonjs/web/browser/BrowserManager.js.map +1 -1
- package/lib/commonjs/web/browser/FavoriteManager.js.map +1 -1
- package/lib/commonjs/web/browser/NavigationErrorManager.js.map +1 -1
- package/lib/commonjs/web/browser/SearchManager.js.map +1 -1
- package/lib/commonjs/web/http/HttpClient.js +15 -2
- package/lib/commonjs/web/http/HttpClient.js.map +1 -1
- package/lib/commonjs/web/http/RequestConfigBuilder.js.map +1 -1
- package/lib/commonjs/web/player/NowPlayingManager.js +9 -0
- package/lib/commonjs/web/player/NowPlayingManager.js.map +1 -1
- package/lib/commonjs/web/player/OptionsManager.js +1 -1
- package/lib/commonjs/web/player/OptionsManager.js.map +1 -1
- package/lib/commonjs/web/util/BrowserPathHelper.js.map +1 -1
- package/lib/module/features/browser.js.map +1 -1
- package/lib/module/features/equalizer.js.map +1 -1
- package/lib/module/features/errors.js.map +1 -1
- package/lib/module/features/favorites.js.map +1 -1
- package/lib/module/features/metadata.js.map +1 -1
- package/lib/module/features/nowPlaying.js +1 -0
- package/lib/module/features/nowPlaying.js.map +1 -1
- package/lib/module/features/output.js.map +1 -1
- package/lib/module/features/playback/state.js.map +1 -1
- package/lib/module/features/player/options.js.map +1 -1
- package/lib/module/features/queue/activeTrack.js.map +1 -1
- package/lib/module/features/queue/queue.js +1 -1
- package/lib/module/features/queue/queue.js.map +1 -1
- package/lib/module/features/remoteControls.js.map +1 -1
- package/lib/module/utils/useDebug.js.map +1 -1
- package/lib/module/utils/validation.js +18 -0
- package/lib/module/utils/validation.js.map +1 -0
- package/lib/module/web/NativeAudioBrowser.js +53 -15
- package/lib/module/web/NativeAudioBrowser.js.map +1 -1
- package/lib/module/web/SimpleRouter.js +5 -4
- package/lib/module/web/SimpleRouter.js.map +1 -1
- package/lib/module/web/TrackPlayer/Player.js +49 -24
- package/lib/module/web/TrackPlayer/Player.js.map +1 -1
- package/lib/module/web/TrackPlayer/PlaylistPlayer.js +54 -45
- package/lib/module/web/TrackPlayer/PlaylistPlayer.js.map +1 -1
- package/lib/module/web/TrackPlayer/State.js.map +1 -1
- package/lib/module/web/browser/BrowserManager.js +10 -17
- package/lib/module/web/browser/BrowserManager.js.map +1 -1
- package/lib/module/web/browser/FavoriteManager.js.map +1 -1
- package/lib/module/web/browser/NavigationErrorManager.js.map +1 -1
- package/lib/module/web/browser/SearchManager.js.map +1 -1
- package/lib/module/web/http/HttpClient.js +15 -2
- package/lib/module/web/http/HttpClient.js.map +1 -1
- package/lib/module/web/http/RequestConfigBuilder.js.map +1 -1
- package/lib/module/web/player/NowPlayingManager.js +9 -0
- package/lib/module/web/player/NowPlayingManager.js.map +1 -1
- package/lib/module/web/player/OptionsManager.js +1 -1
- package/lib/module/web/player/OptionsManager.js.map +1 -1
- package/lib/module/web/util/BrowserPathHelper.js.map +1 -1
- package/lib/typescript/src/features/browser.d.ts.map +1 -1
- package/lib/typescript/src/features/equalizer.d.ts.map +1 -1
- package/lib/typescript/src/features/errors.d.ts.map +1 -1
- package/lib/typescript/src/features/favorites.d.ts.map +1 -1
- package/lib/typescript/src/features/metadata.d.ts +1 -1
- package/lib/typescript/src/features/metadata.d.ts.map +1 -1
- package/lib/typescript/src/features/nowPlaying.d.ts +1 -1
- package/lib/typescript/src/features/nowPlaying.d.ts.map +1 -1
- package/lib/typescript/src/features/output.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/state.d.ts +1 -1
- package/lib/typescript/src/features/playback/state.d.ts.map +1 -1
- package/lib/typescript/src/features/player/options.d.ts +1 -1
- package/lib/typescript/src/features/player/options.d.ts.map +1 -1
- package/lib/typescript/src/features/queue/activeTrack.d.ts.map +1 -1
- package/lib/typescript/src/features/queue/queue.d.ts.map +1 -1
- package/lib/typescript/src/features/remoteControls.d.ts.map +1 -1
- package/lib/typescript/src/specs/audio-browser.nitro.d.ts.map +1 -1
- package/lib/typescript/src/utils/useDebug.d.ts +1 -1
- package/lib/typescript/src/utils/useDebug.d.ts.map +1 -1
- package/lib/typescript/src/utils/validation.d.ts +3 -0
- package/lib/typescript/src/utils/validation.d.ts.map +1 -0
- package/lib/typescript/src/web/NativeAudioBrowser.d.ts +6 -1
- package/lib/typescript/src/web/NativeAudioBrowser.d.ts.map +1 -1
- package/lib/typescript/src/web/SimpleRouter.d.ts.map +1 -1
- package/lib/typescript/src/web/TrackPlayer/Player.d.ts +7 -19
- package/lib/typescript/src/web/TrackPlayer/Player.d.ts.map +1 -1
- package/lib/typescript/src/web/TrackPlayer/PlaylistPlayer.d.ts +3 -3
- package/lib/typescript/src/web/TrackPlayer/PlaylistPlayer.d.ts.map +1 -1
- package/lib/typescript/src/web/browser/BrowserManager.d.ts.map +1 -1
- package/lib/typescript/src/web/browser/FavoriteManager.d.ts.map +1 -1
- package/lib/typescript/src/web/browser/NavigationErrorManager.d.ts.map +1 -1
- package/lib/typescript/src/web/browser/SearchManager.d.ts +1 -1
- package/lib/typescript/src/web/browser/SearchManager.d.ts.map +1 -1
- package/lib/typescript/src/web/http/HttpClient.d.ts.map +1 -1
- package/lib/typescript/src/web/http/RequestConfigBuilder.d.ts.map +1 -1
- package/lib/typescript/src/web/player/NowPlayingManager.d.ts.map +1 -1
- package/lib/typescript/src/web/player/OptionsManager.d.ts.map +1 -1
- package/lib/typescript/src/web/util/BrowserPathHelper.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/features/browser.ts +1 -1
- package/src/features/equalizer.ts +1 -1
- package/src/features/errors.ts +1 -1
- package/src/features/favorites.ts +1 -1
- package/src/features/metadata.ts +1 -1
- package/src/features/nowPlaying.ts +1 -1
- package/src/features/output.ts +1 -1
- package/src/features/playback/state.ts +1 -1
- package/src/features/player/options.ts +2 -2
- package/src/features/queue/activeTrack.ts +1 -1
- package/src/features/queue/queue.ts +2 -2
- package/src/features/remoteControls.ts +2 -2
- package/src/specs/audio-browser.nitro.ts +0 -1
- package/src/utils/useDebug.ts +6 -6
- package/src/utils/validation.ts +27 -0
- package/src/web/NativeAudioBrowser.ts +137 -58
- package/src/web/SimpleRouter.ts +24 -9
- package/src/web/TrackPlayer/Player.ts +58 -30
- package/src/web/TrackPlayer/PlaylistPlayer.ts +72 -63
- package/src/web/TrackPlayer/RepeatMode.ts +1 -1
- package/src/web/TrackPlayer/State.ts +9 -9
- package/src/web/browser/BrowserManager.ts +124 -67
- package/src/web/browser/FavoriteManager.ts +5 -3
- package/src/web/browser/NavigationErrorManager.ts +15 -8
- package/src/web/browser/SearchManager.ts +17 -11
- package/src/web/http/HttpClient.ts +25 -7
- package/src/web/http/RequestConfigBuilder.ts +29 -13
- package/src/web/player/NowPlayingManager.ts +13 -7
- package/src/web/player/OptionsManager.ts +7 -6
- package/src/web/util/BrowserPathHelper.ts +3 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { nativeBrowser } from '../../native'
|
|
2
1
|
import type { Track } from '../../types'
|
|
2
|
+
import { nativeBrowser } from '../../native'
|
|
3
3
|
import { NativeUpdatedValue } from '../../utils/NativeUpdatedValue'
|
|
4
4
|
import { useNativeUpdatedValue } from '../../utils/useNativeUpdatedValue'
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { nativeBrowser } from '../../native'
|
|
2
1
|
import type { Track } from '../../types'
|
|
2
|
+
import { nativeBrowser } from '../../native'
|
|
3
3
|
import { NativeUpdatedValue } from '../../utils/NativeUpdatedValue'
|
|
4
4
|
import { useNativeUpdatedValue } from '../../utils/useNativeUpdatedValue'
|
|
5
5
|
|
|
@@ -31,7 +31,7 @@ export function add(tracks: Track[], insertBeforeIndex?: number): void
|
|
|
31
31
|
* By default the track will be added to the end of the queue.
|
|
32
32
|
*/
|
|
33
33
|
export function add(track: Track, insertBeforeIndex?: number): void
|
|
34
|
-
export function add(tracks: Track | Track[], insertBeforeIndex
|
|
34
|
+
export function add(tracks: Track | Track[], insertBeforeIndex?: number): void {
|
|
35
35
|
const addTracks = Array.isArray(tracks) ? tracks : [tracks]
|
|
36
36
|
if (addTracks.length > 0) {
|
|
37
37
|
nativeBrowser.add(addTracks, insertBeforeIndex)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { nativeBrowser } from '../native'
|
|
2
|
-
import { LazyNativeEmitter } from '../utils/LazyNativeEmitter'
|
|
3
1
|
import type {
|
|
4
2
|
HeartRating,
|
|
5
3
|
PercentageRating,
|
|
6
4
|
StarRating,
|
|
7
5
|
ThumbsRating
|
|
8
6
|
} from './rating'
|
|
7
|
+
import { nativeBrowser } from '../native'
|
|
8
|
+
import { LazyNativeEmitter } from '../utils/LazyNativeEmitter'
|
|
9
9
|
|
|
10
10
|
// MARK: - Event Interfaces
|
|
11
11
|
|
package/src/utils/useDebug.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { useEffect, useRef, useSyncExternalStore } from 'react'
|
|
2
|
+
import type { NowPlayingMetadata } from '../features/metadata'
|
|
3
|
+
import type { PlayingState } from '../features/playback/playing'
|
|
4
|
+
import type { PlaybackState } from '../features/playback/state'
|
|
5
|
+
import type { Options } from '../features/player/options'
|
|
6
|
+
import type { RepeatMode } from '../features/queue/repeatMode'
|
|
7
|
+
import type { Track } from '../types'
|
|
2
8
|
import { useContent, usePath } from '../features/browser'
|
|
3
9
|
import { useNavigationError, usePlaybackError } from '../features/errors'
|
|
4
10
|
import {
|
|
@@ -8,21 +14,15 @@ import {
|
|
|
8
14
|
} from '../features/metadata'
|
|
9
15
|
import { useOnline } from '../features/network'
|
|
10
16
|
import { useNowPlaying } from '../features/nowPlaying'
|
|
11
|
-
import type { PlayingState } from '../features/playback/playing'
|
|
12
17
|
import { usePlayingState } from '../features/playback/playing'
|
|
13
18
|
import { usePlayWhenReady } from '../features/playback/playWhenReady'
|
|
14
19
|
import { useProgress } from '../features/playback/progress'
|
|
15
|
-
import type { PlaybackState } from '../features/playback/state'
|
|
16
20
|
import { usePlayback } from '../features/playback/state'
|
|
17
|
-
import type { Options } from '../features/player/options'
|
|
18
21
|
import { useOptions } from '../features/player/options'
|
|
19
22
|
import { useActiveTrack } from '../features/queue/activeTrack'
|
|
20
23
|
import { useQueue } from '../features/queue/queue'
|
|
21
|
-
import type { RepeatMode } from '../features/queue/repeatMode'
|
|
22
24
|
import { useRepeatMode } from '../features/queue/repeatMode'
|
|
23
25
|
import { useShuffle } from '../features/queue/shuffle'
|
|
24
|
-
import type { NowPlayingMetadata } from '../features/metadata'
|
|
25
|
-
import type { Track } from '../types'
|
|
26
26
|
|
|
27
27
|
// MARK: - Types
|
|
28
28
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
function isNotNullish<T>(val: T | undefined | null | void): val is T {
|
|
2
|
+
return val !== undefined && val !== null
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function assert(
|
|
6
|
+
condition: any,
|
|
7
|
+
message = 'assertion error'
|
|
8
|
+
): asserts condition {
|
|
9
|
+
if (!condition) {
|
|
10
|
+
throw new Error(message)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function assertNotNullish<T>(
|
|
15
|
+
val: T | undefined | null | void,
|
|
16
|
+
message = 'Expected value to not be nullish'
|
|
17
|
+
): asserts val is T {
|
|
18
|
+
assert(isNotNullish(val), message)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function assertedNotNullish<T>(
|
|
22
|
+
val: T | undefined | null | void,
|
|
23
|
+
message = 'Expected value to not be nullish'
|
|
24
|
+
): T {
|
|
25
|
+
assertNotNullish(val, message)
|
|
26
|
+
return val
|
|
27
|
+
}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import type { AudioBrowser as AudioBrowserSpec, IosOutput } from '../specs/audio-browser.nitro'
|
|
2
|
-
import type {
|
|
3
|
-
ResolvedTrack,
|
|
4
|
-
Track,
|
|
5
|
-
} from '../types'
|
|
6
|
-
import type { NativeBrowserConfiguration } from '../types/browser-native'
|
|
7
1
|
import type {
|
|
8
2
|
PlaybackErrorEvent,
|
|
9
3
|
PlaybackError,
|
|
@@ -40,23 +34,32 @@ import type {
|
|
|
40
34
|
BatteryOptimizationStatus,
|
|
41
35
|
BatteryOptimizationStatusChangedEvent,
|
|
42
36
|
BatteryWarningPendingChangedEvent,
|
|
43
|
-
PartialSetupPlayerOptions
|
|
37
|
+
PartialSetupPlayerOptions
|
|
44
38
|
} from '../features'
|
|
45
|
-
import {
|
|
46
|
-
|
|
39
|
+
import type {
|
|
40
|
+
AudioBrowser as AudioBrowserSpec,
|
|
41
|
+
IosOutput
|
|
42
|
+
} from '../specs/audio-browser.nitro'
|
|
43
|
+
import type { ResolvedTrack, Track } from '../types'
|
|
44
|
+
import type { NativeBrowserConfiguration } from '../types/browser-native'
|
|
47
45
|
import { BrowserManager } from './browser/BrowserManager'
|
|
48
46
|
import { FavoriteManager } from './browser/FavoriteManager'
|
|
49
47
|
import { NavigationErrorManager } from './browser/NavigationErrorManager'
|
|
50
48
|
import { SearchManager } from './browser/SearchManager'
|
|
51
|
-
import {
|
|
52
|
-
import { NowPlayingManager } from './player/NowPlayingManager'
|
|
49
|
+
import { HttpClient } from './http/HttpClient'
|
|
53
50
|
import { RequestConfigBuilder } from './http/RequestConfigBuilder'
|
|
51
|
+
import { NowPlayingManager } from './player/NowPlayingManager'
|
|
52
|
+
import { OptionsManager } from './player/OptionsManager'
|
|
53
|
+
import { PlaylistPlayer, SleepTimerManager } from './TrackPlayer'
|
|
54
54
|
import { BrowserPathHelper } from './util/BrowserPathHelper'
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Web implementation of AudioBrowser (unified browser + player)
|
|
58
58
|
*/
|
|
59
|
-
export class NativeAudioBrowser
|
|
59
|
+
export class NativeAudioBrowser
|
|
60
|
+
extends PlaylistPlayer
|
|
61
|
+
implements AudioBrowserSpec
|
|
62
|
+
{
|
|
60
63
|
// HybridObject stuff
|
|
61
64
|
readonly name = 'WebAudioBrowser'
|
|
62
65
|
equals() {
|
|
@@ -83,8 +86,10 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
83
86
|
private nowPlayingManager: NowPlayingManager
|
|
84
87
|
|
|
85
88
|
// Player state
|
|
89
|
+
private currentLoadId = 0
|
|
86
90
|
private progressUpdateEventInterval: NodeJS.Timeout | undefined
|
|
87
|
-
private _online: boolean =
|
|
91
|
+
private _online: boolean =
|
|
92
|
+
typeof navigator !== 'undefined' ? navigator.onLine : true
|
|
88
93
|
private onlineHandler: (() => void) | undefined
|
|
89
94
|
private offlineHandler: (() => void) | undefined
|
|
90
95
|
private sleepTimer = new (class extends SleepTimerManager {
|
|
@@ -128,17 +133,24 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
128
133
|
onContentChanged: (content: ResolvedTrack | undefined) => void = () => {}
|
|
129
134
|
onTabsChanged: (tabs: Track[]) => void = () => {}
|
|
130
135
|
onNavigationError: (data: NavigationErrorEvent) => void = () => {}
|
|
131
|
-
onFormattedNavigationError: (
|
|
136
|
+
onFormattedNavigationError: (
|
|
137
|
+
formattedError: FormattedNavigationError | undefined
|
|
138
|
+
) => void = () => {}
|
|
132
139
|
|
|
133
140
|
// MARK: Player event callbacks
|
|
134
141
|
onChapterMetadata: (chapters: ChapterMetadata[]) => void = () => {}
|
|
135
142
|
onTrackMetadata: (metadata: TrackMetadata) => void = () => {}
|
|
136
143
|
onTimedMetadata: (metadata: TimedMetadata) => void = () => {}
|
|
137
|
-
onPlaybackActiveTrackChanged: (
|
|
144
|
+
onPlaybackActiveTrackChanged: (
|
|
145
|
+
data: PlaybackActiveTrackChangedEvent
|
|
146
|
+
) => void = () => {}
|
|
138
147
|
onPlaybackError: (data: PlaybackErrorEvent) => void = () => {}
|
|
139
|
-
onPlaybackPlayWhenReadyChanged: (
|
|
148
|
+
onPlaybackPlayWhenReadyChanged: (
|
|
149
|
+
data: PlaybackPlayWhenReadyChangedEvent
|
|
150
|
+
) => void = () => {}
|
|
140
151
|
onPlaybackPlayingState: (data: PlayingState) => void = () => {}
|
|
141
|
-
onPlaybackProgressUpdated: (data: PlaybackProgressUpdatedEvent) => void =
|
|
152
|
+
onPlaybackProgressUpdated: (data: PlaybackProgressUpdatedEvent) => void =
|
|
153
|
+
() => {}
|
|
142
154
|
onPlaybackQueueEnded: (data: PlaybackQueueEndedEvent) => void = () => {}
|
|
143
155
|
onPlaybackQueueChanged: (queue: Track[]) => void = () => {}
|
|
144
156
|
onPlaybackRepeatModeChanged: (data: RepeatModeChangedEvent) => void = () => {}
|
|
@@ -165,25 +177,36 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
165
177
|
onNowPlayingChanged: (metadata: NowPlayingMetadata) => void = () => {}
|
|
166
178
|
onOnlineChanged: (online: boolean) => void = () => {}
|
|
167
179
|
onEqualizerChanged: (settings: EqualizerSettings) => void = () => {}
|
|
168
|
-
onBatteryWarningPendingChanged: (
|
|
169
|
-
|
|
180
|
+
onBatteryWarningPendingChanged: (
|
|
181
|
+
event: BatteryWarningPendingChangedEvent
|
|
182
|
+
) => void = () => {}
|
|
183
|
+
onBatteryOptimizationStatusChanged: (
|
|
184
|
+
event: BatteryOptimizationStatusChangedEvent
|
|
185
|
+
) => void = () => {}
|
|
170
186
|
onSystemVolumeChanged: (volume: number) => void = () => {}
|
|
171
187
|
onIosOutputChanged: (output: IosOutput) => void = () => {}
|
|
172
188
|
|
|
173
189
|
// MARK: Remote handlers
|
|
174
190
|
handleRemoteBookmark: (() => void) | undefined = undefined
|
|
175
191
|
handleRemoteDislike: (() => void) | undefined = undefined
|
|
176
|
-
handleRemoteJumpBackward:
|
|
177
|
-
|
|
192
|
+
handleRemoteJumpBackward:
|
|
193
|
+
| ((event: RemoteJumpBackwardEvent) => void)
|
|
194
|
+
| undefined = undefined
|
|
195
|
+
handleRemoteJumpForward:
|
|
196
|
+
| ((event: RemoteJumpForwardEvent) => void)
|
|
197
|
+
| undefined = undefined
|
|
178
198
|
handleRemoteLike: (() => void) | undefined = undefined
|
|
179
199
|
handleRemoteNext: (() => void) | undefined = undefined
|
|
180
200
|
handleRemotePause: (() => void) | undefined = undefined
|
|
181
201
|
handleRemotePlay: (() => void) | undefined = undefined
|
|
182
|
-
handleRemotePlayId: ((event: RemotePlayIdEvent) => void) | undefined =
|
|
183
|
-
|
|
202
|
+
handleRemotePlayId: ((event: RemotePlayIdEvent) => void) | undefined =
|
|
203
|
+
undefined
|
|
204
|
+
handleRemotePlaySearch: ((event: RemotePlaySearchEvent) => void) | undefined =
|
|
205
|
+
undefined
|
|
184
206
|
handleRemotePrevious: (() => void) | undefined = undefined
|
|
185
207
|
handleRemoteSeek: ((event: RemoteSeekEvent) => void) | undefined = undefined
|
|
186
|
-
handleRemoteSetRating: ((event: RemoteSetRatingEvent) => void) | undefined =
|
|
208
|
+
handleRemoteSetRating: ((event: RemoteSetRatingEvent) => void) | undefined =
|
|
209
|
+
undefined
|
|
187
210
|
handleRemoteSkip: (() => void) | undefined = undefined
|
|
188
211
|
handleRemoteStop: (() => void) | undefined = undefined
|
|
189
212
|
|
|
@@ -204,19 +227,21 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
204
227
|
this.navigationErrorManager
|
|
205
228
|
)
|
|
206
229
|
|
|
207
|
-
this.searchManager = new SearchManager(
|
|
208
|
-
this.browserManager,
|
|
209
|
-
this.httpClient
|
|
210
|
-
)
|
|
230
|
+
this.searchManager = new SearchManager(this.browserManager, this.httpClient)
|
|
211
231
|
|
|
212
232
|
// Wire up event callbacks from managers to class callbacks
|
|
213
233
|
this.browserManager.onPathChanged = (path) => this.onPathChanged(path)
|
|
214
|
-
this.browserManager.onContentChanged = (content) =>
|
|
234
|
+
this.browserManager.onContentChanged = (content) =>
|
|
235
|
+
this.onContentChanged(content)
|
|
215
236
|
this.browserManager.onTabsChanged = (tabs) => this.onTabsChanged(tabs)
|
|
216
|
-
this.navigationErrorManager.onNavigationError = (data) =>
|
|
217
|
-
|
|
218
|
-
this.
|
|
219
|
-
|
|
237
|
+
this.navigationErrorManager.onNavigationError = (data) =>
|
|
238
|
+
this.onNavigationError(data)
|
|
239
|
+
this.navigationErrorManager.onFormattedNavigationError = (error) =>
|
|
240
|
+
this.onFormattedNavigationError(error)
|
|
241
|
+
this.optionsManager.onOptionsChanged = (options) =>
|
|
242
|
+
this.onOptionsChanged(options)
|
|
243
|
+
this.nowPlayingManager.onNowPlayingChanged = (metadata) =>
|
|
244
|
+
this.onNowPlayingChanged(metadata)
|
|
220
245
|
|
|
221
246
|
// Setup online/offline listeners
|
|
222
247
|
if (typeof window !== 'undefined') {
|
|
@@ -243,7 +268,8 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
243
268
|
const didStateChange = newState.state !== oldState.state
|
|
244
269
|
const didErrorChange =
|
|
245
270
|
newState.state === 'error' && oldState.state === 'error'
|
|
246
|
-
? newState.error !== oldState.error
|
|
271
|
+
? newState.error?.code !== oldState.error?.code ||
|
|
272
|
+
newState.error?.message !== oldState.error?.message
|
|
247
273
|
: false
|
|
248
274
|
|
|
249
275
|
super.state = newState
|
|
@@ -261,10 +287,18 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
261
287
|
}
|
|
262
288
|
}
|
|
263
289
|
|
|
290
|
+
/**
|
|
291
|
+
* Derives PlayingState from playback state and playWhenReady.
|
|
292
|
+
* Matches Android's PlayingStateFactory.derive() logic.
|
|
293
|
+
*/
|
|
264
294
|
private getPlayingStateFromPlayback(playback: Playback): PlayingState {
|
|
295
|
+
const state = playback.state
|
|
296
|
+
const pwr = this._playWhenReady
|
|
265
297
|
return {
|
|
266
|
-
playing:
|
|
267
|
-
|
|
298
|
+
playing:
|
|
299
|
+
pwr && state !== 'error' && state !== 'ended' && state !== 'none',
|
|
300
|
+
buffering:
|
|
301
|
+
pwr && (state === 'loading' || state === 'buffering')
|
|
268
302
|
}
|
|
269
303
|
}
|
|
270
304
|
|
|
@@ -272,11 +306,17 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
272
306
|
this.clearUpdateEventInterval()
|
|
273
307
|
if (interval) {
|
|
274
308
|
this.progressUpdateEventInterval = setInterval(() => {
|
|
275
|
-
|
|
309
|
+
const state = this.state.state
|
|
310
|
+
// Match Android: emit progress during loading, buffering, and playing
|
|
311
|
+
if (
|
|
312
|
+
state === 'playing' ||
|
|
313
|
+
state === 'loading' ||
|
|
314
|
+
state === 'buffering'
|
|
315
|
+
) {
|
|
276
316
|
const progress = this.getProgress()
|
|
277
317
|
const event: PlaybackProgressUpdatedEvent = {
|
|
278
318
|
...progress,
|
|
279
|
-
track: this.currentIndex || 0
|
|
319
|
+
track: this.currentIndex || 0
|
|
280
320
|
}
|
|
281
321
|
this.onPlaybackProgressUpdated(event)
|
|
282
322
|
}
|
|
@@ -294,7 +334,7 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
294
334
|
super.onPlaylistEnded()
|
|
295
335
|
this.onPlaybackQueueEnded({
|
|
296
336
|
track: this.currentIndex ?? 0,
|
|
297
|
-
position: this.element?.currentTime ?? 0
|
|
337
|
+
position: this.element?.currentTime ?? 0
|
|
298
338
|
})
|
|
299
339
|
}
|
|
300
340
|
|
|
@@ -317,13 +357,16 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
317
357
|
* @param parentPath The parent path to check against queueSourcePath
|
|
318
358
|
* @returns true if successfully skipped to existing track, false otherwise
|
|
319
359
|
*/
|
|
320
|
-
private trySkipToExistingQueueTrack(
|
|
360
|
+
private trySkipToExistingQueueTrack(
|
|
361
|
+
trackId: string,
|
|
362
|
+
parentPath: string
|
|
363
|
+
): boolean {
|
|
321
364
|
if (parentPath !== this.browserManager.queueSourcePath) {
|
|
322
365
|
return false
|
|
323
366
|
}
|
|
324
367
|
|
|
325
368
|
const queue = this.getQueue()
|
|
326
|
-
const index = queue.findIndex(t => t.src === trackId)
|
|
369
|
+
const index = queue.findIndex((t) => t.src === trackId)
|
|
327
370
|
|
|
328
371
|
if (index < 0) {
|
|
329
372
|
return false
|
|
@@ -359,7 +402,10 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
359
402
|
* Async implementation of track navigation with queue expansion support.
|
|
360
403
|
* Matches Android's MediaSessionCallback behavior.
|
|
361
404
|
*/
|
|
362
|
-
private async navigateTrackAsync(
|
|
405
|
+
private async navigateTrackAsync(
|
|
406
|
+
track: Track,
|
|
407
|
+
url: string | undefined
|
|
408
|
+
): Promise<void> {
|
|
363
409
|
try {
|
|
364
410
|
// Handle contextual URL (playable track with queue context)
|
|
365
411
|
if (url && BrowserPathHelper.isContextual(url)) {
|
|
@@ -469,24 +515,49 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
469
515
|
// Clear now playing override when track changes (matches Android's PlayerListener.onMediaItemTransition)
|
|
470
516
|
this.nowPlayingManager.clearNowPlayingOverride()
|
|
471
517
|
|
|
518
|
+
// Match Android: load() modifies the queue.
|
|
519
|
+
// If queue is empty, add the track. If queue has items, replace at currentIndex.
|
|
520
|
+
if (this.playlist.length === 0) {
|
|
521
|
+
this.playlist = [track]
|
|
522
|
+
this._currentIndex = 0
|
|
523
|
+
this.onPlaybackQueueChanged(this.playlist)
|
|
524
|
+
} else if (
|
|
525
|
+
this.currentIndex !== undefined &&
|
|
526
|
+
this.playlist[this.currentIndex] !== track
|
|
527
|
+
) {
|
|
528
|
+
this.playlist[this.currentIndex] = track
|
|
529
|
+
this.onPlaybackQueueChanged(this.playlist)
|
|
530
|
+
}
|
|
531
|
+
|
|
472
532
|
const lastTrack = this.current
|
|
473
533
|
const lastPosition = element.currentTime
|
|
474
534
|
const lastIndex = this.lastIndex
|
|
475
535
|
const currentIndex = this.currentIndex
|
|
476
536
|
|
|
537
|
+
// Set loading flag early so seekTo() calls during async URL resolution
|
|
538
|
+
// are captured as pending seeks rather than silently dropped
|
|
539
|
+
this._loadInProgress = true
|
|
540
|
+
this._pendingSeek = undefined
|
|
541
|
+
|
|
477
542
|
// Resolve the media URL before loading (async but we don't await)
|
|
543
|
+
const loadId = ++this.currentLoadId
|
|
478
544
|
const doLoad = async () => {
|
|
479
545
|
const resolvedTrack: Track = track.src
|
|
480
546
|
? { ...track, src: await this.resolveMediaUrl(track.src) }
|
|
481
547
|
: track
|
|
482
548
|
|
|
549
|
+
// A newer load() was called while resolving — discard this stale result
|
|
550
|
+
if (loadId !== this.currentLoadId) {
|
|
551
|
+
return
|
|
552
|
+
}
|
|
553
|
+
|
|
483
554
|
super.load(resolvedTrack, (loadedTrack) => {
|
|
484
555
|
this.onPlaybackActiveTrackChanged({
|
|
485
556
|
lastTrack,
|
|
486
557
|
lastPosition,
|
|
487
558
|
lastIndex,
|
|
488
559
|
index: currentIndex,
|
|
489
|
-
track
|
|
560
|
+
track
|
|
490
561
|
})
|
|
491
562
|
|
|
492
563
|
// Update now playing metadata
|
|
@@ -504,14 +575,13 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
504
575
|
|
|
505
576
|
// Execute async load without blocking, with error handling
|
|
506
577
|
doLoad().catch((error: unknown) => {
|
|
578
|
+
this._loadInProgress = false
|
|
579
|
+
this._pendingSeek = undefined
|
|
507
580
|
console.error('Error loading track:', error)
|
|
508
|
-
const message =
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
message,
|
|
513
|
-
},
|
|
514
|
-
})
|
|
581
|
+
const message =
|
|
582
|
+
error instanceof Error ? error.message : 'Failed to load track'
|
|
583
|
+
const playbackError = { code: 'load-error', message }
|
|
584
|
+
this.state = { state: 'error', error: playbackError }
|
|
515
585
|
})
|
|
516
586
|
}
|
|
517
587
|
|
|
@@ -525,7 +595,7 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
525
595
|
|
|
526
596
|
if (didChange) {
|
|
527
597
|
this.onPlaybackPlayWhenReadyChanged({
|
|
528
|
-
playWhenReady: this._playWhenReady
|
|
598
|
+
playWhenReady: this._playWhenReady
|
|
529
599
|
})
|
|
530
600
|
}
|
|
531
601
|
}
|
|
@@ -553,7 +623,7 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
553
623
|
|
|
554
624
|
if (didChange) {
|
|
555
625
|
this.onPlaybackRepeatModeChanged({
|
|
556
|
-
repeatMode: mode
|
|
626
|
+
repeatMode: mode
|
|
557
627
|
})
|
|
558
628
|
}
|
|
559
629
|
}
|
|
@@ -619,14 +689,24 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
619
689
|
}
|
|
620
690
|
|
|
621
691
|
// MARK: Queue management
|
|
622
|
-
setQueue(
|
|
692
|
+
setQueue(
|
|
693
|
+
tracks: Track[],
|
|
694
|
+
startIndex?: number,
|
|
695
|
+
startPositionMs?: number
|
|
696
|
+
): void {
|
|
623
697
|
this.stop()
|
|
698
|
+
// Clear stale references from previous queue
|
|
699
|
+
this.current = undefined
|
|
700
|
+
this._currentIndex = undefined
|
|
624
701
|
// Hydrate favorites and transform artwork URLs on all tracks in the queue
|
|
625
702
|
const artworkConfig = this.browserManager.configuration.artwork
|
|
626
|
-
this.playlist = tracks.map(track => {
|
|
703
|
+
this.playlist = tracks.map((track) => {
|
|
627
704
|
try {
|
|
628
705
|
const hydratedTrack = this.favoriteManager.hydrateFavorite(track)
|
|
629
|
-
return RequestConfigBuilder.transformTrackArtwork(
|
|
706
|
+
return RequestConfigBuilder.transformTrackArtwork(
|
|
707
|
+
hydratedTrack,
|
|
708
|
+
artworkConfig
|
|
709
|
+
)
|
|
630
710
|
} catch (error) {
|
|
631
711
|
console.error('Failed to transform track:', error)
|
|
632
712
|
return track // Use original track as fallback
|
|
@@ -673,7 +753,7 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
673
753
|
// Create updated track with new favorited state
|
|
674
754
|
const updatedTrack: Track = {
|
|
675
755
|
...track,
|
|
676
|
-
favorited
|
|
756
|
+
favorited
|
|
677
757
|
}
|
|
678
758
|
|
|
679
759
|
// Replace the track in the playlist
|
|
@@ -688,7 +768,7 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
688
768
|
lastTrack: track,
|
|
689
769
|
lastPosition: this.element?.currentTime ?? 0,
|
|
690
770
|
index,
|
|
691
|
-
track: updatedTrack
|
|
771
|
+
track: updatedTrack
|
|
692
772
|
})
|
|
693
773
|
|
|
694
774
|
// Emit queue changed so useQueue() hook updates
|
|
@@ -777,5 +857,4 @@ export class NativeAudioBrowser extends PlaylistPlayer implements AudioBrowserSp
|
|
|
777
857
|
openIosOutputPicker(): void {
|
|
778
858
|
// No-op on web
|
|
779
859
|
}
|
|
780
|
-
|
|
781
860
|
}
|
package/src/web/SimpleRouter.ts
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
* - Most specific route wins
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { assertedNotNullish } from '../utils/validation'
|
|
18
|
+
|
|
17
19
|
export interface RouteMatch {
|
|
18
20
|
params: Record<string, string>
|
|
19
21
|
specificity: number
|
|
@@ -81,13 +83,19 @@ export class SimpleRouter {
|
|
|
81
83
|
|
|
82
84
|
// Match all segments except the tail wildcard
|
|
83
85
|
for (let i = 0; i < patternSegments.length - 1; i++) {
|
|
84
|
-
if (
|
|
86
|
+
if (
|
|
87
|
+
!this.matchSingleSegment(
|
|
88
|
+
assertedNotNullish(patternSegments[i]),
|
|
89
|
+
assertedNotNullish(pathSegments[i]),
|
|
90
|
+
params
|
|
91
|
+
)
|
|
92
|
+
) {
|
|
85
93
|
return null
|
|
86
94
|
}
|
|
87
95
|
// Note: The Kotlin implementation doesn't update counts here (appears to be a bug)
|
|
88
96
|
// but we'll match it exactly for consistency
|
|
89
97
|
this.updateSegmentCounts(
|
|
90
|
-
patternSegments[i]
|
|
98
|
+
assertedNotNullish(patternSegments[i]),
|
|
91
99
|
constantSegments,
|
|
92
100
|
parameterSegments,
|
|
93
101
|
wildcardSegments
|
|
@@ -106,15 +114,22 @@ export class SimpleRouter {
|
|
|
106
114
|
}
|
|
107
115
|
|
|
108
116
|
for (let i = 0; i < patternSegments.length; i++) {
|
|
109
|
-
if (
|
|
117
|
+
if (
|
|
118
|
+
!this.matchSingleSegment(
|
|
119
|
+
assertedNotNullish(patternSegments[i]),
|
|
120
|
+
assertedNotNullish(pathSegments[i]),
|
|
121
|
+
params
|
|
122
|
+
)
|
|
123
|
+
) {
|
|
110
124
|
return null
|
|
111
125
|
}
|
|
112
|
-
const [constCount, paramCount, wildcardCount] =
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
126
|
+
const [constCount, paramCount, wildcardCount] =
|
|
127
|
+
this.updateSegmentCounts(
|
|
128
|
+
assertedNotNullish(patternSegments[i]),
|
|
129
|
+
constantSegments,
|
|
130
|
+
parameterSegments,
|
|
131
|
+
wildcardSegments
|
|
132
|
+
)
|
|
118
133
|
constantSegments = constCount
|
|
119
134
|
parameterSegments = paramCount
|
|
120
135
|
wildcardSegments = wildcardCount
|