tunzo-player 1.0.7 → 1.0.8

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,5 +1,5 @@
1
1
  export declare class Player {
2
- private static audioInstance;
2
+ private static audio;
3
3
  private static currentSong;
4
4
  private static currentIndex;
5
5
  private static isPlaying;
@@ -9,14 +9,13 @@ export declare class Player {
9
9
  private static queue;
10
10
  private static playlist;
11
11
  private static selectedQuality;
12
- private static readonly audioId;
13
12
  private static isInitialized;
14
- /** Initialize with playlist and quality */
15
13
  static initialize(playlist?: any[], quality?: number): void;
16
14
  static play(song: any, index?: number): Promise<void>;
17
- private static cleanupCurrentPlayback;
15
+ private static setupMusicControls;
18
16
  static pause(): Promise<void>;
19
17
  static resume(): Promise<void>;
18
+ static stop(): Promise<void>;
20
19
  static togglePlayPause(): Promise<void>;
21
20
  static next(): Promise<void>;
22
21
  static prev(): Promise<void>;
@@ -26,10 +25,10 @@ export declare class Player {
26
25
  static addToQueue(song: any): void;
27
26
  static removeFromQueue(index: number): void;
28
27
  static reorderQueue(from: number, to: number): void;
29
- static seekTo(time: number): Promise<void>;
28
+ static seekTo(seconds: number): Promise<void>;
30
29
  static getCurrentTime(): number;
31
30
  static getDuration(): number;
32
- static formatTime(time: number): string;
31
+ static formatTime(t: number): string;
33
32
  static isPlayingSong(): boolean;
34
33
  static getCurrentSong(): any;
35
34
  static setQuality(index: number): void;
@@ -11,12 +11,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.Player = void 0;
13
13
  const core_1 = require("@capacitor/core");
14
- const native_audio_1 = require("@capacitor-community/native-audio");
14
+ const capacitor_music_controls_plugin_1 = require("capacitor-music-controls-plugin");
15
15
  class Player {
16
- /** Initialize with playlist and quality */
17
16
  static initialize(playlist = [], quality = 3) {
18
- if (!core_1.Capacitor.isNativePlatform() && !this.audioInstance) {
19
- this.audioInstance = new Audio();
17
+ if (!core_1.Capacitor.isNativePlatform()) {
18
+ this.audio = new Audio();
20
19
  }
21
20
  this.playlist = [...playlist];
22
21
  this.selectedQuality = quality;
@@ -25,133 +24,77 @@ class Player {
25
24
  static play(song_1) {
26
25
  return __awaiter(this, arguments, void 0, function* (song, index = 0) {
27
26
  var _a, _b;
28
- if (!this.isInitialized) {
29
- console.error('Player not initialized. Call Player.initialize() first.');
27
+ if (!this.isInitialized)
30
28
  return;
31
- }
32
- if (!song || !song.downloadUrl) {
33
- console.error('Invalid song or missing downloadUrl');
29
+ if (!(song === null || song === void 0 ? void 0 : song.downloadUrl))
34
30
  return;
35
- }
36
- // Stop current playback
37
- yield this.cleanupCurrentPlayback();
31
+ yield this.stop();
38
32
  this.currentSong = song;
39
33
  this.currentIndex = index;
40
34
  const url = ((_a = song.downloadUrl[this.selectedQuality]) === null || _a === void 0 ? void 0 : _a.url) || ((_b = song.downloadUrl[0]) === null || _b === void 0 ? void 0 : _b.url);
41
- if (!url) {
42
- console.error('No valid URL found for playback');
35
+ if (!url)
43
36
  return;
44
- }
45
- try {
46
- if (core_1.Capacitor.isNativePlatform()) {
47
- // For native platform, use the correct NativeAudio methods
48
- yield native_audio_1.NativeAudio.configure({
49
- fade: false,
50
- focus: true
51
- });
52
- yield native_audio_1.NativeAudio.preload({
53
- assetId: this.audioId,
54
- assetPath: url,
55
- audioChannelNum: 1,
56
- isUrl: true
57
- });
58
- yield native_audio_1.NativeAudio.play({
59
- assetId: this.audioId
60
- });
61
- // For native, we need to manually track duration
62
- this.duration = song.duration || 0;
63
- }
64
- else {
65
- if (!this.audioInstance) {
66
- this.audioInstance = new Audio();
67
- }
68
- this.audioInstance.src = url;
69
- yield this.audioInstance.play();
70
- this.audioInstance.onloadedmetadata = () => {
71
- var _a;
72
- this.duration = ((_a = this.audioInstance) === null || _a === void 0 ? void 0 : _a.duration) || 0;
73
- };
74
- this.audioInstance.ontimeupdate = () => {
75
- var _a;
76
- this.currentTime = ((_a = this.audioInstance) === null || _a === void 0 ? void 0 : _a.currentTime) || 0;
77
- };
78
- this.audioInstance.onended = () => {
79
- this.autoNext();
80
- };
81
- this.audioInstance.onerror = () => {
82
- console.error('Error during playback');
83
- this.isPlaying = false;
84
- };
85
- }
86
- this.isPlaying = true;
87
- }
88
- catch (err) {
89
- console.error('Playback error:', err);
90
- this.isPlaying = false;
91
- }
37
+ if (!this.audio)
38
+ this.audio = new Audio();
39
+ this.audio.src = url;
40
+ this.audio.play().catch(console.error);
41
+ this.audio.onloadedmetadata = () => this.duration = this.audio.duration;
42
+ this.audio.ontimeupdate = () => this.currentTime = this.audio.currentTime;
43
+ this.audio.onended = () => this.autoNext();
44
+ yield this.setupMusicControls(song, true);
45
+ this.isPlaying = true;
92
46
  });
93
47
  }
94
- static cleanupCurrentPlayback() {
48
+ static setupMusicControls(song, isPlaying) {
95
49
  return __awaiter(this, void 0, void 0, function* () {
96
- if (core_1.Capacitor.isNativePlatform()) {
97
- try {
98
- yield native_audio_1.NativeAudio.stop({ assetId: this.audioId });
99
- yield native_audio_1.NativeAudio.unload({ assetId: this.audioId });
100
- }
101
- catch (err) {
102
- console.debug('No audio to unload');
103
- }
104
- }
105
- else if (this.audioInstance) {
106
- this.audioInstance.pause();
107
- this.audioInstance.src = '';
108
- this.audioInstance.onloadedmetadata = null;
109
- this.audioInstance.ontimeupdate = null;
110
- this.audioInstance.onended = null;
111
- this.audioInstance.onerror = null;
112
- }
50
+ if (!core_1.Capacitor.isNativePlatform())
51
+ return;
52
+ yield capacitor_music_controls_plugin_1.CapacitorMusicControls.destroy(); // clear existing
53
+ yield capacitor_music_controls_plugin_1.CapacitorMusicControls.create({
54
+ track: song.name || '',
55
+ artist: song.primaryArtists || '',
56
+ album: song.album || '',
57
+ cover: song.image || '',
58
+ isPlaying,
59
+ dismissable: true,
60
+ hasPrev: true,
61
+ hasNext: true,
62
+ });
63
+ capacitor_music_controls_plugin_1.CapacitorMusicControls.addListener('music-controls-next', () => this.next());
64
+ capacitor_music_controls_plugin_1.CapacitorMusicControls.addListener('music-controls-previous', () => this.prev());
65
+ capacitor_music_controls_plugin_1.CapacitorMusicControls.addListener('music-controls-pause', () => this.pause());
66
+ capacitor_music_controls_plugin_1.CapacitorMusicControls.addListener('music-controls-play', () => this.resume());
67
+ capacitor_music_controls_plugin_1.CapacitorMusicControls.addListener('music-controls-destroy', () => this.stop());
113
68
  });
114
69
  }
115
70
  static pause() {
116
71
  return __awaiter(this, void 0, void 0, function* () {
117
- if (!this.isInitialized)
118
- return;
119
- try {
120
- if (core_1.Capacitor.isNativePlatform()) {
121
- yield native_audio_1.NativeAudio.pause({ assetId: this.audioId });
122
- }
123
- else if (this.audioInstance) {
124
- this.audioInstance.pause();
125
- }
126
- this.isPlaying = false;
127
- }
128
- catch (err) {
129
- console.error('Pause error:', err);
130
- }
72
+ if (this.audio)
73
+ this.audio.pause();
74
+ this.isPlaying = false;
75
+ core_1.Capacitor.isNativePlatform() && capacitor_music_controls_plugin_1.CapacitorMusicControls.updateIsPlaying({ isPlaying: false });
131
76
  });
132
77
  }
133
78
  static resume() {
134
79
  return __awaiter(this, void 0, void 0, function* () {
135
- if (!this.isInitialized)
136
- return;
137
- try {
138
- if (core_1.Capacitor.isNativePlatform()) {
139
- yield native_audio_1.NativeAudio.play({ assetId: this.audioId });
140
- }
141
- else if (this.audioInstance) {
142
- yield this.audioInstance.play();
143
- }
144
- this.isPlaying = true;
145
- }
146
- catch (err) {
147
- console.error('Resume error:', err);
80
+ if (this.audio)
81
+ yield this.audio.play();
82
+ this.isPlaying = true;
83
+ core_1.Capacitor.isNativePlatform() && capacitor_music_controls_plugin_1.CapacitorMusicControls.updateIsPlaying({ isPlaying: true });
84
+ });
85
+ }
86
+ static stop() {
87
+ return __awaiter(this, void 0, void 0, function* () {
88
+ if (this.audio) {
89
+ this.audio.pause();
90
+ this.audio.src = '';
148
91
  }
92
+ this.isPlaying = false;
93
+ yield capacitor_music_controls_plugin_1.CapacitorMusicControls.destroy();
149
94
  });
150
95
  }
151
96
  static togglePlayPause() {
152
97
  return __awaiter(this, void 0, void 0, function* () {
153
- if (!this.isInitialized)
154
- return;
155
98
  if (this.isPlaying) {
156
99
  yield this.pause();
157
100
  }
@@ -165,12 +108,10 @@ class Player {
165
108
  }
166
109
  static next() {
167
110
  return __awaiter(this, void 0, void 0, function* () {
168
- if (!this.isInitialized)
169
- return;
170
111
  if (this.queue.length > 0) {
171
- const nextQueued = this.queue.shift();
172
- const index = this.playlist.findIndex(s => s.id === nextQueued.id);
173
- yield this.play(nextQueued, index);
112
+ const next = this.queue.shift();
113
+ const index = this.playlist.findIndex(s => s.id === next.id);
114
+ yield this.play(next, index);
174
115
  }
175
116
  else if (this.isShuffle) {
176
117
  yield this.playRandom();
@@ -178,19 +119,11 @@ class Player {
178
119
  else if (this.currentIndex < this.playlist.length - 1) {
179
120
  yield this.play(this.playlist[this.currentIndex + 1], this.currentIndex + 1);
180
121
  }
181
- else {
182
- // End of playlist
183
- this.isPlaying = false;
184
- this.currentSong = null;
185
- }
186
122
  });
187
123
  }
188
124
  static prev() {
189
125
  return __awaiter(this, void 0, void 0, function* () {
190
- if (!this.isInitialized)
191
- return;
192
126
  if (this.currentTime > 3) {
193
- // If more than 3 seconds into song, restart current song
194
127
  yield this.seekTo(0);
195
128
  }
196
129
  else if (this.currentIndex > 0) {
@@ -205,20 +138,20 @@ class Player {
205
138
  }
206
139
  static playRandom() {
207
140
  return __awaiter(this, void 0, void 0, function* () {
208
- if (!this.isInitialized || this.playlist.length <= 1)
141
+ if (this.playlist.length <= 1)
209
142
  return;
210
- let randomIndex;
211
- do {
212
- randomIndex = Math.floor(Math.random() * this.playlist.length);
213
- } while (randomIndex === this.currentIndex && this.playlist.length > 1);
214
- yield this.play(this.playlist[randomIndex], randomIndex);
143
+ let rand = this.currentIndex;
144
+ while (rand === this.currentIndex) {
145
+ rand = Math.floor(Math.random() * this.playlist.length);
146
+ }
147
+ yield this.play(this.playlist[rand], rand);
215
148
  });
216
149
  }
217
150
  static toggleShuffle() {
218
151
  this.isShuffle = !this.isShuffle;
219
152
  }
220
153
  static addToQueue(song) {
221
- if (!this.queue.some(q => q.id === song.id)) {
154
+ if (!this.queue.find(s => s.id === song.id)) {
222
155
  this.queue.push(song);
223
156
  }
224
157
  }
@@ -228,27 +161,16 @@ class Player {
228
161
  }
229
162
  }
230
163
  static reorderQueue(from, to) {
231
- if (from >= 0 && from < this.queue.length && to >= 0 && to < this.queue.length) {
232
- const item = this.queue.splice(from, 1)[0];
233
- this.queue.splice(to, 0, item);
234
- }
164
+ if (from === to)
165
+ return;
166
+ const [item] = this.queue.splice(from, 1);
167
+ this.queue.splice(to, 0, item);
235
168
  }
236
- static seekTo(time) {
169
+ static seekTo(seconds) {
237
170
  return __awaiter(this, void 0, void 0, function* () {
238
- if (!this.isInitialized)
239
- return;
240
- try {
241
- if (core_1.Capacitor.isNativePlatform()) {
242
- // NativeAudio doesn't support seeking directly, might need a plugin extension
243
- console.warn('Seeking not fully supported on native platform');
244
- }
245
- else if (this.audioInstance) {
246
- this.audioInstance.currentTime = time;
247
- }
248
- this.currentTime = time;
249
- }
250
- catch (err) {
251
- console.error('Seek error:', err);
171
+ if (this.audio) {
172
+ this.audio.currentTime = seconds;
173
+ this.currentTime = seconds;
252
174
  }
253
175
  });
254
176
  }
@@ -258,10 +180,10 @@ class Player {
258
180
  static getDuration() {
259
181
  return this.duration;
260
182
  }
261
- static formatTime(time) {
262
- const minutes = Math.floor(time / 60);
263
- const seconds = Math.floor(time % 60);
264
- return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
183
+ static formatTime(t) {
184
+ const m = Math.floor(t / 60);
185
+ const s = Math.floor(t % 60);
186
+ return `${m}:${s < 10 ? '0' : ''}${s}`;
265
187
  }
266
188
  static isPlayingSong() {
267
189
  return this.isPlaying;
@@ -270,9 +192,7 @@ class Player {
270
192
  return this.currentSong;
271
193
  }
272
194
  static setQuality(index) {
273
- if (index >= 0) {
274
- this.selectedQuality = index;
275
- }
195
+ this.selectedQuality = index;
276
196
  }
277
197
  static getQueue() {
278
198
  return [...this.queue];
@@ -285,13 +205,16 @@ class Player {
285
205
  }
286
206
  static destroy() {
287
207
  return __awaiter(this, void 0, void 0, function* () {
288
- yield this.cleanupCurrentPlayback();
208
+ yield this.stop();
209
+ this.playlist = [];
210
+ this.queue = [];
211
+ this.audio = null;
289
212
  this.isInitialized = false;
290
213
  });
291
214
  }
292
215
  }
293
216
  exports.Player = Player;
294
- Player.audioInstance = null;
217
+ Player.audio = null;
295
218
  Player.currentSong = null;
296
219
  Player.currentIndex = 0;
297
220
  Player.isPlaying = false;
@@ -301,5 +224,4 @@ Player.isShuffle = false;
301
224
  Player.queue = [];
302
225
  Player.playlist = [];
303
226
  Player.selectedQuality = 3;
304
- Player.audioId = 'current-song';
305
227
  Player.isInitialized = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tunzo-player",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "A music playback service for Angular and Ionic apps with native audio control support.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -23,6 +23,7 @@
23
23
  "typescript": "^5.8.3"
24
24
  },
25
25
  "dependencies": {
26
- "@capacitor-community/native-audio": "^7.0.0"
26
+ "@capacitor-community/native-audio": "^7.0.0",
27
+ "capacitor-music-controls-plugin": "^6.1.0"
27
28
  }
28
29
  }
@@ -1,9 +1,8 @@
1
-
2
1
  import { Capacitor } from '@capacitor/core';
3
- import { NativeAudio } from '@capacitor-community/native-audio';
2
+ import { CapacitorMusicControls } from 'capacitor-music-controls-plugin';
4
3
 
5
4
  export class Player {
6
- private static audioInstance: HTMLAudioElement | null = null;
5
+ private static audio: HTMLAudioElement | null = null;
7
6
  private static currentSong: any = null;
8
7
  private static currentIndex = 0;
9
8
  private static isPlaying = false;
@@ -13,148 +12,89 @@ export class Player {
13
12
  private static queue: any[] = [];
14
13
  private static playlist: any[] = [];
15
14
  private static selectedQuality = 3;
16
- private static readonly audioId: string = 'current-song';
17
15
  private static isInitialized = false;
18
16
 
19
- /** Initialize with playlist and quality */
20
17
  static initialize(playlist: any[] = [], quality = 3) {
21
- if (!Capacitor.isNativePlatform() && !this.audioInstance) {
22
- this.audioInstance = new Audio();
18
+ if (!Capacitor.isNativePlatform()) {
19
+ this.audio = new Audio();
23
20
  }
24
-
25
21
  this.playlist = [...playlist];
26
22
  this.selectedQuality = quality;
27
23
  this.isInitialized = true;
28
24
  }
29
25
 
30
- static async play(song: any, index: number = 0) {
31
- if (!this.isInitialized) {
32
- console.error('Player not initialized. Call Player.initialize() first.');
33
- return;
34
- }
35
-
36
- if (!song || !song.downloadUrl) {
37
- console.error('Invalid song or missing downloadUrl');
38
- return;
39
- }
26
+ static async play(song: any, index = 0) {
27
+ if (!this.isInitialized) return;
28
+ if (!song?.downloadUrl) return;
40
29
 
41
- // Stop current playback
42
- await this.cleanupCurrentPlayback();
30
+ await this.stop();
43
31
 
44
32
  this.currentSong = song;
45
33
  this.currentIndex = index;
46
34
  const url = song.downloadUrl[this.selectedQuality]?.url || song.downloadUrl[0]?.url;
47
35
 
48
- if (!url) {
49
- console.error('No valid URL found for playback');
50
- return;
51
- }
36
+ if (!url) return;
52
37
 
53
- try {
54
- if (Capacitor.isNativePlatform()) {
55
- // For native platform, use the correct NativeAudio methods
56
- await NativeAudio.configure({
57
- fade: false,
58
- focus: true
59
- });
60
-
61
- await NativeAudio.preload({
62
- assetId: this.audioId,
63
- assetPath: url,
64
- audioChannelNum: 1,
65
- isUrl: true
66
- });
67
-
68
- await NativeAudio.play({
69
- assetId: this.audioId
70
- });
71
-
72
- // For native, we need to manually track duration
73
- this.duration = song.duration || 0;
74
- } else {
75
- if (!this.audioInstance) {
76
- this.audioInstance = new Audio();
77
- }
78
-
79
- this.audioInstance.src = url;
80
- await this.audioInstance.play();
81
-
82
- this.audioInstance.onloadedmetadata = () => {
83
- this.duration = this.audioInstance?.duration || 0;
84
- };
85
-
86
- this.audioInstance.ontimeupdate = () => {
87
- this.currentTime = this.audioInstance?.currentTime || 0;
88
- };
89
-
90
- this.audioInstance.onended = () => {
91
- this.autoNext();
92
- };
93
-
94
- this.audioInstance.onerror = () => {
95
- console.error('Error during playback');
96
- this.isPlaying = false;
97
- };
98
- }
99
-
100
- this.isPlaying = true;
101
- } catch (err) {
102
- console.error('Playback error:', err);
103
- this.isPlaying = false;
104
- }
38
+ if (!this.audio) this.audio = new Audio();
39
+
40
+ this.audio.src = url;
41
+ this.audio.play().catch(console.error);
42
+
43
+ this.audio.onloadedmetadata = () => this.duration = this.audio!.duration;
44
+ this.audio.ontimeupdate = () => this.currentTime = this.audio!.currentTime;
45
+ this.audio.onended = () => this.autoNext();
46
+
47
+ await this.setupMusicControls(song, true);
48
+
49
+ this.isPlaying = true;
105
50
  }
106
51
 
107
- private static async cleanupCurrentPlayback() {
108
- if (Capacitor.isNativePlatform()) {
109
- try {
110
- await NativeAudio.stop({ assetId: this.audioId });
111
- await NativeAudio.unload({ assetId: this.audioId });
112
- } catch (err) {
113
- console.debug('No audio to unload');
114
- }
115
- } else if (this.audioInstance) {
116
- this.audioInstance.pause();
117
- this.audioInstance.src = '';
118
- this.audioInstance.onloadedmetadata = null;
119
- this.audioInstance.ontimeupdate = null;
120
- this.audioInstance.onended = null;
121
- this.audioInstance.onerror = null;
122
- }
52
+ private static async setupMusicControls(song: any, isPlaying: boolean) {
53
+ if (!Capacitor.isNativePlatform()) return;
54
+
55
+ await CapacitorMusicControls.destroy(); // clear existing
56
+ await CapacitorMusicControls.create({
57
+ track: song.name || '',
58
+ artist: song.primaryArtists || '',
59
+ album: song.album || '',
60
+ cover: song.image || '',
61
+ isPlaying,
62
+ dismissable: true,
63
+ hasPrev: true,
64
+ hasNext: true,
65
+ });
66
+
67
+ CapacitorMusicControls.addListener('music-controls-next', () => this.next());
68
+ CapacitorMusicControls.addListener('music-controls-previous', () => this.prev());
69
+ CapacitorMusicControls.addListener('music-controls-pause', () => this.pause());
70
+ CapacitorMusicControls.addListener('music-controls-play', () => this.resume());
71
+ CapacitorMusicControls.addListener('music-controls-destroy', () => this.stop());
123
72
  }
124
73
 
125
74
  static async pause() {
126
- if (!this.isInitialized) return;
75
+ if (this.audio) this.audio.pause();
76
+ this.isPlaying = false;
77
+ Capacitor.isNativePlatform() && CapacitorMusicControls.updateIsPlaying({ isPlaying: false });
127
78
 
128
- try {
129
- if (Capacitor.isNativePlatform()) {
130
- await NativeAudio.pause({ assetId: this.audioId });
131
- } else if (this.audioInstance) {
132
- this.audioInstance.pause();
133
- }
134
- this.isPlaying = false;
135
- } catch (err) {
136
- console.error('Pause error:', err);
137
- }
138
79
  }
139
80
 
140
81
  static async resume() {
141
- if (!this.isInitialized) return;
82
+ if (this.audio) await this.audio.play();
83
+ this.isPlaying = true;
84
+ Capacitor.isNativePlatform() && CapacitorMusicControls.updateIsPlaying({ isPlaying: true });
85
+
86
+ }
142
87
 
143
- try {
144
- if (Capacitor.isNativePlatform()) {
145
- await NativeAudio.play({ assetId: this.audioId });
146
- } else if (this.audioInstance) {
147
- await this.audioInstance.play();
148
- }
149
- this.isPlaying = true;
150
- } catch (err) {
151
- console.error('Resume error:', err);
88
+ static async stop() {
89
+ if (this.audio) {
90
+ this.audio.pause();
91
+ this.audio.src = '';
152
92
  }
93
+ this.isPlaying = false;
94
+ await CapacitorMusicControls.destroy();
153
95
  }
154
96
 
155
97
  static async togglePlayPause() {
156
- if (!this.isInitialized) return;
157
-
158
98
  if (this.isPlaying) {
159
99
  await this.pause();
160
100
  } else if (this.currentSong) {
@@ -165,28 +105,19 @@ export class Player {
165
105
  }
166
106
 
167
107
  static async next() {
168
- if (!this.isInitialized) return;
169
-
170
108
  if (this.queue.length > 0) {
171
- const nextQueued = this.queue.shift();
172
- const index = this.playlist.findIndex(s => s.id === nextQueued.id);
173
- await this.play(nextQueued, index);
109
+ const next = this.queue.shift();
110
+ const index = this.playlist.findIndex(s => s.id === next.id);
111
+ await this.play(next, index);
174
112
  } else if (this.isShuffle) {
175
113
  await this.playRandom();
176
114
  } else if (this.currentIndex < this.playlist.length - 1) {
177
115
  await this.play(this.playlist[this.currentIndex + 1], this.currentIndex + 1);
178
- } else {
179
- // End of playlist
180
- this.isPlaying = false;
181
- this.currentSong = null;
182
116
  }
183
117
  }
184
118
 
185
119
  static async prev() {
186
- if (!this.isInitialized) return;
187
-
188
120
  if (this.currentTime > 3) {
189
- // If more than 3 seconds into song, restart current song
190
121
  await this.seekTo(0);
191
122
  } else if (this.currentIndex > 0) {
192
123
  await this.play(this.playlist[this.currentIndex - 1], this.currentIndex - 1);
@@ -198,14 +129,12 @@ export class Player {
198
129
  }
199
130
 
200
131
  static async playRandom() {
201
- if (!this.isInitialized || this.playlist.length <= 1) return;
202
-
203
- let randomIndex;
204
- do {
205
- randomIndex = Math.floor(Math.random() * this.playlist.length);
206
- } while (randomIndex === this.currentIndex && this.playlist.length > 1);
207
-
208
- await this.play(this.playlist[randomIndex], randomIndex);
132
+ if (this.playlist.length <= 1) return;
133
+ let rand = this.currentIndex;
134
+ while (rand === this.currentIndex) {
135
+ rand = Math.floor(Math.random() * this.playlist.length);
136
+ }
137
+ await this.play(this.playlist[rand], rand);
209
138
  }
210
139
 
211
140
  static toggleShuffle() {
@@ -213,7 +142,7 @@ export class Player {
213
142
  }
214
143
 
215
144
  static addToQueue(song: any) {
216
- if (!this.queue.some(q => q.id === song.id)) {
145
+ if (!this.queue.find(s => s.id === song.id)) {
217
146
  this.queue.push(song);
218
147
  }
219
148
  }
@@ -225,25 +154,15 @@ export class Player {
225
154
  }
226
155
 
227
156
  static reorderQueue(from: number, to: number) {
228
- if (from >= 0 && from < this.queue.length && to >= 0 && to < this.queue.length) {
229
- const item = this.queue.splice(from, 1)[0];
230
- this.queue.splice(to, 0, item);
231
- }
157
+ if (from === to) return;
158
+ const [item] = this.queue.splice(from, 1);
159
+ this.queue.splice(to, 0, item);
232
160
  }
233
161
 
234
- static async seekTo(time: number) {
235
- if (!this.isInitialized) return;
236
-
237
- try {
238
- if (Capacitor.isNativePlatform()) {
239
- // NativeAudio doesn't support seeking directly, might need a plugin extension
240
- console.warn('Seeking not fully supported on native platform');
241
- } else if (this.audioInstance) {
242
- this.audioInstance.currentTime = time;
243
- }
244
- this.currentTime = time;
245
- } catch (err) {
246
- console.error('Seek error:', err);
162
+ static async seekTo(seconds: number) {
163
+ if (this.audio) {
164
+ this.audio.currentTime = seconds;
165
+ this.currentTime = seconds;
247
166
  }
248
167
  }
249
168
 
@@ -255,10 +174,10 @@ export class Player {
255
174
  return this.duration;
256
175
  }
257
176
 
258
- static formatTime(time: number): string {
259
- const minutes = Math.floor(time / 60);
260
- const seconds = Math.floor(time % 60);
261
- return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
177
+ static formatTime(t: number): string {
178
+ const m = Math.floor(t / 60);
179
+ const s = Math.floor(t % 60);
180
+ return `${m}:${s < 10 ? '0' : ''}${s}`;
262
181
  }
263
182
 
264
183
  static isPlayingSong(): boolean {
@@ -270,9 +189,7 @@ export class Player {
270
189
  }
271
190
 
272
191
  static setQuality(index: number) {
273
- if (index >= 0) {
274
- this.selectedQuality = index;
275
- }
192
+ this.selectedQuality = index;
276
193
  }
277
194
 
278
195
  static getQueue(): any[] {
@@ -288,7 +205,10 @@ export class Player {
288
205
  }
289
206
 
290
207
  static async destroy() {
291
- await this.cleanupCurrentPlayback();
208
+ await this.stop();
209
+ this.playlist = [];
210
+ this.queue = [];
211
+ this.audio = null;
292
212
  this.isInitialized = false;
293
213
  }
294
- }
214
+ }