@khang07/zing-mp3-api 1.1.0 → 1.3.4

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.
@@ -5,11 +5,22 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var axios = require('axios');
6
6
  var m3u8stream = require('m3u8stream');
7
7
  var node_stream = require('node:stream');
8
+ var node_url = require('node:url');
8
9
  var cookies = require('./utils/cookies.cjs');
9
10
  var encrypt = require('./utils/encrypt.cjs');
10
11
  var lapse = require('./utils/lapse.cjs');
12
+ var refined = require('./utils/refined.cjs');
11
13
 
12
- class ZingClient {
14
+ const isURL = (value) => {
15
+ try {
16
+ new node_url.URL(value);
17
+ return true;
18
+ }
19
+ catch {
20
+ return false;
21
+ }
22
+ };
23
+ class Client {
13
24
  static BASE_URL = 'https://zingmp3.vn/';
14
25
  static VERSION_URL_V1 = '1.6.34';
15
26
  static VERSION_URL_V2 = '1.13.13';
@@ -17,35 +28,47 @@ class ZingClient {
17
28
  static SECRET_KEY_V2 = '10a01dcf33762d3a204cb96429918ff6';
18
29
  static API_KEY_V1 = '88265e23d4284f25963e6eedac8fbfa3';
19
30
  static API_KEY_V2 = '38e8643fb0dc04e8d65b99994d3dafff';
31
+ static API_VIDEO_PATH = '/api/v2/page/get/video';
32
+ static API_MUSIC_PATH = '/api/v2/song/get/streaming';
33
+ static EXTRA_API_MUSIC_PATH = '/api/song/get-song-info';
34
+ static API_SEARCH_PATH = '/api/v2/search';
35
+ static API_PLAYLIST_PATH = '/api/v2/page/get/playlist';
36
+ static API_MEDIA_DETAILS_PATH = '/api/v2/song/get/info';
37
+ static API_ARTIST_PATH = '/api/v2/page/get/artist';
38
+ static getIDFromURL(url) {
39
+ if (typeof url !== 'string' || !url.trim().length)
40
+ throw new lapse.Lapse('URL must be a non-empty string', 'ERROR_INVALID_URL');
41
+ const match = url.match(/\/([A-Z0-9]{8})\.html(?:\?|#|$)/i) || url.match(/^https?:\/\/zingmp3\.vn\/([^/?#]+)\/?(?:[?#].*)?$/i);
42
+ if (!match)
43
+ throw new lapse.Lapse('Could not extract ID from URL', 'ERROR_INVALID_URL');
44
+ return match[1];
45
+ }
20
46
  ctime = Math.floor(Date.now() / 1000).toString();
21
- jar;
22
47
  instance;
23
- maxRate;
48
+ maxLoad;
49
+ maxHighWaterMark;
50
+ userAgent;
51
+ jar;
24
52
  constructor(options = {}) {
25
- this.maxRate = [
26
- options?.maxRate?.[0] ?? 100 * 1024,
27
- options?.maxRate?.[1] ?? 16 * 1024
28
- ];
29
- this.jar = new cookies.Cookies();
30
- const axiosOptions = {
31
- baseURL: ZingClient.BASE_URL,
53
+ this.maxLoad = options.maxLoad ?? 1024 * 1024;
54
+ this.maxHighWaterMark = options.maxHighWaterMark ?? 16 * 1024;
55
+ this.userAgent = options?.userAgent ?? 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3';
56
+ this.jar = options.jar instanceof cookies.Cookies ? options.jar : new cookies.Cookies();
57
+ this.instance = axios.create({
58
+ baseURL: Client.BASE_URL,
32
59
  params: {
33
- version: ZingClient.VERSION_URL_V1,
34
- apiKey: ZingClient.API_KEY_V1,
60
+ version: Client.VERSION_URL_V1,
61
+ apiKey: Client.API_KEY_V1,
35
62
  ctime: this.ctime
36
63
  },
37
- maxRate: [
38
- 100 * 1024,
39
- this.maxRate[0]
40
- ],
64
+ maxRate: this.maxLoad,
41
65
  headers: {
42
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
66
+ 'User-Agent': this.userAgent
43
67
  }
44
- };
45
- this.instance = axios.create(axiosOptions);
46
- this.instance.interceptors.request.use((options) => {
68
+ });
69
+ this.instance.interceptors.request.use(async (options) => {
47
70
  const base = options.baseURL ?? '';
48
- const url = new URL(options.url ?? '/', base).toString();
71
+ const url = new node_url.URL(options.url ?? '/', base).toString();
49
72
  const additionalHeaders = this.jar.applyToHeaders(url);
50
73
  for (const [key, value] of Object.entries(additionalHeaders))
51
74
  options.headers.set(key, value);
@@ -56,34 +79,37 @@ class ZingClient {
56
79
  const requestUrl = response.request?.res?.responseUrl ?? response.config.url;
57
80
  if (requestUrl && Array.isArray(setCookie))
58
81
  this.jar.setCookies(setCookie, requestUrl);
59
- return response;
82
+ return response.data;
60
83
  });
61
84
  }
85
+ async ensureCookies() {
86
+ if (this.jar.getCookies(Client.BASE_URL).length === 0)
87
+ void await this.instance.get('/');
88
+ }
62
89
  async video(videoID) {
63
- if (typeof videoID !== 'string' || !videoID.length)
90
+ const value = videoID instanceof node_url.URL ? videoID.toString() : videoID;
91
+ if (typeof value !== 'string' || !value.trim().length)
64
92
  throw new lapse.Lapse('ID must be a non-empty string', 'ERROR_INVALID_ID');
65
- const uri = '/api/v2/page/get/video';
66
93
  try {
67
- if (this.jar.getCookies(ZingClient.BASE_URL).length === 0)
68
- void await this.instance.get('/');
69
- const response = await this.instance.get(uri, {
94
+ videoID = isURL(value) ? Client.getIDFromURL(value) : value;
95
+ void await this.ensureCookies();
96
+ const response = await this.instance.get(Client.API_VIDEO_PATH, {
70
97
  params: {
71
98
  id: videoID,
72
- sig: encrypt.createSignature(uri, 'ctime=' + this.ctime + 'id=' + videoID + 'version=' + ZingClient.VERSION_URL_V1, ZingClient.SECRET_KEY_V1)
99
+ sig: encrypt.createSignature(Client.API_VIDEO_PATH, 'ctime=' + this.ctime + 'id=' + videoID + 'version=' + Client.VERSION_URL_V1, Client.SECRET_KEY_V1)
73
100
  }
74
101
  });
75
- const body = response.data;
76
- if (body.err !== 0)
77
- throw new lapse.Lapse('Video could not be found', 'ERROR_VIDEO_NOT_FOUND', response.status, body);
78
- const videoURL = body.data?.streaming?.hls?.['360p'];
102
+ if (response.err !== 0)
103
+ throw new lapse.Lapse('Video could not be found', 'ERROR_VIDEO_NOT_FOUND', response.err, response);
104
+ const videoURL = response.data?.streaming?.hls?.['720p'] || response.data?.streaming?.hls?.['360p'];
79
105
  if (!videoURL || !videoURL.length)
80
106
  throw new lapse.Lapse('Streaming URL not found', 'ERROR_STREAM_URL_NOT_FOUND');
81
- const streamVideo = m3u8stream(videoURL);
82
- streamVideo.once('error', (error) => {
107
+ const source = m3u8stream(videoURL);
108
+ source.once('error', (error) => {
83
109
  const lapse$1 = new lapse.Lapse('Stream download failed', 'ERROR_STREAM_DOWNLOAD', void 0, error);
84
- streamVideo.destroy(lapse$1);
110
+ source.destroy(lapse$1);
85
111
  });
86
- return streamVideo;
112
+ return source;
87
113
  }
88
114
  catch (error) {
89
115
  if (error instanceof lapse.Lapse)
@@ -91,78 +117,87 @@ class ZingClient {
91
117
  throw new lapse.Lapse('Failed to fetch video stream', 'ERROR_VIDEO_FETCH', axios.isAxiosError(error) ? error.response?.status : void 0, error);
92
118
  }
93
119
  }
94
- videoSyncLike(videoID) {
95
- const video = new node_stream.PassThrough({ highWaterMark: this.maxRate[1] });
120
+ videoSync(videoID) {
121
+ const video = new node_stream.PassThrough({ highWaterMark: this.maxHighWaterMark });
122
+ let copySource;
123
+ let closed = false;
124
+ let sourceDestroyed = false;
125
+ const destroy = () => {
126
+ if (!copySource || sourceDestroyed)
127
+ return;
128
+ sourceDestroyed = true;
129
+ if (!copySource)
130
+ return;
131
+ copySource.unpipe(video);
132
+ if (!copySource.destroyed)
133
+ copySource.destroy();
134
+ };
135
+ const closer = () => {
136
+ closed = true;
137
+ destroy();
138
+ };
139
+ video.once('close', closer);
140
+ video.once('error', closer);
96
141
  void this.video(videoID)
97
142
  .then((source) => {
143
+ copySource = source;
98
144
  source.once('error', (error) => {
99
145
  const lapse$1 = error instanceof lapse.Lapse ? error : new lapse.Lapse('Stream download failed', 'ERROR_STREAM_DOWNLOAD', void 0, error);
100
146
  video.destroy(lapse$1);
101
147
  });
102
- const destroy = () => {
103
- if (!source.destroyed)
104
- source.destroy();
105
- };
106
- video.once('close', destroy);
107
- video.once('error', destroy);
148
+ if (closed || video.destroyed) {
149
+ destroy();
150
+ return;
151
+ }
108
152
  source.pipe(video);
109
153
  })
110
154
  .catch((error) => {
111
- if (error instanceof lapse.Lapse)
112
- throw error;
113
- throw new lapse.Lapse('Failed to fetch video stream', 'ERROR_VIDEO_FETCH', axios.isAxiosError(error) ? error.response?.status : void 0, error);
155
+ const lapse$1 = error instanceof lapse.Lapse ? error : new lapse.Lapse('Failed to fetch video stream', 'ERROR_VIDEO_FETCH', axios.isAxiosError(error) ? error.response?.status : void 0, error);
156
+ video.destroy(lapse$1);
114
157
  });
115
158
  return video;
116
159
  }
117
160
  async music(musicID) {
118
- if (typeof musicID !== 'string' || !musicID.trim().length)
161
+ const value = musicID instanceof node_url.URL ? musicID.toString() : musicID;
162
+ if (typeof value !== 'string' || !value.trim().length)
119
163
  throw new lapse.Lapse('ID must be a non-empty string', 'ERROR_INVALID_ID');
120
- let musicURL;
121
- const uri = '/api/v2/song/get/streaming';
122
164
  try {
123
- if (this.jar.getCookies(ZingClient.BASE_URL).length === 0)
124
- void await this.instance.get('/');
125
- const response = await this.instance.get(uri, {
165
+ musicID = isURL(value) ? Client.getIDFromURL(value) : value;
166
+ void await this.ensureCookies();
167
+ const response = await this.instance.get(Client.API_MUSIC_PATH, {
126
168
  params: {
127
169
  id: musicID,
128
- sig: encrypt.createSignature(uri, 'ctime=' + this.ctime + 'id=' + musicID + 'version=' + ZingClient.VERSION_URL_V1, ZingClient.SECRET_KEY_V1)
170
+ sig: encrypt.createSignature(Client.API_MUSIC_PATH, 'ctime=' + this.ctime + 'id=' + musicID + 'version=' + Client.VERSION_URL_V1, Client.SECRET_KEY_V1)
129
171
  }
130
172
  });
131
- const body = response.data;
132
- if (body.err === -1150) {
133
- let retrySuccess = false;
134
- const uri_v2 = '/api/song/get-song-info';
135
- for (let step = 0; step < 2; step++) {
136
- const retry = await this.instance.get(uri_v2, {
173
+ let musicURL = response.data?.[320] && response.data[320] !== 'VIP' ? response.data[320] : response.data?.[128];
174
+ if (response.err === -1150) {
175
+ const retry = async (step, before) => {
176
+ if (step > 3)
177
+ throw new lapse.Lapse('Music requested by VIP, PRI', 'ERROR_MUSIC_VIP_ONLY', before ? before.err : void 0, before);
178
+ const retryData = await this.instance.get(Client.EXTRA_API_MUSIC_PATH, {
137
179
  params: {
138
180
  id: musicID,
139
- api_key: ZingClient.API_KEY_V2,
140
- sig: encrypt.createSignature('/song/get-song-info', 'ctime=' + this.ctime + 'id=' + musicID, ZingClient.SECRET_KEY_V2),
181
+ api_key: Client.API_KEY_V2,
182
+ sig: encrypt.createSignature('/song/get-song-info', 'ctime=' + this.ctime + 'id=' + musicID, Client.SECRET_KEY_V2),
141
183
  version: void 0,
142
184
  apiKey: void 0
143
185
  }
144
186
  });
145
- if (retry.data.err === 0) {
146
- retrySuccess = true;
147
- musicURL = retry.data.data?.streaming?.default?.[128];
148
- break;
149
- }
150
- }
151
- if (!retrySuccess)
152
- throw new lapse.Lapse('Music requested by VIP, PRI', 'ERROR_MUSIC_VIP_ONLY', response.status, body);
187
+ if (retryData.err === 0)
188
+ return retryData.data?.streaming?.default?.[128];
189
+ return retry(step + 1, retryData);
190
+ };
191
+ musicURL = await retry(0);
153
192
  }
154
- else if (body.err === 0)
155
- musicURL = body.data?.[128];
156
- else
157
- throw new lapse.Lapse('This song could not be found', 'ERROR_MUSIC_NOT_FOUND', response.status, body);
158
193
  if (!musicURL || !musicURL.length)
159
194
  throw new lapse.Lapse('Streaming URL not found', 'ERROR_STREAM_URL_NOT_FOUND');
160
- const streamMusic = await this.instance.get(musicURL, { responseType: 'stream' });
161
- streamMusic.data.once('error', (error) => {
162
- const lapse$1 = new lapse.Lapse('Stream download failed', 'ERROR_STREAM_DOWNLOAD', streamMusic.status, error);
163
- streamMusic.data.destroy(lapse$1);
195
+ const source = await this.instance.get(musicURL, { responseType: 'stream' });
196
+ source.once('error', (error) => {
197
+ const lapse$1 = new lapse.Lapse('Stream download failed', 'ERROR_STREAM_DOWNLOAD', void 0, error);
198
+ source.destroy(lapse$1);
164
199
  });
165
- return streamMusic.data;
200
+ return source;
166
201
  }
167
202
  catch (error) {
168
203
  if (error instanceof lapse.Lapse)
@@ -170,84 +205,217 @@ class ZingClient {
170
205
  throw new lapse.Lapse('Failed to fetch music stream', 'ERROR_MUSIC_FETCH', axios.isAxiosError(error) ? error.response?.status : void 0, error);
171
206
  }
172
207
  }
173
- musicSyncLike(musicID) {
174
- const music = new node_stream.PassThrough({ highWaterMark: this.maxRate[1] });
208
+ musicSync(musicID) {
209
+ const music = new node_stream.PassThrough({ highWaterMark: this.maxHighWaterMark });
210
+ let copySource;
211
+ let closed = false;
212
+ let sourceDestroyed = false;
213
+ const destroy = () => {
214
+ if (!copySource || sourceDestroyed)
215
+ return;
216
+ sourceDestroyed = true;
217
+ copySource.unpipe(music);
218
+ if (!copySource.destroyed)
219
+ copySource.destroy();
220
+ };
221
+ const closer = () => {
222
+ closed = true;
223
+ destroy();
224
+ };
225
+ music.once('close', closer);
226
+ music.once('error', closer);
175
227
  void this.music(musicID)
176
228
  .then((source) => {
229
+ copySource = source;
177
230
  source.once('error', (error) => {
178
231
  const lapse$1 = error instanceof lapse.Lapse ? error : new lapse.Lapse('Stream download failed', 'ERROR_STREAM_DOWNLOAD', void 0, error);
179
232
  music.destroy(lapse$1);
180
233
  });
181
- const destroy = () => {
182
- if (!source.destroyed)
183
- source.destroy();
184
- };
185
- music.once('close', destroy);
186
- music.once('error', destroy);
234
+ if (closed || music.destroyed) {
235
+ destroy();
236
+ return;
237
+ }
187
238
  source.pipe(music);
188
239
  })
189
240
  .catch((error) => {
190
- if (error instanceof lapse.Lapse)
191
- throw error;
192
- throw new lapse.Lapse('Failed to fetch music stream', 'ERROR_MUSIC_FETCH', axios.isAxiosError(error) ? error.response?.status : void 0, error);
241
+ const lapse$1 = error instanceof lapse.Lapse ? error : new lapse.Lapse('Failed to fetch music stream', 'ERROR_MUSIC_FETCH', axios.isAxiosError(error) ? error.response?.status : void 0, error);
242
+ music.destroy(lapse$1);
193
243
  });
194
244
  return music;
195
245
  }
196
- async search(keyword) {
197
- if (typeof keyword !== 'string' || !keyword.trim().length)
198
- throw new lapse.Lapse('Keyword must be a non-empty string', 'ERROR_INVALID_KEYWORD');
199
- const uri = '/api/v2/search/multi';
246
+ async playlist(playlistID) {
247
+ const value = playlistID instanceof node_url.URL ? playlistID.toString() : playlistID;
248
+ if (typeof value !== 'string' || !value.trim().length)
249
+ throw new lapse.Lapse('ID must be a non-empty string', 'ERROR_INVALID_ID');
250
+ try {
251
+ playlistID = isURL(value) ? Client.getIDFromURL(value) : value;
252
+ void await this.ensureCookies();
253
+ const response = await this.instance.get(Client.API_PLAYLIST_PATH, {
254
+ params: {
255
+ id: playlistID,
256
+ sig: encrypt.createSignature(Client.API_PLAYLIST_PATH, 'ctime=' + this.ctime + 'id=' + playlistID + 'version=' + Client.VERSION_URL_V1, Client.SECRET_KEY_V1)
257
+ }
258
+ });
259
+ if (response.err !== 0)
260
+ throw new lapse.Lapse('Could not find playlist', 'ERROR_PLAYLIST_NOT_FOUND', response.err, response);
261
+ return refined.createPlayList(response.data);
262
+ }
263
+ catch (error) {
264
+ if (error instanceof lapse.Lapse)
265
+ throw error;
266
+ throw new lapse.Lapse('Failed to fetch playlist', 'ERROR_PLAYLIST_FETCH', axios.isAxiosError(error) ? error.response?.status : void 0, error);
267
+ }
268
+ }
269
+ async artist(aliasID) {
270
+ const value = aliasID instanceof node_url.URL ? aliasID.toString() : aliasID;
271
+ if (typeof value !== 'string' || !value.trim().length)
272
+ throw new lapse.Lapse('ID must be a non-empty string', 'ERROR_INVALID_ID');
200
273
  try {
201
- if (this.jar.getCookies(ZingClient.BASE_URL).length === 0)
202
- void await this.instance.get('/');
203
- const response = await this.instance.get(uri, {
274
+ aliasID = isURL(value) ? Client.getIDFromURL(value) : value;
275
+ void await this.ensureCookies();
276
+ const response = await this.instance.get(Client.API_ARTIST_PATH, {
204
277
  params: {
205
- q: keyword,
206
- sig: encrypt.createSignature(uri, 'ctime=' + this.ctime + 'version=' + ZingClient.VERSION_URL_V1, ZingClient.SECRET_KEY_V1)
278
+ alias: aliasID,
279
+ sig: encrypt.createSignature(Client.API_ARTIST_PATH, 'ctime=' + this.ctime + 'version=' + Client.VERSION_URL_V1, Client.SECRET_KEY_V1)
207
280
  }
208
281
  });
209
- const body = response.data;
210
- if (body.err !== 0)
211
- throw new lapse.Lapse('Could not perform search', 'ERROR_SEARCH_FAILED', response.status, body);
212
- const songs = body.data?.songs ?? [];
213
- return songs.map((song) => ({
214
- id: song.encodeId,
215
- name: song.title,
216
- alias: song.alias,
217
- isOffical: song.isOffical,
218
- username: song.username,
219
- artists: song.artists.map((artist) => ({
220
- id: artist.id,
221
- name: artist.name,
222
- alias: artist.alias,
223
- thumbnail: {
224
- w240: artist.thumbnailM,
225
- w360: artist.thumbnail
226
- }
227
- })),
228
- thumbnail: {
229
- w94: song.thumbnailM,
230
- w240: song.thumbnail
231
- },
232
- duration: song.duration,
233
- releaseDate: song.releaseDate
234
- }));
282
+ if (response.err === -108)
283
+ throw new lapse.Lapse('Artist not found', 'ERROR_ARTIST_NOT_FOUND', response.err, response);
284
+ if (response.err !== 0)
285
+ throw new lapse.Lapse('Could not fetch artist', 'ERROR_ARTIST_FETCH', response.err, response);
286
+ return refined.createArtist(response.data);
235
287
  }
236
288
  catch (error) {
237
289
  if (error instanceof lapse.Lapse)
238
290
  throw error;
239
- throw new lapse.Lapse('Failed to perform search', 'ERROR_SEARCH', axios.isAxiosError(error) ? error.response?.status : void 0, error);
291
+ throw new lapse.Lapse('Failed to fetch artist', 'ERROR_ARTIST_FETCH', axios.isAxiosError(error) ? error.response?.status : void 0, error);
292
+ }
293
+ }
294
+ async mediaDetails(mediaID) {
295
+ const value = mediaID instanceof node_url.URL ? mediaID.toString() : mediaID;
296
+ if (typeof value !== 'string' || !value.trim().length)
297
+ throw new lapse.Lapse('ID must be a non-empty string', 'ERROR_INVALID_ID');
298
+ try {
299
+ mediaID = isURL(value) ? Client.getIDFromURL(value) : value;
300
+ void await this.ensureCookies();
301
+ const response = await this.instance.get(Client.API_MEDIA_DETAILS_PATH, {
302
+ params: {
303
+ id: mediaID,
304
+ sig: encrypt.createSignature(Client.API_MEDIA_DETAILS_PATH, 'ctime=' + this.ctime + 'id=' + mediaID + 'version=' + Client.VERSION_URL_V1, Client.SECRET_KEY_V1)
305
+ }
306
+ });
307
+ if (response.err === -1023)
308
+ throw new lapse.Lapse('Media not found', 'ERROR_MEDIA_NOT_FOUND', response.err, response);
309
+ if (response.err !== 0)
310
+ throw new lapse.Lapse('Could not fetch media', 'ERROR_MEDIA_FETCH', response.err, response);
311
+ return refined.createMedia(response.data);
312
+ }
313
+ catch (error) {
314
+ if (error instanceof lapse.Lapse)
315
+ throw error;
316
+ throw new lapse.Lapse('Failed to fetch media', 'ERROR_MEDIA_FETCH', axios.isAxiosError(error) ? error.response?.status : void 0, error);
317
+ }
318
+ }
319
+ async searchMusic(query) {
320
+ if (typeof query !== 'string' || !query.trim().length)
321
+ throw new lapse.Lapse('Query must be a non-empty string', 'ERROR_INVALID_QUERY');
322
+ try {
323
+ void await this.ensureCookies();
324
+ const response = await this.instance.get(Client.API_SEARCH_PATH, {
325
+ params: {
326
+ q: query,
327
+ type: 'song',
328
+ page: 1,
329
+ count: 20,
330
+ sig: encrypt.createSignature(Client.API_SEARCH_PATH, 'count=20ctime=' + this.ctime + 'page=1type=songversion=' + Client.VERSION_URL_V1, Client.SECRET_KEY_V1)
331
+ }
332
+ });
333
+ if (response.err !== 0)
334
+ throw new lapse.Lapse('Search could not be fetched', 'ERROR_SEARCH_FAILED', response.err, response);
335
+ return response.data.items.map(refined.createSearchMedia);
336
+ }
337
+ catch (error) {
338
+ if (error instanceof lapse.Lapse)
339
+ throw error;
340
+ throw new lapse.Lapse('Search could not be fetch', 'ERROR_SEARCH_FETCH', axios.isAxiosError(error) ? error.response?.status : void 0, error);
341
+ }
342
+ }
343
+ async searchVideo(query) {
344
+ if (typeof query !== 'string' || !query.trim().length)
345
+ throw new lapse.Lapse('Query must be a non-empty string', 'ERROR_INVALID_QUERY');
346
+ try {
347
+ void await this.ensureCookies();
348
+ const response = await this.instance.get(Client.API_SEARCH_PATH, {
349
+ params: {
350
+ q: query,
351
+ type: 'video',
352
+ page: 1,
353
+ count: 20,
354
+ sig: encrypt.createSignature(Client.API_SEARCH_PATH, 'count=20ctime=' + this.ctime + 'page=1type=videoversion=' + Client.VERSION_URL_V1, Client.SECRET_KEY_V1)
355
+ }
356
+ });
357
+ if (response.err !== 0)
358
+ throw new lapse.Lapse('Search could not be fetched', 'ERROR_SEARCH_FAILED', response.err, response);
359
+ return response.data.items.filter(item => item.artists).map(refined.createSearchMedia);
360
+ }
361
+ catch (error) {
362
+ if (error instanceof lapse.Lapse)
363
+ throw error;
364
+ throw new lapse.Lapse('Search could not be fetch', 'ERROR_SEARCH_FETCH', axios.isAxiosError(error) ? error.response?.status : void 0, error);
365
+ }
366
+ }
367
+ async searchList(query) {
368
+ if (typeof query !== 'string' || !query.trim().length)
369
+ throw new lapse.Lapse('Query must be a non-empty string', 'ERROR_INVALID_QUERY');
370
+ try {
371
+ void await this.ensureCookies();
372
+ const response = await this.instance.get(Client.API_SEARCH_PATH, {
373
+ params: {
374
+ q: query,
375
+ type: 'playlist',
376
+ page: 1,
377
+ count: 20,
378
+ sig: encrypt.createSignature(Client.API_SEARCH_PATH, 'count=20ctime=' + this.ctime + 'page=1type=playlistversion=' + Client.VERSION_URL_V1, Client.SECRET_KEY_V1)
379
+ }
380
+ });
381
+ if (response.err !== 0)
382
+ throw new lapse.Lapse('Search could not be fetched', 'ERROR_SEARCH_FAILED', response.err, response);
383
+ return response.data.items.map(refined.createSearchPlayList);
384
+ }
385
+ catch (error) {
386
+ if (error instanceof lapse.Lapse)
387
+ throw error;
388
+ throw new lapse.Lapse('Search could not be fetch', 'ERROR_SEARCH_FETCH', axios.isAxiosError(error) ? error.response?.status : void 0, error);
389
+ }
390
+ }
391
+ async searchArtist(query) {
392
+ if (typeof query !== 'string' || !query.trim().length)
393
+ throw new lapse.Lapse('Query must be a non-empty string', 'ERROR_INVALID_QUERY');
394
+ try {
395
+ void await this.ensureCookies();
396
+ const response = await this.instance.get(Client.API_SEARCH_PATH, {
397
+ params: {
398
+ q: query,
399
+ type: 'artist',
400
+ page: 1,
401
+ count: 20,
402
+ sig: encrypt.createSignature(Client.API_SEARCH_PATH, 'count=20ctime=' + this.ctime + 'page=1type=artistversion=' + Client.VERSION_URL_V1, Client.SECRET_KEY_V1)
403
+ }
404
+ });
405
+ if (response.err !== 0)
406
+ throw new lapse.Lapse('Search could not be fetched', 'ERROR_SEARCH_FAILED', response.err, response);
407
+ return response.data.items.map(refined.createSearchArtist);
408
+ }
409
+ catch (error) {
410
+ if (error instanceof lapse.Lapse)
411
+ throw error;
412
+ throw new lapse.Lapse('Search could not be fetch', 'ERROR_SEARCH_FETCH', axios.isAxiosError(error) ? error.response?.status : void 0, error);
240
413
  }
241
414
  }
242
415
  }
243
- const clientOptions = {
244
- maxRate: [
245
- 100 * 1024,
246
- 16 * 1024
247
- ]
248
- };
249
- const client = new ZingClient(clientOptions);
416
+ const client = new Client();
417
+ client.searchMusic('skyfall');
250
418
 
251
- exports.ZingClient = ZingClient;
419
+ exports.Client = Client;
252
420
  exports.default = client;
253
421
  //# sourceMappingURL=index.cjs.map