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 }; } }