tunzo-player 1.0.9 → 1.0.12

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,3 +1,4 @@
1
+ import { BehaviorSubject } from 'rxjs';
1
2
  export declare class Player {
2
3
  private static audio;
3
4
  private static currentSong;
@@ -7,6 +8,7 @@ export declare class Player {
7
8
  private static duration;
8
9
  private static isShuffle;
9
10
  private static queue;
11
+ static queue$: BehaviorSubject<any[]>;
10
12
  private static playlist;
11
13
  private static selectedQuality;
12
14
  /** Initialize with playlist and quality */
@@ -23,6 +25,7 @@ export declare class Player {
23
25
  static autoNext(): void;
24
26
  static playRandom(): void;
25
27
  static toggleShuffle(): void;
28
+ static getShuffleStatus(): boolean;
26
29
  static addToQueue(song: any): void;
27
30
  static removeFromQueue(index: number): void;
28
31
  static reorderQueue(from: number, to: number): void;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Player = void 0;
4
+ const rxjs_1 = require("rxjs");
4
5
  class Player {
5
6
  /** Initialize with playlist and quality */
6
7
  static initialize(playlist, quality = 3) {
@@ -19,12 +20,16 @@ class Player {
19
20
  return;
20
21
  this.currentSong = song;
21
22
  this.currentIndex = index;
22
- this.audio.src = ((_a = song.downloadUrl[this.selectedQuality]) === null || _a === void 0 ? void 0 : _a.url) || '';
23
+ let url = ((_a = song.downloadUrl[this.selectedQuality]) === null || _a === void 0 ? void 0 : _a.url) || '';
24
+ // 🚀 Auto-convert http → https
25
+ if (url.startsWith('http://')) {
26
+ url = url.replace('http://', 'https://');
27
+ }
28
+ this.audio.src = url;
23
29
  this.audio.load(); // Ensure audio is loaded before play
24
30
  this.audio.play().then(() => {
25
31
  this.isPlaying = true;
26
32
  }).catch((err) => {
27
- // Handle play errors (autoplay, WebView restrictions)
28
33
  this.isPlaying = false;
29
34
  console.warn('Audio play failed:', err);
30
35
  });
@@ -40,6 +45,10 @@ class Player {
40
45
  this.audio.onended = () => {
41
46
  this.autoNext();
42
47
  };
48
+ // Catch errors
49
+ this.audio.onerror = (e) => {
50
+ console.error('Audio error:', this.audio.error, e);
51
+ };
43
52
  }
44
53
  static pause() {
45
54
  this.audio.pause();
@@ -60,6 +69,7 @@ class Player {
60
69
  static next() {
61
70
  if (this.queue.length > 0) {
62
71
  const nextQueued = this.queue.shift();
72
+ this.queue$.next([...this.queue]);
63
73
  const index = this.playlist.findIndex(s => s.id === nextQueued.id);
64
74
  this.play(nextQueued, index);
65
75
  }
@@ -93,17 +103,23 @@ class Player {
93
103
  static toggleShuffle() {
94
104
  this.isShuffle = !this.isShuffle;
95
105
  }
106
+ static getShuffleStatus() {
107
+ return this.isShuffle;
108
+ }
96
109
  static addToQueue(song) {
97
110
  if (!this.queue.some(q => q.id === song.id)) {
98
111
  this.queue.push(song);
112
+ this.queue$.next([...this.queue]);
99
113
  }
100
114
  }
101
115
  static removeFromQueue(index) {
102
116
  this.queue.splice(index, 1);
117
+ this.queue$.next([...this.queue]);
103
118
  }
104
119
  static reorderQueue(from, to) {
105
120
  const item = this.queue.splice(from, 1)[0];
106
121
  this.queue.splice(to, 0, item);
122
+ this.queue$.next([...this.queue]);
107
123
  }
108
124
  static getCurrentTime() {
109
125
  return this.currentTime;
@@ -141,5 +157,6 @@ Player.currentTime = 0;
141
157
  Player.duration = 0;
142
158
  Player.isShuffle = true;
143
159
  Player.queue = [];
160
+ Player.queue$ = new rxjs_1.BehaviorSubject([]);
144
161
  Player.playlist = [];
145
162
  Player.selectedQuality = 3;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tunzo-player",
3
- "version": "1.0.9",
3
+ "version": "1.0.12",
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",
@@ -27,5 +27,8 @@
27
27
  "license": "MIT",
28
28
  "publishConfig": {
29
29
  "access": "public"
30
+ },
31
+ "dependencies": {
32
+ "rxjs": "^7.8.2"
30
33
  }
31
34
  }
@@ -1,164 +1,188 @@
1
+ import { BehaviorSubject } from 'rxjs';
2
+
1
3
  export class Player {
2
- private static audio = new Audio();
3
- private static currentSong: any = null;
4
- private static currentIndex = 0;
5
- private static isPlaying = false;
6
- private static currentTime = 0;
7
- private static duration = 0;
8
- private static isShuffle = true;
9
- private static queue: any[] = [];
10
- private static playlist: any[] = [];
11
- private static selectedQuality = 3;
12
-
13
- /** Initialize with playlist and quality */
14
- static initialize(playlist: any[], quality = 3) {
15
- this.playlist = playlist;
16
- this.selectedQuality = quality;
17
- }
18
-
19
- /** Call this once on user gesture to unlock audio in WebView */
20
- static unlockAudio() {
21
- this.audio.src = '';
22
- this.audio.load();
23
- this.audio.play().catch(() => {});
24
- }
25
-
26
- static play(song: any, index: number = 0) {
27
- if (!song || !song.downloadUrl) return;
28
-
29
- this.currentSong = song;
30
- this.currentIndex = index;
31
- this.audio.src = song.downloadUrl[this.selectedQuality]?.url || '';
32
- this.audio.load(); // Ensure audio is loaded before play
33
- this.audio.play().then(() => {
34
- this.isPlaying = true;
35
- }).catch((err) => {
36
- // Handle play errors (autoplay, WebView restrictions)
37
- this.isPlaying = false;
38
- console.warn('Audio play failed:', err);
39
- });
40
-
41
- // Set duration
42
- this.audio.onloadedmetadata = () => {
43
- this.duration = this.audio.duration;
44
- };
45
-
46
- // Set current time
47
- this.audio.ontimeupdate = () => {
48
- this.currentTime = this.audio.currentTime;
49
- };
50
-
51
- // Auto-play next song
52
- this.audio.onended = () => {
53
- this.autoNext();
54
- };
55
- }
56
-
57
- static pause() {
58
- this.audio.pause();
59
- this.isPlaying = false;
60
- }
61
-
62
- static resume() {
63
- this.audio.play();
4
+ private static audio = new Audio();
5
+ private static currentSong: any = null;
6
+ private static currentIndex = 0;
7
+ private static isPlaying = false;
8
+ private static currentTime = 0;
9
+ private static duration = 0;
10
+ private static isShuffle = true;
11
+ private static queue: any[] = [];
12
+ static queue$ = new BehaviorSubject<any[]>([]);
13
+ private static playlist: any[] = [];
14
+ private static selectedQuality = 3;
15
+
16
+ /** Initialize with playlist and quality */
17
+ static initialize(playlist: any[], quality = 3) {
18
+ this.playlist = playlist;
19
+ this.selectedQuality = quality;
20
+ }
21
+
22
+ /** Call this once on user gesture to unlock audio in WebView */
23
+ static unlockAudio() {
24
+ this.audio.src = '';
25
+ this.audio.load();
26
+ this.audio.play().catch(() => { });
27
+ }
28
+
29
+ static play(song: any, index: number = 0) {
30
+ if (!song || !song.downloadUrl) return;
31
+
32
+ this.currentSong = song;
33
+ this.currentIndex = index;
34
+
35
+ let url = song.downloadUrl[this.selectedQuality]?.url || '';
36
+
37
+ // 🚀 Auto-convert http → https
38
+ if (url.startsWith('http://')) {
39
+ url = url.replace('http://', 'https://');
40
+ }
41
+
42
+ this.audio.src = url;
43
+ this.audio.load(); // Ensure audio is loaded before play
44
+ this.audio.play().then(() => {
64
45
  this.isPlaying = true;
46
+ }).catch((err) => {
47
+ this.isPlaying = false;
48
+ console.warn('Audio play failed:', err);
49
+ });
50
+
51
+ // Set duration
52
+ this.audio.onloadedmetadata = () => {
53
+ this.duration = this.audio.duration;
54
+ };
55
+
56
+ // Set current time
57
+ this.audio.ontimeupdate = () => {
58
+ this.currentTime = this.audio.currentTime;
59
+ };
60
+
61
+ // Auto-play next song
62
+ this.audio.onended = () => {
63
+ this.autoNext();
64
+ };
65
+
66
+ // Catch errors
67
+ this.audio.onerror = (e) => {
68
+ console.error('Audio error:', this.audio.error, e);
69
+ };
70
+ }
71
+
72
+
73
+ static pause() {
74
+ this.audio.pause();
75
+ this.isPlaying = false;
76
+ }
77
+
78
+ static resume() {
79
+ this.audio.play();
80
+ this.isPlaying = true;
81
+ }
82
+
83
+ static togglePlayPause() {
84
+ if (this.isPlaying) {
85
+ this.pause();
86
+ } else {
87
+ this.resume();
65
88
  }
66
-
67
- static togglePlayPause() {
68
- if (this.isPlaying) {
69
- this.pause();
70
- } else {
71
- this.resume();
72
- }
73
- }
74
-
75
- static next() {
76
- if (this.queue.length > 0) {
77
- const nextQueued = this.queue.shift();
78
- const index = this.playlist.findIndex(s => s.id === nextQueued.id);
79
- this.play(nextQueued, index);
80
- } else if (this.isShuffle) {
81
- this.playRandom();
82
- } else if (this.currentIndex < this.playlist.length - 1) {
83
- this.play(this.playlist[this.currentIndex + 1], this.currentIndex + 1);
84
- }
85
- }
86
-
87
- static prev() {
88
- if (this.currentIndex > 0) {
89
- this.play(this.playlist[this.currentIndex - 1], this.currentIndex - 1);
90
- }
91
- }
92
-
93
- static seek(seconds: number) {
94
- this.audio.currentTime = seconds;
95
- }
96
-
97
- static autoNext() {
98
- this.next();
99
- }
100
-
101
- static playRandom() {
102
- if (this.playlist.length <= 1) return;
103
-
104
- let randomIndex;
105
- do {
106
- randomIndex = Math.floor(Math.random() * this.playlist.length);
107
- } while (randomIndex === this.currentIndex);
108
-
109
- this.play(this.playlist[randomIndex], randomIndex);
110
- }
111
-
112
- static toggleShuffle() {
113
- this.isShuffle = !this.isShuffle;
114
- }
115
-
116
- static addToQueue(song: any) {
117
- if (!this.queue.some(q => q.id === song.id)) {
118
- this.queue.push(song);
119
- }
120
- }
121
-
122
- static removeFromQueue(index: number) {
123
- this.queue.splice(index, 1);
124
- }
125
-
126
- static reorderQueue(from: number, to: number) {
127
- const item = this.queue.splice(from, 1)[0];
128
- this.queue.splice(to, 0, item);
129
- }
130
-
131
- static getCurrentTime(): number {
132
- return this.currentTime;
133
- }
134
-
135
- static getDuration(): number {
136
- return this.duration;
137
- }
138
-
139
- static formatTime(time: number): string {
140
- const minutes = Math.floor(time / 60);
141
- const seconds = Math.floor(time % 60);
142
- return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
143
- }
144
-
145
- static isPlayingSong(): boolean {
146
- return this.isPlaying;
147
- }
148
-
149
- static getCurrentSong(): any {
150
- return this.currentSong;
151
- }
152
-
153
- static setQuality(index: number) {
154
- this.selectedQuality = index;
89
+ }
90
+
91
+ static next() {
92
+ if (this.queue.length > 0) {
93
+ const nextQueued = this.queue.shift();
94
+ this.queue$.next([...this.queue]);
95
+ const index = this.playlist.findIndex(s => s.id === nextQueued.id);
96
+ this.play(nextQueued, index);
97
+ } else if (this.isShuffle) {
98
+ this.playRandom();
99
+ } else if (this.currentIndex < this.playlist.length - 1) {
100
+ this.play(this.playlist[this.currentIndex + 1], this.currentIndex + 1);
155
101
  }
156
-
157
- static getQueue(): any[] {
158
- return this.queue;
102
+ }
103
+
104
+ static prev() {
105
+ if (this.currentIndex > 0) {
106
+ this.play(this.playlist[this.currentIndex - 1], this.currentIndex - 1);
159
107
  }
160
-
161
- static getPlaylist(): any[] {
162
- return this.playlist;
108
+ }
109
+
110
+ static seek(seconds: number) {
111
+ this.audio.currentTime = seconds;
112
+ }
113
+
114
+ static autoNext() {
115
+ this.next();
116
+ }
117
+
118
+ static playRandom() {
119
+ if (this.playlist.length <= 1) return;
120
+
121
+ let randomIndex;
122
+ do {
123
+ randomIndex = Math.floor(Math.random() * this.playlist.length);
124
+ } while (randomIndex === this.currentIndex);
125
+
126
+ this.play(this.playlist[randomIndex], randomIndex);
127
+ }
128
+
129
+ static toggleShuffle() {
130
+ this.isShuffle = !this.isShuffle;
131
+ }
132
+
133
+ static getShuffleStatus(): boolean {
134
+ return this.isShuffle;
135
+ }
136
+
137
+ static addToQueue(song: any) {
138
+ if (!this.queue.some(q => q.id === song.id)) {
139
+ this.queue.push(song);
140
+ this.queue$.next([...this.queue]);
163
141
  }
164
142
  }
143
+
144
+ static removeFromQueue(index: number) {
145
+ this.queue.splice(index, 1);
146
+ this.queue$.next([...this.queue]);
147
+ }
148
+
149
+ static reorderQueue(from: number, to: number) {
150
+ const item = this.queue.splice(from, 1)[0];
151
+ this.queue.splice(to, 0, item);
152
+ this.queue$.next([...this.queue]);
153
+ }
154
+
155
+ static getCurrentTime(): number {
156
+ return this.currentTime;
157
+ }
158
+
159
+ static getDuration(): number {
160
+ return this.duration;
161
+ }
162
+
163
+ static formatTime(time: number): string {
164
+ const minutes = Math.floor(time / 60);
165
+ const seconds = Math.floor(time % 60);
166
+ return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
167
+ }
168
+
169
+ static isPlayingSong(): boolean {
170
+ return this.isPlaying;
171
+ }
172
+
173
+ static getCurrentSong(): any {
174
+ return this.currentSong;
175
+ }
176
+
177
+ static setQuality(index: number) {
178
+ this.selectedQuality = index;
179
+ }
180
+
181
+ static getQueue(): any[] {
182
+ return this.queue;
183
+ }
184
+
185
+ static getPlaylist(): any[] {
186
+ return this.playlist;
187
+ }
188
+ }