tunzo-player 1.0.22 → 1.0.24
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/api-calles.d.ts +25 -0
- package/dist/core/api-calles.js +95 -0
- package/dist/core/player.d.ts +3 -0
- package/dist/core/player.js +65 -0
- package/package.json +1 -1
- package/src/core/api-calles.ts +120 -22
- package/src/core/player.ts +68 -0
|
@@ -6,4 +6,29 @@ export declare class TunzoPlayerAPI {
|
|
|
6
6
|
* @returns Array of song result objects
|
|
7
7
|
*/
|
|
8
8
|
searchSongs(query: string, limit?: number): Promise<any[]>;
|
|
9
|
+
/**
|
|
10
|
+
* Search for playlists
|
|
11
|
+
* @param query Search keyword
|
|
12
|
+
* @param limit Number of results (default: 1000)
|
|
13
|
+
*/
|
|
14
|
+
searchPlaylists(query: string, limit?: number): Promise<any[]>;
|
|
15
|
+
/**
|
|
16
|
+
* Get playlist details
|
|
17
|
+
* @param id Playlist ID
|
|
18
|
+
* @param link Playlist URL/Link (optional but recommended if available)
|
|
19
|
+
* @param limit Number of songs to return (default: 1000)
|
|
20
|
+
*/
|
|
21
|
+
getPlaylistDetails(id: string, link?: string, limit?: number): Promise<any>;
|
|
22
|
+
/**
|
|
23
|
+
* Search for albums
|
|
24
|
+
* @param query Search keyword
|
|
25
|
+
* @param limit Number of results (default: 1000)
|
|
26
|
+
*/
|
|
27
|
+
searchAlbums(query: string, limit?: number): Promise<any[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Get album details
|
|
30
|
+
* @param id Album ID
|
|
31
|
+
* @param link Album URL/Link (optional but recommended if available)
|
|
32
|
+
*/
|
|
33
|
+
getAlbumDetails(id: string, link?: string): Promise<any>;
|
|
9
34
|
}
|
package/dist/core/api-calles.js
CHANGED
|
@@ -34,5 +34,100 @@ class TunzoPlayerAPI {
|
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Search for playlists
|
|
39
|
+
* @param query Search keyword
|
|
40
|
+
* @param limit Number of results (default: 1000)
|
|
41
|
+
*/
|
|
42
|
+
searchPlaylists(query_1) {
|
|
43
|
+
return __awaiter(this, arguments, void 0, function* (query, limit = 1000) {
|
|
44
|
+
var _a;
|
|
45
|
+
try {
|
|
46
|
+
const response = yield fetch(`https://saavn.sumit.co/api/search/playlists?query=${encodeURIComponent(query)}&limit=${limit}`);
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
49
|
+
}
|
|
50
|
+
const json = yield response.json();
|
|
51
|
+
return ((_a = json === null || json === void 0 ? void 0 : json.data) === null || _a === void 0 ? void 0 : _a.results) || [];
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
console.error("TunzoPlayerAPI Error (searchPlaylists):", error);
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get playlist details
|
|
61
|
+
* @param id Playlist ID
|
|
62
|
+
* @param link Playlist URL/Link (optional but recommended if available)
|
|
63
|
+
* @param limit Number of songs to return (default: 1000)
|
|
64
|
+
*/
|
|
65
|
+
getPlaylistDetails(id_1) {
|
|
66
|
+
return __awaiter(this, arguments, void 0, function* (id, link = "", limit = 1000) {
|
|
67
|
+
try {
|
|
68
|
+
let url = `https://saavn.sumit.co/api/playlists?id=${id}&limit=${limit}`;
|
|
69
|
+
if (link) {
|
|
70
|
+
url += `&link=${encodeURIComponent(link)}`;
|
|
71
|
+
}
|
|
72
|
+
const response = yield fetch(url);
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
75
|
+
}
|
|
76
|
+
const json = yield response.json();
|
|
77
|
+
return (json === null || json === void 0 ? void 0 : json.data) || null;
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.error("TunzoPlayerAPI Error (getPlaylistDetails):", error);
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Search for albums
|
|
87
|
+
* @param query Search keyword
|
|
88
|
+
* @param limit Number of results (default: 1000)
|
|
89
|
+
*/
|
|
90
|
+
searchAlbums(query_1) {
|
|
91
|
+
return __awaiter(this, arguments, void 0, function* (query, limit = 1000) {
|
|
92
|
+
var _a;
|
|
93
|
+
try {
|
|
94
|
+
const response = yield fetch(`https://saavn.sumit.co/api/search/albums?query=${encodeURIComponent(query)}&limit=${limit}`);
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
97
|
+
}
|
|
98
|
+
const json = yield response.json();
|
|
99
|
+
return ((_a = json === null || json === void 0 ? void 0 : json.data) === null || _a === void 0 ? void 0 : _a.results) || [];
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
console.error("TunzoPlayerAPI Error (searchAlbums):", error);
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get album details
|
|
109
|
+
* @param id Album ID
|
|
110
|
+
* @param link Album URL/Link (optional but recommended if available)
|
|
111
|
+
*/
|
|
112
|
+
getAlbumDetails(id_1) {
|
|
113
|
+
return __awaiter(this, arguments, void 0, function* (id, link = "") {
|
|
114
|
+
try {
|
|
115
|
+
let url = `https://saavn.sumit.co/api/albums?id=${id}`;
|
|
116
|
+
if (link) {
|
|
117
|
+
url += `&link=${encodeURIComponent(link)}`;
|
|
118
|
+
}
|
|
119
|
+
const response = yield fetch(url);
|
|
120
|
+
if (!response.ok) {
|
|
121
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
122
|
+
}
|
|
123
|
+
const json = yield response.json();
|
|
124
|
+
return (json === null || json === void 0 ? void 0 : json.data) || null;
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
console.error("TunzoPlayerAPI Error (getAlbumDetails):", error);
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
37
132
|
}
|
|
38
133
|
exports.TunzoPlayerAPI = TunzoPlayerAPI;
|
package/dist/core/player.d.ts
CHANGED
package/dist/core/player.js
CHANGED
|
@@ -7,6 +7,7 @@ class Player {
|
|
|
7
7
|
static initialize(playlist, quality = 3) {
|
|
8
8
|
this.playlist = playlist;
|
|
9
9
|
this.selectedQuality = quality;
|
|
10
|
+
this.setupMediaSession();
|
|
10
11
|
}
|
|
11
12
|
/** Call this once on user gesture to unlock audio in WebView */
|
|
12
13
|
static unlockAudio() {
|
|
@@ -27,9 +28,14 @@ class Player {
|
|
|
27
28
|
url = url.replace('http://', 'https://');
|
|
28
29
|
}
|
|
29
30
|
this.audio.src = url;
|
|
31
|
+
this.audio.preload = 'auto'; // Improve loading
|
|
30
32
|
this.audio.load(); // Ensure audio is loaded before play
|
|
31
33
|
this.audio.play().then(() => {
|
|
32
34
|
this.isPlaying = true;
|
|
35
|
+
this.updateMediaSessionMetadata(song);
|
|
36
|
+
if ('mediaSession' in navigator) {
|
|
37
|
+
navigator.mediaSession.playbackState = 'playing';
|
|
38
|
+
}
|
|
33
39
|
}).catch((err) => {
|
|
34
40
|
this.isPlaying = false;
|
|
35
41
|
console.warn('Audio play failed:', err);
|
|
@@ -37,6 +43,7 @@ class Player {
|
|
|
37
43
|
// Set duration
|
|
38
44
|
this.audio.onloadedmetadata = () => {
|
|
39
45
|
this.duration = this.audio.duration;
|
|
46
|
+
this.updatePositionState();
|
|
40
47
|
};
|
|
41
48
|
// Set current time
|
|
42
49
|
this.audio.ontimeupdate = () => {
|
|
@@ -54,10 +61,16 @@ class Player {
|
|
|
54
61
|
static pause() {
|
|
55
62
|
this.audio.pause();
|
|
56
63
|
this.isPlaying = false;
|
|
64
|
+
if ('mediaSession' in navigator) {
|
|
65
|
+
navigator.mediaSession.playbackState = 'paused';
|
|
66
|
+
}
|
|
57
67
|
}
|
|
58
68
|
static resume() {
|
|
59
69
|
this.audio.play();
|
|
60
70
|
this.isPlaying = true;
|
|
71
|
+
if ('mediaSession' in navigator) {
|
|
72
|
+
navigator.mediaSession.playbackState = 'playing';
|
|
73
|
+
}
|
|
61
74
|
}
|
|
62
75
|
static togglePlayPause() {
|
|
63
76
|
if (this.isPlaying) {
|
|
@@ -88,6 +101,7 @@ class Player {
|
|
|
88
101
|
}
|
|
89
102
|
static seek(seconds) {
|
|
90
103
|
this.audio.currentTime = seconds;
|
|
104
|
+
this.updatePositionState();
|
|
91
105
|
}
|
|
92
106
|
static autoNext() {
|
|
93
107
|
this.next();
|
|
@@ -148,6 +162,57 @@ class Player {
|
|
|
148
162
|
static getPlaylist() {
|
|
149
163
|
return this.playlist;
|
|
150
164
|
}
|
|
165
|
+
// -------------------------------------------------------------------------
|
|
166
|
+
// Native Media Session (Lock Screen Controls)
|
|
167
|
+
// -------------------------------------------------------------------------
|
|
168
|
+
static setupMediaSession() {
|
|
169
|
+
if ('mediaSession' in navigator) {
|
|
170
|
+
navigator.mediaSession.setActionHandler('play', () => this.resume());
|
|
171
|
+
navigator.mediaSession.setActionHandler('pause', () => this.pause());
|
|
172
|
+
navigator.mediaSession.setActionHandler('previoustrack', () => this.prev());
|
|
173
|
+
navigator.mediaSession.setActionHandler('nexttrack', () => this.next());
|
|
174
|
+
navigator.mediaSession.setActionHandler('seekto', (details) => {
|
|
175
|
+
if (details.seekTime !== undefined) {
|
|
176
|
+
this.seek(details.seekTime);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
static updateMediaSessionMetadata(song) {
|
|
182
|
+
var _a;
|
|
183
|
+
if ('mediaSession' in navigator) {
|
|
184
|
+
const artwork = [];
|
|
185
|
+
if (song.image) {
|
|
186
|
+
if (Array.isArray(song.image)) {
|
|
187
|
+
// Assuming image array contains objects with url/link and quality
|
|
188
|
+
song.image.forEach((img) => {
|
|
189
|
+
const src = img.link || img.url || (typeof img === 'string' ? img : '');
|
|
190
|
+
if (src) {
|
|
191
|
+
artwork.push({ src, sizes: '500x500', type: 'image/jpeg' });
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
else if (typeof song.image === 'string') {
|
|
196
|
+
artwork.push({ src: song.image, sizes: '500x500', type: 'image/jpeg' });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
navigator.mediaSession.metadata = new MediaMetadata({
|
|
200
|
+
title: song.name || song.title || 'Unknown Title',
|
|
201
|
+
artist: song.primaryArtists || song.artist || 'Unknown Artist',
|
|
202
|
+
album: ((_a = song.album) === null || _a === void 0 ? void 0 : _a.name) || song.album || '',
|
|
203
|
+
artwork: artwork.length > 0 ? artwork : undefined
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
static updatePositionState() {
|
|
208
|
+
if ('mediaSession' in navigator && this.duration > 0) {
|
|
209
|
+
navigator.mediaSession.setPositionState({
|
|
210
|
+
duration: this.duration,
|
|
211
|
+
playbackRate: this.audio.playbackRate,
|
|
212
|
+
position: this.audio.currentTime
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
151
216
|
}
|
|
152
217
|
exports.Player = Player;
|
|
153
218
|
Player.audio = new Audio();
|
package/package.json
CHANGED
package/src/core/api-calles.ts
CHANGED
|
@@ -1,26 +1,124 @@
|
|
|
1
1
|
export class TunzoPlayerAPI {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const json = await response.json();
|
|
19
|
-
return json?.data?.results || [];
|
|
20
|
-
} catch (error) {
|
|
21
|
-
console.error("TunzoPlayerAPI Error:", error);
|
|
22
|
-
return [];
|
|
2
|
+
/**
|
|
3
|
+
* Search for songs using the saavn.dev API
|
|
4
|
+
* @param query Search keyword (e.g., artist name, song name)
|
|
5
|
+
* @param limit Number of results to return (default: 250)
|
|
6
|
+
* @returns Array of song result objects
|
|
7
|
+
*/
|
|
8
|
+
async searchSongs(query: string, limit: number = 250): Promise<any[]> {
|
|
9
|
+
try {
|
|
10
|
+
const response = await fetch(
|
|
11
|
+
`https://saavn.sumit.co/api/search/songs?query=${encodeURIComponent(query)}&limit=${limit}`
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
if (!response.ok) {
|
|
15
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
23
16
|
}
|
|
17
|
+
|
|
18
|
+
const json = await response.json();
|
|
19
|
+
return json?.data?.results || [];
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error("TunzoPlayerAPI Error:", error);
|
|
22
|
+
return [];
|
|
24
23
|
}
|
|
25
24
|
}
|
|
26
|
-
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Search for playlists
|
|
28
|
+
* @param query Search keyword
|
|
29
|
+
* @param limit Number of results (default: 1000)
|
|
30
|
+
*/
|
|
31
|
+
async searchPlaylists(query: string, limit: number = 1000): Promise<any[]> {
|
|
32
|
+
try {
|
|
33
|
+
const response = await fetch(
|
|
34
|
+
`https://saavn.sumit.co/api/search/playlists?query=${encodeURIComponent(query)}&limit=${limit}`
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const json = await response.json();
|
|
42
|
+
return json?.data?.results || [];
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error("TunzoPlayerAPI Error (searchPlaylists):", error);
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Get playlist details
|
|
51
|
+
* @param id Playlist ID
|
|
52
|
+
* @param link Playlist URL/Link (optional but recommended if available)
|
|
53
|
+
* @param limit Number of songs to return (default: 1000)
|
|
54
|
+
*/
|
|
55
|
+
async getPlaylistDetails(id: string, link: string = "", limit: number = 1000): Promise<any> {
|
|
56
|
+
try {
|
|
57
|
+
let url = `https://saavn.sumit.co/api/playlists?id=${id}&limit=${limit}`;
|
|
58
|
+
if (link) {
|
|
59
|
+
url += `&link=${encodeURIComponent(link)}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const response = await fetch(url);
|
|
63
|
+
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const json = await response.json();
|
|
69
|
+
return json?.data || null;
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error("TunzoPlayerAPI Error (getPlaylistDetails):", error);
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Search for albums
|
|
78
|
+
* @param query Search keyword
|
|
79
|
+
* @param limit Number of results (default: 1000)
|
|
80
|
+
*/
|
|
81
|
+
async searchAlbums(query: string, limit: number = 1000): Promise<any[]> {
|
|
82
|
+
try {
|
|
83
|
+
const response = await fetch(
|
|
84
|
+
`https://saavn.sumit.co/api/search/albums?query=${encodeURIComponent(query)}&limit=${limit}`
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
if (!response.ok) {
|
|
88
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const json = await response.json();
|
|
92
|
+
return json?.data?.results || [];
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error("TunzoPlayerAPI Error (searchAlbums):", error);
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get album details
|
|
101
|
+
* @param id Album ID
|
|
102
|
+
* @param link Album URL/Link (optional but recommended if available)
|
|
103
|
+
*/
|
|
104
|
+
async getAlbumDetails(id: string, link: string = ""): Promise<any> {
|
|
105
|
+
try {
|
|
106
|
+
let url = `https://saavn.sumit.co/api/albums?id=${id}`;
|
|
107
|
+
if (link) {
|
|
108
|
+
url += `&link=${encodeURIComponent(link)}`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const response = await fetch(url);
|
|
112
|
+
|
|
113
|
+
if (!response.ok) {
|
|
114
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const json = await response.json();
|
|
118
|
+
return json?.data || null;
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error("TunzoPlayerAPI Error (getAlbumDetails):", error);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
package/src/core/player.ts
CHANGED
|
@@ -17,6 +17,7 @@ export class Player {
|
|
|
17
17
|
static initialize(playlist: any[], quality = 3) {
|
|
18
18
|
this.playlist = playlist;
|
|
19
19
|
this.selectedQuality = quality;
|
|
20
|
+
this.setupMediaSession();
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
/** Call this once on user gesture to unlock audio in WebView */
|
|
@@ -41,9 +42,14 @@ export class Player {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
this.audio.src = url;
|
|
45
|
+
this.audio.preload = 'auto'; // Improve loading
|
|
44
46
|
this.audio.load(); // Ensure audio is loaded before play
|
|
45
47
|
this.audio.play().then(() => {
|
|
46
48
|
this.isPlaying = true;
|
|
49
|
+
this.updateMediaSessionMetadata(song);
|
|
50
|
+
if ('mediaSession' in navigator) {
|
|
51
|
+
navigator.mediaSession.playbackState = 'playing';
|
|
52
|
+
}
|
|
47
53
|
}).catch((err) => {
|
|
48
54
|
this.isPlaying = false;
|
|
49
55
|
console.warn('Audio play failed:', err);
|
|
@@ -52,6 +58,7 @@ export class Player {
|
|
|
52
58
|
// Set duration
|
|
53
59
|
this.audio.onloadedmetadata = () => {
|
|
54
60
|
this.duration = this.audio.duration;
|
|
61
|
+
this.updatePositionState();
|
|
55
62
|
};
|
|
56
63
|
|
|
57
64
|
// Set current time
|
|
@@ -74,11 +81,17 @@ export class Player {
|
|
|
74
81
|
static pause() {
|
|
75
82
|
this.audio.pause();
|
|
76
83
|
this.isPlaying = false;
|
|
84
|
+
if ('mediaSession' in navigator) {
|
|
85
|
+
navigator.mediaSession.playbackState = 'paused';
|
|
86
|
+
}
|
|
77
87
|
}
|
|
78
88
|
|
|
79
89
|
static resume() {
|
|
80
90
|
this.audio.play();
|
|
81
91
|
this.isPlaying = true;
|
|
92
|
+
if ('mediaSession' in navigator) {
|
|
93
|
+
navigator.mediaSession.playbackState = 'playing';
|
|
94
|
+
}
|
|
82
95
|
}
|
|
83
96
|
|
|
84
97
|
static togglePlayPause() {
|
|
@@ -110,6 +123,7 @@ export class Player {
|
|
|
110
123
|
|
|
111
124
|
static seek(seconds: number) {
|
|
112
125
|
this.audio.currentTime = seconds;
|
|
126
|
+
this.updatePositionState();
|
|
113
127
|
}
|
|
114
128
|
|
|
115
129
|
static autoNext() {
|
|
@@ -186,4 +200,58 @@ export class Player {
|
|
|
186
200
|
static getPlaylist(): any[] {
|
|
187
201
|
return this.playlist;
|
|
188
202
|
}
|
|
203
|
+
|
|
204
|
+
// -------------------------------------------------------------------------
|
|
205
|
+
// Native Media Session (Lock Screen Controls)
|
|
206
|
+
// -------------------------------------------------------------------------
|
|
207
|
+
|
|
208
|
+
private static setupMediaSession() {
|
|
209
|
+
if ('mediaSession' in navigator) {
|
|
210
|
+
navigator.mediaSession.setActionHandler('play', () => this.resume());
|
|
211
|
+
navigator.mediaSession.setActionHandler('pause', () => this.pause());
|
|
212
|
+
navigator.mediaSession.setActionHandler('previoustrack', () => this.prev());
|
|
213
|
+
navigator.mediaSession.setActionHandler('nexttrack', () => this.next());
|
|
214
|
+
navigator.mediaSession.setActionHandler('seekto', (details) => {
|
|
215
|
+
if (details.seekTime !== undefined) {
|
|
216
|
+
this.seek(details.seekTime);
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private static updateMediaSessionMetadata(song: any) {
|
|
223
|
+
if ('mediaSession' in navigator) {
|
|
224
|
+
const artwork = [];
|
|
225
|
+
if (song.image) {
|
|
226
|
+
if (Array.isArray(song.image)) {
|
|
227
|
+
// Assuming image array contains objects with url/link and quality
|
|
228
|
+
song.image.forEach((img: any) => {
|
|
229
|
+
const src = img.link || img.url || (typeof img === 'string' ? img : '');
|
|
230
|
+
if (src) {
|
|
231
|
+
artwork.push({ src, sizes: '500x500', type: 'image/jpeg' });
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
} else if (typeof song.image === 'string') {
|
|
235
|
+
artwork.push({ src: song.image, sizes: '500x500', type: 'image/jpeg' });
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
navigator.mediaSession.metadata = new MediaMetadata({
|
|
240
|
+
title: song.name || song.title || 'Unknown Title',
|
|
241
|
+
artist: song.primaryArtists || song.artist || 'Unknown Artist',
|
|
242
|
+
album: song.album?.name || song.album || '',
|
|
243
|
+
artwork: artwork.length > 0 ? artwork : undefined
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private static updatePositionState() {
|
|
249
|
+
if ('mediaSession' in navigator && this.duration > 0) {
|
|
250
|
+
navigator.mediaSession.setPositionState({
|
|
251
|
+
duration: this.duration,
|
|
252
|
+
playbackRate: this.audio.playbackRate,
|
|
253
|
+
position: this.audio.currentTime
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
189
257
|
}
|