@javascriptcommon/react-native-track-player 4.1.8 → 4.1.9

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.
@@ -1,153 +0,0 @@
1
- import { DeviceEventEmitter } from 'react-native';
2
- import { Event, State } from '../src';
3
- import { PlaylistPlayer, RepeatMode } from './TrackPlayer';
4
- import { SetupNotCalledError } from './TrackPlayer/SetupNotCalledError';
5
- export class TrackPlayerModule extends PlaylistPlayer {
6
- emitter = DeviceEventEmitter;
7
- progressUpdateEventInterval;
8
- // Capabilities
9
- CAPABILITY_PLAY = 'CAPABILITY_PLAY';
10
- CAPABILITY_PLAY_FROM_ID = 'CAPABILITY_PLAY_FROM_ID';
11
- CAPABILITY_PLAY_FROM_SEARCH = 'CAPABILITY_PLAY_FROM_SEARCH';
12
- CAPABILITY_PAUSE = 'CAPABILITY_PAUSE';
13
- CAPABILITY_STOP = 'CAPABILITY_STOP';
14
- CAPABILITY_SEEK_TO = 'CAPABILITY_SEEK_TO';
15
- CAPABILITY_SKIP = 'CAPABILITY_SKIP';
16
- CAPABILITY_SKIP_TO_NEXT = 'CAPABILITY_SKIP_TO_NEXT';
17
- CAPABILITY_SKIP_TO_PREVIOUS = 'CAPABILITY_SKIP_TO_PREVIOUS';
18
- CAPABILITY_JUMP_FORWARD = 'CAPABILITY_JUMP_FORWARD';
19
- CAPABILITY_JUMP_BACKWARD = 'CAPABILITY_JUMP_BACKWARD';
20
- CAPABILITY_SET_RATING = 'CAPABILITY_SET_RATING';
21
- CAPABILITY_LIKE = 'CAPABILITY_LIKE';
22
- CAPABILITY_DISLIKE = 'CAPABILITY_DISLIKE';
23
- CAPABILITY_BOOKMARK = 'CAPABILITY_BOOKMARK';
24
- // States
25
- STATE_NONE = 'STATE_NONE';
26
- STATE_READY = 'STATE_READY';
27
- STATE_PLAYING = 'STATE_PLAYING';
28
- STATE_PAUSED = 'STATE_PAUSED';
29
- STATE_STOPPED = 'STATE_STOPPED';
30
- STATE_BUFFERING = 'STATE_BUFFERING';
31
- STATE_CONNECTING = 'STATE_CONNECTING';
32
- // Rating Types
33
- RATING_HEART = 'RATING_HEART';
34
- RATING_THUMBS_UP_DOWN = 'RATING_THUMBS_UP_DOWN';
35
- RATING_3_STARS = 'RATING_3_STARS';
36
- RATING_4_STARS = 'RATING_4_STARS';
37
- RATING_5_STARS = 'RATING_5_STARS';
38
- RATING_PERCENTAGE = 'RATING_PERCENTAGE';
39
- // Repeat Modes
40
- REPEAT_OFF = RepeatMode.Off;
41
- REPEAT_TRACK = RepeatMode.Track;
42
- REPEAT_QUEUE = RepeatMode.Playlist;
43
- // Pitch Algorithms
44
- PITCH_ALGORITHM_LINEAR = 'PITCH_ALGORITHM_LINEAR';
45
- PITCH_ALGORITHM_MUSIC = 'PITCH_ALGORITHM_MUSIC';
46
- PITCH_ALGORITHM_VOICE = 'PITCH_ALGORITHM_VOICE';
47
- // observe and emit state changes
48
- get state() {
49
- return super.state;
50
- }
51
- set state(newState) {
52
- super.state = newState;
53
- this.emitter.emit(Event.PlaybackState, newState);
54
- }
55
- async updateOptions(options) {
56
- this.setupProgressUpdates(options.progressUpdateEventInterval);
57
- }
58
- setupProgressUpdates(interval) {
59
- // clear and reset interval
60
- this.clearUpdateEventInterval();
61
- if (interval) {
62
- this.clearUpdateEventInterval();
63
- this.progressUpdateEventInterval = setInterval(async () => {
64
- if (this.state.state === State.Playing) {
65
- const progress = await this.getProgress();
66
- this.emitter.emit(Event.PlaybackProgressUpdated, {
67
- ...progress,
68
- track: this.currentIndex,
69
- });
70
- }
71
- }, interval * 1000);
72
- }
73
- }
74
- clearUpdateEventInterval() {
75
- if (this.progressUpdateEventInterval) {
76
- clearInterval(this.progressUpdateEventInterval);
77
- }
78
- }
79
- async onTrackEnded() {
80
- const position = this.element.currentTime;
81
- await super.onTrackEnded();
82
- this.emitter.emit(Event.PlaybackTrackChanged, {
83
- track: this.lastIndex,
84
- position,
85
- nextTrack: this.currentIndex,
86
- });
87
- }
88
- async onPlaylistEnded() {
89
- await super.onPlaylistEnded();
90
- this.emitter.emit(Event.PlaybackQueueEnded, {
91
- track: this.currentIndex,
92
- position: this.element.currentTime,
93
- });
94
- }
95
- get playWhenReady() {
96
- return super.playWhenReady;
97
- }
98
- set playWhenReady(pwr) {
99
- const didChange = pwr !== this._playWhenReady;
100
- super.playWhenReady = pwr;
101
- if (didChange) {
102
- this.emitter.emit(Event.PlaybackPlayWhenReadyChanged, { playWhenReady: this._playWhenReady });
103
- }
104
- }
105
- getPlayWhenReady() {
106
- return this.playWhenReady;
107
- }
108
- setPlayWhenReady(pwr) {
109
- this.playWhenReady = pwr;
110
- return this.playWhenReady;
111
- }
112
- async load(track) {
113
- if (!this.element)
114
- throw new SetupNotCalledError();
115
- const lastTrack = this.current;
116
- const lastPosition = this.element.currentTime;
117
- await super.load(track);
118
- this.emitter.emit(Event.PlaybackActiveTrackChanged, {
119
- lastTrack,
120
- lastPosition,
121
- lastIndex: this.lastIndex,
122
- index: this.currentIndex,
123
- track,
124
- });
125
- }
126
- getQueue() {
127
- return this.playlist;
128
- }
129
- async setQueue(queue) {
130
- await this.stop();
131
- this.playlist = queue;
132
- }
133
- getActiveTrack() {
134
- return this.current;
135
- }
136
- getActiveTrackIndex() {
137
- // per the existing spec, this should throw if setup hasn't been called
138
- if (!this.element || !this.player)
139
- throw new SetupNotCalledError();
140
- return this.currentIndex;
141
- }
142
- /**
143
- * @deprecated
144
- * @returns State
145
- */
146
- getState() {
147
- return this.state.state;
148
- }
149
- getPlaybackState() {
150
- return this.state;
151
- }
152
- }
153
- ;
@@ -1,3 +0,0 @@
1
- import { TrackPlayerModule } from './TrackPlayerModule';
2
- declare const module: TrackPlayerModule;
3
- export default module;
package/lib/web/index.js DELETED
@@ -1,3 +0,0 @@
1
- import { TrackPlayerModule } from './TrackPlayerModule';
2
- const module = new TrackPlayerModule();
3
- export default module;
@@ -1,2 +0,0 @@
1
- import TrackPlayerModule from '../web';
2
- export default TrackPlayerModule;
@@ -1,10 +0,0 @@
1
- const resolveAssetResource = (base64: unknown) => {
2
- if (/^https?:\/\//.test(base64 as string)) {
3
- return base64;
4
- }
5
-
6
- // TODO: resolveAssetResource for web
7
- return base64;
8
- };
9
-
10
- export default resolveAssetResource;
@@ -1,201 +0,0 @@
1
- import { State } from '../../src/constants/State';
2
- import type { Track, Progress, PlaybackState } from '../../src/interfaces';
3
- import { SetupNotCalledError } from './SetupNotCalledError';
4
-
5
- export class Player {
6
- protected hasInitialized: boolean = false;
7
- protected element?: HTMLMediaElement;
8
- protected player?: shaka.Player;
9
- protected _current?: Track = undefined;
10
- protected _playWhenReady: boolean = false;
11
- protected _state: PlaybackState = { state: State.None };
12
-
13
- // current getter/setter
14
- public get current(): Track | undefined {
15
- return this._current;
16
- }
17
- public set current(cur: Track | undefined) {
18
- this._current = cur;
19
- }
20
-
21
- // state getter/setter
22
- public get state(): PlaybackState {
23
- return this._state;
24
- }
25
- public set state(newState: PlaybackState) {
26
- this._state = newState;
27
- }
28
-
29
- // playWhenReady getter/setter
30
- public get playWhenReady(): boolean {
31
- return this._playWhenReady;
32
- }
33
- public set playWhenReady(pwr: boolean) {
34
- this._playWhenReady = pwr;
35
- }
36
-
37
- async setupPlayer() {
38
- // shaka only runs in a browser
39
- if (typeof window === 'undefined') return;
40
- if (this.hasInitialized === true) {
41
- // TODO: double check the structure of this error message
42
- throw { code: 'player_already_initialized', message: 'The player has already been initialized via setupPlayer.' };
43
- }
44
-
45
- // @ts-ignore
46
- const shaka = (await import('shaka-player/dist/shaka-player.ui')).default;
47
- // Install built-in polyfills to patch browser incompatibilities.
48
- shaka.polyfill.installAll();
49
- // Check to see if the browser supports the basic APIs Shaka needs.
50
- if (!shaka.Player.isBrowserSupported()) {
51
- // This browser does not have the minimum set of APIs we need.
52
- this.state = {
53
- state: State.Error,
54
- error: {
55
- code: 'not_supported',
56
- message: 'Browser not supported.',
57
- },
58
- };
59
- throw new Error('Browser not supported.');
60
- }
61
-
62
- // build dom element and attach shaka-player
63
- this.element = document.createElement('audio');
64
- this.element.setAttribute('id', 'react-native-track-player');
65
- this.player = new shaka.Player();
66
- this.player?.attach(this.element);
67
-
68
- // Listen for relevant events events.
69
- this.player!.addEventListener('error', (error: any) => {
70
- // Extract the shaka.util.Error object from the event.
71
- this.onError(error.detail);
72
- });
73
- this.element.addEventListener('ended', this.onStateUpdate.bind(this, State.Ended));
74
- this.element.addEventListener('playing', this.onStateUpdate.bind(this, State.Playing));
75
- this.element.addEventListener('pause', this.onStateUpdate.bind(this, State.Paused));
76
- this.player!.addEventListener('loading', this.onStateUpdate.bind(this, State.Loading));
77
- this.player!.addEventListener('loaded', this.onStateUpdate.bind(this, State.Ready));
78
- this.player!.addEventListener('buffering', ({ buffering }: any) => {
79
- if (buffering === true) {
80
- this.onStateUpdate(State.Buffering);
81
- }
82
- });
83
-
84
- // Attach player to the window to make it easy to access in the JS console.
85
- // @ts-ignore
86
- window.rntp = this.player;
87
- this.hasInitialized = true;
88
- }
89
-
90
- /**
91
- * event handlers
92
- */
93
- protected onStateUpdate(state: Exclude<State, State.Error>) {
94
- this.state = { state };
95
- }
96
-
97
- protected onError(error: any) {
98
- // unload the current track to allow for clean playback on other
99
- this.player?.unload();
100
- this.state = {
101
- state: State.Error,
102
- error: {
103
- code: error.code.toString(),
104
- message: error.message,
105
- },
106
- };
107
-
108
- // Log the error.
109
- console.debug('Error code', error.code, 'object', error);
110
- }
111
-
112
- /**
113
- * player control
114
- */
115
- public async load(track: Track) {
116
- if (!this.player) throw new SetupNotCalledError();
117
- await this.player.load(track.url as string);
118
- this.current = track;
119
- }
120
-
121
- public async retry() {
122
- if (!this.player) throw new SetupNotCalledError();
123
- this.player.retryStreaming();
124
- }
125
-
126
- public async stop() {
127
- if (!this.player) throw new SetupNotCalledError();
128
- this.current = undefined;
129
- await this.player.unload()
130
- }
131
-
132
- public play() {
133
- if (!this.element) throw new SetupNotCalledError();
134
- this.playWhenReady = true;
135
- return this.element.play()
136
- .catch(err => {
137
- console.error(err);
138
- })
139
- ;
140
- }
141
-
142
- public pause() {
143
- if (!this.element) throw new SetupNotCalledError();
144
- this.playWhenReady = false;
145
- return this.element.pause();
146
- }
147
-
148
- public setRate(rate: number) {
149
- if (!this.element) throw new SetupNotCalledError();
150
- return this.element.playbackRate = rate;
151
- }
152
-
153
- public getRate() {
154
- if (!this.element) throw new SetupNotCalledError();
155
- return this.element.playbackRate;
156
- }
157
-
158
- public seekBy(offset: number) {
159
- if (!this.element) throw new SetupNotCalledError();
160
- this.element.currentTime += offset;
161
- }
162
-
163
- public seekTo(seconds: number) {
164
- if (!this.element) throw new SetupNotCalledError();
165
- this.element.currentTime = seconds;
166
- }
167
-
168
- public setVolume(volume: number) {
169
- if (!this.element) throw new SetupNotCalledError();
170
- this.element.volume = volume;
171
- }
172
-
173
- public getVolume() {
174
- if (!this.element) throw new SetupNotCalledError();
175
- return this.element.volume;
176
- }
177
-
178
- public getDuration() {
179
- if (!this.element) throw new SetupNotCalledError();
180
- return this.element.duration
181
- }
182
-
183
- public getPosition() {
184
- if (!this.element) throw new SetupNotCalledError();
185
- return this.element.currentTime
186
- }
187
-
188
- public getProgress(): Progress {
189
- if (!this.element) throw new SetupNotCalledError();
190
- return {
191
- position: this.element.currentTime,
192
- duration: this.element.duration || 0,
193
- buffered: 0, // TODO: this.element.buffered.end,
194
- }
195
- }
196
-
197
- public getBufferedPosition() {
198
- if (!this.element) throw new SetupNotCalledError();
199
- return this.element.buffered.end;
200
- }
201
- }
@@ -1,215 +0,0 @@
1
- import { Player } from './Player';
2
-
3
- import type { Track } from '../../src/interfaces';
4
- import {RepeatMode} from './RepeatMode';
5
- import { State } from '../../src';
6
-
7
- export class PlaylistPlayer extends Player {
8
- // TODO: use immer to make the `playlist` immutable
9
- protected playlist: Track[] = [];
10
- protected lastIndex?: number;
11
- protected _currentIndex?: number;
12
- protected repeatMode: RepeatMode = RepeatMode.Off;
13
-
14
- protected async onStateUpdate(state: Exclude<State, State.Error>) {
15
- super.onStateUpdate(state);
16
-
17
- if (state === State.Ended) {
18
- await this.onTrackEnded();
19
- }
20
- }
21
-
22
- protected async onTrackEnded() {
23
- switch (this.repeatMode) {
24
- case RepeatMode.Track:
25
- if (this.currentIndex !== undefined) {
26
- await this.goToIndex(this.currentIndex);
27
- }
28
- break;
29
- case RepeatMode.Playlist:
30
- if (this.currentIndex === this.playlist.length - 1) {
31
- await this.goToIndex(0);
32
- } else {
33
- await this.skipToNext();
34
- }
35
- break;
36
- default:
37
- try {
38
- await this.skipToNext();
39
- } catch (err) {
40
- if ((err as Error).message !== 'playlist_exhausted') {
41
- throw err;
42
- }
43
- this.onPlaylistEnded();
44
- }
45
- break;
46
- }
47
- }
48
-
49
- // eslint-disable-next-line @typescript-eslint/no-empty-function
50
- protected onPlaylistEnded() {}
51
-
52
- protected get currentIndex() {
53
- return this._currentIndex;
54
- }
55
-
56
- protected set currentIndex(current: number | undefined) {
57
- this.lastIndex = this.currentIndex;
58
- this._currentIndex = current;
59
- }
60
-
61
- protected async goToIndex(index: number, initialPosition?: number) {
62
- const track = this.playlist[index];
63
-
64
- if (!track) {
65
- throw new Error('playlist_exhausted');
66
- }
67
-
68
- if (this.currentIndex !== index) {
69
- this.currentIndex = index;
70
- await this.load(track);
71
- }
72
-
73
- if (initialPosition) {
74
- this.seekTo(initialPosition);
75
- }
76
-
77
- if (this.playWhenReady) {
78
- await this.play();
79
- }
80
- }
81
-
82
- public async add(tracks: Track[], insertBeforeIndex?: number) {
83
- if (insertBeforeIndex !== -1 && insertBeforeIndex !== undefined) {
84
- this.playlist.splice(insertBeforeIndex, 0, ...tracks);
85
- } else {
86
- this.playlist.push(...tracks);
87
- }
88
-
89
- if (this.currentIndex === undefined) {
90
- await this.goToIndex(0);
91
- }
92
- }
93
-
94
- public async skip(index: number, initialPosition?: number) {
95
- const track = this.playlist[index];
96
-
97
- if (track === undefined) {
98
- throw new Error('index out of bounds');
99
- }
100
-
101
- await this.goToIndex(index, initialPosition);
102
- }
103
-
104
- public async skipToNext(initialPosition?: number) {
105
- if (this.currentIndex === undefined) return;
106
-
107
- const index = this.currentIndex + 1;
108
- await this.goToIndex(index, initialPosition);
109
- }
110
-
111
- public async skipToPrevious(initialPosition?: number) {
112
- if (this.currentIndex === undefined) return;
113
-
114
- const index = this.currentIndex - 1;
115
- await this.goToIndex(index, initialPosition);
116
- }
117
-
118
- public getTrack(index: number): Track | null {
119
- const track = this.playlist[index];
120
- return track || null;
121
- }
122
-
123
- public setRepeatMode(mode: RepeatMode) {
124
- this.repeatMode = mode;
125
- }
126
-
127
- public getRepeatMode() {
128
- return this.repeatMode;
129
- }
130
-
131
- public async remove(indexes: number[]) {
132
- const idxMap = indexes.reduce<Record<number, boolean>>((acc, elem) => {
133
- acc[elem] = true
134
- return acc;
135
- }, {});
136
- let isCurrentRemoved = false;
137
- this.playlist = this.playlist.filter((_track, idx) => {
138
- const keep = !idxMap[idx]
139
-
140
- if (!keep && idx === this.currentIndex) {
141
- isCurrentRemoved = true;
142
- }
143
-
144
- return keep;
145
- });
146
-
147
- if (this.currentIndex === undefined) {
148
- return;
149
- }
150
-
151
- const hasItems = this.playlist.length > 0;
152
- if (isCurrentRemoved && hasItems) {
153
- await this.goToIndex(this.currentIndex % this.playlist.length);
154
- } else if (isCurrentRemoved) {
155
- await this.stop();
156
- }
157
- }
158
-
159
- public async stop() {
160
- await super.stop();
161
- this.currentIndex = undefined;
162
- }
163
-
164
- public async reset() {
165
- await this.stop();
166
- this.playlist = [];
167
- }
168
-
169
- public async removeUpcomingTracks() {
170
- if (this.currentIndex === undefined) return;
171
- this.playlist = this.playlist.slice(0, this.currentIndex + 1);
172
- }
173
-
174
- public async move(fromIndex: number, toIndex: number): Promise<void> {
175
- if (!this.playlist[fromIndex]) {
176
- throw new Error('index out of bounds');
177
- }
178
-
179
- if (this.currentIndex === fromIndex) {
180
- throw new Error('you cannot move the currently playing track');
181
- }
182
-
183
- if (this.currentIndex === toIndex) {
184
- throw new Error('you cannot replace the currently playing track');
185
- }
186
-
187
- // calculate `currentIndex` after move
188
- let shift: number | undefined = undefined;
189
- if (this.currentIndex) {
190
- if (fromIndex < this.currentIndex && toIndex > this.currentIndex) {
191
- shift = -1;
192
- } else if (fromIndex > this.currentIndex && toIndex < this.currentIndex) {
193
- shift = + 1;
194
- }
195
- }
196
-
197
- // move the track
198
- const fromItem = this.playlist[fromIndex];
199
- this.playlist.splice(fromIndex, 1);
200
- this.playlist.splice(toIndex, 0, fromItem);
201
-
202
- if (this.currentIndex && shift) {
203
- this.currentIndex = this.currentIndex + shift
204
- }
205
- }
206
-
207
- // TODO
208
- // eslint-disable-next-line @typescript-eslint/no-empty-function
209
- public updateMetadataForTrack(index: number, metadata: Partial<Track>) {}
210
- // eslint-disable-next-line @typescript-eslint/no-empty-function
211
- public clearNowPlayingMetadata() {}
212
- // eslint-disable-next-line @typescript-eslint/no-empty-function
213
- public updateNowPlayingMetadata(metadata: Partial<Track>) {}
214
-
215
- }
@@ -1,6 +0,0 @@
1
-
2
- export enum RepeatMode {
3
- Off = 'REPEAT_OFF',
4
- Track = 'REPEAT_TRACK',
5
- Playlist = 'REPEAT_PLAYLIST',
6
- }
@@ -1,5 +0,0 @@
1
- export class SetupNotCalledError extends Error {
2
- constructor() {
3
- super('You must call `setupPlayer` prior to interacting with the player.');
4
- }
5
- }
@@ -1,3 +0,0 @@
1
- export * from './Player';
2
- export * from './PlaylistPlayer';
3
- export * from './RepeatMode';