youtubedl.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. import axios from 'axios';
  2. import crypto from 'crypto';
  3. const ogmp3 = {
  4. api: {
  5. base: "https://api3.apiapi.lat",
  6. endpoints: {
  7. a: "https://api5.apiapi.lat",
  8. b: "https://api.apiapi.lat",
  9. c: "https://api3.apiapi.lat"
  10. }
  11. },
  12. headers: {
  13. 'authority': 'api.apiapi.lat',
  14. 'content-type': 'application/json',
  15. 'origin': 'https://ogmp3.lat',
  16. 'referer': 'https://ogmp3.lat/',
  17. 'user-agent': 'Postify/1.0.0'
  18. },
  19. formats: {
  20. video: ['240', '360', '480', '720', '1080'],
  21. audio: ['64', '96', '128', '192', '256', '320']
  22. },
  23. default_fmt: {
  24. video: '720',
  25. audio: '320'
  26. },
  27. restrictedTimezones: new Set(["-330", "-420", "-480", "-540"]),
  28. utils: {
  29. hash: () => {
  30. const array = new Uint8Array(16);
  31. crypto.getRandomValues(array);
  32. return Array.from(array, byte => byte.toString(16).padStart(2, "0")).join("");
  33. },
  34. encoded: (str) => {
  35. let result = "";
  36. for (let i = 0; i < str.length; i++) {
  37. result += String.fromCharCode(str.charCodeAt(i) ^ 1);
  38. }
  39. return result;
  40. },
  41. enc_url: (url, separator = ",") => {
  42. const codes = [];
  43. for (let i = 0; i < url.length; i++) {
  44. codes.push(url.charCodeAt(i));
  45. }
  46. return codes.join(separator).split(separator).reverse().join(separator);
  47. }
  48. },
  49. isUrl: str => {
  50. try {
  51. const url = new URL(str);
  52. const hostname = url.hostname.toLowerCase();
  53. const b = [/^(.+\.)?youtube\.com$/, /^(.+\.)?youtube-nocookie\.com$/, /^youtu\.be$/];
  54. return b.some(a => a.test(hostname)) && !url.searchParams.has("playlist");
  55. } catch (_) {
  56. return false;
  57. }
  58. },
  59. youtube: url => {
  60. if (!url) return null;
  61. const b = [
  62. /youtube\.com\/watch\?v=([a-zA-Z0-9_-]{11})/,
  63. /youtube\.com\/embed\/([a-zA-Z0-9_-]{11})/,
  64. /youtube\.com\/v\/([a-zA-Z0-9_-]{11})/,
  65. /youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/,
  66. /youtu\.be\/([a-zA-Z0-9_-]{11})/
  67. ];
  68. for (let a of b) {
  69. if (a.test(url)) return url.match(a)[1];
  70. }
  71. return null;
  72. },
  73. request: async (endpoint, data = {}, method = 'post') => {
  74. try {
  75. const ae = Object.values(ogmp3.api.endpoints);
  76. const be = ae[Math.floor(Math.random() * ae.length)];
  77. const fe = endpoint.startsWith('http') ? endpoint : `${be}${endpoint}`;
  78. const { data: response } = await axios({
  79. method,
  80. url: fe,
  81. data: method === 'post' ? data : undefined,
  82. headers: ogmp3.headers
  83. });
  84. return {
  85. status: true,
  86. code: 200,
  87. data: response
  88. };
  89. } catch (error) {
  90. return {
  91. status: false,
  92. code: error.response?.status || 500,
  93. error: error.message
  94. };
  95. }
  96. },
  97. async checkStatus(id) {
  98. try {
  99. const c = this.utils.hash();
  100. const d = this.utils.hash();
  101. const endpoint = `/${c}/status/${this.utils.encoded(id)}/${d}/`;
  102. const response = await this.request(endpoint, {
  103. data: id
  104. });
  105. return response;
  106. } catch (error) {
  107. return {
  108. status: false,
  109. code: 500,
  110. error: error.message
  111. };
  112. }
  113. },
  114. async checkProgress(data) {
  115. try {
  116. let attempts = 0;
  117. let maxAttempts = 300;
  118. while (attempts < maxAttempts) {
  119. attempts++;
  120. const res = await this.checkStatus(data.i);
  121. if (!res.status) {
  122. await new Promise(resolve => setTimeout(resolve, 2000));
  123. continue;
  124. }
  125. const stat = res.data;
  126. if (stat.s === "C") {
  127. return stat;
  128. }
  129. if (stat.s === "P") {
  130. await new Promise(resolve => setTimeout(resolve, 2000));
  131. continue;
  132. }
  133. return null;
  134. }
  135. return null;
  136. } catch (error) {
  137. return null;
  138. }
  139. },
  140. download: async (link, format, type = 'video') => {
  141. if (!link) {
  142. return {
  143. status: false,
  144. code: 400,
  145. error: "¿Que es lo que descarga? ingresa en link idiota"
  146. };
  147. }
  148. if (!ogmp3.isUrl(link)) {
  149. return {
  150. status: false,
  151. code: 400,
  152. error: "Ese link es invalido pon en link de un video de youtube valido idiotas 🗿"
  153. };
  154. }
  155. if (type !== 'video' && type !== 'audio') {
  156. return {
  157. status: false,
  158. code: 400,
  159. error: "Elejir video o audio?"
  160. };
  161. }
  162. if (!format) {
  163. format = type === 'audio' ? ogmp3.default_fmt.audio : ogmp3.default_fmt.video;
  164. }
  165. const valid_fmt = type === 'audio' ? ogmp3.formats.audio : ogmp3.formats.video;
  166. if (!valid_fmt.includes(format)) {
  167. return {
  168. status: false,
  169. code: 400,
  170. error: `Formato ${format} no es valido para ${type} pero puedes elegir unos de estos: ${valid_fmt.join(', ')}`
  171. };
  172. }
  173. const id = ogmp3.youtube(link);
  174. if (!id) {
  175. return {
  176. status: false,
  177. code: 400,
  178. error: "Donde pito esta la ID del video? no puedo extraerlo hdp"
  179. };
  180. }
  181. try {
  182. let retries = 0;
  183. const maxRetries = 20;
  184. while (retries < maxRetries) {
  185. retries++;
  186. const c = ogmp3.utils.hash();
  187. const d = ogmp3.utils.hash();
  188. const req = {
  189. data: ogmp3.utils.encoded(link),
  190. format: type === 'audio' ? "0" : "1",
  191. referer: "https://ogmp3.cc",
  192. mp3Quality: type === 'audio' ? format : null,
  193. mp4Quality: type === 'video' ? format : null,
  194. userTimeZone: new Date().getTimezoneOffset().toString()
  195. };
  196. const resx = await ogmp3.request(
  197. `/${c}/init/${ogmp3.utils.enc_url(link)}/${d}/`,
  198. req
  199. );
  200. if (!resx.status) {
  201. if (retries === maxRetries) return resx;
  202. continue;
  203. }
  204. const data = resx.data;
  205. if (data.le) {
  206. return {
  207. status: false,
  208. code: 400,
  209. error: "La duración del video es demasiado larga, amigo. El máximo es de 3 horas, no puedes superar eso, ¿entendido? 👍🏻"
  210. };
  211. }
  212. if (data.i === "blacklisted") {
  213. const limit = ogmp3.restrictedTimezones.has(new Date().getTimezoneOffset().toString()) ? 5 : 100;
  214. return {
  215. status: false,
  216. code: 429,
  217. error: `Limite de descargas diarias (${limit}) alcanzados, intente de nuevo mas tardes.`
  218. };
  219. }
  220. if (data.e || data.i === "invalid") {
  221. return {
  222. status: false,
  223. code: 400,
  224. error: "El video no existe. No sé si fue eliminado o si YouTube lo restringió... no tengo idea 🤷🏻"
  225. };
  226. }
  227. if (data.s === "C") {
  228. return {
  229. status: true,
  230. code: 200,
  231. result: {
  232. title: data.t || "Kagak tau",
  233. type: type,
  234. format: format,
  235. thumbnail: `https://i.ytimg.com/vi/${id}/maxresdefault.jpg`,
  236. download: `${ogmp3.api.base}/${ogmp3.utils.hash()}/download/${ogmp3.utils.encoded(data.i)}/${ogmp3.utils.hash()}/`,
  237. id: id,
  238. quality: format
  239. }
  240. };
  241. }
  242. const prod = await ogmp3.checkProgress(data);
  243. if (prod && prod.s === "C") {
  244. return {
  245. status: true,
  246. code: 200,
  247. result: {
  248. title: prod.t || "Kagak tau",
  249. type: type,
  250. format: format,
  251. thumbnail: `https://i.ytimg.com/vi/${id}/maxresdefault.jpg`,
  252. download: `${ogmp3.api.base}/${ogmp3.utils.hash()}/download/${ogmp3.utils.encoded(prod.i)}/${ogmp3.utils.hash()}/`,
  253. id: id,
  254. quality: format
  255. }
  256. };
  257. }
  258. }
  259. return {
  260. status: false,
  261. code: 500,
  262. error: "Estoy exhausto.... Ya intenté hacer la solicitud varias veces y sigue sin funcionar, así que dejaré la solicitud para más tarde, ¡hasta luego! 🤨"
  263. };
  264. } catch (error) {
  265. return {
  266. status: false,
  267. code: 500,
  268. error: error.message
  269. };
  270. }
  271. }
  272. };
  273. export { ogmp3 };