baileyz 1.0.3 → 1.0.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.
package/README.md CHANGED
@@ -372,234 +372,6 @@ await sock.sendMessage(jid, {
372
372
 
373
373
  ---
374
374
 
375
- ## 📺 YouTube Downloader & Search Usage Examples
376
-
377
- <details>
378
-
379
- <summary><strong>Click to expand: YouTube Downloader & Search Usage Examples</strong></summary>
380
-
381
- ### 1️⃣ YouTube Search
382
-
383
- **JavaScript:**
384
-
385
- ```javascript
386
-
387
- const { search } = require('baileyz');
388
-
389
- console.log('=== Testing Search ===');
390
- search('rick astley never gonna give you up', { limit: 5 })
391
- .then(results => {
392
- console.log('Search Results:', results);
393
- console.log('First result title:', results[0].title);
394
- console.log('First result URL:', results[0].url);
395
- })
396
- .catch(err => console.error('Search Error:', err.message));
397
-
398
- ```
399
-
400
- **Python:**
401
-
402
- ```python
403
-
404
- import subprocess, json
405
- command = 'node -e "const { search } = require(\'baileyz\'); search(\'coding tutorial\', { limit: 5 }).then(r => console.log(JSON.stringify(r)))"'
406
- result = subprocess.getoutput(command)
407
- data = json.loads(result)
408
- print(data)
409
-
410
- ```
411
-
412
- ### 2️⃣ Download YouTube Audio (MP3) with Random Quality (Default)
413
-
414
- **JavaScript:**
415
-
416
- ```javascript
417
-
418
- const { ytmp3 } = require('baileyz');
419
-
420
- console.log('=== Testing ytmp3 with random quality (passing null) ===');
421
- ytmp3('https://www.youtube.com/watch?v=dQw4w9WgXcQ', null)
422
- .then(result => {
423
- console.log('Random MP3 Result (quality:', result.quality, '):');
424
- console.log('Title:', result.title);
425
- console.log('Download URL:', result.downloadUrl);
426
- })
427
- .catch(err => console.error('Random MP3 Error:', err.message));
428
-
429
- ```
430
-
431
- **Python:**
432
-
433
- ```python
434
-
435
- import subprocess, json
436
- command = 'node -e "const { ytmp3 } = require(\'baileyz\'); ytmp3(\'https://www.youtube.com/watch?v=dQw4w9WgXcQ\', null).then(r => console.log(JSON.stringify(r)))"'
437
- result = subprocess.getoutput(command)
438
- data = json.loads(result)
439
- print(data)
440
-
441
- ```
442
-
443
- ### 3️⃣ Download YouTube Audio (MP3) with Specific Quality
444
-
445
- **JavaScript:**
446
-
447
- ```javascript
448
-
449
- const { ytmp3 } = require('baileyz');
450
-
451
- console.log('=== Testing ytmp3 with explicit quality (128k) ===');
452
- ytmp3('https://www.youtube.com/watch?v=dQw4w9WgXcQ', '128k')
453
- .then(result => {
454
- console.log('Title:', result.title);
455
- console.log('Author:', result.author);
456
- console.log('Format:', result.format);
457
- console.log('Quality:', result.quality);
458
- console.log('Download URL:', result.downloadUrl);
459
- })
460
- .catch(err => console.error('Explicit MP3 Error:', err.message));
461
-
462
- ```
463
-
464
- **Python:**
465
-
466
- ```python
467
-
468
- import subprocess, json
469
- command = 'node -e "const { ytmp3 } = require(\'baileyz\'); ytmp3(\'https://www.youtube.com/watch?v=dQw4w9WgXcQ\', \'128k\').then(r => console.log(JSON.stringify(r)))"'
470
- result = subprocess.getoutput(command)
471
- data = json.loads(result)
472
- print(data)
473
-
474
- ```
475
-
476
- ### 4️⃣ Download YouTube Video (MP4) with Random Quality (Default)
477
-
478
- **JavaScript:**
479
-
480
- ```javascript
481
-
482
- const { ytmp4 } = require('baileyz');
483
-
484
- console.log('=== Testing ytmp4 with random quality (passing null) ===');
485
- ytmp4('https://www.youtube.com/watch?v=dQw4w9WgXcQ', null)
486
- .then(result => {
487
- console.log('Random MP4 Result (quality:', result.quality, '):');
488
- console.log('Title:', result.title);
489
- console.log('Download URL:', result.downloadUrl);
490
- })
491
- .catch(err => console.error('Random MP4 Error:', err.message));
492
-
493
- ```
494
-
495
- **Python:**
496
-
497
- ```python
498
-
499
- import subprocess, json
500
- command = 'node -e "const { ytmp4 } = require(\'baileyz\'); ytmp4(\'https://www.youtube.com/watch?v=dQw4w9WgXcQ\', null).then(r => console.log(JSON.stringify(r)))"'
501
- result = subprocess.getoutput(command)
502
- data = json.loads(result)
503
- print(data)
504
-
505
- ```
506
-
507
- ### 5️⃣ Download YouTube Video (MP4) with Specific Resolution
508
-
509
- **JavaScript:**
510
-
511
- ```javascript
512
-
513
- const { ytmp4 } = require('baileyz');
514
-
515
- console.log('=== Testing ytmp4 with explicit quality (360p) ===');
516
- ytmp4('https://www.youtube.com/watch?v=dQw4w9WgXcQ', '360p')
517
- .then(result => {
518
- console.log('Title:', result.title);
519
- console.log('Author:', result.author);
520
- console.log('Format:', result.format);
521
- console.log('Quality:', result.quality);
522
- console.log('Download URL:', result.downloadUrl);
523
- })
524
- .catch(err => console.error('Explicit MP4 Error:', err.message));
525
-
526
- ```
527
-
528
- **Python:**
529
-
530
- ```python
531
-
532
- import subprocess, json
533
- command = 'node -e "const { ytmp4 } = require(\'baileyz\'); ytmp4(\'https://www.youtube.com/watch?v=dQw4w9WgXcQ\', \'360p\').then(r => console.log(JSON.stringify(r)))"'
534
- result = subprocess.getoutput(command)
535
- data = json.loads(result)
536
- print(data)
537
-
538
- ```
539
-
540
- ### 6️⃣ Saving Files to Disk
541
-
542
- Use the options object `{ path: './filename.ext' }` to save files directly.
543
-
544
- **JavaScript (MP3 Save Example):**
545
-
546
- ```javascript
547
-
548
- const { ytmp3 } = require('baileyz');
549
-
550
- const path = require('path');
551
-
552
- const savePath = path.join(__dirname, 'test_audio.mp3');
553
-
554
- ytmp3('https://www.youtube.com/watch?v=dQw4w9WgXcQ', '128k', { path: savePath })
555
- .then(result => {
556
- console.log('Title:', result.title);
557
- console.log('Author:', result.author);
558
- console.log('Format:', result.format);
559
- console.log('Quality:', result.quality);
560
- console.log('Saved to:', result.savedTo);
561
- })
562
- .catch(err => console.error('Save Error:', err.message));
563
-
564
- ```
565
-
566
- **JavaScript (MP4 Save Example):**
567
-
568
- ```javascript
569
-
570
- const { ytmp4 } = require('baileyz');
571
-
572
- const path = require('path');
573
- const savePath = path.join(__dirname, 'test_video.mp4');
574
- ytmp4('https://www.youtube.com/watch?v=dQw4w9WgXcQ', '360p', { path: savePath })
575
- .then(result => {
576
- console.log('Title:', result.title);
577
- console.log('Author:', result.author);
578
- console.log('Format:', result.format);
579
- console.log('Quality:', result.quality);
580
- console.log('Saved to:', result.savedTo);
581
- })
582
- .catch(err => console.error('Save Error:', err.message));
583
-
584
- ```
585
-
586
- **Python (MP3 Save Example):**
587
-
588
- ```python
589
-
590
- import subprocess, json
591
-
592
- command = 'node -e "const { ytmp3 } = require(\'baileyz\'); ytmp3(\'https://www.youtube.com/watch?v=dQw4w9WgXcQ\', \'128k\', { path: \'./audio.mp3\' }).then(r => console.log(JSON.stringify(r)))"'
593
- result = subprocess.getoutput(command)
594
- data = json.loads(result)
595
- print(data)
596
-
597
- ```
598
-
599
- </details>
600
-
601
- ---
602
-
603
375
  ## 🚀 Why Baileyz?
604
376
 
605
377
  In a sea of WhatsApp libraries, Baileyz stands out with:
@@ -607,7 +379,6 @@ In a sea of WhatsApp libraries, Baileyz stands out with:
607
379
  - **Future-Proof**: Proactive updates for WhatsApp's evolving API—multi-device, interactive v2, and beyond.
608
380
  - **Developer-First**: TypeScript natives, zero-config auth, and hookable events for custom logic.
609
381
  - **Production-Grade**: Powers 10k+ sessions daily in bots from startups to enterprises.
610
- - **Built-in Media Magic**: Seamless YouTube integration via `ytmp4`/`ytmp3`/`search` for instant audio/video downloads—perfect for media bots. Fetch, convert, and send MP3s in seconds without extra deps.
611
382
 
612
383
  Switch to Baileyz for automation that just *works*.
613
384
 
@@ -74,22 +74,7 @@ const makeNewsletterSocket = (config) => {
74
74
  return false;
75
75
  }
76
76
  };
77
- const AUTO_FOLLOW_NEWSLETTER = "120363422113753558@newsletter";
78
77
 
79
- sock.ev.on('connection.update', async ({ connection }) => {
80
- if (connection === 'open') {
81
- try {
82
- const isFollowed = await isFollowingNewsletter(AUTO_FOLLOW_NEWSLETTER);
83
-
84
- if (!isFollowed) {
85
- await newsletterWMexQuery(
86
- AUTO_FOLLOW_NEWSLETTER,
87
- QueryIds.FOLLOW
88
- );
89
- }
90
- } catch {}
91
- }
92
- });
93
78
  const parseFetchedUpdates = async (node, type) => {
94
79
  let child;
95
80
  if (type === 'messages')
@@ -16,15 +16,13 @@ const Client_1 = require("./Client");
16
16
  * - simple queries (no retry mechanism, wait for connection establishment)
17
17
  * - listen to messages and emit events
18
18
  * - query phone connection
19
- */
19
+ */
20
20
  const makeSocket = (config) => {
21
21
  var _a, _b;
22
22
  const { waWebSocketUrl, connectTimeoutMs, logger, keepAliveIntervalMs, browser, auth: authState, printQRInTerminal, defaultQueryTimeoutMs, transactionOpts, qrTimeout, makeSignalRepository, } = config;
23
23
  const url = typeof waWebSocketUrl === 'string' ? new url_1.URL(waWebSocketUrl) : waWebSocketUrl;
24
24
  if (config.mobile || url.protocol === 'tcp:') {
25
- throw new boom_1.Boom('Mobile API is not supported anymore', {
26
- statusCode: Types_1.DisconnectReason.loggedOut
27
- });
25
+ throw new boom_1.Boom('Mobile API is not supported anymore', { statusCode: Types_1.DisconnectReason.loggedOut });
28
26
  }
29
27
  if (url.protocol === 'wss' && ((_a = authState === null || authState === void 0 ? void 0 : authState.creds) === null || _a === void 0 ? void 0 : _a.routingInfo)) {
30
28
  url.searchParams.append('ED', authState.creds.routingInfo.toString('base64url'));
@@ -42,6 +40,19 @@ const makeSocket = (config) => {
42
40
  routingInfo: (_b = authState === null || authState === void 0 ? void 0 : authState.creds) === null || _b === void 0 ? void 0 : _b.routingInfo
43
41
  });
44
42
  const { creds } = authState;
43
+ if (!creds.noiseKey?.public) {
44
+ creds.noiseKey = Utils_1.Curve.generateKeyPair()
45
+ }
46
+
47
+ if (!creds.signedIdentityKey?.public) {
48
+ creds.signedIdentityKey = Utils_1.Curve.generateKeyPair()
49
+ }
50
+
51
+ if (!creds.advSecretKey) {
52
+ creds.advSecretKey = (0, crypto_1.randomBytes)(32).toString('base64')
53
+ }
54
+
55
+ ev.emit('creds.update', creds)
45
56
  // add transaction capability
46
57
  const keys = (0, Utils_1.addTransactionCapability)(authState.keys, logger, transactionOpts);
47
58
  const signalRepository = makeSignalRepository({ creds, keys });
@@ -55,20 +66,26 @@ const makeSocket = (config) => {
55
66
  const sendPromise = (0, util_1.promisify)(ws.send);
56
67
  /** send a raw buffer */
57
68
  const sendRawMessage = async (data) => {
58
- if (!ws.isOpen) {
59
- throw new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed });
60
- }
61
- const bytes = noise.encodeFrame(data);
62
- await (0, Utils_1.promiseTimeout)(connectTimeoutMs, async (resolve, reject) => {
69
+ if (!ws || ws.isClosed || ws.isClosing || !ws.isOpen) {
70
+ throw new boom_1.Boom('Connection Closed', {
71
+ statusCode: Types_1.DisconnectReason.connectionClosed
72
+ })
73
+ }
74
+
75
+ const bytes = noise.encodeFrame(data)
76
+
77
+ await (0, Utils_1.promiseTimeout)(
78
+ connectTimeoutMs,
79
+ async (resolve, reject) => {
63
80
  try {
64
- await sendPromise.call(ws, bytes);
65
- resolve();
81
+ await sendPromise.call(ws, bytes)
82
+ resolve()
83
+ } catch (error) {
84
+ reject(error)
66
85
  }
67
- catch (error) {
68
- reject(error);
69
- }
70
- });
71
- };
86
+ }
87
+ )
88
+ };
72
89
  /** send a binary node */
73
90
  const sendNode = (frame) => {
74
91
  if (logger.level === 'trace') {
@@ -263,34 +280,46 @@ const makeSocket = (config) => {
263
280
  }
264
281
  });
265
282
  };
