frostpv 1.0.21 → 1.0.24
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/index.js +57 -12
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -4,25 +4,27 @@ const path = require("path");
|
|
|
4
4
|
const os = require("os");
|
|
5
5
|
const FormData = require("form-data");
|
|
6
6
|
const crypto = require("crypto");
|
|
7
|
-
const { igdl, ttdl, fbdown, mediafire, capcut, gdrive, pinterest, twitter } = require("btch-downloader");
|
|
8
|
-
const { TwitterDL } = require("twitter-downloader");
|
|
9
|
-
const instagramCustom = require('./instagramcustom');
|
|
10
|
-
const tiktokCustom = require('./tiktokcustom');
|
|
11
|
-
const btch = require("btch-downloader");
|
|
12
|
-
const btchOld = require("btch-downloader-old");
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const Tiktok = require("@tobyg74/tiktok-api-dl");
|
|
16
|
-
const ab = require("ab-downloader");
|
|
17
|
-
const ffmpegPath = require('ffmpeg-ffprobe-static').ffmpegPath;
|
|
18
7
|
const { v4: uuidv4 } = require('uuid');
|
|
19
|
-
|
|
20
8
|
const pathToFfmpeg = require("ffmpeg-ffprobe-static");
|
|
21
9
|
const ffmpeg = require("fluent-ffmpeg");
|
|
22
10
|
ffmpeg.setFfmpegPath(pathToFfmpeg.ffmpegPath);
|
|
23
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Aciona a coleta de lixo se o Node for iniciado com --expose-gc
|
|
14
|
+
*/
|
|
15
|
+
function triggerGC() {
|
|
16
|
+
if (global.gc) {
|
|
17
|
+
try {
|
|
18
|
+
global.gc();
|
|
19
|
+
} catch (e) {
|
|
20
|
+
// Ignora silenciosamente se falhar
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
24
25
|
const OUTPUT_DIR = process.cwd();
|
|
25
26
|
try { fs.mkdirSync(OUTPUT_DIR, { recursive: true }); } catch (_) { }
|
|
27
|
+
|
|
26
28
|
const TEMP_DIR = path.join(os.tmpdir(), "downloader-dl-bot");
|
|
27
29
|
try { fs.mkdirSync(TEMP_DIR, { recursive: true }); } catch (_) { }
|
|
28
30
|
const OUTPUT_RETENTION_MIN = Number(process.env.OUTPUT_RETENTION_MIN || 5);
|
|
@@ -288,6 +290,17 @@ function getPlatformType(url) {
|
|
|
288
290
|
async function tryFallbackDownload(url, maxRetries = 3) {
|
|
289
291
|
const platform = getPlatformType(url);
|
|
290
292
|
|
|
293
|
+
// Importações dinâmicas para economizar RAM
|
|
294
|
+
const btch = require("btch-downloader");
|
|
295
|
+
const { igdl, ttdl, fbdown, mediafire, pinterest } = btch;
|
|
296
|
+
const { TwitterDL } = require("twitter-downloader");
|
|
297
|
+
const btchOld = require("btch-downloader-old");
|
|
298
|
+
const Tiktok = require("@tobyg74/tiktok-api-dl");
|
|
299
|
+
const ab = require("ab-downloader");
|
|
300
|
+
const instagramCustom = require('./instagramcustom');
|
|
301
|
+
const tiktokCustom = require('./tiktokcustom');
|
|
302
|
+
|
|
303
|
+
|
|
291
304
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
292
305
|
try {
|
|
293
306
|
let videoUrl = null;
|
|
@@ -852,8 +865,13 @@ async function downloadSmartVideo(url, config) {
|
|
|
852
865
|
let videoUrl = null;
|
|
853
866
|
let platform = getPlatformType(url);
|
|
854
867
|
|
|
868
|
+
// Importações dinâmicas por plataforma para economizar RAM
|
|
869
|
+
let downloader = null;
|
|
870
|
+
|
|
871
|
+
|
|
855
872
|
switch (platform) {
|
|
856
873
|
case "instagram": {
|
|
874
|
+
const { igdl } = require("btch-downloader");
|
|
857
875
|
let data = null;
|
|
858
876
|
let attempts = 0;
|
|
859
877
|
const maxAttempts = 3;
|
|
@@ -874,6 +892,7 @@ async function downloadSmartVideo(url, config) {
|
|
|
874
892
|
await new Promise(resolve => setTimeout(resolve, 1000 * attempts));
|
|
875
893
|
}
|
|
876
894
|
}
|
|
895
|
+
|
|
877
896
|
if (!videoUrl) {
|
|
878
897
|
throw new Error("Video unavailable or invalid link for Instagram.");
|
|
879
898
|
}
|
|
@@ -882,6 +901,8 @@ async function downloadSmartVideo(url, config) {
|
|
|
882
901
|
case "tiktok": {
|
|
883
902
|
let data = null;
|
|
884
903
|
let fallbackError = null;
|
|
904
|
+
const { ttdl } = require("btch-downloader");
|
|
905
|
+
const Tiktok = require("@tobyg74/tiktok-api-dl");
|
|
885
906
|
try {
|
|
886
907
|
data = await ttdl(url);
|
|
887
908
|
if (!data || !data.video || !data.video[0]) {
|
|
@@ -925,7 +946,10 @@ async function downloadSmartVideo(url, config) {
|
|
|
925
946
|
}
|
|
926
947
|
break;
|
|
927
948
|
}
|
|
949
|
+
|
|
950
|
+
|
|
928
951
|
case "facebook": {
|
|
952
|
+
const { fbdown } = require("btch-downloader");
|
|
929
953
|
try {
|
|
930
954
|
const data = await fbdown(url);
|
|
931
955
|
if (!data || (!data.Normal_video && !data.HD)) {
|
|
@@ -949,7 +973,9 @@ async function downloadSmartVideo(url, config) {
|
|
|
949
973
|
}
|
|
950
974
|
break;
|
|
951
975
|
}
|
|
976
|
+
|
|
952
977
|
case "mediafire": {
|
|
978
|
+
const { mediafire } = require("btch-downloader");
|
|
953
979
|
try {
|
|
954
980
|
const data = await mediafire(url);
|
|
955
981
|
if (!data || !data.url) {
|
|
@@ -961,7 +987,9 @@ async function downloadSmartVideo(url, config) {
|
|
|
961
987
|
}
|
|
962
988
|
break;
|
|
963
989
|
}
|
|
990
|
+
|
|
964
991
|
case "pinterest": {
|
|
992
|
+
const { pinterest } = require("btch-downloader");
|
|
965
993
|
try {
|
|
966
994
|
const data = await pinterest(url);
|
|
967
995
|
let directUrl = null;
|
|
@@ -1004,7 +1032,9 @@ async function downloadSmartVideo(url, config) {
|
|
|
1004
1032
|
}
|
|
1005
1033
|
break;
|
|
1006
1034
|
}
|
|
1035
|
+
|
|
1007
1036
|
case "twitter": {
|
|
1037
|
+
const { twitter } = require("btch-downloader");
|
|
1008
1038
|
try {
|
|
1009
1039
|
const data = await twitter(url);
|
|
1010
1040
|
if (data && data.url) {
|
|
@@ -1049,6 +1079,7 @@ async function downloadSmartVideo(url, config) {
|
|
|
1049
1079
|
}
|
|
1050
1080
|
break;
|
|
1051
1081
|
}
|
|
1082
|
+
|
|
1052
1083
|
default:
|
|
1053
1084
|
throw new Error("Platform not supported or invalid link.");
|
|
1054
1085
|
}
|
|
@@ -1078,7 +1109,9 @@ async function downloadSmartVideo(url, config) {
|
|
|
1078
1109
|
videoWriter.on("finish", async () => {
|
|
1079
1110
|
try {
|
|
1080
1111
|
const finalFilePath = await processDownloadedFile(fileName, config, platform);
|
|
1112
|
+
triggerGC(); // Limpar memória após processamento pesado
|
|
1081
1113
|
resolve(finalFilePath);
|
|
1114
|
+
|
|
1082
1115
|
} catch (error) {
|
|
1083
1116
|
reject(new Error(`Error processing downloaded video: ${error.message}`));
|
|
1084
1117
|
}
|
|
@@ -1092,6 +1125,7 @@ async function downloadSmartVideo(url, config) {
|
|
|
1092
1125
|
}
|
|
1093
1126
|
}
|
|
1094
1127
|
|
|
1128
|
+
|
|
1095
1129
|
// Function for direct video download
|
|
1096
1130
|
async function downloadDirectVideo(url, config) {
|
|
1097
1131
|
try {
|
|
@@ -1183,6 +1217,7 @@ async function rotateVideo(fileName, rotation) {
|
|
|
1183
1217
|
return new Promise((resolve, reject) => {
|
|
1184
1218
|
ffmpeg(fileName)
|
|
1185
1219
|
.videoFilters(angle)
|
|
1220
|
+
.audioCodec('copy')
|
|
1186
1221
|
.output(outputPath)
|
|
1187
1222
|
.on('end', async () => {
|
|
1188
1223
|
await safeUnlinkWithRetry(fileName);
|
|
@@ -1231,7 +1266,9 @@ async function cleanupTempFiles() {
|
|
|
1231
1266
|
for (const file of tempFiles) {
|
|
1232
1267
|
await safeUnlinkWithRetry(path.join(TEMP_DIR, file));
|
|
1233
1268
|
}
|
|
1269
|
+
triggerGC();
|
|
1234
1270
|
} catch (error) {
|
|
1271
|
+
|
|
1235
1272
|
if (error && error.code !== 'ENOENT') {
|
|
1236
1273
|
console.error(`Error during temp file cleanup: ${error.message}`);
|
|
1237
1274
|
}
|
|
@@ -1256,9 +1293,11 @@ async function cleanupOutputFiles() {
|
|
|
1256
1293
|
}
|
|
1257
1294
|
} catch (_) { }
|
|
1258
1295
|
}
|
|
1296
|
+
triggerGC();
|
|
1259
1297
|
} catch (_) { }
|
|
1260
1298
|
}
|
|
1261
1299
|
|
|
1300
|
+
|
|
1262
1301
|
// Schedule periodic cleanup (every 10 minutes)
|
|
1263
1302
|
setInterval(() => {
|
|
1264
1303
|
cleanupTempFiles();
|
|
@@ -1291,6 +1330,7 @@ async function autoCrop(fileName) {
|
|
|
1291
1330
|
}
|
|
1292
1331
|
ffmpeg(inputPath)
|
|
1293
1332
|
.outputOptions('-vf', cropValues)
|
|
1333
|
+
.audioCodec('copy')
|
|
1294
1334
|
.output(outputPath)
|
|
1295
1335
|
.on('end', async () => {
|
|
1296
1336
|
await safeUnlinkWithRetry(inputPath);
|
|
@@ -1326,6 +1366,7 @@ async function checkAndCompressVideo(filePath, limitSizeMB, platform = null) {
|
|
|
1326
1366
|
'-crf', '28',
|
|
1327
1367
|
'-preset', 'slow'
|
|
1328
1368
|
)
|
|
1369
|
+
.audioCodec('aac')
|
|
1329
1370
|
.output(outputPath)
|
|
1330
1371
|
.on('end', async () => {
|
|
1331
1372
|
await safeUnlinkWithRetry(filePath);
|
|
@@ -1500,7 +1541,9 @@ const AudioDownloader = async (url, options = {}) => {
|
|
|
1500
1541
|
await safeUnlinkWithRetry(downloadedFilePath);
|
|
1501
1542
|
|
|
1502
1543
|
const result = await uploadToGoFileIfNeeded(audioFilePath);
|
|
1544
|
+
triggerGC();
|
|
1503
1545
|
return result;
|
|
1546
|
+
|
|
1504
1547
|
} else {
|
|
1505
1548
|
throw new Error("Failed to obtain downloaded file path.");
|
|
1506
1549
|
}
|
|
@@ -1522,8 +1565,10 @@ async function extractAudioMp3(videoPath) {
|
|
|
1522
1565
|
.format('mp3')
|
|
1523
1566
|
.save(audioPath)
|
|
1524
1567
|
.on('end', () => {
|
|
1568
|
+
triggerGC();
|
|
1525
1569
|
resolve(audioPath);
|
|
1526
1570
|
})
|
|
1571
|
+
|
|
1527
1572
|
.on('error', (err) => {
|
|
1528
1573
|
reject(new Error(`Error extracting audio: ${err.message}`));
|
|
1529
1574
|
});
|