frostpv 1.0.13 → 1.0.15

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.
Files changed (2) hide show
  1. package/index.js +42 -127
  2. package/package.json +5 -5
package/index.js CHANGED
@@ -9,9 +9,9 @@ const { TwitterDL } = require("twitter-downloader");
9
9
  const btch = require("btch-downloader");
10
10
  const btchOld = require("btch-downloader-old");
11
11
 
12
- // Fallback libs
12
+
13
13
  const Tiktok = require("@tobyg74/tiktok-api-dl");
14
- const { YtDlp } = require('ytdlp-nodejs');
14
+ const ab = require("ab-downloader");
15
15
  const ffmpegPath = require('ffmpeg-ffprobe-static').ffmpegPath;
16
16
  const { v4: uuidv4 } = require('uuid');
17
17
 
@@ -19,13 +19,10 @@ const pathToFfmpeg = require("ffmpeg-ffprobe-static");
19
19
  const ffmpeg = require("fluent-ffmpeg");
20
20
  ffmpeg.setFfmpegPath(pathToFfmpeg.ffmpegPath);
21
21
 
22
- // Output directory is the caller's working directory (keeps files next to the running app)
23
22
  const OUTPUT_DIR = process.cwd();
24
23
  try { fs.mkdirSync(OUTPUT_DIR, { recursive: true }); } catch (_) { }
25
- // Keep an OS temp directory for any future transient needs
26
24
  const TEMP_DIR = path.join(os.tmpdir(), "downloader-dl-bot");
27
25
  try { fs.mkdirSync(TEMP_DIR, { recursive: true }); } catch (_) { }
28
- // TTL (minutes) for files in OUTPUT_DIR (audio/video) before they are pruned
29
26
  const OUTPUT_RETENTION_MIN = Number(process.env.OUTPUT_RETENTION_MIN || 5);
30
27
 
31
28
  const GOFILE_API = "Vs4e2PL8n65ExPz6wgDlqSY8kcEBRrzN";
