@vicociv/instaloader 0.1.0 → 0.3.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 +401 -0
- package/dist/index.d.mts +72 -4
- package/dist/index.d.ts +72 -4
- package/dist/index.js +240 -103
- package/dist/index.mjs +236 -103
- package/package.json +38 -14
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024
|
|
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,401 @@
|
|
|
1
|
+
# @vicociv/instaloader
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@vicociv/instaloader)
|
|
4
|
+
[](https://www.npmjs.com/package/@vicociv/instaloader)
|
|
5
|
+
[](https://bundlephobia.com/package/@vicociv/instaloader)
|
|
6
|
+
[](https://github.com/star8ks/instaloader.js/actions/workflows/ci.yml)
|
|
7
|
+
[](https://codecov.io/gh/star8ks/instaloader.js)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
[](https://www.typescriptlang.org/)
|
|
10
|
+
[](https://nodejs.org/)
|
|
11
|
+
|
|
12
|
+
TypeScript port of [instaloader](https://github.com/instaloader/instaloader) - Download Instagram content (posts, stories, profiles) with metadata.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @vicociv/instaloader
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Requirements:** Node.js >= 18.0.0
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { Instaloader, Profile, Post, Hashtag } from '@vicociv/instaloader';
|
|
26
|
+
|
|
27
|
+
const L = new Instaloader();
|
|
28
|
+
|
|
29
|
+
// Get a post by shortcode (works without login)
|
|
30
|
+
const post = await L.getPost('DSsaqgbkhAd');
|
|
31
|
+
console.log(post.caption);
|
|
32
|
+
console.log(post.typename); // 'GraphImage' | 'GraphVideo' | 'GraphSidecar'
|
|
33
|
+
|
|
34
|
+
// Get a profile
|
|
35
|
+
const profile = await L.getProfile('instagram');
|
|
36
|
+
console.log(await profile.getFollowers()); // follower count
|
|
37
|
+
|
|
38
|
+
// Iterate posts
|
|
39
|
+
for await (const post of profile.getPosts()) {
|
|
40
|
+
console.log(post.shortcode, post.likes);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Authentication
|
|
45
|
+
|
|
46
|
+
Most operations work without login. However, login is required for:
|
|
47
|
+
- Accessing private profiles
|
|
48
|
+
- Viewing stories and highlights
|
|
49
|
+
- Saved posts
|
|
50
|
+
- Some rate-limited operations
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// Login with credentials
|
|
54
|
+
await L.login('username', 'password');
|
|
55
|
+
|
|
56
|
+
// Handle 2FA if required
|
|
57
|
+
try {
|
|
58
|
+
await L.login('username', 'password');
|
|
59
|
+
} catch (e) {
|
|
60
|
+
if (e instanceof TwoFactorAuthRequiredException) {
|
|
61
|
+
await L.twoFactorLogin('123456');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Save/load session
|
|
66
|
+
await L.saveSessionToFile('session.json');
|
|
67
|
+
await L.loadSessionFromFile('username', 'session.json');
|
|
68
|
+
|
|
69
|
+
// Test if session is valid
|
|
70
|
+
const username = await L.testLogin(); // returns username or null
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## API Reference
|
|
74
|
+
|
|
75
|
+
### Instaloader
|
|
76
|
+
|
|
77
|
+
Main class for downloading Instagram content.
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
const L = new Instaloader(options?: InstaloaderOptions);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Options:**
|
|
84
|
+
| Option | Type | Default | Description |
|
|
85
|
+
|--------|------|---------|-------------|
|
|
86
|
+
| `sleep` | boolean | true | Enable rate limiting delays |
|
|
87
|
+
| `quiet` | boolean | false | Suppress console output |
|
|
88
|
+
| `userAgent` | string | - | Custom user agent |
|
|
89
|
+
| `downloadPictures` | boolean | true | Download images |
|
|
90
|
+
| `downloadVideos` | boolean | true | Download videos |
|
|
91
|
+
| `saveMetadata` | boolean | true | Save JSON metadata |
|
|
92
|
+
|
|
93
|
+
#### Get Content
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// Get profile/post/hashtag
|
|
97
|
+
const profile = await L.getProfile('username');
|
|
98
|
+
const post = await L.getPost('shortcode');
|
|
99
|
+
const hashtag = await L.getHashtag('nature');
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
#### Download Content
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// Download a single post
|
|
106
|
+
await L.downloadPost(post, 'target_folder');
|
|
107
|
+
|
|
108
|
+
// Download profile posts
|
|
109
|
+
await L.downloadProfile(profile, {
|
|
110
|
+
maxCount: 10,
|
|
111
|
+
fastUpdate: true, // stop at already downloaded
|
|
112
|
+
postFilter: (p) => p.likes > 100,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Download hashtag posts
|
|
116
|
+
await L.downloadHashtag(hashtag, { maxCount: 50 });
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Profile
|
|
120
|
+
|
|
121
|
+
Represents an Instagram user profile.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { Profile } from '@vicociv/instaloader';
|
|
125
|
+
|
|
126
|
+
// Create from username
|
|
127
|
+
const profile = await Profile.fromUsername(context, 'instagram');
|
|
128
|
+
|
|
129
|
+
// Properties (sync)
|
|
130
|
+
profile.username // lowercase username
|
|
131
|
+
profile.userid // numeric user ID
|
|
132
|
+
profile.is_private // is private account
|
|
133
|
+
profile.followed_by_viewer
|
|
134
|
+
profile.follows_viewer
|
|
135
|
+
|
|
136
|
+
// Properties (async - may fetch metadata)
|
|
137
|
+
await profile.getFollowers()
|
|
138
|
+
await profile.getFollowees()
|
|
139
|
+
await profile.getMediacount()
|
|
140
|
+
await profile.getBiography()
|
|
141
|
+
await profile.getFullName()
|
|
142
|
+
await profile.getProfilePicUrl()
|
|
143
|
+
await profile.getIsVerified()
|
|
144
|
+
await profile.getExternalUrl()
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
#### Iterate Posts
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// All posts
|
|
151
|
+
for await (const post of profile.getPosts()) {
|
|
152
|
+
console.log(post.shortcode);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Saved posts (requires login as owner)
|
|
156
|
+
for await (const post of profile.getSavedPosts()) {
|
|
157
|
+
console.log(post.shortcode);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Tagged posts
|
|
161
|
+
for await (const post of profile.getTaggedPosts()) {
|
|
162
|
+
console.log(post.shortcode);
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Post
|
|
167
|
+
|
|
168
|
+
Represents an Instagram post.
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { Post } from '@vicociv/instaloader';
|
|
172
|
+
|
|
173
|
+
// Create from shortcode
|
|
174
|
+
const post = await Post.fromShortcode(context, 'ABC123');
|
|
175
|
+
|
|
176
|
+
// Properties
|
|
177
|
+
post.shortcode // URL shortcode
|
|
178
|
+
post.mediaid // BigInt media ID
|
|
179
|
+
post.typename // 'GraphImage' | 'GraphVideo' | 'GraphSidecar'
|
|
180
|
+
post.url // image/thumbnail URL
|
|
181
|
+
post.video_url // video URL (if video)
|
|
182
|
+
post.is_video // boolean
|
|
183
|
+
post.caption // caption text
|
|
184
|
+
post.caption_hashtags // ['tag1', 'tag2']
|
|
185
|
+
post.caption_mentions // ['user1', 'user2']
|
|
186
|
+
post.likes // like count
|
|
187
|
+
post.comments // comment count
|
|
188
|
+
post.date_utc // Date object
|
|
189
|
+
post.tagged_users // tagged usernames
|
|
190
|
+
|
|
191
|
+
// Get owner profile
|
|
192
|
+
const owner = await post.getOwnerProfile();
|
|
193
|
+
|
|
194
|
+
// Sidecar (carousel) posts
|
|
195
|
+
for (const node of post.getSidecarNodes()) {
|
|
196
|
+
console.log(node.is_video, node.display_url, node.video_url);
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Hashtag
|
|
201
|
+
|
|
202
|
+
Represents an Instagram hashtag.
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { Hashtag } from '@vicociv/instaloader';
|
|
206
|
+
|
|
207
|
+
const hashtag = await Hashtag.fromName(context, 'photography');
|
|
208
|
+
|
|
209
|
+
// Properties
|
|
210
|
+
hashtag.name // lowercase name (without #)
|
|
211
|
+
await hashtag.getHashtagId()
|
|
212
|
+
await hashtag.getMediacount()
|
|
213
|
+
await hashtag.getProfilePicUrl()
|
|
214
|
+
|
|
215
|
+
// Get posts (use getPostsResumable for reliable pagination)
|
|
216
|
+
const iterator = hashtag.getPostsResumable();
|
|
217
|
+
for await (const post of iterator) {
|
|
218
|
+
console.log(post.shortcode);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Top posts
|
|
222
|
+
for await (const post of hashtag.getTopPosts()) {
|
|
223
|
+
console.log(post.shortcode);
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Story & StoryItem
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
import { Story, StoryItem } from '@vicociv/instaloader';
|
|
231
|
+
|
|
232
|
+
// Story contains multiple StoryItems
|
|
233
|
+
for await (const item of story.getItems()) {
|
|
234
|
+
console.log(item.mediaid);
|
|
235
|
+
console.log(item.typename); // 'GraphStoryImage' | 'GraphStoryVideo'
|
|
236
|
+
console.log(item.url); // image URL
|
|
237
|
+
console.log(item.video_url); // video URL (if video)
|
|
238
|
+
console.log(item.date_utc);
|
|
239
|
+
console.log(item.expiring_utc);
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Highlight
|
|
244
|
+
|
|
245
|
+
Extends Story for profile highlights.
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import { Highlight } from '@vicociv/instaloader';
|
|
249
|
+
|
|
250
|
+
highlight.title // highlight title
|
|
251
|
+
highlight.cover_url // cover image URL
|
|
252
|
+
|
|
253
|
+
for await (const item of highlight.getItems()) {
|
|
254
|
+
// ...
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### TopSearchResults
|
|
259
|
+
|
|
260
|
+
Search Instagram for profiles, hashtags, and locations.
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
import { TopSearchResults } from '@vicociv/instaloader';
|
|
264
|
+
|
|
265
|
+
const search = new TopSearchResults(context, 'query');
|
|
266
|
+
|
|
267
|
+
for await (const profile of search.getProfiles()) {
|
|
268
|
+
console.log(profile.username);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
for await (const hashtag of search.getHashtags()) {
|
|
272
|
+
console.log(hashtag.name);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
for await (const location of search.getLocations()) {
|
|
276
|
+
console.log(location.name, location.lat, location.lng);
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### NodeIterator
|
|
281
|
+
|
|
282
|
+
Paginated iterator with resume support.
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import { NodeIterator, FrozenNodeIterator } from '@vicociv/instaloader';
|
|
286
|
+
|
|
287
|
+
const iterator = profile.getPosts();
|
|
288
|
+
|
|
289
|
+
// Iterate
|
|
290
|
+
for await (const post of iterator) {
|
|
291
|
+
// Save state for resume
|
|
292
|
+
const state = iterator.freeze();
|
|
293
|
+
fs.writeFileSync('state.json', JSON.stringify(state));
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Resume later
|
|
298
|
+
const savedState = JSON.parse(fs.readFileSync('state.json', 'utf-8'));
|
|
299
|
+
const frozen = new FrozenNodeIterator(savedState);
|
|
300
|
+
const resumed = frozen.thaw(context);
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Helper Functions
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
import {
|
|
307
|
+
shortcodeToMediaid,
|
|
308
|
+
mediaidToShortcode,
|
|
309
|
+
extractHashtags,
|
|
310
|
+
extractMentions,
|
|
311
|
+
parseInstagramUrl,
|
|
312
|
+
extractShortcode,
|
|
313
|
+
extractUsername,
|
|
314
|
+
extractHashtagFromUrl,
|
|
315
|
+
getJsonStructure,
|
|
316
|
+
loadStructure,
|
|
317
|
+
} from '@vicociv/instaloader';
|
|
318
|
+
|
|
319
|
+
// Convert between shortcode and mediaid
|
|
320
|
+
const mediaid = shortcodeToMediaid('ABC123'); // BigInt
|
|
321
|
+
const shortcode = mediaidToShortcode(mediaid); // string
|
|
322
|
+
|
|
323
|
+
// Extract from text
|
|
324
|
+
extractHashtags('Hello #world #test'); // ['world', 'test']
|
|
325
|
+
extractMentions('Hello @user1 @user2'); // ['user1', 'user2']
|
|
326
|
+
|
|
327
|
+
// Parse Instagram URLs
|
|
328
|
+
parseInstagramUrl('https://www.instagram.com/p/DSsaqgbkhAd/')
|
|
329
|
+
// => { type: 'post', shortcode: 'DSsaqgbkhAd' }
|
|
330
|
+
|
|
331
|
+
parseInstagramUrl('https://www.instagram.com/instagram/')
|
|
332
|
+
// => { type: 'profile', username: 'instagram' }
|
|
333
|
+
|
|
334
|
+
parseInstagramUrl('https://www.instagram.com/explore/tags/nature/')
|
|
335
|
+
// => { type: 'hashtag', hashtag: 'nature' }
|
|
336
|
+
|
|
337
|
+
// Extract specific identifiers from URLs
|
|
338
|
+
extractShortcode('https://www.instagram.com/p/DSsaqgbkhAd/?img_index=1')
|
|
339
|
+
// => 'DSsaqgbkhAd'
|
|
340
|
+
|
|
341
|
+
extractUsername('https://www.instagram.com/instagram/')
|
|
342
|
+
// => 'instagram'
|
|
343
|
+
|
|
344
|
+
extractHashtagFromUrl('https://www.instagram.com/explore/tags/nature/')
|
|
345
|
+
// => 'nature'
|
|
346
|
+
|
|
347
|
+
// JSON serialization
|
|
348
|
+
const json = getJsonStructure(post);
|
|
349
|
+
const restored = loadStructure(context, json);
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### InstaloaderContext
|
|
353
|
+
|
|
354
|
+
Low-level API for direct Instagram requests. Usually accessed via `Instaloader.context`.
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
const context = L.context;
|
|
358
|
+
|
|
359
|
+
// Check login status
|
|
360
|
+
context.is_logged_in // boolean
|
|
361
|
+
context.username // string | null
|
|
362
|
+
|
|
363
|
+
// Make GraphQL queries
|
|
364
|
+
const data = await context.graphql_query(queryHash, variables);
|
|
365
|
+
const data = await context.doc_id_graphql_query(docId, variables);
|
|
366
|
+
|
|
367
|
+
// Generic JSON request
|
|
368
|
+
const data = await context.getJson('path', params);
|
|
369
|
+
|
|
370
|
+
// iPhone API
|
|
371
|
+
const data = await context.get_iphone_json('api/v1/...', params);
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Exceptions
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
import {
|
|
378
|
+
InstaloaderException, // Base exception
|
|
379
|
+
LoginException, // Login failed
|
|
380
|
+
LoginRequiredException, // Action requires login
|
|
381
|
+
TwoFactorAuthRequiredException,
|
|
382
|
+
BadCredentialsException, // Wrong password
|
|
383
|
+
ConnectionException, // Network error
|
|
384
|
+
TooManyRequestsException, // Rate limited (429)
|
|
385
|
+
ProfileNotExistsException, // Profile not found
|
|
386
|
+
QueryReturnedNotFoundException,
|
|
387
|
+
QueryReturnedForbiddenException,
|
|
388
|
+
PostChangedException, // Post changed during download
|
|
389
|
+
InvalidArgumentException,
|
|
390
|
+
} from '@vicociv/instaloader';
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## License
|
|
394
|
+
|
|
395
|
+
MIT
|
|
396
|
+
|
|
397
|
+
## Buy Me a Coffee
|
|
398
|
+
|
|
399
|
+
If you find this project helpful, consider supporting its development:
|
|
400
|
+
|
|
401
|
+
[](https://ko-fi.com/nickyoung)
|
package/dist/index.d.mts
CHANGED
|
@@ -474,6 +474,8 @@ interface FrozenIteratorState {
|
|
|
474
474
|
declare function defaultUserAgent(): string;
|
|
475
475
|
/**
|
|
476
476
|
* Returns default iPhone headers for API requests.
|
|
477
|
+
* Note: x-pigeon-session-id and x-ig-connection-speed are randomized per call
|
|
478
|
+
* to make each request appear as a different client (important for bypassing rate limits).
|
|
477
479
|
*/
|
|
478
480
|
declare function defaultIphoneHeaders(): HttpHeaders;
|
|
479
481
|
/**
|
|
@@ -541,7 +543,7 @@ declare class InstaloaderContext {
|
|
|
541
543
|
readonly quiet: boolean;
|
|
542
544
|
readonly iphoneSupport: boolean;
|
|
543
545
|
readonly fatalStatusCodes: number[];
|
|
544
|
-
private
|
|
546
|
+
private _cookieStore;
|
|
545
547
|
private _csrfToken;
|
|
546
548
|
private _username;
|
|
547
549
|
private _userId;
|
|
@@ -608,7 +610,7 @@ declare class InstaloaderContext {
|
|
|
608
610
|
*/
|
|
609
611
|
updateCookies(cookies: CookieData): void;
|
|
610
612
|
/**
|
|
611
|
-
* Build cookie header string from cookie
|
|
613
|
+
* Build cookie header string from cookie store.
|
|
612
614
|
*/
|
|
613
615
|
private _getCookieHeader;
|
|
614
616
|
/**
|
|
@@ -627,17 +629,24 @@ declare class InstaloaderContext {
|
|
|
627
629
|
usePost?: boolean;
|
|
628
630
|
attempt?: number;
|
|
629
631
|
headers?: HttpHeaders;
|
|
632
|
+
/** If true, refresh dynamic headers (timestamp, session ID, speed) on each attempt */
|
|
633
|
+
refreshDynamicHeaders?: boolean;
|
|
630
634
|
}): Promise<JsonObject>;
|
|
631
635
|
/**
|
|
632
636
|
* Do a GraphQL Query.
|
|
633
637
|
*/
|
|
634
638
|
graphql_query(queryHash: string, variables: JsonObject, referer?: string): Promise<JsonObject>;
|
|
635
639
|
/**
|
|
636
|
-
* Do a doc_id-based GraphQL Query
|
|
640
|
+
* Do a doc_id-based GraphQL Query.
|
|
641
|
+
*
|
|
642
|
+
* Uses GET for anonymous requests (works without login) and POST for authenticated
|
|
643
|
+
* requests. This is the correct behavior - Instagram's API accepts GET for public
|
|
644
|
+
* data but requires POST with session for authenticated operations.
|
|
637
645
|
*/
|
|
638
646
|
doc_id_graphql_query(docId: string, variables: JsonObject, referer?: string): Promise<JsonObject>;
|
|
639
647
|
/**
|
|
640
648
|
* JSON request to i.instagram.com.
|
|
649
|
+
* Each request uses fresh dynamic headers to appear as different clients.
|
|
641
650
|
*/
|
|
642
651
|
get_iphone_json(path: string, params: JsonObject): Promise<JsonObject>;
|
|
643
652
|
/**
|
|
@@ -964,6 +973,65 @@ declare function extractHashtags(text: string): string[];
|
|
|
964
973
|
* Extract @mentions from text.
|
|
965
974
|
*/
|
|
966
975
|
declare function extractMentions(text: string): string[];
|
|
976
|
+
/**
|
|
977
|
+
* Result of parsing an Instagram URL
|
|
978
|
+
*/
|
|
979
|
+
interface ParsedInstagramUrl {
|
|
980
|
+
type: 'post' | 'profile' | 'hashtag' | 'unknown';
|
|
981
|
+
shortcode?: string;
|
|
982
|
+
username?: string;
|
|
983
|
+
hashtag?: string;
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
* Parse an Instagram URL to extract the type and identifier.
|
|
987
|
+
*
|
|
988
|
+
* @param url - The Instagram URL to parse
|
|
989
|
+
* @returns Parsed URL information
|
|
990
|
+
*
|
|
991
|
+
* @example
|
|
992
|
+
* parseInstagramUrl('https://www.instagram.com/p/DSsaqgbkhAd/')
|
|
993
|
+
* // => { type: 'post', shortcode: 'DSsaqgbkhAd' }
|
|
994
|
+
*
|
|
995
|
+
* parseInstagramUrl('https://www.instagram.com/instagram/')
|
|
996
|
+
* // => { type: 'profile', username: 'instagram' }
|
|
997
|
+
*
|
|
998
|
+
* parseInstagramUrl('https://www.instagram.com/explore/tags/nature/')
|
|
999
|
+
* // => { type: 'hashtag', hashtag: 'nature' }
|
|
1000
|
+
*/
|
|
1001
|
+
declare function parseInstagramUrl(url: string): ParsedInstagramUrl;
|
|
1002
|
+
/**
|
|
1003
|
+
* Extract shortcode from a post URL.
|
|
1004
|
+
*
|
|
1005
|
+
* @param url - The Instagram post URL
|
|
1006
|
+
* @returns The shortcode, or null if not found
|
|
1007
|
+
*
|
|
1008
|
+
* @example
|
|
1009
|
+
* extractShortcode('https://www.instagram.com/p/DSsaqgbkhAd/?img_index=1')
|
|
1010
|
+
* // => 'DSsaqgbkhAd'
|
|
1011
|
+
*/
|
|
1012
|
+
declare function extractShortcode(url: string): string | null;
|
|
1013
|
+
/**
|
|
1014
|
+
* Extract username from a profile URL.
|
|
1015
|
+
*
|
|
1016
|
+
* @param url - The Instagram profile URL
|
|
1017
|
+
* @returns The username, or null if not found
|
|
1018
|
+
*
|
|
1019
|
+
* @example
|
|
1020
|
+
* extractUsername('https://www.instagram.com/instagram/')
|
|
1021
|
+
* // => 'instagram'
|
|
1022
|
+
*/
|
|
1023
|
+
declare function extractUsername(url: string): string | null;
|
|
1024
|
+
/**
|
|
1025
|
+
* Extract hashtag from a hashtag URL.
|
|
1026
|
+
*
|
|
1027
|
+
* @param url - The Instagram hashtag URL
|
|
1028
|
+
* @returns The hashtag (without #), or null if not found
|
|
1029
|
+
*
|
|
1030
|
+
* @example
|
|
1031
|
+
* extractHashtagFromUrl('https://www.instagram.com/explore/tags/nature/')
|
|
1032
|
+
* // => 'nature'
|
|
1033
|
+
*/
|
|
1034
|
+
declare function extractHashtagFromUrl(url: string): string | null;
|
|
967
1035
|
/**
|
|
968
1036
|
* Represents a comment on a post.
|
|
969
1037
|
*/
|
|
@@ -1661,4 +1729,4 @@ declare class Instaloader {
|
|
|
1661
1729
|
getHashtag(name: string): Promise<Hashtag>;
|
|
1662
1730
|
}
|
|
1663
1731
|
|
|
1664
|
-
export { AbortDownloadException, BadCredentialsException, BadResponseException, CheckpointRequiredException, type CommentNode, ConnectionException, type CookieData, type EdgeConnection, type FrozenIteratorState, FrozenNodeIterator, type GraphQLResponse, Hashtag, type HashtagNode, Highlight, type HighlightNode, type HttpHeaders, type IPhoneHeaders, IPhoneSupportDisabledException, Instaloader, InstaloaderContext, type InstaloaderContextOptions, InstaloaderException, type InstaloaderOptions, InvalidArgumentException, InvalidIteratorException, type JsonExportable, type JsonObject, type JsonValue, type LocationNode, LoginException, LoginRequiredException, type LoginResponse, NodeIterator, type NodeIteratorOptions, type PageInfo, type PhoneVerificationSettings, Post, PostChangedException, PostComment, type PostCommentAnswer, type PostLocation, type PostNode, type PostSidecarNode, PrivateProfileNotFollowedException, Profile, ProfileHasNoPicsException, type ProfileNode, ProfileNotExistsException, QueryReturnedBadRequestException, QueryReturnedForbiddenException, QueryReturnedNotFoundException, type QueryTimestamps, RateController, type RequestOptions, type ResponseInfo, type ResumableIterationOptions, type ResumableIterationResult, type SessionData, SessionNotFoundException, Story, StoryItem, type StoryItemNode, NodeIterator as StructureNodeIterator, TooManyRequestsException, TopSearchResults, TwoFactorAuthRequiredException, type TwoFactorInfo, defaultIphoneHeaders, defaultUserAgent, extractHashtags, extractMentions, formatFilename, formatStringContainsKey, getConfigDir, getDefaultSessionFilename, getDefaultStampsFilename, getJsonStructure, loadStructure, mediaidToShortcode, resumableIteration, sanitizePath, shortcodeToMediaid };
|
|
1732
|
+
export { AbortDownloadException, BadCredentialsException, BadResponseException, CheckpointRequiredException, type CommentNode, ConnectionException, type CookieData, type EdgeConnection, type FrozenIteratorState, FrozenNodeIterator, type GraphQLResponse, Hashtag, type HashtagNode, Highlight, type HighlightNode, type HttpHeaders, type IPhoneHeaders, IPhoneSupportDisabledException, Instaloader, InstaloaderContext, type InstaloaderContextOptions, InstaloaderException, type InstaloaderOptions, InvalidArgumentException, InvalidIteratorException, type JsonExportable, type JsonObject, type JsonValue, type LocationNode, LoginException, LoginRequiredException, type LoginResponse, NodeIterator, type NodeIteratorOptions, type PageInfo, type ParsedInstagramUrl, type PhoneVerificationSettings, Post, PostChangedException, PostComment, type PostCommentAnswer, type PostLocation, type PostNode, type PostSidecarNode, PrivateProfileNotFollowedException, Profile, ProfileHasNoPicsException, type ProfileNode, ProfileNotExistsException, QueryReturnedBadRequestException, QueryReturnedForbiddenException, QueryReturnedNotFoundException, type QueryTimestamps, RateController, type RequestOptions, type ResponseInfo, type ResumableIterationOptions, type ResumableIterationResult, type SessionData, SessionNotFoundException, Story, StoryItem, type StoryItemNode, NodeIterator as StructureNodeIterator, TooManyRequestsException, TopSearchResults, TwoFactorAuthRequiredException, type TwoFactorInfo, defaultIphoneHeaders, defaultUserAgent, extractHashtagFromUrl, extractHashtags, extractMentions, extractShortcode, extractUsername, formatFilename, formatStringContainsKey, getConfigDir, getDefaultSessionFilename, getDefaultStampsFilename, getJsonStructure, loadStructure, mediaidToShortcode, parseInstagramUrl, resumableIteration, sanitizePath, shortcodeToMediaid };
|
package/dist/index.d.ts
CHANGED
|
@@ -474,6 +474,8 @@ interface FrozenIteratorState {
|
|
|
474
474
|
declare function defaultUserAgent(): string;
|
|
475
475
|
/**
|
|
476
476
|
* Returns default iPhone headers for API requests.
|
|
477
|
+
* Note: x-pigeon-session-id and x-ig-connection-speed are randomized per call
|
|
478
|
+
* to make each request appear as a different client (important for bypassing rate limits).
|
|
477
479
|
*/
|
|
478
480
|
declare function defaultIphoneHeaders(): HttpHeaders;
|
|
479
481
|
/**
|
|
@@ -541,7 +543,7 @@ declare class InstaloaderContext {
|
|
|
541
543
|
readonly quiet: boolean;
|
|
542
544
|
readonly iphoneSupport: boolean;
|
|
543
545
|
readonly fatalStatusCodes: number[];
|
|
544
|
-
private
|
|
546
|
+
private _cookieStore;
|
|
545
547
|
private _csrfToken;
|
|
546
548
|
private _username;
|
|
547
549
|
private _userId;
|
|
@@ -608,7 +610,7 @@ declare class InstaloaderContext {
|
|
|
608
610
|
*/
|
|
609
611
|
updateCookies(cookies: CookieData): void;
|
|
610
612
|
/**
|
|
611
|
-
* Build cookie header string from cookie
|
|
613
|
+
* Build cookie header string from cookie store.
|
|
612
614
|
*/
|
|
613
615
|
private _getCookieHeader;
|
|
614
616
|
/**
|
|
@@ -627,17 +629,24 @@ declare class InstaloaderContext {
|
|
|
627
629
|
usePost?: boolean;
|
|
628
630
|
attempt?: number;
|
|
629
631
|
headers?: HttpHeaders;
|
|
632
|
+
/** If true, refresh dynamic headers (timestamp, session ID, speed) on each attempt */
|
|
633
|
+
refreshDynamicHeaders?: boolean;
|
|
630
634
|
}): Promise<JsonObject>;
|
|
631
635
|
/**
|
|
632
636
|
* Do a GraphQL Query.
|
|
633
637
|
*/
|
|
634
638
|
graphql_query(queryHash: string, variables: JsonObject, referer?: string): Promise<JsonObject>;
|
|
635
639
|
/**
|
|
636
|
-
* Do a doc_id-based GraphQL Query
|
|
640
|
+
* Do a doc_id-based GraphQL Query.
|
|
641
|
+
*
|
|
642
|
+
* Uses GET for anonymous requests (works without login) and POST for authenticated
|
|
643
|
+
* requests. This is the correct behavior - Instagram's API accepts GET for public
|
|
644
|
+
* data but requires POST with session for authenticated operations.
|
|
637
645
|
*/
|
|
638
646
|
doc_id_graphql_query(docId: string, variables: JsonObject, referer?: string): Promise<JsonObject>;
|
|
639
647
|
/**
|
|
640
648
|
* JSON request to i.instagram.com.
|
|
649
|
+
* Each request uses fresh dynamic headers to appear as different clients.
|
|
641
650
|
*/
|
|
642
651
|
get_iphone_json(path: string, params: JsonObject): Promise<JsonObject>;
|
|
643
652
|
/**
|
|
@@ -964,6 +973,65 @@ declare function extractHashtags(text: string): string[];
|
|
|
964
973
|
* Extract @mentions from text.
|
|
965
974
|
*/
|
|
966
975
|
declare function extractMentions(text: string): string[];
|
|
976
|
+
/**
|
|
977
|
+
* Result of parsing an Instagram URL
|
|
978
|
+
*/
|
|
979
|
+
interface ParsedInstagramUrl {
|
|
980
|
+
type: 'post' | 'profile' | 'hashtag' | 'unknown';
|
|
981
|
+
shortcode?: string;
|
|
982
|
+
username?: string;
|
|
983
|
+
hashtag?: string;
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
* Parse an Instagram URL to extract the type and identifier.
|
|
987
|
+
*
|
|
988
|
+
* @param url - The Instagram URL to parse
|
|
989
|
+
* @returns Parsed URL information
|
|
990
|
+
*
|
|
991
|
+
* @example
|
|
992
|
+
* parseInstagramUrl('https://www.instagram.com/p/DSsaqgbkhAd/')
|
|
993
|
+
* // => { type: 'post', shortcode: 'DSsaqgbkhAd' }
|
|
994
|
+
*
|
|
995
|
+
* parseInstagramUrl('https://www.instagram.com/instagram/')
|
|
996
|
+
* // => { type: 'profile', username: 'instagram' }
|
|
997
|
+
*
|
|
998
|
+
* parseInstagramUrl('https://www.instagram.com/explore/tags/nature/')
|
|
999
|
+
* // => { type: 'hashtag', hashtag: 'nature' }
|
|
1000
|
+
*/
|
|
1001
|
+
declare function parseInstagramUrl(url: string): ParsedInstagramUrl;
|
|
1002
|
+
/**
|
|
1003
|
+
* Extract shortcode from a post URL.
|
|
1004
|
+
*
|
|
1005
|
+
* @param url - The Instagram post URL
|
|
1006
|
+
* @returns The shortcode, or null if not found
|
|
1007
|
+
*
|
|
1008
|
+
* @example
|
|
1009
|
+
* extractShortcode('https://www.instagram.com/p/DSsaqgbkhAd/?img_index=1')
|
|
1010
|
+
* // => 'DSsaqgbkhAd'
|
|
1011
|
+
*/
|
|
1012
|
+
declare function extractShortcode(url: string): string | null;
|
|
1013
|
+
/**
|
|
1014
|
+
* Extract username from a profile URL.
|
|
1015
|
+
*
|
|
1016
|
+
* @param url - The Instagram profile URL
|
|
1017
|
+
* @returns The username, or null if not found
|
|
1018
|
+
*
|
|
1019
|
+
* @example
|
|
1020
|
+
* extractUsername('https://www.instagram.com/instagram/')
|
|
1021
|
+
* // => 'instagram'
|
|
1022
|
+
*/
|
|
1023
|
+
declare function extractUsername(url: string): string | null;
|
|
1024
|
+
/**
|
|
1025
|
+
* Extract hashtag from a hashtag URL.
|
|
1026
|
+
*
|
|
1027
|
+
* @param url - The Instagram hashtag URL
|
|
1028
|
+
* @returns The hashtag (without #), or null if not found
|
|
1029
|
+
*
|
|
1030
|
+
* @example
|
|
1031
|
+
* extractHashtagFromUrl('https://www.instagram.com/explore/tags/nature/')
|
|
1032
|
+
* // => 'nature'
|
|
1033
|
+
*/
|
|
1034
|
+
declare function extractHashtagFromUrl(url: string): string | null;
|
|
967
1035
|
/**
|
|
968
1036
|
* Represents a comment on a post.
|
|
969
1037
|
*/
|
|
@@ -1661,4 +1729,4 @@ declare class Instaloader {
|
|
|
1661
1729
|
getHashtag(name: string): Promise<Hashtag>;
|
|
1662
1730
|
}
|
|
1663
1731
|
|
|
1664
|
-
export { AbortDownloadException, BadCredentialsException, BadResponseException, CheckpointRequiredException, type CommentNode, ConnectionException, type CookieData, type EdgeConnection, type FrozenIteratorState, FrozenNodeIterator, type GraphQLResponse, Hashtag, type HashtagNode, Highlight, type HighlightNode, type HttpHeaders, type IPhoneHeaders, IPhoneSupportDisabledException, Instaloader, InstaloaderContext, type InstaloaderContextOptions, InstaloaderException, type InstaloaderOptions, InvalidArgumentException, InvalidIteratorException, type JsonExportable, type JsonObject, type JsonValue, type LocationNode, LoginException, LoginRequiredException, type LoginResponse, NodeIterator, type NodeIteratorOptions, type PageInfo, type PhoneVerificationSettings, Post, PostChangedException, PostComment, type PostCommentAnswer, type PostLocation, type PostNode, type PostSidecarNode, PrivateProfileNotFollowedException, Profile, ProfileHasNoPicsException, type ProfileNode, ProfileNotExistsException, QueryReturnedBadRequestException, QueryReturnedForbiddenException, QueryReturnedNotFoundException, type QueryTimestamps, RateController, type RequestOptions, type ResponseInfo, type ResumableIterationOptions, type ResumableIterationResult, type SessionData, SessionNotFoundException, Story, StoryItem, type StoryItemNode, NodeIterator as StructureNodeIterator, TooManyRequestsException, TopSearchResults, TwoFactorAuthRequiredException, type TwoFactorInfo, defaultIphoneHeaders, defaultUserAgent, extractHashtags, extractMentions, formatFilename, formatStringContainsKey, getConfigDir, getDefaultSessionFilename, getDefaultStampsFilename, getJsonStructure, loadStructure, mediaidToShortcode, resumableIteration, sanitizePath, shortcodeToMediaid };
|
|
1732
|
+
export { AbortDownloadException, BadCredentialsException, BadResponseException, CheckpointRequiredException, type CommentNode, ConnectionException, type CookieData, type EdgeConnection, type FrozenIteratorState, FrozenNodeIterator, type GraphQLResponse, Hashtag, type HashtagNode, Highlight, type HighlightNode, type HttpHeaders, type IPhoneHeaders, IPhoneSupportDisabledException, Instaloader, InstaloaderContext, type InstaloaderContextOptions, InstaloaderException, type InstaloaderOptions, InvalidArgumentException, InvalidIteratorException, type JsonExportable, type JsonObject, type JsonValue, type LocationNode, LoginException, LoginRequiredException, type LoginResponse, NodeIterator, type NodeIteratorOptions, type PageInfo, type ParsedInstagramUrl, type PhoneVerificationSettings, Post, PostChangedException, PostComment, type PostCommentAnswer, type PostLocation, type PostNode, type PostSidecarNode, PrivateProfileNotFollowedException, Profile, ProfileHasNoPicsException, type ProfileNode, ProfileNotExistsException, QueryReturnedBadRequestException, QueryReturnedForbiddenException, QueryReturnedNotFoundException, type QueryTimestamps, RateController, type RequestOptions, type ResponseInfo, type ResumableIterationOptions, type ResumableIterationResult, type SessionData, SessionNotFoundException, Story, StoryItem, type StoryItemNode, NodeIterator as StructureNodeIterator, TooManyRequestsException, TopSearchResults, TwoFactorAuthRequiredException, type TwoFactorInfo, defaultIphoneHeaders, defaultUserAgent, extractHashtagFromUrl, extractHashtags, extractMentions, extractShortcode, extractUsername, formatFilename, formatStringContainsKey, getConfigDir, getDefaultSessionFilename, getDefaultStampsFilename, getJsonStructure, loadStructure, mediaidToShortcode, parseInstagramUrl, resumableIteration, sanitizePath, shortcodeToMediaid };
|