@lmna22/aio-downloader 1.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/README.md +416 -0
- package/package.json +51 -0
- package/src/download.js +53 -0
- package/src/index.js +62 -0
- package/src/lib/instagram.js +395 -0
- package/src/lib/pinterest.js +313 -0
- package/src/lib/pixiv.js +425 -0
- package/src/lib/tiktok.js +120 -0
- package/src/lib/twitter.js +239 -0
- package/src/lib/youtube.js +257 -0
- package/src/utils.js +93 -0
package/README.md
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
# @lmna22/aio-downloader
|
|
2
|
+
|
|
3
|
+
> All-in-one media downloader for YouTube, Instagram, TikTok, Pinterest, Pixiv, and X/Twitter.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@lmna22/aio-downloader)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://nodejs.org/)
|
|
8
|
+
|
|
9
|
+
Scrape and download videos, audio, and images from multiple platforms with a single, unified API. No API keys required.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## ✨ Features
|
|
14
|
+
|
|
15
|
+
| Platform | Video | Audio | Image | Search |
|
|
16
|
+
|---|---|---|---|---|
|
|
17
|
+
| **YouTube** | ✅ (Multiple qualities) | ✅ (MP3) | — | — |
|
|
18
|
+
| **Instagram** | ✅ | — | ✅ | — |
|
|
19
|
+
| **TikTok** | ✅ (Buffer) | ✅ | — | — |
|
|
20
|
+
| **Pinterest** | — | — | ✅ | ✅ |
|
|
21
|
+
| **Pixiv** | — | — | ✅ (Original Resolution) | ✅ |
|
|
22
|
+
| **X / Twitter** | ✅ (Best quality) | — | ✅ | — |
|
|
23
|
+
|
|
24
|
+
- 🔗 **Auto-detect platform** from URL — just pass any supported link
|
|
25
|
+
- 📦 **Programmatic API** — designed for Node.js applications, bots, and scripts
|
|
26
|
+
- 📥 **Built-in download helper** with progress callback
|
|
27
|
+
- 🔍 **Search support** for Pinterest and Pixiv (pass keywords instead of URLs)
|
|
28
|
+
- 🚫 **No API keys** — all data is scraped from public sources
|
|
29
|
+
- 🔄 **Multi-method fallback** — Instagram uses 4 different methods for maximum reliability
|
|
30
|
+
- 🎬 **YouTube quality selection** — choose from 144p to 2160p, or audio-only MP3
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 📦 Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install @lmna22/aio-downloader
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
All required dependencies are bundled and will be installed automatically.
|
|
41
|
+
|
|
42
|
+
**Optional:** For Pinterest/Pixiv fallback when axios scraping is blocked:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install puppeteer
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 🚀 Quick Start
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
const { aioDownloader } = require("@lmna22/aio-downloader");
|
|
54
|
+
|
|
55
|
+
// Auto-detects the platform from the URL
|
|
56
|
+
const result = await aioDownloader("https://www.youtube.com/watch?v=dQw4w9WgXcQ", { quality: 5 });
|
|
57
|
+
console.log(result);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 📖 Usage Examples
|
|
63
|
+
|
|
64
|
+
### YouTube
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
const { youtubeDownloader, youtubePlaylistDownloader } = require("@lmna22/aio-downloader");
|
|
68
|
+
|
|
69
|
+
// Quality options:
|
|
70
|
+
// 1 = 144p, 2 = 360p, 3 = 480p, 4 = 720p,
|
|
71
|
+
// 5 = 1080p, 6 = 1440p, 7 = 2160p,
|
|
72
|
+
// 8 = Audio only (MP3), 9 = Get bitrate list
|
|
73
|
+
|
|
74
|
+
// Download a video in 1080p
|
|
75
|
+
const result = await youtubeDownloader("https://www.youtube.com/watch?v=dQw4w9WgXcQ", 5);
|
|
76
|
+
|
|
77
|
+
if (result.status) {
|
|
78
|
+
console.log(result.data.title); // "Rick Astley - Never Gonna Give You Up"
|
|
79
|
+
console.log(result.data.channel); // "Rick Astley"
|
|
80
|
+
console.log(result.data.views); // 1500000000
|
|
81
|
+
console.log(result.data.size); // Buffer size in bytes
|
|
82
|
+
console.log(result.data.type); // "mp4" or "mp3"
|
|
83
|
+
|
|
84
|
+
// Save to file
|
|
85
|
+
const fs = require("fs");
|
|
86
|
+
fs.writeFileSync(`${result.data.title}.${result.data.type}`, result.data.result);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Download audio only
|
|
90
|
+
const audio = await youtubeDownloader("https://www.youtube.com/watch?v=dQw4w9WgXcQ", 8);
|
|
91
|
+
|
|
92
|
+
// Get available audio bitrates
|
|
93
|
+
const bitrates = await youtubeDownloader("https://www.youtube.com/watch?v=dQw4w9WgXcQ", 9);
|
|
94
|
+
console.log(bitrates.data.bitrateList);
|
|
95
|
+
|
|
96
|
+
// Download entire playlist
|
|
97
|
+
const playlist = await youtubePlaylistDownloader(
|
|
98
|
+
"https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf",
|
|
99
|
+
5, // quality
|
|
100
|
+
"./my-playlist" // output folder
|
|
101
|
+
);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Instagram
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
const { instagramDownloader } = require("@lmna22/aio-downloader");
|
|
108
|
+
|
|
109
|
+
const result = await instagramDownloader("https://www.instagram.com/p/ABC123/");
|
|
110
|
+
|
|
111
|
+
if (result.status) {
|
|
112
|
+
console.log(result.data.url); // Array of download URLs
|
|
113
|
+
console.log(result.data.caption); // Post caption
|
|
114
|
+
console.log(result.data.username); // "@username"
|
|
115
|
+
console.log(result.data.like); // Like count
|
|
116
|
+
console.log(result.data.comment); // Comment count
|
|
117
|
+
console.log(result.data.isVideo); // true/false
|
|
118
|
+
|
|
119
|
+
// Download all media
|
|
120
|
+
const { download } = require("@lmna22/aio-downloader");
|
|
121
|
+
for (let i = 0; i < result.data.url.length; i++) {
|
|
122
|
+
await download(result.data.url[i], `./downloads/ig_${i + 1}.mp4`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### TikTok
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
const { tiktokDownloader } = require("@lmna22/aio-downloader");
|
|
131
|
+
|
|
132
|
+
const result = await tiktokDownloader("https://www.tiktok.com/@user/video/1234567890");
|
|
133
|
+
|
|
134
|
+
if (result.status) {
|
|
135
|
+
const data = result.data;
|
|
136
|
+
|
|
137
|
+
console.log(data.description); // Video description
|
|
138
|
+
console.log(data.author.nickname); // Author name
|
|
139
|
+
console.log(data.author.uniqueId); // @username
|
|
140
|
+
console.log(data.stats.likes); // Like count
|
|
141
|
+
console.log(data.stats.comments); // Comment count
|
|
142
|
+
console.log(data.stats.plays); // Play count
|
|
143
|
+
console.log(data.music.title); // Music title
|
|
144
|
+
console.log(data.videoInfo.duration); // Duration in seconds
|
|
145
|
+
console.log(data.videoInfo.width); // Video width
|
|
146
|
+
console.log(data.videoInfo.height); // Video height
|
|
147
|
+
|
|
148
|
+
// Video is returned as a Buffer — save directly
|
|
149
|
+
if (data.videoBuffer) {
|
|
150
|
+
const fs = require("fs");
|
|
151
|
+
fs.writeFileSync("tiktok_video.mp4", data.videoBuffer);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Pinterest
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
const { pinterestDownloader } = require("@lmna22/aio-downloader");
|
|
160
|
+
|
|
161
|
+
// From a direct pin URL
|
|
162
|
+
const data = await pinterestDownloader("https://www.pinterest.com/pin/123456789/");
|
|
163
|
+
|
|
164
|
+
// Or search by keyword
|
|
165
|
+
const searchResults = await pinterestDownloader("aesthetic wallpaper", { limit: 20 });
|
|
166
|
+
|
|
167
|
+
console.log(data.results);
|
|
168
|
+
// [
|
|
169
|
+
// {
|
|
170
|
+
// id: "123456789",
|
|
171
|
+
// title: "Beautiful Wallpaper",
|
|
172
|
+
// link: "https://www.pinterest.com/pin/123456789/",
|
|
173
|
+
// image: "https://i.pinimg.com/originals/...",
|
|
174
|
+
// source: "example.com"
|
|
175
|
+
// }
|
|
176
|
+
// ]
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Pixiv
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
const { pixivDownloader } = require("@lmna22/aio-downloader");
|
|
183
|
+
|
|
184
|
+
// From an artwork URL
|
|
185
|
+
const data = await pixivDownloader("https://www.pixiv.net/artworks/12345678");
|
|
186
|
+
|
|
187
|
+
// Or search by tag/keyword
|
|
188
|
+
const searchResults = await pixivDownloader("landscape", { limit: 5 });
|
|
189
|
+
|
|
190
|
+
console.log(data.results);
|
|
191
|
+
// [
|
|
192
|
+
// {
|
|
193
|
+
// id: "12345678",
|
|
194
|
+
// title: "Beautiful Landscape",
|
|
195
|
+
// link: "https://www.pixiv.net/artworks/12345678",
|
|
196
|
+
// image: "https://i.pximg.net/img-original/...",
|
|
197
|
+
// artist: "ArtistName",
|
|
198
|
+
// artistUrl: "https://www.pixiv.net/users/999",
|
|
199
|
+
// userId: "999",
|
|
200
|
+
// images: ["https://i.pximg.net/img-original/..."]
|
|
201
|
+
// }
|
|
202
|
+
// ]
|
|
203
|
+
|
|
204
|
+
// Skip enrichment for faster results (no original resolution images)
|
|
205
|
+
const fast = await pixivDownloader("landscape", { limit: 10, enrich: false });
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### X / Twitter
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
const { twitterDownloader } = require("@lmna22/aio-downloader");
|
|
212
|
+
|
|
213
|
+
const result = await twitterDownloader("https://x.com/user/status/1234567890");
|
|
214
|
+
|
|
215
|
+
if (result.status) {
|
|
216
|
+
console.log(result.data.author); // "username"
|
|
217
|
+
console.log(result.data.description); // Tweet text
|
|
218
|
+
console.log(result.data.like); // Like count
|
|
219
|
+
console.log(result.data.view); // View count
|
|
220
|
+
console.log(result.data.retweet); // Retweet count
|
|
221
|
+
console.log(result.data.sensitiveContent); // true/false
|
|
222
|
+
|
|
223
|
+
// result.data.result contains media items:
|
|
224
|
+
// [
|
|
225
|
+
// { type: "video", thumb: "https://...", url: "https://..." },
|
|
226
|
+
// { type: "image", url: "https://...?format=png&name=large" },
|
|
227
|
+
// { type: "gif", thumb: "https://...", url: "https://..." }
|
|
228
|
+
// ]
|
|
229
|
+
|
|
230
|
+
// Download all media
|
|
231
|
+
const { download } = require("@lmna22/aio-downloader");
|
|
232
|
+
for (let i = 0; i < result.data.result.length; i++) {
|
|
233
|
+
const media = result.data.result[i];
|
|
234
|
+
const ext = media.type === "image" ? ".png" : ".mp4";
|
|
235
|
+
await download(media.url, `./downloads/tweet_${i + 1}${ext}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## 📥 Download Helper
|
|
243
|
+
|
|
244
|
+
Use the built-in `download` helper to save files to disk:
|
|
245
|
+
|
|
246
|
+
```javascript
|
|
247
|
+
const { download } = require("@lmna22/aio-downloader");
|
|
248
|
+
|
|
249
|
+
// Download with progress tracking
|
|
250
|
+
const result = await download("https://example.com/video.mp4", "./downloads/video.mp4", {
|
|
251
|
+
onProgress: ({ downloaded, total, percentage }) => {
|
|
252
|
+
console.log(`${percentage}% - ${downloaded}/${total} bytes`);
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
console.log(result);
|
|
257
|
+
// { path: "./downloads/video.mp4", size: 26345678, filename: "video.mp4" }
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## 🌐 Auto-detect Platform
|
|
263
|
+
|
|
264
|
+
```javascript
|
|
265
|
+
const { aioDownloader, detectPlatform } = require("@lmna22/aio-downloader");
|
|
266
|
+
|
|
267
|
+
// Auto-detect and scrape
|
|
268
|
+
await aioDownloader("https://www.youtube.com/watch?v=abc123", { quality: 5 });
|
|
269
|
+
await aioDownloader("https://www.instagram.com/p/xyz/");
|
|
270
|
+
await aioDownloader("https://www.tiktok.com/@user/video/123");
|
|
271
|
+
await aioDownloader("https://www.pinterest.com/pin/456/");
|
|
272
|
+
await aioDownloader("https://www.pixiv.net/artworks/789");
|
|
273
|
+
await aioDownloader("https://x.com/user/status/101112");
|
|
274
|
+
|
|
275
|
+
// Force a specific platform
|
|
276
|
+
await aioDownloader("https://example.com/video", { platform: "youtube", quality: 5 });
|
|
277
|
+
|
|
278
|
+
// Detect platform only
|
|
279
|
+
detectPlatform("https://youtube.com/watch?v=abc"); // "youtube"
|
|
280
|
+
detectPlatform("https://instagram.com/p/xyz"); // "instagram"
|
|
281
|
+
detectPlatform("https://tiktok.com/@user/video/1"); // "tiktok"
|
|
282
|
+
detectPlatform("https://pinterest.com/pin/123"); // "pinterest"
|
|
283
|
+
detectPlatform("https://pixiv.net/artworks/456"); // "pixiv"
|
|
284
|
+
detectPlatform("https://x.com/user/status/789"); // "twitter"
|
|
285
|
+
detectPlatform("https://unknown.com"); // null
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## 📚 API Reference
|
|
291
|
+
|
|
292
|
+
### `aioDownloader(url, options?)`
|
|
293
|
+
|
|
294
|
+
Auto-detect platform and scrape media data.
|
|
295
|
+
|
|
296
|
+
| Parameter | Type | Description |
|
|
297
|
+
|---|---|---|
|
|
298
|
+
| `url` | `string` | The URL to scrape |
|
|
299
|
+
| `options.platform` | `string` | Force a specific platform |
|
|
300
|
+
| `options.quality` | `number` | YouTube quality (1-9) |
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
### `youtubeDownloader(url, quality)`
|
|
305
|
+
|
|
306
|
+
| Parameter | Type | Description |
|
|
307
|
+
|---|---|---|
|
|
308
|
+
| `url` | `string` | YouTube video URL |
|
|
309
|
+
| `quality` | `number` | 1=144p, 2=360p, 3=480p, 4=720p, 5=1080p, 6=1440p, 7=2160p, 8=MP3, 9=bitrate list |
|
|
310
|
+
|
|
311
|
+
**Returns:** `{ creator, status, data: { title, result (Buffer), size, quality, desc, views, likes, channel, uploadDate, thumb, type } }`
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
### `youtubePlaylistDownloader(url, quality, folderPath?)`
|
|
316
|
+
|
|
317
|
+
Downloads all videos from a YouTube playlist.
|
|
318
|
+
|
|
319
|
+
**Returns:** `{ creator, status, data: { title, resultPath[], metadata[] } }`
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
### `instagramDownloader(url)`
|
|
324
|
+
|
|
325
|
+
Uses 4 fallback methods for maximum reliability.
|
|
326
|
+
|
|
327
|
+
**Returns:** `{ creator, status, data: { url[], caption, username, like, comment, isVideo } }`
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
### `tiktokDownloader(url)`
|
|
332
|
+
|
|
333
|
+
Returns video as a Buffer (no watermark).
|
|
334
|
+
|
|
335
|
+
**Returns:** `{ creator, status, data: { videoId, description, videoUrl, videoBuffer (Buffer), videoInfo, author, music, stats, locationCreated } }`
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
### `pinterestDownloader(input, options?)`
|
|
340
|
+
|
|
341
|
+
| Parameter | Type | Description |
|
|
342
|
+
|---|---|---|
|
|
343
|
+
| `input` | `string` | Pin URL or search keyword |
|
|
344
|
+
| `options.limit` | `number` | Max results for search (default: 10) |
|
|
345
|
+
|
|
346
|
+
**Returns:** `{ status, platform, method, total, results: [{ id, title, link, image, source }] }`
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
### `pixivDownloader(input, options?)`
|
|
351
|
+
|
|
352
|
+
| Parameter | Type | Description |
|
|
353
|
+
|---|---|---|
|
|
354
|
+
| `input` | `string` | Artwork URL or search keyword |
|
|
355
|
+
| `options.limit` | `number` | Max results (default: 10) |
|
|
356
|
+
| `options.enrich` | `boolean` | Fetch original resolution images (default: true) |
|
|
357
|
+
|
|
358
|
+
**Returns:** `{ status, platform, method, total, results: [{ id, title, link, image, artist, artistUrl, userId, images[] }] }`
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
### `twitterDownloader(url)`
|
|
363
|
+
|
|
364
|
+
Extracts best quality video/image/gif from tweets via Twitter GraphQL API.
|
|
365
|
+
|
|
366
|
+
**Returns:** `{ creator, status, data: { author, like, view, retweet, description, sensitiveContent, result: [{ type, url, thumb? }] } }`
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
### `download(url, outputPath, options?)`
|
|
371
|
+
|
|
372
|
+
Helper to download any file to disk.
|
|
373
|
+
|
|
374
|
+
| Parameter | Type | Description |
|
|
375
|
+
|---|---|---|
|
|
376
|
+
| `url` | `string` | Direct download URL |
|
|
377
|
+
| `outputPath` | `string` | Local file path |
|
|
378
|
+
| `options.headers` | `object` | Custom request headers |
|
|
379
|
+
| `options.timeout` | `number` | Timeout in ms (default: 120000) |
|
|
380
|
+
| `options.onProgress` | `function` | `({ downloaded, total, percentage })` |
|
|
381
|
+
|
|
382
|
+
**Returns:** `{ path, size, filename }`
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
### `detectPlatform(url)`
|
|
387
|
+
|
|
388
|
+
**Returns:** `"youtube"` | `"instagram"` | `"tiktok"` | `"pinterest"` | `"pixiv"` | `"twitter"` | `null`
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## ⚠️ Error Handling
|
|
393
|
+
|
|
394
|
+
All functions return `{ status: false, message: "..." }` on failure:
|
|
395
|
+
|
|
396
|
+
```javascript
|
|
397
|
+
const { youtubeDownloader } = require("@lmna22/aio-downloader");
|
|
398
|
+
|
|
399
|
+
const result = await youtubeDownloader("https://www.youtube.com/watch?v=invalid", 5);
|
|
400
|
+
if (!result.status) {
|
|
401
|
+
console.error("Failed:", result.message);
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## 📋 Requirements
|
|
408
|
+
|
|
409
|
+
- **Node.js** >= 14.0.0
|
|
410
|
+
- **puppeteer** (optional) — fallback for Pinterest/Pixiv when axios scraping is blocked
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## 📄 License
|
|
415
|
+
|
|
416
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lmna22/aio-downloader",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "All-in-one media downloader for YouTube, Instagram, TikTok, Pinterest, Pixiv, and X/Twitter. Scrape and download videos, audio, and images from multiple platforms with a single library.",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node -e \"const aio = require('./src/index.js'); console.log('Exports:', Object.keys(aio)); console.log('Platform detection:', aio.detectPlatform('https://youtube.com/watch?v=test'));\""
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"downloader",
|
|
11
|
+
"youtube",
|
|
12
|
+
"instagram",
|
|
13
|
+
"tiktok",
|
|
14
|
+
"pinterest",
|
|
15
|
+
"pixiv",
|
|
16
|
+
"twitter",
|
|
17
|
+
"x",
|
|
18
|
+
"video",
|
|
19
|
+
"audio",
|
|
20
|
+
"image",
|
|
21
|
+
"media",
|
|
22
|
+
"scraper",
|
|
23
|
+
"aio"
|
|
24
|
+
],
|
|
25
|
+
"author": "",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": ""
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"axios": "^1.7.0",
|
|
33
|
+
"axios-cookiejar-support": "^5.0.0",
|
|
34
|
+
"cheerio": "^1.0.0",
|
|
35
|
+
"ffmpeg-static": "^5.0.0",
|
|
36
|
+
"qs": "^6.13.0",
|
|
37
|
+
"tough-cookie": "^5.1.0",
|
|
38
|
+
"youtube-dl-exec": "^3.0.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"puppeteer": ">=20.0.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependenciesMeta": {
|
|
44
|
+
"puppeteer": {
|
|
45
|
+
"optional": true
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=14.0.0"
|
|
50
|
+
}
|
|
51
|
+
}
|
package/src/download.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const axios = require("axios");
|
|
4
|
+
const { DEFAULT_UA } = require("./utils");
|
|
5
|
+
|
|
6
|
+
async function download(url, outputPath, options = {}) {
|
|
7
|
+
const dir = path.dirname(outputPath);
|
|
8
|
+
if (!fs.existsSync(dir)) {
|
|
9
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const res = await axios.get(url, {
|
|
13
|
+
responseType: "stream",
|
|
14
|
+
headers: {
|
|
15
|
+
"User-Agent": DEFAULT_UA,
|
|
16
|
+
...options.headers,
|
|
17
|
+
},
|
|
18
|
+
timeout: options.timeout || 120000,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const totalBytes = parseInt(res.headers["content-length"] || "0", 10);
|
|
22
|
+
let downloadedBytes = 0;
|
|
23
|
+
|
|
24
|
+
if (options.onProgress && typeof options.onProgress === "function") {
|
|
25
|
+
res.data.on("data", (chunk) => {
|
|
26
|
+
downloadedBytes += chunk.length;
|
|
27
|
+
options.onProgress({
|
|
28
|
+
downloaded: downloadedBytes,
|
|
29
|
+
total: totalBytes,
|
|
30
|
+
percentage: totalBytes > 0 ? Math.round((downloadedBytes / totalBytes) * 100) : 0,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
const writer = fs.createWriteStream(outputPath);
|
|
37
|
+
res.data.pipe(writer);
|
|
38
|
+
|
|
39
|
+
writer.on("finish", () => {
|
|
40
|
+
const stats = fs.statSync(outputPath);
|
|
41
|
+
resolve({
|
|
42
|
+
path: outputPath,
|
|
43
|
+
size: stats.size,
|
|
44
|
+
filename: path.basename(outputPath),
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
writer.on("error", reject);
|
|
49
|
+
res.data.on("error", reject);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = download;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const { youtubeDownloader, youtubePlaylistDownloader } = require("./lib/youtube");
|
|
2
|
+
const instagramDownloader = require("./lib/instagram");
|
|
3
|
+
const tiktokDownloader = require("./lib/tiktok");
|
|
4
|
+
const pinterestDownloader = require("./lib/pinterest");
|
|
5
|
+
const pixivDownloader = require("./lib/pixiv");
|
|
6
|
+
const twitterDownloader = require("./lib/twitter");
|
|
7
|
+
const download = require("./download");
|
|
8
|
+
|
|
9
|
+
const PLATFORM_PATTERNS = [
|
|
10
|
+
{ name: "youtube", test: (url) => /(?:youtube\.com\/watch|youtu\.be\/|youtube\.com\/shorts|youtube\.com\/playlist)/i.test(url) },
|
|
11
|
+
{ name: "instagram", test: (url) => /instagram\.com\//i.test(url) },
|
|
12
|
+
{ name: "tiktok", test: (url) => /tiktok\.com\//i.test(url) },
|
|
13
|
+
{ name: "pinterest", test: (url) => /pinterest\./i.test(url) },
|
|
14
|
+
{ name: "pixiv", test: (url) => /pixiv\.net\//i.test(url) },
|
|
15
|
+
{ name: "twitter", test: (url) => /(?:twitter\.com\/|x\.com\/)/i.test(url) },
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
function detectPlatform(url) {
|
|
19
|
+
for (const p of PLATFORM_PATTERNS) {
|
|
20
|
+
if (p.test(url)) return p.name;
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const scrapers = {
|
|
26
|
+
youtube: (url, options) => youtubeDownloader(url, options?.quality),
|
|
27
|
+
instagram: (url) => instagramDownloader(url),
|
|
28
|
+
tiktok: (url) => tiktokDownloader(url),
|
|
29
|
+
pinterest: (url, options) => pinterestDownloader(url, options),
|
|
30
|
+
pixiv: (url, options) => pixivDownloader(url, options),
|
|
31
|
+
twitter: (url) => twitterDownloader(url),
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
async function aioDownloader(url, options = {}) {
|
|
35
|
+
const platform = options.platform || detectPlatform(url);
|
|
36
|
+
|
|
37
|
+
if (!platform) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
`Unsupported or unrecognized URL: ${url}. Supported platforms: YouTube, Instagram, TikTok, Pinterest, Pixiv, X/Twitter.`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const scraper = scrapers[platform];
|
|
44
|
+
if (!scraper) {
|
|
45
|
+
throw new Error(`No scraper found for platform: ${platform}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return scraper(url, options);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = {
|
|
52
|
+
aioDownloader,
|
|
53
|
+
detectPlatform,
|
|
54
|
+
download,
|
|
55
|
+
youtubeDownloader,
|
|
56
|
+
youtubePlaylistDownloader,
|
|
57
|
+
instagramDownloader,
|
|
58
|
+
tiktokDownloader,
|
|
59
|
+
pinterestDownloader,
|
|
60
|
+
pixivDownloader,
|
|
61
|
+
twitterDownloader,
|
|
62
|
+
};
|