@@ -47,6 +44,7 @@ const videoPlatforms = [
47
44
  "https://www.fb.watch",
48
45
  "https://fb.com",
49
46
  "https://www.fb.com",
47
+ "https://web.facebook.com",
50
48
  "https://www.mediafire.com",
51
49
  "https://mediafire.com",
52
50
  "https://www.capcut.com",
@@ -84,7 +82,7 @@ const blacklistLink = (link) => {
84
82
 
85
83
  const defaultConfig = {
86
84
  autocrop: false,
87
- limitSizeMB: null, // For compression, not for GoFile limit
85
+ limitSizeMB: null,
88
86
  rotation: null,
89
87
  outputFormat: null,
90
88
  };
@@ -264,102 +262,6 @@ function getYoutubeCookiesPath() {
264
262
  return null;
265
263
  }
266
264
 
267
- // Função utilitária para obter duração do vídeo/áudio em segundos
268
- async function getYoutubeDurationSeconds(url) {
269
- try {
270
- const ytdlp = new YtDlp({ ffmpegPath });
271
- const info = await ytdlp.getInfoAsync(url);
272
- if (info && info.duration) return info.duration;
273
- return null;
274
- } catch (e) {
275
- return null;
276
- }
277
- }
278
-
279
- // Função para baixar áudio do YouTube
280
- async function downloadYoutubeAudio(url, outputPath) {
281
- // Verificar duração máxima de 15 minutos
282
- const duration = await getYoutubeDurationSeconds(url);
283
- if (duration && duration > 900) {
284
- throw new Error('The audio is longer than 15 minutes. Test limit: 15 minutes. This feature is still in beta.');
285
- }
286
- return new Promise(async (resolve, reject) => {
287
- try {
288
- const ytdlp = new YtDlp({ ffmpegPath });
289
- const cookiesPath = getYoutubeCookiesPath();
290
-
291
- // Garantir que o nome do arquivo tenha a extensão correta
292
- const baseName = outputPath.replace(/\.[^/.]+$/, ""); // Remove extensão se existir
293
-
294
- // Primeiro, tentar com a API de opções
295
- try {
296
- const options = {
297
- format: {
298
- filter: 'audioonly',
299
- type: 'mp3',
300
- quality: 'highestaudio'
301
- },
302
- output: outputPath
303
- };
304
-
305
- if (cookiesPath) {
306
- options.cookies = cookiesPath;
307
- }
308
-
309
- // Remover logs detalhados para download de áudio do YouTube
310
- const result = await ytdlp.downloadAsync(url, options);
311
- // Verificar se o arquivo foi criado
312
- const actualFileName = baseName + '.mp3';
313
- if (fs.existsSync(actualFileName)) {
314
- resolve(actualFileName);
315
- return;
316
- }
317
-
318
- // Tentar encontrar o arquivo com extensão diferente
319
- const files = fs.readdirSync('./');
320
- const downloadedFile = files.find(file => file.startsWith(baseName.split('/').pop()));
321
- if (downloadedFile) {
322
- resolve(downloadedFile);
323
- return;
324
- }
325
- } catch (apiError) {
326
- console.log('API method failed, trying direct args method:', apiError.message);
327
- }
328
-
329
- // Fallback: usar argumentos diretos para máxima qualidade de áudio
330
- const args = [
331
- url,
332
- '-f', 'bestaudio[ext=mp3]/bestaudio',
333
- '-o', outputPath
334
- ];
335
-
336
- if (cookiesPath) {
337
- args.push('--cookies', cookiesPath);
338
- }
339
-
340
- // Remover logs detalhados para download de áudio do YouTube
341
- const result = await ytdlp.execAsync(args);
342
- // Verificar se o arquivo foi criado
343
- const actualFileName = baseName + '.mp3';
344
- if (fs.existsSync(actualFileName)) {
345
- resolve(actualFileName);
346
- } else {
347
- // Tentar encontrar o arquivo com extensão diferente
348
- const files = fs.readdirSync('./');
349
- const downloadedFile = files.find(file => file.startsWith(baseName.split('/').pop()));
350
- if (downloadedFile) {
351
- resolve(downloadedFile);
352
- } else {
353
- reject(new Error('YouTube audio download completed but file not found'));
354
- }
355
- }
356
- } catch (error) {
357
- console.error('YouTube audio download error:', error);
358
- reject(new Error('This URL is not from a supported platform. Supported platforms: Instagram, X(Twitter), TikTok and Facebook'));
359
- }
360
- });
361
- }
362
-
363
265
  // Enhanced function to get platform type from URL
364
266
  function getPlatformType(url) {
365
267
  const lowerUrl = url.toLowerCase();
@@ -374,7 +276,6 @@ function getPlatformType(url) {
374
276
  return "unknown";
375
277
  }
376
278
 
377
- // Enhanced fallback download function with platform-specific methods
378
279
  async function tryFallbackDownload(url, maxRetries = 3) {
379
280
  const platform = getPlatformType(url);
380
281
 
@@ -382,10 +283,8 @@ async function tryFallbackDownload(url, maxRetries = 3) {
382
283
  try {
383
284
  let videoUrl = null;
384
285
 
385
- // Platform-specific fallback methods
386
286
  switch (platform) {
387
287
  case "instagram": {
388
- // Try multiple Instagram methods
389
288
  const methods = [
390
289
  async () => {
391
290
  const data = await igdl(url);
@@ -412,7 +311,6 @@ async function tryFallbackDownload(url, maxRetries = 3) {
412
311
  throw new Error("No valid URL in igdl response with custom headers");
413
312
  },
414
313
  async () => {
415
- // Fallback: try using the old version of btch-downloader
416
314
  try {
417
315
  const { igdl: igdlOld } = btchOld;
418
316
  if (typeof igdlOld === 'function') {
@@ -421,10 +319,17 @@ async function tryFallbackDownload(url, maxRetries = 3) {
421
319
  return data[0].url;
422
320
  }
423
321
  }
424
- throw new Error("Old btch-downloader igdl not available or failed");
322
+ throw new Error("Old downloader not available or failed");
425
323
  } catch (oldError) {
426
- throw new Error(`Old btch-downloader fallback failed: ${oldError.message}`);
324
+ throw new Error(`Old downloader fallback failed: ${oldError.message}`);
325
+ }
326
+ },
327
+ async () => {
328
+ const data = await ab.igdl(url);
329
+ if (data && Array.isArray(data) && data[0] && data[0].url) {
330
+ return data[0].url;
427
331
  }
332
+ throw new Error("No valid URL");
428
333
  }
429
334
  ];
430
335
 
@@ -440,7 +345,7 @@ async function tryFallbackDownload(url, maxRetries = 3) {
440
345
  }
441
346
 
442
347
  case "tiktok": {
443
- // Try multiple TikTok methods
348
+
444
349
  const methods = [
445
350
  async () => {
446
351
  const data = await ttdl(url);
@@ -471,6 +376,13 @@ async function tryFallbackDownload(url, maxRetries = 3) {
471
376
  }
472
377
  }
473
378
  throw new Error("No valid video in Tiktok.Downloader v2 response");
379
+ },
380
+ async () => {
381
+ const data = await ab.ttdl(url);
382
+ if (data && data.video && data.video[0]) {
383
+ return data.video[0];
384
+ }
385
+ throw new Error("No valid video");
474
386
  }
475
387
  ];
476
388
 
@@ -506,6 +418,13 @@ async function tryFallbackDownload(url, maxRetries = 3) {
506
418
  return data.Normal_video || data.HD;
507
419
  }
508
420
  throw new Error("No valid video in fbdown response with custom headers");
421
+ },
422
+ async () => {
423
+ const data = await ab.fbdown(url);
424
+ if (data && (data.Normal_video || data.HD)) {
425
+ return data.Normal_video || data.HD;
426
+ }
427
+ throw new Error("No valid video");
509
428
  }
510
429
  ];
511
430
 
@@ -652,7 +571,6 @@ async function tryFallbackDownload(url, maxRetries = 3) {
652
571
  }
653
572
  },
654
573
  async () => {
655
- // Fallback: try using the old version of btch-downloader for Twitter/X
656
574
  try {
657
575
  const cleanUrl = validateTwitterUrl(url);
658
576
  // Try to find any Twitter-related function in the old version
@@ -686,10 +604,20 @@ async function tryFallbackDownload(url, maxRetries = 3) {
686
604
  }
687
605
  }
688
606
  }
689
- throw new Error("No Twitter functions found in old btch-downloader");
607
+ throw new Error("No Twitter functions found");
690
608
  } catch (oldError) {
691
- throw new Error(`Old btch-downloader Twitter fallback failed: ${oldError.message}`);
609
+ throw new Error(`Twitter fallback failed: ${oldError.message}`);
692
610
  }
611
+ },
612
+ async () => {
613
+ const data = await ab.twitter(url);
614
+ if (data && data.result && data.result.url) {
615
+ return data.result.url;
616
+ }
617
+ if (data && Array.isArray(data) && data[0] && data[0].url) {
618
+ return data[0].url;
619
+ }
620
+ throw new Error("No valid video");
693
621
  }
694
622
  ];
695
623
 
@@ -705,12 +633,10 @@ async function tryFallbackDownload(url, maxRetries = 3) {
705
633
  }
706
634
 
707
635
  case "youtube": {
708
- // YouTube doesn't need fallback - it has its own specific method
709
636
  throw new Error("YouTube downloads should use the primary method, not fallback");
710
637
  }
711
638
 
712
639
  case "mediafire": {
713
- // Try MediaFire method
714
640
  try {
715
641
  const data = await mediafire(url);
716
642
  if (data && data.url) {
@@ -719,7 +645,6 @@ async function tryFallbackDownload(url, maxRetries = 3) {
719
645
  throw new Error("No valid URL in mediafire response");
720
646
  }
721
647
  } catch (methodError) {
722
- // Continue to next attempt
723
648
  }
724
649
  break;
725
650
  }
@@ -751,7 +676,6 @@ async function tryFallbackDownload(url, maxRetries = 3) {
751
676
  }
752
677
 
753
678
  default: {
754
- // Generic fallback for unknown platforms
755
679
  try {
756
680
  const data = await igdl(url);
757
681
  if (data && Array.isArray(data) && data[0] && data[0].url) {
@@ -760,15 +684,12 @@ async function tryFallbackDownload(url, maxRetries = 3) {
760
684
  throw new Error("No valid URL in generic igdl response");
761
685
  }
762
686
  } catch (methodError) {
763
- // Continue to next attempt
764
687
  }
765
688
  break;
766
689
  }
767
690
  }
768
691
 
769
- // If we got a video URL, validate it
770
692
  if (videoUrl && videoUrl.includes("http")) {
771
- // Validate the URL is accessible
772
693
  try {
773
694
  const response = await axios.head(videoUrl, {
774
695
  timeout: 10000,
@@ -942,7 +863,6 @@ async function downloadSmartVideo(url, config) {
942
863
  }
943
864
  videoUrl = data.video[0];
944
865
  } catch (error) {
945
- // Fallback: @tobyg74/tiktok-api-dl
946
866
  try {
947
867
  const result = await Tiktok.Downloader(url, { version: "v1" });
948
868
  if (result.status === "success" && result.result) {
@@ -1017,10 +937,7 @@ async function downloadSmartVideo(url, config) {
1017
937
  }
1018
938
  case "pinterest": {
1019
939
  try {
1020
- // Supports both pin links and search queries
1021
940
  const data = await pinterest(url);
1022
- // data may be array or object depending on query or pin
1023
- // Try to find best url (image or video)
1024
941
  let directUrl = null;
1025
942
  const pickFrom = (obj) => {
1026
943
  if (!obj) return null;
@@ -1081,7 +998,6 @@ async function downloadSmartVideo(url, config) {
1081
998
  if (highQuality) {
1082
999
  videoUrl = highQuality.url;
1083
1000
  } else {
1084
- // Fallback: pega o primeiro que tiver url
1085
1001
  const anyVideo = data.url.find(v => v.url);
1086
1002
  videoUrl = anyVideo ? anyVideo.url : data.url[0];
1087
1003
  }
@@ -1092,7 +1008,6 @@ async function downloadSmartVideo(url, config) {
1092
1008
  }
1093
1009
 
1094
1010
  if (!videoUrl) {
1095
- // Fallback para estrutura antiga ou diferente
1096
1011
  if (Array.isArray(data) && data[0] && data[0].url) {
1097
1012
  videoUrl = data[0].url;
1098
1013
  } else if (data && data.HD) {
@@ -1101,7 +1016,7 @@ async function downloadSmartVideo(url, config) {
1101
1016
  }
1102
1017
 
1103
1018
  if (!videoUrl) {
1104
- throw new Error("No video URL found in btch-downloader twitter response");
1019
+ throw new Error("No video URL found in downloader twitter response");
1105
1020
  }
1106
1021
  } catch (error) {
1107
1022
  throw new Error(`Twitter download failed: ${error.message}`);
@@ -1527,7 +1442,7 @@ const AudioDownloader = async (url, options = {}) => {
1527
1442
  try {
1528
1443
  let platform = getPlatformType(url);
1529
1444
  if (platform === "y124outube") {
1530
- // Baixar áudio do YouTube usando ytdlp-nodejs
1445
+
1531
1446
  let fileName = "temp_audio.mp3";
1532
1447
  let count = 1;
1533
1448
  while (fs.existsSync(fileName)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frostpv",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "downloads",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -12,6 +12,8 @@
12
12
  "author": "Delta",
13
13
  "license": "ISC",
14
14
  "dependencies": {
15
+ "@tobyg74/tiktok-api-dl": "^1.3.7",
16
+ "ab-downloader": "^1.0.1",
15
17
  "axios": "1.12.0",
16
18
  "btch-downloader": "6.0.25",
17
19
  "btch-downloader-old": "npm:btch-downloader@4.0.15",
@@ -21,8 +23,6 @@
21
23
  "fs": "^0.0.1-security",
22
24
  "path": "^0.12.7",
23
25
  "twitter-downloader": "^1.1.8",
24
- "uuid": "^11.1.0",
25
- "@tobyg74/tiktok-api-dl": "^1.3.7",
26
- "ytdlp-nodejs": "2.3.4"
26
+ "uuid": "^11.1.0"
27
27
  }
28
- }
28
+ }