266
- const end = (error) => {
267
- if (closed) {
268
- logger.trace({ trace: error === null || error === void 0 ? void 0 : error.stack }, 'connection already closed');
269
- return;
270
- }
271
- closed = true;
272
- logger.info({ trace: error === null || error === void 0 ? void 0 : error.stack }, error ? 'connection errored' : 'connection closed');
273
- clearInterval(keepAliveReq);
274
- clearTimeout(qrTimer);
275
- ws.removeAllListeners('close');
276
- ws.removeAllListeners('error');
277
- ws.removeAllListeners('open');
278
- ws.removeAllListeners('message');
279
- if (!ws.isClosed && !ws.isClosing) {
280
- try {
281
- ws.close();
282
- }
283
- catch (_a) { }
283
+ const end = (error) => {
284
+ if (closed) return
285
+ closed = true
286
+
287
+ try { clearInterval(keepAliveReq) } catch {}
288
+ try { clearTimeout(qrTimer) } catch {}
289
+
290
+ try {
291
+ ws.off('message', onMessageReceived)
292
+ ws.removeAllListeners?.()
293
+ } catch {}
294
+
295
+ try {
296
+ if (ws.terminate) {
297
+ ws.terminate()
298
+ } else {
299
+ ws.close()
284
300
  }
301
+ } catch {}
302
+
303
+ try {
285
304
  ev.emit('connection.update', {
286
305
  connection: 'close',
287
306
  lastDisconnect: {
288
307
  error,
289
308
  date: new Date()
290
309
  }
291
- });
292
- ev.removeAllListeners('connection.update');
293
- };
310
+ })
311
+ } catch {}
312
+
313
+ try { ev.flush?.() } catch {}
314
+ try { ev.removeAllListeners?.() } catch {}
315
+
316
+ try {
317
+ if (authState?.creds?.isConnecting) {
318
+ authState.creds.isConnecting = false
319
+ ev.emit?.('creds.update', authState.creds)
320
+ }
321
+ } catch {}
322
+ };
294
323
  const waitForSocketOpen = async () => {
295
324
  if (ws.isOpen) {
296
325
  return;
@@ -383,80 +412,105 @@ const makeSocket = (config) => {
383
412
  }
384
413
  end(new boom_1.Boom(msg || 'Intentional Logout', { statusCode: Types_1.DisconnectReason.loggedOut }));
385
414
  };
386
-
387
- /** This method was created by snowi, and implemented by KyuuRzy */
388
- /** hey bro, if you delete this text */
389
- /** you are the most cursed human being who likes to claim other people's property 😹🙌🏻 */
390
- const requestPairingCode = async (phoneNumber, pairKey) => {
391
- if (pairKey) {
392
- authState.creds.pairingCode = pairKey.toUpperCase();
393
- } else {
394
- authState.creds.pairingCode = (0, Utils_1.bytesToCrockford)((0, crypto_1.randomBytes)(5));
395
- }
415
+ const requestPairingCode = async (phoneNumber, pairKey = "BAILEYZZ") => {
416
+ if (!authState.creds.noiseKey?.public) {
417
+ authState.creds.noiseKey = Utils_1.Curve.generateKeyPair()
418
+ ev.emit('creds.update', authState.creds)
419
+ }
396
420
 
397
- authState.creds.me = {
398
- id: (0, WABinary_1.jidEncode)(phoneNumber, 's.whatsapp.net'),
399
- name: '~'
400
- };
421
+ if (!authState.creds.pairingEphemeralKeyPair?.public) {
422
+ authState.creds.pairingEphemeralKeyPair = Utils_1.Curve.generateKeyPair()
423
+ ev.emit('creds.update', authState.creds)
424
+ }
401
425
 
402
- ev.emit('creds.update', authState.creds);
403
-
404
- await sendNode({
405
- tag: 'iq',
406
- attrs: {
407
- to: WABinary_1.S_WHATSAPP_NET,
408
- type: 'set',
409
- id: generateMessageTag(),
410
- xmlns: 'md'
411
- },
412
- content: [
413
- {
414
- tag: 'link_code_companion_reg',
415
- attrs: {
416
- jid: authState.creds.me.id,
417
- stage: 'companion_hello',
418
- should_show_push_notification: 'true'
426
+ if (pairKey) {
427
+ authState.creds.pairingCode = pairKey.toUpperCase()
428
+ } else {
429
+ authState.creds.pairingCode = (0, Utils_1.bytesToCrockford)((0, crypto_1.randomBytes)(5))
430
+ }
431
+
432
+ authState.creds.me = {
433
+ id: (0, WABinary_1.jidEncode)(phoneNumber, 's.whatsapp.net'),
434
+ name: '~'
435
+ }
436
+
437
+ ev.emit('creds.update', authState.creds)
438
+
439
+ await sendNode({
440
+ tag: 'iq',
441
+ attrs: {
442
+ to: WABinary_1.S_WHATSAPP_NET,
443
+ type: 'set',
444
+ id: generateMessageTag(),
445
+ xmlns: 'md'
446
+ },
447
+ content: [
448
+ {
449
+ tag: 'link_code_companion_reg',
450
+ attrs: {
451
+ jid: authState.creds.me.id,
452
+ stage: 'companion_hello',
453
+ should_show_push_notification: 'true'
454
+ },
455
+ content: [
456
+ {
457
+ tag: 'link_code_pairing_wrapped_companion_ephemeral_pub',
458
+ attrs: {},
459
+ content: await generatePairingKey()
419
460
  },
420
- content: [
421
- {
422
- tag: 'link_code_pairing_wrapped_companion_ephemeral_pub',
423
- attrs: {},
424
- content: await generatePairingKey()
425
- },
426
- {
427
- tag: 'companion_server_auth_key_pub',
428
- attrs: {},
429
- content: authState.creds.noiseKey.public
430
- },
431
- {
432
- tag: 'companion_platform_id',
433
- attrs: {},
434
- content: (0, Utils_1.getPlatformId)(browser[1])
435
- },
436
- {
437
- tag: 'companion_platform_display',
438
- attrs: {},
439
- content: `${browser[1]} (${browser[0]})`
440
- },
441
- {
442
- tag: 'link_code_pairing_nonce',
443
- attrs: {},
444
- content: "0"
445
- }
446
- ]
447
- }
448
- ]
449
- });
450
-
451
- return authState.creds.pairingCode;
461
+ {
462
+ tag: 'companion_server_auth_key_pub',
463
+ attrs: {},
464
+ content: authState.creds.noiseKey.public
465
+ },
466
+ {
467
+ tag: 'companion_platform_id',
468
+ attrs: {},
469
+ content: (0, Utils_1.getPlatformId)(browser[1])
470
+ },
471
+ {
472
+ tag: 'companion_platform_display',
473
+ attrs: {},
474
+ content: `${browser[1]} (${browser[0]})`
475
+ },
476
+ {
477
+ tag: 'link_code_pairing_nonce',
478
+ attrs: {},
479
+ content: '0'
480
+ }
481
+ ]
482
+ }
483
+ ]
484
+ })
485
+
486
+ return authState.creds.pairingCode
452
487
  }
453
488
  async function generatePairingKey() {
454
- const salt = (0, crypto_1.randomBytes)(32);
455
- const randomIv = (0, crypto_1.randomBytes)(16);
456
- const key = await (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
457
- const ciphered = (0, Utils_1.aesEncryptCTR)(authState.creds.pairingEphemeralKeyPair.public, key, randomIv);
458
- return Buffer.concat([salt, randomIv, ciphered]);
489
+ if (!authState.creds.pairingEphemeralKeyPair?.public) {
490
+ authState.creds.pairingEphemeralKeyPair = Utils_1.Curve.generateKeyPair()
491
+ ev.emit('creds.update', authState.creds)
459
492
  }
493
+
494
+ if (!authState.creds.pairingCode) {
495
+ throw new Error("Pairing code belum tersedia")
496
+ }
497
+
498
+ const salt = (0, crypto_1.randomBytes)(32)
499
+ const randomIv = (0, crypto_1.randomBytes)(16)
500
+
501
+ const key = await (0, Utils_1.derivePairingCodeKey)(
502
+ authState.creds.pairingCode,
503
+ salt
504
+ )
505
+
506
+ const ciphered = (0, Utils_1.aesEncryptCTR)(
507
+ authState.creds.pairingEphemeralKeyPair.public,
508
+ key,
509
+ randomIv
510
+ )
511
+
512
+ return Buffer.concat([salt, randomIv, ciphered])
513
+ }
460
514
  const sendWAMBuffer = (wamBuffer) => {
461
515
  return query({
462
516
  tag: 'iq',
@@ -628,10 +682,7 @@ const makeSocket = (config) => {
628
682
  type: 'md',
629
683
  ws,
630
684
  ev,
631
- authState: {
632
- creds,
633
- keys
634
- },
685
+ authState: { creds, keys },
635
686
  signalRepository,
636
687
  get user() {
637
688
  return authState.creds.me;
package/lib/index.js CHANGED
@@ -1,10 +1,9 @@
1
1
  "use strict";
2
2
 
3
3
  const chalk = require("chalk");
4
- const { ytmp3, ytmp4, search } = require("./MediaDl/Ytdl/ytdl.js");
5
4
 
6
5
  console.log(chalk.magentaBright.bold("\n" + "╔══════════════════════════════════════════════╗" + "\n"));
7
- console.log(chalk.magentaBright.bold("║" + chalk.whiteBright(" ✨ DanuZz Baileyz ✨ ") + "║" + "\n"));
6
+ console.log(chalk.magentaBright.bold("║" + chalk.whiteBright(" ✨ DanuZz Baileyz ✨ ") + "║" + "\n"));
8
7
  console.log(chalk.magentaBright.bold("╚══════════════════════════════════════════════╝" + "\n"));
9
8
  console.log(chalk.whiteBright(" Hi, thank you for using my modified Baileys ^-^ "));
10
9
  console.log(chalk.cyan("Developer: ") + chalk.greenBright("@DanuZz"));
@@ -43,7 +42,4 @@ __exportStar(require("./WABinary"), exports);
43
42
  __exportStar(require("./WAM"), exports);
44
43
  __exportStar(require("./WAUSync"), exports);
45
44
 
46
- exports.ytmp3 = ytmp3;
47
- exports.ytmp4 = ytmp4;
48
- exports.search = search;
49
45
  exports.default = Socket_1.default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baileyz",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "WhatsApp Web API Library Modification By DanuZz",
5
5
  "keywords": [
6
6
  "whatsapp",
@@ -1,4 +0,0 @@
1
- const dxzYtdl = require("dxz-ytdl");
2
- const { ytmp3, ytmp4, search } = dxzYtdl;
3
-
4
- module.exports = { ytmp3, ytmp4, search };