ultra-igdl 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/LICENSE +21 -0
- package/README.md +594 -0
- package/dist/cli/index.cjs +3565 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +2 -0
- package/dist/index.cjs +3303 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +180 -0
- package/dist/index.d.ts +180 -0
- package/dist/index.js +3270 -0
- package/dist/index.js.map +1 -0
- package/package.json +90 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ultra-igdl contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
# ultra-igdl
|
|
2
|
+
|
|
3
|
+
**Production-grade Instagram media extractor for Node.js 20+**
|
|
4
|
+
|
|
5
|
+
Fetch direct CDN URLs for reels, posts, carousels, stories, and highlights. Built from scratch with a multi-layer HTML/JSON parser, optional logged-in session API, connection pooling, LRU cache, and a CLI — **no wrapper around other Instagram downloader packages**.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of contents
|
|
10
|
+
|
|
11
|
+
1. [Who is this for?](#who-is-this-for)
|
|
12
|
+
2. [Requirements](#requirements)
|
|
13
|
+
3. [Installation](#installation)
|
|
14
|
+
4. [Quick start (beginner)](#quick-start-beginner)
|
|
15
|
+
5. [Instagram session (important)](#instagram-session-important)
|
|
16
|
+
6. [CLI guide](#cli-guide)
|
|
17
|
+
7. [Supported URLs](#supported-urls)
|
|
18
|
+
8. [Response format](#response-format)
|
|
19
|
+
9. [Content types explained](#content-types-explained)
|
|
20
|
+
10. [JavaScript / TypeScript API](#javascript--typescript-api)
|
|
21
|
+
11. [Configuration options](#configuration-options)
|
|
22
|
+
12. [Pro features](#pro-features)
|
|
23
|
+
13. [Error codes & troubleshooting](#error-codes--troubleshooting)
|
|
24
|
+
14. [Examples in this repo](#examples-in-this-repo)
|
|
25
|
+
15. [Architecture](#architecture)
|
|
26
|
+
16. [Development](#development)
|
|
27
|
+
17. [Publishing to npm](#publishing-to-npm)
|
|
28
|
+
18. [Legal & disclaimer](#legal--disclaimer)
|
|
29
|
+
19. [License](#license)
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Who is this for?
|
|
34
|
+
|
|
35
|
+
| Level | You can… |
|
|
36
|
+
|--------|-----------|
|
|
37
|
+
| **Beginner** | Install with npm, run `npx ultra-igdl <url> --json`, paste a browser cookie for full carousels |
|
|
38
|
+
| **Intermediate** | Use `ultraigdl` in Express/Fastify bots, batch URLs, download files with `--download` |
|
|
39
|
+
| **Pro** | Tune cache/Redis, `fastMode` + `prefetch`, `maxConcurrency`, integrate `DownloaderCore` |
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Requirements
|
|
44
|
+
|
|
45
|
+
- **Node.js** 20.18.1+ or 22 (LTS recommended)
|
|
46
|
+
- **npm** 9+ (or pnpm/yarn)
|
|
47
|
+
- Public Instagram URLs (no login required for basic post/reel preview)
|
|
48
|
+
- **Optional:** Instagram `sessionid` cookie for carousels (all slides), reel MP4, stories, highlights
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm install ultra-igdl
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
CLI only (no install into project):
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npx ultra-igdl --help
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Quick start (beginner)
|
|
67
|
+
|
|
68
|
+
### 1. Programmatic (ESM)
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
import { ultraigdl } from "ultra-igdl";
|
|
72
|
+
|
|
73
|
+
const ig = new ultraigdl();
|
|
74
|
+
const result = await ig.download("https://www.instagram.com/reel/SHORTCODE/");
|
|
75
|
+
|
|
76
|
+
if (result.code === 200) {
|
|
77
|
+
console.log("User:", result.username);
|
|
78
|
+
console.log("Caption:", result.caption);
|
|
79
|
+
console.log("Files:", result.media.length);
|
|
80
|
+
result.media.forEach((m, i) => console.log(i + 1, m.type, m.url));
|
|
81
|
+
} else {
|
|
82
|
+
console.error(result.code, result.message);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 2. CommonJS
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
const { ultraigdl } = require("ultra-igdl");
|
|
90
|
+
|
|
91
|
+
(async () => {
|
|
92
|
+
const ig = new ultraigdl();
|
|
93
|
+
const result = await ig.download("https://www.instagram.com/p/SHORTCODE/");
|
|
94
|
+
console.log(result);
|
|
95
|
+
})();
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 3. CLI (JSON)
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npx ultra-igdl "https://www.instagram.com/p/SHORTCODE/" --json
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
On **Windows PowerShell**, always wrap URLs in **double quotes** (see [CLI guide](#cli-guide)).
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Instagram session (important)
|
|
109
|
+
|
|
110
|
+
Instagram limits what **logged-out** visitors see:
|
|
111
|
+
|
|
112
|
+
| Feature | Without session | With session (`sessionId` / `cookies`) |
|
|
113
|
+
|---------|-----------------|----------------------------------------|
|
|
114
|
+
| Single post image | Usually yes | Yes (full resolution) |
|
|
115
|
+
| **Carousel (2+ photos)** | Often **1 slide only** | **All slides** |
|
|
116
|
+
| **Reel MP4** | Often thumbnail only | **Video URL** |
|
|
117
|
+
| **Story** | Usually fails / preview | **Media URL** |
|
|
118
|
+
| **Highlight** | Limited | **Video** when available |
|
|
119
|
+
|
|
120
|
+
### How to get cookies (browser)
|
|
121
|
+
|
|
122
|
+
1. Log in to [instagram.com](https://www.instagram.com) in Chrome/Edge/Firefox.
|
|
123
|
+
2. Open DevTools → **Application** → **Cookies** → `https://www.instagram.com`.
|
|
124
|
+
3. Copy:
|
|
125
|
+
- `sessionid`
|
|
126
|
+
- `csrftoken`
|
|
127
|
+
- `ds_user_id`
|
|
128
|
+
|
|
129
|
+
### Option A — full cookie string (recommended)
|
|
130
|
+
|
|
131
|
+
```js
|
|
132
|
+
const ig = new ultraigdl({
|
|
133
|
+
cookies:
|
|
134
|
+
"sessionid=YOUR_ID; csrftoken=YOUR_CSRF; ds_user_id=YOUR_USER_ID",
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Option B — session id only
|
|
139
|
+
|
|
140
|
+
```js
|
|
141
|
+
const ig = new ultraigdl({
|
|
142
|
+
sessionId: "YOUR_SESSIONID_VALUE",
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Environment variables (CLI)
|
|
147
|
+
|
|
148
|
+
The CLI auto-loads `.env` from the current directory or `../ultra-igdl-live-test/.env`.
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# Linux / macOS
|
|
152
|
+
export INSTAGRAM_COOKIES="sessionid=...; csrftoken=...; ds_user_id=..."
|
|
153
|
+
npx ultra-igdl "https://www.instagram.com/p/SHORTCODE/" --json
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
```powershell
|
|
157
|
+
# Windows PowerShell — use TWO lines, or semicolon before npx
|
|
158
|
+
$env:INSTAGRAM_COOKIES = "sessionid=...; csrftoken=...; ds_user_id=..."
|
|
159
|
+
npx ultra-igdl "https://www.instagram.com/p/SHORTCODE/" --json
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Never commit real cookies to git.** Add `.env` to `.gitignore` (already included).
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## CLI guide
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
npx ultra-igdl <url> [options]
|
|
170
|
+
npx ultra-igdl urls.txt # one URL per line
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
| Flag | Short | Description |
|
|
174
|
+
|------|-------|-------------|
|
|
175
|
+
| `--json` | `-j` | Print full API response as JSON |
|
|
176
|
+
| `--download` | `-d` | Save media files under `--output` |
|
|
177
|
+
| `--output <dir>` | `-o` | Download folder (default: `./downloads`) |
|
|
178
|
+
| `--verbose` | `-v` | Debug logging |
|
|
179
|
+
| `--help` | `-h` | Show help |
|
|
180
|
+
|
|
181
|
+
### PowerShell rules
|
|
182
|
+
|
|
183
|
+
1. Wrap URLs in `"quotes"` when the link contains `&` (e.g. `?igsh=...&...`).
|
|
184
|
+
2. Set env vars on **line 1**, run `npx` on **line 2**, **or** use `;` between them:
|
|
185
|
+
|
|
186
|
+
```powershell
|
|
187
|
+
$env:INSTAGRAM_COOKIES = "sessionid=...; csrftoken=...; ds_user_id=..."; npx ultra-igdl "https://www.instagram.com/p/ABC/" --json
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### CLI examples
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# Human-readable summary
|
|
194
|
+
npx ultra-igdl "https://www.instagram.com/reel/ABC123/"
|
|
195
|
+
|
|
196
|
+
# JSON for scripts
|
|
197
|
+
npx ultra-igdl "https://www.instagram.com/p/ABC123/" --json
|
|
198
|
+
|
|
199
|
+
# Download all carousel images
|
|
200
|
+
npx ultra-igdl "https://www.instagram.com/p/ABC123/" --download -o ./downloads
|
|
201
|
+
|
|
202
|
+
# Batch file (urls.txt)
|
|
203
|
+
npx ultra-igdl urls.txt --json
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Supported URLs
|
|
209
|
+
|
|
210
|
+
| Type | Example pattern |
|
|
211
|
+
|------|-----------------|
|
|
212
|
+
| Post | `https://www.instagram.com/p/{shortcode}/` |
|
|
213
|
+
| Reel | `https://www.instagram.com/reel/{shortcode}/` |
|
|
214
|
+
| IGTV | `https://www.instagram.com/tv/{shortcode}/` |
|
|
215
|
+
| Story | `https://www.instagram.com/stories/{username}/{storyId}/` |
|
|
216
|
+
| Highlight (path) | `https://www.instagram.com/stories/highlights/{id}/` |
|
|
217
|
+
| Highlight (share) | `https://www.instagram.com/s/{token}?story_media_id=...` |
|
|
218
|
+
|
|
219
|
+
Validate before download:
|
|
220
|
+
|
|
221
|
+
```js
|
|
222
|
+
const { valid, type, normalized } = await ig.validate(url);
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Response format
|
|
228
|
+
|
|
229
|
+
### Success (`code: 200`)
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{
|
|
233
|
+
"code": 200,
|
|
234
|
+
"meta": { "extractor": "ultra-igdl", "version": "1.0.0" },
|
|
235
|
+
"media": [
|
|
236
|
+
{
|
|
237
|
+
"type": "image",
|
|
238
|
+
"url": "https://...cdninstagram.../....jpg",
|
|
239
|
+
"width": 1440,
|
|
240
|
+
"height": 1800
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"type": "video",
|
|
244
|
+
"url": "https://...mp4",
|
|
245
|
+
"thumbnail": "https://...jpg",
|
|
246
|
+
"width": 1080,
|
|
247
|
+
"height": 1920,
|
|
248
|
+
"duration": 24
|
|
249
|
+
}
|
|
250
|
+
],
|
|
251
|
+
"caption": "Post caption as a single clean line for posts",
|
|
252
|
+
"username": "creator",
|
|
253
|
+
"engagement": {
|
|
254
|
+
"likes": 1200,
|
|
255
|
+
"comments": 45
|
|
256
|
+
},
|
|
257
|
+
"tags": ["carousel"]
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Media object
|
|
262
|
+
|
|
263
|
+
| Field | Type | Description |
|
|
264
|
+
|-------|------|-------------|
|
|
265
|
+
| `type` | `"image"` \| `"video"` | Primary media type |
|
|
266
|
+
| `url` | `string` | Direct CDN URL (signed; do not edit query params) |
|
|
267
|
+
| `thumbnail` | `string?` | Poster frame for video |
|
|
268
|
+
| `width` / `height` | `number?` | Pixel dimensions when known |
|
|
269
|
+
| `duration` | `number?` | Video length in seconds |
|
|
270
|
+
|
|
271
|
+
### Tags (`tags` array)
|
|
272
|
+
|
|
273
|
+
| Tag | Meaning |
|
|
274
|
+
|-----|---------|
|
|
275
|
+
| `carousel` | Multi-slide post; `media.length` ≥ 2 |
|
|
276
|
+
| `partial_carousel` | Carousel detected but only one slide returned |
|
|
277
|
+
| `session_recommended` | Add `sessionId` / `cookies` for full carousel |
|
|
278
|
+
| `likes_hidden` | Creator hid like counts |
|
|
279
|
+
| `comments_hidden` | Comments disabled or hidden |
|
|
280
|
+
| `engagement_hidden` | Both likes and comments hidden |
|
|
281
|
+
|
|
282
|
+
### Error (`code` ≠ 200)
|
|
283
|
+
|
|
284
|
+
```json
|
|
285
|
+
{
|
|
286
|
+
"code": 404,
|
|
287
|
+
"message": "Media not found",
|
|
288
|
+
"meta": { "extractor": "ultra-igdl", "version": "1.0.0" }
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Some responses include `retryAfterMs` when using `fastMode` / `responseBudgetMs` (background fetch still running).
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Content types explained
|
|
297
|
+
|
|
298
|
+
### Posts (single image)
|
|
299
|
+
|
|
300
|
+
```js
|
|
301
|
+
const result = await ig.download("https://www.instagram.com/p/SHORTCODE/");
|
|
302
|
+
// result.media.length === 1 typically
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Carousels (2+ photos)
|
|
306
|
+
|
|
307
|
+
- **Auto-detected** from any `/p/` URL — no special URL or env var.
|
|
308
|
+
- Without session: often 1 image + tags `partial_carousel`, `session_recommended`.
|
|
309
|
+
- With session: all slides, tag `carousel`.
|
|
310
|
+
|
|
311
|
+
```js
|
|
312
|
+
const ig = new ultraigdl({ cookies: process.env.INSTAGRAM_COOKIES });
|
|
313
|
+
const result = await ig.download("https://www.instagram.com/p/SHORTCODE/");
|
|
314
|
+
console.log(result.media.length); // e.g. 4
|
|
315
|
+
console.log(result.tags); // ["carousel"]
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Reels
|
|
319
|
+
|
|
320
|
+
```js
|
|
321
|
+
const ig = new ultraigdl({ sessionId: process.env.INSTAGRAM_SESSION_ID });
|
|
322
|
+
const result = await ig.download("https://www.instagram.com/reel/SHORTCODE/");
|
|
323
|
+
const video = result.media.find((m) => m.type === "video");
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Stories
|
|
327
|
+
|
|
328
|
+
Requires session. Story must still be live (not expired).
|
|
329
|
+
|
|
330
|
+
```js
|
|
331
|
+
const result = await ig.download(
|
|
332
|
+
"https://www.instagram.com/stories/username/1234567890/"
|
|
333
|
+
);
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Highlights
|
|
337
|
+
|
|
338
|
+
Works with highlight URLs or `/s/` share links; session improves reliability.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## JavaScript / TypeScript API
|
|
343
|
+
|
|
344
|
+
```ts
|
|
345
|
+
import { ultraigdl, type ApiResponse, type DownloadResponse } from "ultra-igdl";
|
|
346
|
+
|
|
347
|
+
const ig = new ultraigdl({ cache: true, retries: 2 });
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
| Method | Returns | Description |
|
|
351
|
+
|--------|---------|-------------|
|
|
352
|
+
| `download(url)` | `Promise<ApiResponse>` | Full extraction (main method) |
|
|
353
|
+
| `info(url)` | `Promise<ApiResponse>` | Alias of `download` |
|
|
354
|
+
| `validate(url)` | `Promise<{ valid, type?, normalized? }>` | URL check + normalization |
|
|
355
|
+
| `media(url)` | `Promise<Media[] \| ErrorResponse>` | Media array only |
|
|
356
|
+
| `batch(urls)` | `Promise<BatchResult[]>` | Parallel downloads with per-URL timing |
|
|
357
|
+
| `prefetch(url)` | `Promise<ApiResponse>` | Warm cache for `fastMode` |
|
|
358
|
+
| `health()` | `Promise<HealthStatus>` | Cache stats, pool, version |
|
|
359
|
+
| `clearCache()` | `void` | Clear in-memory LRU cache |
|
|
360
|
+
|
|
361
|
+
### TypeScript
|
|
362
|
+
|
|
363
|
+
Types are shipped in `dist/index.d.ts`. Narrow success responses:
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
const result = await ig.download(url);
|
|
367
|
+
if (result.code === 200) {
|
|
368
|
+
const data = result as DownloadResponse;
|
|
369
|
+
data.media.forEach((m) => { /* ... */ });
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Helpers (also exported)
|
|
374
|
+
|
|
375
|
+
```ts
|
|
376
|
+
import { validateUrl, parseInstagramUrl, isInstagramUrl } from "ultra-igdl";
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## Configuration options
|
|
382
|
+
|
|
383
|
+
```ts
|
|
384
|
+
const ig = new ultraigdl({
|
|
385
|
+
// Cache
|
|
386
|
+
cache: true, // default: true
|
|
387
|
+
cacheTtlMs: 300_000, // 5 min fresh TTL
|
|
388
|
+
staleCacheTtlMs: 86_400_000, // 24h stale-while-revalidate
|
|
389
|
+
cacheMaxSize: 500,
|
|
390
|
+
|
|
391
|
+
// Network
|
|
392
|
+
maxConcurrency: 100,
|
|
393
|
+
timeoutMs: 15_000,
|
|
394
|
+
retries: 3,
|
|
395
|
+
userAgentRotation: true,
|
|
396
|
+
|
|
397
|
+
// Session
|
|
398
|
+
sessionId: "...",
|
|
399
|
+
cookies: "sessionid=...; csrftoken=...; ds_user_id=...",
|
|
400
|
+
|
|
401
|
+
// Low-latency mode (bots that reply in <500ms)
|
|
402
|
+
fastMode: true, // sets responseBudgetMs: 500, retries: 0
|
|
403
|
+
responseBudgetMs: 800,
|
|
404
|
+
|
|
405
|
+
// Optional Redis (implement RedisAdapter interface)
|
|
406
|
+
redis: myRedisAdapter,
|
|
407
|
+
|
|
408
|
+
verbose: false,
|
|
409
|
+
});
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## Pro features
|
|
415
|
+
|
|
416
|
+
### Batch processing
|
|
417
|
+
|
|
418
|
+
```ts
|
|
419
|
+
const results = await ig.batch([
|
|
420
|
+
"https://www.instagram.com/p/A/",
|
|
421
|
+
"https://www.instagram.com/reel/B/",
|
|
422
|
+
]);
|
|
423
|
+
for (const { url, result, durationMs } of results) {
|
|
424
|
+
console.log(url, result.code, `${durationMs}ms`);
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### Fast mode + prefetch (Telegram/Discord bots)
|
|
429
|
+
|
|
430
|
+
```ts
|
|
431
|
+
const ig = new ultraigdl({ fastMode: true, cookies: "..." });
|
|
432
|
+
|
|
433
|
+
// Warm extraction while user types
|
|
434
|
+
await ig.prefetch(url);
|
|
435
|
+
|
|
436
|
+
// Often returns from cache within budget
|
|
437
|
+
let result = await ig.download(url);
|
|
438
|
+
if (result.code === 503 && result.retryAfterMs) {
|
|
439
|
+
await new Promise((r) => setTimeout(r, result.retryAfterMs));
|
|
440
|
+
result = await ig.download(url);
|
|
441
|
+
}
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### Redis cache adapter
|
|
445
|
+
|
|
446
|
+
```ts
|
|
447
|
+
import { ultraigdl, type RedisAdapter } from "ultra-igdl";
|
|
448
|
+
|
|
449
|
+
const redis: RedisAdapter = {
|
|
450
|
+
async get(key) { /* return string | null */ },
|
|
451
|
+
async set(key, value, ttlMs) { /* ... */ },
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
const ig = new ultraigdl({ redis });
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### Download files to disk (library)
|
|
458
|
+
|
|
459
|
+
Use your own `fetch` on `media[].url`, or the CLI `--download` flag (uses built-in file downloader).
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
## Error codes & troubleshooting
|
|
464
|
+
|
|
465
|
+
| Code | Typical cause | What to do |
|
|
466
|
+
|------|---------------|------------|
|
|
467
|
+
| **400** | Invalid URL | Use `validate()`; check link format |
|
|
468
|
+
| **403** | Private account | Cannot extract without access |
|
|
469
|
+
| **404** | Deleted / wrong id / expired story | Verify URL in browser |
|
|
470
|
+
| **429** | Rate limited | Slow down; reduce concurrency; wait |
|
|
471
|
+
| **500** | Parse/network failure | Retry; update package; report issue |
|
|
472
|
+
| **503** | `fastMode` budget exceeded | Retry after `retryAfterMs` or disable fast mode |
|
|
473
|
+
| **504** | Timeout | Increase `timeoutMs` |
|
|
474
|
+
|
|
475
|
+
| Symptom | Fix |
|
|
476
|
+
|---------|-----|
|
|
477
|
+
| Carousel returns 1 image | Set `cookies` or `sessionId` |
|
|
478
|
+
| Reel has no MP4 | Add session cookie |
|
|
479
|
+
| CLI `Unexpected token 'npx'` | Use `;` or two lines in PowerShell |
|
|
480
|
+
| `Invalid or unexpected token` on CLI | Run `npm run build`; use published version |
|
|
481
|
+
| Caption has weird dots/lines | Post captions are flattened to one line by design |
|
|
482
|
+
| 403 on CDN URL when downloading | Do not modify signed URL query string |
|
|
483
|
+
|
|
484
|
+
---
|
|
485
|
+
|
|
486
|
+
## Examples in this repo
|
|
487
|
+
|
|
488
|
+
| File | Description |
|
|
489
|
+
|------|-------------|
|
|
490
|
+
| [`examples/basic.mjs`](./examples/basic.mjs) | Minimal JSON dump |
|
|
491
|
+
| [`examples/bot-example.ts`](./examples/bot-example.ts) | Generic bot handler |
|
|
492
|
+
| [`examples/express-api.ts`](./examples/express-api.ts) | REST API with Express |
|
|
493
|
+
| [`examples/fastify-api.ts`](./examples/fastify-api.ts) | REST API with Fastify |
|
|
494
|
+
| [`examples/telegram-bot.ts`](./examples/telegram-bot.ts) | Telegram-style handler |
|
|
495
|
+
| [`examples/discord-bot.ts`](./examples/discord-bot.ts) | Discord-style handler |
|
|
496
|
+
| [`examples/cookie-generator.mjs`](./examples/cookie-generator.mjs) | Cookie helper notes |
|
|
497
|
+
|
|
498
|
+
Run locally after build:
|
|
499
|
+
|
|
500
|
+
```bash
|
|
501
|
+
npm run build
|
|
502
|
+
node examples/basic.mjs "https://www.instagram.com/p/SHORTCODE/"
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
**Live Instagram tests** are kept in a separate repo folder: `ultra-igdl-live-test` (not published to npm).
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## Architecture
|
|
510
|
+
|
|
511
|
+
```
|
|
512
|
+
src/
|
|
513
|
+
├── core/ # downloader orchestration, cache, parser, extractor
|
|
514
|
+
├── extractors/ # post, reel, story, highlight
|
|
515
|
+
├── network/ # undici client, headers, retry, pool, Instagram API
|
|
516
|
+
├── utils/ # captions, carousel, media quality, URLs
|
|
517
|
+
├── cli/ # CLI entry (published as ultra-igdl bin)
|
|
518
|
+
└── types/ # TypeScript definitions
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
**Extraction layers** (first useful result wins, posts scan multiple layers for carousels):
|
|
522
|
+
|
|
523
|
+
1. Open Graph / meta tags
|
|
524
|
+
2. Embedded `application/json` / script blobs
|
|
525
|
+
3. `window.__additionalDataLoaded` / `_sharedData`
|
|
526
|
+
4. Next.js `__NEXT_DATA__`
|
|
527
|
+
5. GraphQL / CDN discovery in HTML
|
|
528
|
+
6. Regex fallback
|
|
529
|
+
|
|
530
|
+
With **session**: parallel `media/info` API for posts (carousels), reels, stories, highlights.
|
|
531
|
+
|
|
532
|
+
---
|
|
533
|
+
|
|
534
|
+
## Development
|
|
535
|
+
|
|
536
|
+
```bash
|
|
537
|
+
git clone https://github.com/your-username/ultra-igdl.git
|
|
538
|
+
cd ultra-igdl
|
|
539
|
+
npm install
|
|
540
|
+
npm run build
|
|
541
|
+
npm test
|
|
542
|
+
npm run test:coverage
|
|
543
|
+
npm run test:stress
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
| Script | Purpose |
|
|
547
|
+
|--------|---------|
|
|
548
|
+
| `npm run build` | Compile ESM + CJS + CLI to `dist/` |
|
|
549
|
+
| `npm test` | Unit + integration tests (mocked HTTP; excludes stress) |
|
|
550
|
+
| `npm run cli -- "<url>" --json` | Run CLI from source tree |
|
|
551
|
+
| `npm run lint` | Typecheck |
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
## Publishing to npm
|
|
556
|
+
|
|
557
|
+
Maintainers:
|
|
558
|
+
|
|
559
|
+
```bash
|
|
560
|
+
# 1. Login
|
|
561
|
+
npm login
|
|
562
|
+
|
|
563
|
+
# 2. Set author/repository in package.json (your GitHub username)
|
|
564
|
+
|
|
565
|
+
# 3. Dry run — only dist/, README, LICENSE should be listed
|
|
566
|
+
npm pack --dry-run
|
|
567
|
+
|
|
568
|
+
# 4. Publish (runs build + tests via prepublishOnly)
|
|
569
|
+
npm publish
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
Consumers install with:
|
|
573
|
+
|
|
574
|
+
```bash
|
|
575
|
+
npm install ultra-igdl
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
**Before first publish:** change `repository`, `bugs`, and `homepage` in `package.json` from `your-username` to your real GitHub path.
|
|
579
|
+
|
|
580
|
+
---
|
|
581
|
+
|
|
582
|
+
## Legal & disclaimer
|
|
583
|
+
|
|
584
|
+
- This project is **not affiliated with Instagram / Meta**.
|
|
585
|
+
- You are responsible for complying with Instagram's Terms of Use and applicable laws.
|
|
586
|
+
- Only download content you have the right to access and use.
|
|
587
|
+
- Session cookies are credentials — treat them like passwords.
|
|
588
|
+
- CDN URLs are **signed** and expire; download promptly and do not strip query parameters.
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
592
|
+
## License
|
|
593
|
+
|
|
594
|
+
[MIT](./LICENSE) © 2026 ultra-igdl contributors
|