@media-downloaders/v2 2.0.1
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/.old/index old.js +439 -0
- package/.old/index old2.js +528 -0
- package/.old/index.js +277 -0
- package/.old/old.js +513 -0
- package/.old/package.json +38 -0
- package/README.md +133 -0
- package/index.js +641 -0
- package/instagramcakkatrok.js +25 -0
- package/instagramcustom.js +27 -0
- package/package.json +40 -0
- package/tiktokcustom.js +114 -0
package/.old/index.js
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const ytdl = require('@distube/ytdl-core');
|
|
4
|
+
const Tiktok = require("@tobyg74/tiktok-api-dl");
|
|
5
|
+
const instagramDl = require("@sasmeee/igdl");
|
|
6
|
+
const { TwitterDL } = require("twitter-downloader");
|
|
7
|
+
|
|
8
|
+
const defaultConfig = {
|
|
9
|
+
autocrop: false, // Paramètre par défaut
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const MediaDownloader = async (url, options = {}) => {
|
|
13
|
+
const config = { ...defaultConfig, ...options };
|
|
14
|
+
|
|
15
|
+
if (!url || !url.includes("http")) {
|
|
16
|
+
throw new Error("Please specify a video URL...");
|
|
17
|
+
}
|
|
18
|
+
url = extractUrlFromString(url);
|
|
19
|
+
await deleteTempVideos();
|
|
20
|
+
|
|
21
|
+
if (url.includes("instagram.com/")) {
|
|
22
|
+
try {
|
|
23
|
+
const dataList = await instagramDl(url);
|
|
24
|
+
if (!dataList || !dataList[0]) {
|
|
25
|
+
throw new Error("Error: Invalid video URL...");
|
|
26
|
+
}
|
|
27
|
+
const videoURL = dataList[0].download_link;
|
|
28
|
+
const videofile = await downloadDirectVideo(videoURL, config);
|
|
29
|
+
|
|
30
|
+
return videofile;
|
|
31
|
+
|
|
32
|
+
} catch (error) {
|
|
33
|
+
throw new Error("Error downloading or sending Instagram video: " + error.message);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
} else if (url.includes('tiktok.com/')) {
|
|
37
|
+
try {
|
|
38
|
+
const result = await Tiktok.Downloader(url, {
|
|
39
|
+
version: "v2" // version: "v1" | "v2" | "v3"
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const videoLink = result.result.video;
|
|
43
|
+
const videofile = await downloadDirectVideo(videoLink, config);
|
|
44
|
+
|
|
45
|
+
return videofile;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
throw new Error("Error downloading TikTok video: " + error.message);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
} else if (url.includes("youtu.be/") || url.includes("youtube.com/")) {
|
|
51
|
+
try {
|
|
52
|
+
const videoLink = await downloadYoutubeVideo(url, config);
|
|
53
|
+
return videoLink;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
throw new Error("Error downloading YouTube video: " + error.message);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
} else if (url.includes("twitter.com") || url.includes("x.com/")) {
|
|
59
|
+
try {
|
|
60
|
+
const result = await TwitterDL(url);
|
|
61
|
+
const videoLink = result.result.media[0].videos[result.result.media[0].videos.length - 1].url;
|
|
62
|
+
const videofile = await downloadDirectVideo(videoLink, config);
|
|
63
|
+
|
|
64
|
+
return videofile;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
throw new Error("Error downloading Twitter video: " + error.message);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
} else if (url.includes("http")) {
|
|
70
|
+
const videofile = await downloadDirectVideo(url, config);
|
|
71
|
+
|
|
72
|
+
return videofile;
|
|
73
|
+
} else {
|
|
74
|
+
throw new Error("Please specify a video URL from Instagram, YouTube, or TikTok...");
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
async function downloadDirectVideo(url, config) {
|
|
79
|
+
try {
|
|
80
|
+
const response = await axios({
|
|
81
|
+
url: url,
|
|
82
|
+
method: 'GET',
|
|
83
|
+
responseType: 'stream'
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Check if the downloaded content is a MP4 video
|
|
87
|
+
const contentType = response.headers['content-type'];
|
|
88
|
+
|
|
89
|
+
// Generate a unique file name
|
|
90
|
+
let fileName = 'temp_video.mp4';
|
|
91
|
+
let count = 1;
|
|
92
|
+
while (fs.existsSync(fileName)) {
|
|
93
|
+
fileName = `temp_video_${count}.mp4`;
|
|
94
|
+
count++;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Create a write stream to save the video
|
|
98
|
+
const videoWriter = fs.createWriteStream(fileName);
|
|
99
|
+
response.data.pipe(videoWriter);
|
|
100
|
+
|
|
101
|
+
// Return a promise that resolves when the download is finished
|
|
102
|
+
return new Promise((resolve, reject) => {
|
|
103
|
+
videoWriter.on('finish', async () => {
|
|
104
|
+
if (config.autocrop) {
|
|
105
|
+
try {
|
|
106
|
+
const croppedFileName = await autoCrop(fileName);
|
|
107
|
+
resolve(croppedFileName);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
reject(error);
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
resolve(fileName);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
videoWriter.on('error', (error) => reject(error));
|
|
116
|
+
});
|
|
117
|
+
} catch (error) {
|
|
118
|
+
throw new Error(`An error occurred while downloading video: ${error.message}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function downloadYoutubeVideo(url, config) {
|
|
123
|
+
try {
|
|
124
|
+
const info = await ytdl.getInfo(url);
|
|
125
|
+
const formats = ytdl.filterFormats(info.formats, 'videoandaudio');
|
|
126
|
+
|
|
127
|
+
// Choose the format with the highest quality up to 25MB
|
|
128
|
+
let format;
|
|
129
|
+
for (let i = 0; i < formats.length; i++) {
|
|
130
|
+
const currentFormat = formats[i];
|
|
131
|
+
let contentLength = currentFormat?.contentLength;
|
|
132
|
+
if (!contentLength) {
|
|
133
|
+
contentLength = await getContentLength(currentFormat.url);
|
|
134
|
+
currentFormat.contentLength = contentLength;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (contentLength && contentLength <= 25 * 1024 * 1024) {
|
|
138
|
+
format = currentFormat;
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!format) {
|
|
144
|
+
throw new Error('No suitable format found within 25 MB.');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Ensure unique file name
|
|
148
|
+
let count = 0;
|
|
149
|
+
let fileName = `temp_video.mp4`;
|
|
150
|
+
while (fs.existsSync(fileName)) {
|
|
151
|
+
count++;
|
|
152
|
+
fileName = `temp_video_${count}.mp4`;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const videoStream = ytdl.downloadFromInfo(info, {
|
|
156
|
+
format: format,
|
|
157
|
+
filter: 'videoandaudio',
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const writeStream = fs.createWriteStream(fileName);
|
|
161
|
+
|
|
162
|
+
// Pipe video stream to file
|
|
163
|
+
videoStream.pipe(writeStream);
|
|
164
|
+
|
|
165
|
+
// Promisify the writeStream finish event
|
|
166
|
+
return new Promise((resolve, reject) => {
|
|
167
|
+
writeStream.on('finish', async () => {
|
|
168
|
+
if (config.autocrop) {
|
|
169
|
+
try {
|
|
170
|
+
const croppedFileName = await autoCrop(fileName);
|
|
171
|
+
resolve(croppedFileName);
|
|
172
|
+
} catch (error) {
|
|
173
|
+
reject(error);
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
resolve(fileName);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
writeStream.on('error', reject);
|
|
180
|
+
});
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.log(error);
|
|
183
|
+
throw error;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Helper function to get content length
|
|
188
|
+
async function getContentLength(url) {
|
|
189
|
+
try {
|
|
190
|
+
const response = await axios.head(url);
|
|
191
|
+
const contentLength = response.headers['content-length'];
|
|
192
|
+
console.log(`Content-Length: ${contentLength} bytes`);
|
|
193
|
+
return contentLength;
|
|
194
|
+
} catch (error) {
|
|
195
|
+
console.error(`Error fetching content length: ${error.message}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function extractUrlFromString(text) {
|
|
200
|
+
const urlRegex = /(https?:\/\/[^\s]+)/;
|
|
201
|
+
const match = text.match(urlRegex);
|
|
202
|
+
if (match) {
|
|
203
|
+
return match[0];
|
|
204
|
+
} else {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async function deleteTempVideos() {
|
|
210
|
+
try {
|
|
211
|
+
const files = fs.readdirSync("./");
|
|
212
|
+
const tempVideoFiles = files.filter(file => file.startsWith('temp_video'));
|
|
213
|
+
|
|
214
|
+
for (const file of tempVideoFiles) {
|
|
215
|
+
fs.unlinkSync("./" + file);
|
|
216
|
+
}
|
|
217
|
+
} catch (error) {
|
|
218
|
+
throw new Error(`Error deleting temp_video files: ${error.message}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async function autoCrop(fileName) {
|
|
223
|
+
const pathToFfmpeg = require('ffmpeg-ffprobe-static');
|
|
224
|
+
const ffmpeg = require('fluent-ffmpeg');
|
|
225
|
+
ffmpeg.setFfmpegPath(pathToFfmpeg.ffmpegPath);
|
|
226
|
+
|
|
227
|
+
const inputPath = fileName;
|
|
228
|
+
const outputPath = fileName.split('.')[0] + "_cropped.mp4";
|
|
229
|
+
|
|
230
|
+
return new Promise((resolve, reject) => {
|
|
231
|
+
ffmpeg(inputPath)
|
|
232
|
+
.videoFilters('cropdetect')
|
|
233
|
+
.output(outputPath)
|
|
234
|
+
.on('end', function(stdout, stderr) {
|
|
235
|
+
const crop = parseCrop(stderr);
|
|
236
|
+
if (!crop) {
|
|
237
|
+
reject(new Error('Erreur: Impossible de détecter les valeurs de crop.'));
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
console.log('Valeurs de crop détectées:', crop);
|
|
242
|
+
|
|
243
|
+
// CROP
|
|
244
|
+
ffmpeg(inputPath)
|
|
245
|
+
.videoFilters(`crop=${crop.width}:${crop.height}:${crop.x}:${crop.y}`)
|
|
246
|
+
.on('end', () => {
|
|
247
|
+
console.log('Rogner terminé avec succès.');
|
|
248
|
+
resolve(outputPath);
|
|
249
|
+
})
|
|
250
|
+
.on('error', (err) => {
|
|
251
|
+
reject(new Error('Erreur lors du rognage: ' + err.message));
|
|
252
|
+
})
|
|
253
|
+
.save(outputPath);
|
|
254
|
+
})
|
|
255
|
+
.on('error', (err) => {
|
|
256
|
+
reject(new Error('Erreur lors de la détection du crop: ' + err.message));
|
|
257
|
+
})
|
|
258
|
+
.run();
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
function parseCrop(stderr) {
|
|
262
|
+
const cropRegex = /crop=([0-9]+):([0-9]+):([0-9]+):([0-9]+)/;
|
|
263
|
+
const match = stderr.match(cropRegex);
|
|
264
|
+
if (match) {
|
|
265
|
+
return {
|
|
266
|
+
width: match[1],
|
|
267
|
+
height: match[2],
|
|
268
|
+
x: match[3],
|
|
269
|
+
y: match[4],
|
|
270
|
+
};
|
|
271
|
+
} else {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
module.exports = MediaDownloader;
|