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.
- package/dist/core/player.d.ts +3 -0
- package/dist/core/player.js +19 -2
- package/package.json +4 -1
- package/src/core/player.ts +181 -157
package/dist/core/player.d.ts
CHANGED
|
@@ -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;
|
package/dist/core/player.js
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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
|
}
|
package/src/core/player.ts
CHANGED
|
@@ -1,164 +1,188 @@
|
|
|
1
|
+
import { BehaviorSubject } from 'rxjs';
|
|
2
|
+
|
|
1
3
|
export class Player {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
158
|
-
|
|
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
|
-
|
|
162
|
-
|
|
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
|
+
}
|