File size: 2,483 Bytes
0bafb27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
const crypto = require("crypto")
const axios = require("axios")

class savetube {
  constructor() {
    this.ky = 'C5D58EF67A7584E4A29F6C35BBC4EB12';
    this.fmt = ['144', '240', '360', '480', '720', '1080', 'mp3'];
    this.m = /^((?:https?:)?\/\/)?((?:www|m|music)\.)?(?:youtube\.com|youtu\.be)\/(?:watch\?v=)?(?:embed\/)?(?:v\/)?(?:shorts\/)?([a-zA-Z0-9_-]{11})/;
    this.is = axios.create({
      headers: {
        'content-type': 'application/json',
        'origin': 'https://yt.savetube.me',
        'user-agent': 'Mozilla/5.0 (Android 15; Mobile; SM-F958; rv:130.0) Gecko/130.0 Firefox/130.0'
      }
    })
  }
  
  async decrypt(enc) {
    try {
      const [sr, ky] = [Buffer.from(enc,'base64'), Buffer.from(this.ky,'hex')]
      const [iv, dt] = [sr.slice(0,16), sr.slice(16)]
      const dc = crypto.createDecipheriv('aes-128-cbc', ky, iv);
      return JSON.parse(Buffer.concat([dc.update(dt), dc.final()]).toString());
    } catch (e) {
      throw new Error(`Error while decrypting data: ${e.message}`);
    }
  }
  
  async getCdn() {
    const response = await this.is.get("https://media.savetube.vip/api/random-cdn");
    if (!response.status) return response;
    return {
      status: true,
      data: response.data.cdn
    };
  }
  
  async download(url, format = 'mp3') {
    const id = url.match(this.m)?.[3];
    if (!id) {
      return {
        status: false,
        msg: "ID cannot be extracted from url"
      };
    }
    if (!format || !this.fmt.includes(format)) {
      return {
        status: false,
        msg: "Formats not found",
        list: this.fmt
      };
    }
    try {
      const u = await this.getCdn();
      if (!u.status) return u;
      const res = await this.is.post(`https://${u.data}/v2/info`, {
        url: `https://www.youtube.com/watch?v=${id}`
      });
      const dec = await this.decrypt(res.data.data);
      const dl = await this.is.post(`https://${u.data}/download`, {
        id: id,
        downloadType: format === 'mp3' ? 'audio' : 'video',
        quality: format === 'mp3' ? '128' : format,
        key: dec.key
      })

      return {
        status: true,
        title: dec.title,
        format: format,
        thumb: dec.thumbnail || `https://i.ytimg.com/vi/${id}/hqdefault.jpg`,
        duration: dec.duration,
        cached: dec.fromCache,
        dl: dl.data.data.downloadUrl
      };
    } catch (error) {
      return {
        status: false,
        error: error.message
      };
    }
  }