shadowx-fbdl 1.0.0
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/README.md +86 -0
- package/index.js +384 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
shadowx-fbdl
|
|
2
|
+
|
|
3
|
+
π€DEV : Mueid Mursalin Rifat
|
|
4
|
+
|
|
5
|
+
π Simple Facebook video downloader - Supports FB, FB Watch, Reels & Shares
|
|
6
|
+
|
|
7
|
+
π¦ Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install shadowx-fbdl
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
π Quick Usage
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
const ShadowXFB = require('shadowx-fbdl');
|
|
17
|
+
const fbdl = new ShadowXFB();
|
|
18
|
+
|
|
19
|
+
// Download Facebook video
|
|
20
|
+
fbdl.download('https://fb.watch/abc123/')
|
|
21
|
+
.then(result => {
|
|
22
|
+
console.log('Title:', result.video.title);
|
|
23
|
+
console.log('Download URL:', result.download.url);
|
|
24
|
+
})
|
|
25
|
+
.catch(error => console.log(error.message));
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
π Examples
|
|
29
|
+
|
|
30
|
+
Get video info only
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
const info = await fbdl.getInfo('https://fb.watch/abc123/');
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Get direct download URL
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
const url = await fbdl.getDownloadUrl('https://fb.watch/abc123/');
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Check if URL is valid
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
if (fbdl.isValidUrl('https://fb.watch/abc123/')) {
|
|
46
|
+
console.log('β
Valid Facebook URL');
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
π Supported URLs
|
|
51
|
+
|
|
52
|
+
Β· https://www.facebook.com/watch?v=ID
|
|
53
|
+
Β· https://fb.watch/ID/
|
|
54
|
+
Β· https://www.facebook.com/reel/ID
|
|
55
|
+
Β· https://www.facebook.com/share/v/ID/
|
|
56
|
+
|
|
57
|
+
π€ Response Example
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
{
|
|
61
|
+
video: {
|
|
62
|
+
title: "Video Title",
|
|
63
|
+
duration: "2:30",
|
|
64
|
+
uploader: "Page Name",
|
|
65
|
+
views: "1.2M"
|
|
66
|
+
},
|
|
67
|
+
download: {
|
|
68
|
+
quality: "HD",
|
|
69
|
+
size: "5.2 MB",
|
|
70
|
+
url: "https://.../video.mp4"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
βοΈ Options
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
const fbdl = new ShadowXFB({
|
|
79
|
+
timeout: 30000, // Timeout in ms
|
|
80
|
+
apiKey: 'shadowx' // API key
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
π License
|
|
85
|
+
|
|
86
|
+
MIT Β©
|
package/index.js
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
class ShadowXFB {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
this.baseURL = options.baseURL || 'https://shadowx-downloader.vercel.app';
|
|
6
|
+
this.apiKey = options.apiKey || 'shadowx';
|
|
7
|
+
this.timeout = options.timeout || 30000;
|
|
8
|
+
this.userAgent = options.userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
|
|
9
|
+
|
|
10
|
+
// Create axios instance with default config
|
|
11
|
+
this.client = axios.create({
|
|
12
|
+
baseURL: this.baseURL,
|
|
13
|
+
timeout: this.timeout,
|
|
14
|
+
headers: {
|
|
15
|
+
'User-Agent': this.userAgent,
|
|
16
|
+
'Accept': 'application/json'
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get package metadata
|
|
23
|
+
* @returns {Object} Metadata information
|
|
24
|
+
*/
|
|
25
|
+
static getMeta() {
|
|
26
|
+
return {
|
|
27
|
+
name: "shadowx-fbdl",
|
|
28
|
+
version: "2.0.0",
|
|
29
|
+
description: "Download videos from Facebook (FB, FB Watch, Reels, Shares)",
|
|
30
|
+
author: "Mueid Mursalin Rifat",
|
|
31
|
+
license: "MIT",
|
|
32
|
+
supported_urls: [
|
|
33
|
+
"https://www.facebook.com/watch?v=VIDEO_ID",
|
|
34
|
+
"https://fb.watch/VIDEO_ID/",
|
|
35
|
+
"https://www.facebook.com/reel/VIDEO_ID",
|
|
36
|
+
"https://www.facebook.com/share/v/VIDEO_ID/",
|
|
37
|
+
"https://www.facebook.com/username/videos/VIDEO_ID"
|
|
38
|
+
]
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Validate Facebook URL
|
|
44
|
+
* @param {string} url - URL to validate
|
|
45
|
+
* @returns {boolean} True if valid Facebook video URL
|
|
46
|
+
*/
|
|
47
|
+
isValidUrl(url) {
|
|
48
|
+
if (!url || typeof url !== 'string') return false;
|
|
49
|
+
|
|
50
|
+
const patterns = [
|
|
51
|
+
/facebook\.com\/.*\/videos/i,
|
|
52
|
+
/facebook\.com\/watch(?:\?v=|.*?\bv=)/i,
|
|
53
|
+
/fb\.watch\//i,
|
|
54
|
+
/facebook\.com\/reel/i,
|
|
55
|
+
/facebook\.com\/share\/v/i,
|
|
56
|
+
/fb\.com\//i,
|
|
57
|
+
/facebook\.com\/[^\/]+\/videos/i,
|
|
58
|
+
/web\.facebook\.com/i
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
return patterns.some(pattern => pattern.test(url));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Extract video ID from Facebook URL
|
|
66
|
+
* @param {string} url - Facebook URL
|
|
67
|
+
* @returns {string|null} Video ID or null
|
|
68
|
+
*/
|
|
69
|
+
extractVideoId(url) {
|
|
70
|
+
const patterns = [
|
|
71
|
+
/videos[\/=](\d+)/i,
|
|
72
|
+
/watch\?v=(\d+)/i,
|
|
73
|
+
/reel\/(\d+)/i,
|
|
74
|
+
/share\/v\/(\d+)/i,
|
|
75
|
+
/fb\.watch\/([a-zA-Z0-9]+)/i,
|
|
76
|
+
/\/(\d+)\//
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
for (const pattern of patterns) {
|
|
80
|
+
const match = url.match(pattern);
|
|
81
|
+
if (match) return match[1];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Download Facebook video
|
|
89
|
+
* @param {string} url - Facebook video URL
|
|
90
|
+
* @param {Object} options - Download options
|
|
91
|
+
* @returns {Promise<Object>} Video information and download links
|
|
92
|
+
*/
|
|
93
|
+
async download(url, options = {}) {
|
|
94
|
+
// Validate input
|
|
95
|
+
if (!url) {
|
|
96
|
+
throw new Error('Facebook URL is required');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!this.isValidUrl(url)) {
|
|
100
|
+
throw new Error('Invalid Facebook URL format. Supported: Watch, Reels, Shares, FB Watch links');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const startTime = Date.now();
|
|
104
|
+
const videoId = this.extractVideoId(url);
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
console.log(`π shadowx-fbdl: Fetching video from ${url}`);
|
|
108
|
+
|
|
109
|
+
// Make request to ShadowX API
|
|
110
|
+
const response = await this.client.get('/dl', {
|
|
111
|
+
params: {
|
|
112
|
+
url: url,
|
|
113
|
+
key: options.apiKey || this.apiKey
|
|
114
|
+
},
|
|
115
|
+
timeout: options.timeout || this.timeout
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const data = response.data;
|
|
119
|
+
const endTime = Date.now();
|
|
120
|
+
const downloadTime = ((endTime - startTime) / 1000).toFixed(2);
|
|
121
|
+
|
|
122
|
+
// Check API response
|
|
123
|
+
if (!data || !data.success) {
|
|
124
|
+
throw new Error(data?.error || 'Failed to fetch video information');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Format the response
|
|
128
|
+
return this._formatResponse(data, url, videoId, downloadTime);
|
|
129
|
+
|
|
130
|
+
} catch (error) {
|
|
131
|
+
throw this._handleError(error, url);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Format API response
|
|
137
|
+
* @param {Object} data - Raw API data
|
|
138
|
+
* @param {string} originalUrl - Original URL
|
|
139
|
+
* @param {string} videoId - Video ID
|
|
140
|
+
* @param {string} downloadTime - Download time
|
|
141
|
+
* @returns {Object} Formatted response
|
|
142
|
+
* @private
|
|
143
|
+
*/
|
|
144
|
+
_formatResponse(data, originalUrl, videoId, downloadTime) {
|
|
145
|
+
const baseURL = this.baseURL;
|
|
146
|
+
const downloadUrl = data.download?.url ?
|
|
147
|
+
(data.download.url.startsWith('http') ? data.download.url : `${baseURL}${data.download.url}`) :
|
|
148
|
+
null;
|
|
149
|
+
|
|
150
|
+
// Generate filename
|
|
151
|
+
const filename = data.download?.filename ||
|
|
152
|
+
`facebook_video_${videoId || Date.now()}.mp4`;
|
|
153
|
+
|
|
154
|
+
// Calculate file size in human readable format
|
|
155
|
+
const filesizeBytes = data.download?.filesize_bytes || 0;
|
|
156
|
+
const filesizeMB = filesizeBytes ? (filesizeBytes / (1024 * 1024)).toFixed(2) : 0;
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
success: true,
|
|
160
|
+
message: 'Video fetched successfully',
|
|
161
|
+
|
|
162
|
+
// Package info
|
|
163
|
+
package: {
|
|
164
|
+
name: 'shadowx-fbdl',
|
|
165
|
+
version: '2.0.0',
|
|
166
|
+
author: 'Mueid Mursalin Rifat'
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
// Video metadata
|
|
170
|
+
video: {
|
|
171
|
+
id: data.id || videoId || 'N/A',
|
|
172
|
+
title: data.title || 'Facebook Video',
|
|
173
|
+
description: data.description || '',
|
|
174
|
+
duration: data.duration || 'Unknown',
|
|
175
|
+
thumbnail: data.thumbnail || null,
|
|
176
|
+
uploader: data.uploader || 'Unknown',
|
|
177
|
+
uploader_id: data.uploader_id || null,
|
|
178
|
+
view_count: this._formatNumber(data.view_count),
|
|
179
|
+
like_count: this._formatNumber(data.like_count),
|
|
180
|
+
comment_count: this._formatNumber(data.comment_count),
|
|
181
|
+
share_count: this._formatNumber(data.share_count),
|
|
182
|
+
was_live: data.was_live || false,
|
|
183
|
+
platform: data.download?.platform || 'Facebook',
|
|
184
|
+
url: data.url || originalUrl,
|
|
185
|
+
created_time: data.created_time || null
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
// Download information
|
|
189
|
+
download: {
|
|
190
|
+
quality: data.download?.quality || 'HD',
|
|
191
|
+
format: data.download?.format || 'mp4',
|
|
192
|
+
size: filesizeMB ? `${filesizeMB} MB` : 'Unknown',
|
|
193
|
+
size_bytes: filesizeBytes,
|
|
194
|
+
url: downloadUrl,
|
|
195
|
+
filename: filename,
|
|
196
|
+
direct_url: downloadUrl, // Alias for url
|
|
197
|
+
|
|
198
|
+
// Additional download info
|
|
199
|
+
expires_in: data.download?.expires_in || null,
|
|
200
|
+
download_time: `${downloadTime}s`
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
// Audio info (if available)
|
|
204
|
+
audio: data.audio_download ? {
|
|
205
|
+
url: data.audio_download.url,
|
|
206
|
+
size: data.audio_download.size,
|
|
207
|
+
format: data.audio_download.format
|
|
208
|
+
} : null,
|
|
209
|
+
|
|
210
|
+
// Additional metadata
|
|
211
|
+
metadata: {
|
|
212
|
+
requested_url: originalUrl,
|
|
213
|
+
extracted_id: videoId,
|
|
214
|
+
timestamp: new Date().toISOString(),
|
|
215
|
+
api_response_time: downloadTime
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
// Raw data for debugging
|
|
219
|
+
raw: data
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Format large numbers with K/M/B suffixes
|
|
225
|
+
* @param {number|string} num - Number to format
|
|
226
|
+
* @returns {string} Formatted number
|
|
227
|
+
* @private
|
|
228
|
+
*/
|
|
229
|
+
_formatNumber(num) {
|
|
230
|
+
if (!num && num !== 0) return 'N/A';
|
|
231
|
+
if (typeof num === 'string') num = parseInt(num.replace(/,/g, ''));
|
|
232
|
+
if (isNaN(num)) return 'N/A';
|
|
233
|
+
|
|
234
|
+
if (num >= 1000000000) return (num / 1000000000).toFixed(1) + 'B';
|
|
235
|
+
if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M';
|
|
236
|
+
if (num >= 1000) return (num / 1000).toFixed(1) + 'K';
|
|
237
|
+
return num.toString();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Handle and format errors
|
|
242
|
+
* @param {Error} error - Error object
|
|
243
|
+
* @param {string} url - Original URL
|
|
244
|
+
* @returns {Error} Formatted error
|
|
245
|
+
* @private
|
|
246
|
+
*/
|
|
247
|
+
_handleError(error, url) {
|
|
248
|
+
let errorMessage = 'Failed to download Facebook video';
|
|
249
|
+
let statusCode = 500;
|
|
250
|
+
let errorCode = 'UNKNOWN_ERROR';
|
|
251
|
+
|
|
252
|
+
if (error.response) {
|
|
253
|
+
// API responded with error
|
|
254
|
+
statusCode = error.response.status;
|
|
255
|
+
const apiError = error.response.data?.error || error.response.statusText;
|
|
256
|
+
|
|
257
|
+
switch (statusCode) {
|
|
258
|
+
case 400:
|
|
259
|
+
errorMessage = 'Invalid Facebook URL or video not accessible';
|
|
260
|
+
errorCode = 'INVALID_URL';
|
|
261
|
+
break;
|
|
262
|
+
case 401:
|
|
263
|
+
case 403:
|
|
264
|
+
errorMessage = 'Access denied or invalid API key';
|
|
265
|
+
errorCode = 'ACCESS_DENIED';
|
|
266
|
+
break;
|
|
267
|
+
case 404:
|
|
268
|
+
errorMessage = 'Video not found or has been removed';
|
|
269
|
+
errorCode = 'VIDEO_NOT_FOUND';
|
|
270
|
+
break;
|
|
271
|
+
case 429:
|
|
272
|
+
errorMessage = 'Rate limit exceeded. Please try again later';
|
|
273
|
+
errorCode = 'RATE_LIMITED';
|
|
274
|
+
break;
|
|
275
|
+
case 500:
|
|
276
|
+
case 502:
|
|
277
|
+
case 503:
|
|
278
|
+
errorMessage = 'Download service is temporarily unavailable';
|
|
279
|
+
errorCode = 'SERVICE_UNAVAILABLE';
|
|
280
|
+
break;
|
|
281
|
+
default:
|
|
282
|
+
errorMessage = `API Error: ${apiError}`;
|
|
283
|
+
errorCode = 'API_ERROR';
|
|
284
|
+
}
|
|
285
|
+
} else if (error.code === 'ECONNABORTED') {
|
|
286
|
+
errorMessage = 'Request timeout. The server might be busy';
|
|
287
|
+
errorCode = 'TIMEOUT';
|
|
288
|
+
statusCode = 408;
|
|
289
|
+
} else if (error.code === 'ENOTFOUND') {
|
|
290
|
+
errorMessage = 'Network error - cannot connect to download server';
|
|
291
|
+
errorCode = 'NETWORK_ERROR';
|
|
292
|
+
statusCode = 503;
|
|
293
|
+
} else if (error.message.includes('Invalid Facebook URL')) {
|
|
294
|
+
errorMessage = error.message;
|
|
295
|
+
errorCode = 'VALIDATION_ERROR';
|
|
296
|
+
statusCode = 400;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const formattedError = new Error(errorMessage);
|
|
300
|
+
formattedError.code = errorCode;
|
|
301
|
+
formattedError.statusCode = statusCode;
|
|
302
|
+
formattedError.url = url;
|
|
303
|
+
formattedError.originalError = error;
|
|
304
|
+
formattedError.timestamp = new Date().toISOString();
|
|
305
|
+
formattedError.suggestion = this._getSuggestion(errorCode);
|
|
306
|
+
|
|
307
|
+
return formattedError;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Get suggestion based on error code
|
|
312
|
+
* @param {string} errorCode - Error code
|
|
313
|
+
* @returns {string} Suggestion
|
|
314
|
+
* @private
|
|
315
|
+
*/
|
|
316
|
+
_getSuggestion(errorCode) {
|
|
317
|
+
const suggestions = {
|
|
318
|
+
'INVALID_URL': 'Make sure the URL is correct and the video is public',
|
|
319
|
+
'VIDEO_NOT_FOUND': 'The video may have been deleted or made private',
|
|
320
|
+
'RATE_LIMITED': 'Wait a few minutes before making more requests',
|
|
321
|
+
'ACCESS_DENIED': 'Check your API key or try again later',
|
|
322
|
+
'SERVICE_UNAVAILABLE': 'Try again in a few minutes',
|
|
323
|
+
'TIMEOUT': 'Try again or use a shorter video',
|
|
324
|
+
'NETWORK_ERROR': 'Check your internet connection',
|
|
325
|
+
'VALIDATION_ERROR': 'Use a supported Facebook URL format',
|
|
326
|
+
'API_ERROR': 'The download service encountered an error',
|
|
327
|
+
'UNKNOWN_ERROR': 'Please report this issue on GitHub'
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
return suggestions[errorCode] || 'Please check the URL and try again';
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Get video information without download links
|
|
335
|
+
* @param {string} url - Facebook video URL
|
|
336
|
+
* @returns {Promise<Object>} Video metadata
|
|
337
|
+
*/
|
|
338
|
+
async getInfo(url) {
|
|
339
|
+
const result = await this.download(url);
|
|
340
|
+
// Remove download URLs from response
|
|
341
|
+
delete result.download.url;
|
|
342
|
+
delete result.download.direct_url;
|
|
343
|
+
result.download.available = true;
|
|
344
|
+
return result;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Get download URL only
|
|
349
|
+
* @param {string} url - Facebook video URL
|
|
350
|
+
* @param {string} quality - Video quality (hd, sd)
|
|
351
|
+
* @returns {Promise<string>} Direct download URL
|
|
352
|
+
*/
|
|
353
|
+
async getDownloadUrl(url, quality = 'hd') {
|
|
354
|
+
const result = await this.download(url);
|
|
355
|
+
return result.download.url;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Check if URL is downloadable
|
|
360
|
+
* @param {string} url - Facebook URL
|
|
361
|
+
* @returns {Promise<boolean>} True if downloadable
|
|
362
|
+
*/
|
|
363
|
+
async isDownloadable(url) {
|
|
364
|
+
try {
|
|
365
|
+
if (!this.isValidUrl(url)) return false;
|
|
366
|
+
const result = await this.getInfo(url);
|
|
367
|
+
return result.success && result.download.available;
|
|
368
|
+
} catch {
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Export for CommonJS
|
|
375
|
+
module.exports = ShadowXFB;
|
|
376
|
+
|
|
377
|
+
// Export factory function
|
|
378
|
+
module.exports.create = (options) => new ShadowXFB(options);
|
|
379
|
+
|
|
380
|
+
// Export default instance
|
|
381
|
+
module.exports.default = new ShadowXFB();
|
|
382
|
+
|
|
383
|
+
// Export metadata
|
|
384
|
+
module.exports.meta = ShadowXFB.getMeta();
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "shadowx-fbdl",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Powerful Facebook video downloader - Supports FB, FB Watch, Reels, Shares using ShadowX API",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node examples/basic-usage.js",
|
|
8
|
+
"start": "node index.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"facebook",
|
|
12
|
+
"downloader",
|
|
13
|
+
"video",
|
|
14
|
+
"facebook-video",
|
|
15
|
+
"fb-downloader",
|
|
16
|
+
"fb",
|
|
17
|
+
"reels",
|
|
18
|
+
"facebook-reels",
|
|
19
|
+
"facebook-watch",
|
|
20
|
+
"shadowx",
|
|
21
|
+
"video-downloader",
|
|
22
|
+
"social-media-downloader",
|
|
23
|
+
"facebook-downloader",
|
|
24
|
+
"fb-video",
|
|
25
|
+
"reels-downloader"
|
|
26
|
+
],
|
|
27
|
+
"author": "Mueid Mursalin Rifat",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"axios": "^1.6.2"
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/mueidmursalin/shadowx-fbdl.git"
|
|
35
|
+
},
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/mueidmursalin/shadowx-fbdl/issues"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/mueidmursalin/shadowx-fbdl#readme",
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=12.0.0"
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"index.js",
|
|
45
|
+
"README.md",
|
|
46
|
+
"LICENSE",
|
|
47
|
+
"examples/"
|
|
48
|
+
]
|
|
49
|
+
}
|