@chilfish/gallery-dl-instagram 0.1.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/cli/adapter.ts +284 -0
- package/cli/cookies.ts +59 -0
- package/cli/index.ts +337 -0
- package/config.ts +80 -0
- package/core/extractor.ts +217 -0
- package/core/job.ts +581 -0
- package/dist/adapter-Bt86eL1R.mjs +189 -0
- package/dist/cli/index.d.mts +1 -0
- package/dist/cli/index.mjs +3160 -0
- package/dist/extractors-Byw-2lPL.mjs +1943 -0
- package/dist/index.d.mts +187 -0
- package/dist/index.mjs +40 -0
- package/dist/sdk-B9fRyc1e.d.mts +737 -0
- package/dist/sdk.d.mts +2 -0
- package/dist/sdk.mjs +93 -0
- package/index.ts +159 -0
- package/instagram/api.ts +531 -0
- package/instagram/base.ts +275 -0
- package/instagram/extractors.ts +521 -0
- package/instagram/index.ts +43 -0
- package/instagram/parsers.ts +583 -0
- package/instagram/types.ts +244 -0
- package/message.ts +31 -0
- package/package.json +68 -0
- package/types.ts +115 -0
- package/utils/id-codec.ts +39 -0
- package/utils/text.ts +178 -0
|
@@ -0,0 +1,737 @@
|
|
|
1
|
+
//#region types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Shared type definitions for the gallery-dl TypeScript port.
|
|
4
|
+
*
|
|
5
|
+
* Message types form a discriminated union — the `type` tag determines
|
|
6
|
+
* which handler a Job should invoke.
|
|
7
|
+
*/
|
|
8
|
+
/** HTTP abstraction */
|
|
9
|
+
interface RequestConfig {
|
|
10
|
+
headers?: Record<string, string>;
|
|
11
|
+
params?: Record<string, string | number | null | undefined>;
|
|
12
|
+
method?: string;
|
|
13
|
+
data?: unknown;
|
|
14
|
+
timeout?: number;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
/** WithCredentials / CORS cookie passthrough for browsers */
|
|
17
|
+
withCredentials?: boolean;
|
|
18
|
+
/** For binary downloads — 'arraybuffer' returns raw bytes */
|
|
19
|
+
responseType?: 'arraybuffer' | 'text' | 'json';
|
|
20
|
+
}
|
|
21
|
+
interface HttpResponse<T = unknown> {
|
|
22
|
+
status: number;
|
|
23
|
+
data: T;
|
|
24
|
+
headers: Record<string, string>;
|
|
25
|
+
/** Final URL after redirects */
|
|
26
|
+
url: string;
|
|
27
|
+
request?: RequestConfig;
|
|
28
|
+
}
|
|
29
|
+
interface HttpClient {
|
|
30
|
+
request: <T = unknown>(config: {
|
|
31
|
+
url: string;
|
|
32
|
+
method?: string;
|
|
33
|
+
headers?: Record<string, string>;
|
|
34
|
+
params?: Record<string, string | number | null | undefined>;
|
|
35
|
+
data?: unknown;
|
|
36
|
+
signal?: AbortSignal;
|
|
37
|
+
timeout?: number;
|
|
38
|
+
responseType?: 'arraybuffer' | 'text' | 'json';
|
|
39
|
+
}) => Promise<HttpResponse<T>>;
|
|
40
|
+
}
|
|
41
|
+
/** Storage abstraction */
|
|
42
|
+
interface Storage {
|
|
43
|
+
exists: (path: string) => Promise<boolean>;
|
|
44
|
+
write: (path: string, data: Uint8Array | string) => Promise<void>;
|
|
45
|
+
mkdir: (path: string) => Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
type ConfigValue = string | number | boolean | null | ConfigValue[] | {
|
|
48
|
+
[key: string]: ConfigValue;
|
|
49
|
+
};
|
|
50
|
+
interface Config {
|
|
51
|
+
[key: string]: ConfigValue;
|
|
52
|
+
}
|
|
53
|
+
/** Metadata & messages */
|
|
54
|
+
/**
|
|
55
|
+
* Flat string-keyed metadata dictionary.
|
|
56
|
+
* In gallery-dl every kwdict is a plain `{string → value}` map.
|
|
57
|
+
*/
|
|
58
|
+
type Metadata = Record<string, unknown>;
|
|
59
|
+
interface DirectoryMsg {
|
|
60
|
+
readonly type: 'directory';
|
|
61
|
+
readonly metadata: Metadata;
|
|
62
|
+
}
|
|
63
|
+
interface UrlMsg {
|
|
64
|
+
readonly type: 'url';
|
|
65
|
+
readonly url: string;
|
|
66
|
+
readonly metadata: Metadata;
|
|
67
|
+
}
|
|
68
|
+
interface QueueMsg {
|
|
69
|
+
readonly type: 'queue';
|
|
70
|
+
readonly url: string;
|
|
71
|
+
readonly metadata: Metadata & {
|
|
72
|
+
readonly _extractor?: ExtractorClass;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
type Message = DirectoryMsg | UrlMsg | QueueMsg;
|
|
76
|
+
/**
|
|
77
|
+
* Async generator that yields Message values.
|
|
78
|
+
*/
|
|
79
|
+
type MessageIter = AsyncGenerator<Message, void, unknown>;
|
|
80
|
+
/** Extractor class reference (for Queue dispatch) */
|
|
81
|
+
/**
|
|
82
|
+
* Minimal shape that every Extractor class must expose so the Dispatch
|
|
83
|
+
* logic can re-instantiate from a URL.
|
|
84
|
+
*/
|
|
85
|
+
interface ExtractorClass {
|
|
86
|
+
pattern: RegExp;
|
|
87
|
+
subcategory: string;
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region config.d.ts
|
|
91
|
+
declare class ConfigManager {
|
|
92
|
+
private readonly data;
|
|
93
|
+
constructor(data?: Config);
|
|
94
|
+
/**
|
|
95
|
+
* Read a value at a dot-path like ``'extractor.instagram.videos'``.
|
|
96
|
+
* Returns ``undefined`` when the path doesn't exist.
|
|
97
|
+
*/
|
|
98
|
+
get(path: string, defaultValue?: ConfigValue): ConfigValue | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* Interpolate a config key through a hierarchy of paths.
|
|
101
|
+
*/
|
|
102
|
+
interpolate(cfgPath: readonly string[], key: string, defaultVal?: ConfigValue): ConfigValue | undefined;
|
|
103
|
+
/**
|
|
104
|
+
* Mutate the config at a given dot-path.
|
|
105
|
+
*/
|
|
106
|
+
set(path: string, value: unknown): void;
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region core/extractor.d.ts
|
|
110
|
+
interface ExtractorOptions {
|
|
111
|
+
url: string;
|
|
112
|
+
match: RegExpMatchArray;
|
|
113
|
+
config: ConfigManager;
|
|
114
|
+
http: HttpClient;
|
|
115
|
+
storage: Storage;
|
|
116
|
+
/** The logger interface — at minimum a debug/info/warn/error contract */
|
|
117
|
+
log: Logger;
|
|
118
|
+
}
|
|
119
|
+
interface Logger {
|
|
120
|
+
debug: (message: string, ...args: unknown[]) => void;
|
|
121
|
+
info: (message: string, ...args: unknown[]) => void;
|
|
122
|
+
warn: (message: string, ...args: unknown[]) => void;
|
|
123
|
+
error: (message: string, ...args: unknown[]) => void;
|
|
124
|
+
}
|
|
125
|
+
/** A no-op logger */
|
|
126
|
+
declare const noopLogger: Logger;
|
|
127
|
+
declare abstract class Extractor {
|
|
128
|
+
/** Human-readable category (e.g. ``'instagram'``) */
|
|
129
|
+
abstract readonly category: string;
|
|
130
|
+
/** Sub-category (e.g. ``'post'``, ``'posts'``, ``'reels'``) */
|
|
131
|
+
abstract readonly subcategory: string;
|
|
132
|
+
/** Root URL (e.g. ``'https://www.instagram.com'``) */
|
|
133
|
+
abstract readonly root: string;
|
|
134
|
+
/** Regex pattern to match against URLs */
|
|
135
|
+
static readonly pattern: RegExp;
|
|
136
|
+
/** The input URL */
|
|
137
|
+
readonly url: string;
|
|
138
|
+
/** Regex match groups from ``fromURL`` */
|
|
139
|
+
readonly groups: readonly string[];
|
|
140
|
+
readonly config: ConfigManager;
|
|
141
|
+
/** HTTP client — public so Job can access for downloads */
|
|
142
|
+
readonly http: HttpClient;
|
|
143
|
+
/** Storage backend — public so Job can access for writes */
|
|
144
|
+
readonly storage: Storage;
|
|
145
|
+
/** Logger instance — public so Job can access for reporting */
|
|
146
|
+
readonly log: Logger;
|
|
147
|
+
/** Delay range in seconds — random between [min, max] before each request */
|
|
148
|
+
protected requestInterval: [number, number];
|
|
149
|
+
private _initialized;
|
|
150
|
+
constructor(opts: ExtractorOptions);
|
|
151
|
+
/** Initialization */
|
|
152
|
+
/**
|
|
153
|
+
* One-time async setup (cookies, session, internal state).
|
|
154
|
+
* Safe to call multiple times — after the first call it becomes a no-op.
|
|
155
|
+
*/
|
|
156
|
+
initialize(): Promise<void>;
|
|
157
|
+
/**
|
|
158
|
+
* Subclass hook for one-time setup.
|
|
159
|
+
*/
|
|
160
|
+
protected _init(): Promise<void>;
|
|
161
|
+
/** Async iteration */
|
|
162
|
+
[Symbol.asyncIterator](): MessageIter;
|
|
163
|
+
/**
|
|
164
|
+
* The main extraction pipeline. Subclasses *must* implement this.
|
|
165
|
+
*/
|
|
166
|
+
abstract items(): MessageIter;
|
|
167
|
+
/** Config helpers */
|
|
168
|
+
/**
|
|
169
|
+
* Read a config value using the interpolated hierarchy.
|
|
170
|
+
*/
|
|
171
|
+
protected _cfg(key: string, defaultVal?: ConfigValue): ConfigValue | undefined;
|
|
172
|
+
/** HTTP */
|
|
173
|
+
private _lastRequestTime;
|
|
174
|
+
/**
|
|
175
|
+
* Rate-limited HTTP request wrapper.
|
|
176
|
+
*/
|
|
177
|
+
request(url: string, cfg?: RequestConfig): Promise<HttpResponse<unknown>>;
|
|
178
|
+
/**
|
|
179
|
+
* Convenience: request + parse JSON body.
|
|
180
|
+
*/
|
|
181
|
+
requestJSON(url: string, cfg?: RequestConfig): Promise<unknown>;
|
|
182
|
+
/** Rate limiting */
|
|
183
|
+
/**
|
|
184
|
+
* Sleep long enough to keep the minimum interval between requests.
|
|
185
|
+
*/
|
|
186
|
+
private _throttle;
|
|
187
|
+
/** Utility */
|
|
188
|
+
/**
|
|
189
|
+
* Convert a Unix timestamp (seconds or ms) to an ISO-8601 string.
|
|
190
|
+
*/
|
|
191
|
+
parseTimestamp(ts: number | null | undefined): string;
|
|
192
|
+
/**
|
|
193
|
+
* Generate a random hex token (used for CSRF).
|
|
194
|
+
*/
|
|
195
|
+
static generateToken(size?: number): string;
|
|
196
|
+
}
|
|
197
|
+
//#endregion
|
|
198
|
+
//#region instagram/types.d.ts
|
|
199
|
+
/**
|
|
200
|
+
* Instagram API & parsed-post type definitions.
|
|
201
|
+
*
|
|
202
|
+
* These mirror the actual JSON shapes returned by Instagram's internal API
|
|
203
|
+
* (``/api/v1/…``).
|
|
204
|
+
*/
|
|
205
|
+
/** API response types */
|
|
206
|
+
interface InstagramUser {
|
|
207
|
+
pk: string;
|
|
208
|
+
id?: string;
|
|
209
|
+
username: string;
|
|
210
|
+
full_name: string;
|
|
211
|
+
is_private?: boolean;
|
|
212
|
+
profile_pic_url?: string;
|
|
213
|
+
profile_pic_url_hd?: string;
|
|
214
|
+
hd_profile_pic_url_info?: ImageCandidate;
|
|
215
|
+
hd_profile_pic_versions?: ImageCandidate[];
|
|
216
|
+
profile_pic_id?: string;
|
|
217
|
+
edge_owner_to_timeline_media?: {
|
|
218
|
+
count: number;
|
|
219
|
+
};
|
|
220
|
+
edge_felix_video_timeline?: {
|
|
221
|
+
count: number;
|
|
222
|
+
};
|
|
223
|
+
edge_saved_media?: {
|
|
224
|
+
count: number;
|
|
225
|
+
};
|
|
226
|
+
edge_mutual_followed_by?: {
|
|
227
|
+
count: number;
|
|
228
|
+
};
|
|
229
|
+
edge_follow?: {
|
|
230
|
+
count: number;
|
|
231
|
+
};
|
|
232
|
+
edge_followed_by?: {
|
|
233
|
+
count: number;
|
|
234
|
+
};
|
|
235
|
+
edge_media_collections?: {
|
|
236
|
+
count: number;
|
|
237
|
+
};
|
|
238
|
+
followed_by_viewer?: boolean;
|
|
239
|
+
}
|
|
240
|
+
interface ImageCandidate {
|
|
241
|
+
url: string;
|
|
242
|
+
width: number;
|
|
243
|
+
height: number;
|
|
244
|
+
}
|
|
245
|
+
interface VideoVersion {
|
|
246
|
+
url: string;
|
|
247
|
+
width: number;
|
|
248
|
+
height: number;
|
|
249
|
+
type: number;
|
|
250
|
+
}
|
|
251
|
+
interface InstagramLocation {
|
|
252
|
+
pk: string;
|
|
253
|
+
short_name: string;
|
|
254
|
+
}
|
|
255
|
+
interface Caption {
|
|
256
|
+
text: string;
|
|
257
|
+
}
|
|
258
|
+
interface UserTag {
|
|
259
|
+
user: InstagramUser;
|
|
260
|
+
}
|
|
261
|
+
interface ReelMention {
|
|
262
|
+
user: InstagramUser;
|
|
263
|
+
}
|
|
264
|
+
interface BloksSticker {
|
|
265
|
+
bloks_sticker: {
|
|
266
|
+
bloks_sticker_type: string;
|
|
267
|
+
sticker_data: {
|
|
268
|
+
ig_mention: {
|
|
269
|
+
account_id: string;
|
|
270
|
+
username: string;
|
|
271
|
+
full_name: string;
|
|
272
|
+
};
|
|
273
|
+
};
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
interface MusicSticker {
|
|
277
|
+
music_asset_info?: MusicAssetInfo;
|
|
278
|
+
music_consumption_info?: MusicConsumptionInfo;
|
|
279
|
+
}
|
|
280
|
+
interface MusicAssetInfo {
|
|
281
|
+
id: string;
|
|
282
|
+
title?: string;
|
|
283
|
+
display_artist?: string;
|
|
284
|
+
ig_artist?: string;
|
|
285
|
+
duration_in_ms?: number;
|
|
286
|
+
highlight_start_times_in_ms?: number[];
|
|
287
|
+
progressive_download_url: string;
|
|
288
|
+
cover_artwork_uri?: string;
|
|
289
|
+
}
|
|
290
|
+
interface MusicConsumptionInfo {
|
|
291
|
+
display_artist?: string;
|
|
292
|
+
ig_artist?: string;
|
|
293
|
+
}
|
|
294
|
+
interface MusicMetadata {
|
|
295
|
+
music_info?: MusicAssetInfo;
|
|
296
|
+
}
|
|
297
|
+
interface InstagramPost {
|
|
298
|
+
pk: string;
|
|
299
|
+
id?: string;
|
|
300
|
+
code: string;
|
|
301
|
+
caption: Caption | null;
|
|
302
|
+
taken_at: number;
|
|
303
|
+
created_at?: number;
|
|
304
|
+
like_count?: number;
|
|
305
|
+
has_liked?: boolean;
|
|
306
|
+
user: InstagramUser;
|
|
307
|
+
carousel_media?: InstagramCarouselItem[];
|
|
308
|
+
image_versions2: {
|
|
309
|
+
candidates: ImageCandidate[];
|
|
310
|
+
};
|
|
311
|
+
video_versions?: VideoVersion[];
|
|
312
|
+
video_dash_manifest?: string;
|
|
313
|
+
original_width?: number;
|
|
314
|
+
original_height?: number;
|
|
315
|
+
media_type?: number;
|
|
316
|
+
original_media_type?: number;
|
|
317
|
+
location?: InstagramLocation;
|
|
318
|
+
coauthor_producers?: InstagramUser[];
|
|
319
|
+
usertags?: {
|
|
320
|
+
in: UserTag[];
|
|
321
|
+
};
|
|
322
|
+
reel_mentions?: ReelMention[];
|
|
323
|
+
story_bloks_stickers?: BloksSticker[];
|
|
324
|
+
story_music_stickers?: MusicSticker[];
|
|
325
|
+
music_metadata?: MusicMetadata;
|
|
326
|
+
expiring_at?: number;
|
|
327
|
+
seen?: number;
|
|
328
|
+
items?: InstagramCarouselItem[];
|
|
329
|
+
timeline_pinned_user_ids?: string[];
|
|
330
|
+
clips_tab_pinned_user_ids?: string[];
|
|
331
|
+
subscription_media_visibility?: string;
|
|
332
|
+
audience?: string;
|
|
333
|
+
title?: string;
|
|
334
|
+
pins?: unknown[];
|
|
335
|
+
}
|
|
336
|
+
interface InstagramCarouselItem {
|
|
337
|
+
pk: string;
|
|
338
|
+
id?: string;
|
|
339
|
+
code?: string;
|
|
340
|
+
taken_at?: number;
|
|
341
|
+
image_versions2: {
|
|
342
|
+
candidates: ImageCandidate[];
|
|
343
|
+
};
|
|
344
|
+
video_versions?: VideoVersion[];
|
|
345
|
+
video_dash_manifest?: string;
|
|
346
|
+
original_width?: number;
|
|
347
|
+
original_height?: number;
|
|
348
|
+
media_type?: number;
|
|
349
|
+
original_media_type?: number;
|
|
350
|
+
owner?: InstagramUser;
|
|
351
|
+
reshared_story_media_author?: InstagramUser;
|
|
352
|
+
expiring_at?: number;
|
|
353
|
+
subscription_media_visibility?: string;
|
|
354
|
+
audience?: string;
|
|
355
|
+
story_music_stickers?: MusicSticker[];
|
|
356
|
+
usertags?: {
|
|
357
|
+
in: UserTag[];
|
|
358
|
+
};
|
|
359
|
+
reel_mentions?: ReelMention[];
|
|
360
|
+
story_bloks_stickers?: BloksSticker[];
|
|
361
|
+
}
|
|
362
|
+
/** Parsed post (normalized output) */
|
|
363
|
+
interface ParsedPost {
|
|
364
|
+
post_id: string;
|
|
365
|
+
post_shortcode: string;
|
|
366
|
+
post_url: string;
|
|
367
|
+
owner_id: string;
|
|
368
|
+
username: string;
|
|
369
|
+
fullname: string;
|
|
370
|
+
post_date: string;
|
|
371
|
+
date: string;
|
|
372
|
+
description: string;
|
|
373
|
+
tags?: string[];
|
|
374
|
+
location_id?: string;
|
|
375
|
+
location_slug?: string;
|
|
376
|
+
location_url?: string;
|
|
377
|
+
likes: number;
|
|
378
|
+
liked: boolean;
|
|
379
|
+
pinned: string[];
|
|
380
|
+
coauthors?: Coauthor[];
|
|
381
|
+
sidecar_media_id?: string;
|
|
382
|
+
sidecar_shortcode?: string;
|
|
383
|
+
type: 'post' | 'reel' | 'story' | 'highlight';
|
|
384
|
+
count: number;
|
|
385
|
+
_files: ParsedMedia[];
|
|
386
|
+
user?: InstagramUser;
|
|
387
|
+
expires?: string;
|
|
388
|
+
highlight_title?: string;
|
|
389
|
+
tagged_owner_id?: string;
|
|
390
|
+
tagged_username?: string;
|
|
391
|
+
tagged_full_name?: string;
|
|
392
|
+
subscription?: string;
|
|
393
|
+
/** For graphql: */
|
|
394
|
+
typename?: string;
|
|
395
|
+
}
|
|
396
|
+
interface ParsedMedia {
|
|
397
|
+
num: number;
|
|
398
|
+
date: string;
|
|
399
|
+
media_id: string;
|
|
400
|
+
shortcode: string;
|
|
401
|
+
display_url: string;
|
|
402
|
+
video_url: string | null;
|
|
403
|
+
width: number;
|
|
404
|
+
width_original: number;
|
|
405
|
+
height: number;
|
|
406
|
+
height_original: number;
|
|
407
|
+
tagged_users: TaggedUser[];
|
|
408
|
+
owner?: InstagramUser;
|
|
409
|
+
author?: InstagramUser;
|
|
410
|
+
expires?: string;
|
|
411
|
+
subscription?: string;
|
|
412
|
+
audience?: string;
|
|
413
|
+
audio_url?: string;
|
|
414
|
+
audio_user?: string;
|
|
415
|
+
audio_title?: string;
|
|
416
|
+
audio_artist?: string;
|
|
417
|
+
audio_duration?: number;
|
|
418
|
+
audio_timestamps?: number[];
|
|
419
|
+
_ytdl_manifest_data?: string;
|
|
420
|
+
sidecar_media_id?: string;
|
|
421
|
+
sidecar_shortcode?: string;
|
|
422
|
+
}
|
|
423
|
+
interface Coauthor {
|
|
424
|
+
id: string;
|
|
425
|
+
username: string;
|
|
426
|
+
full_name?: string;
|
|
427
|
+
}
|
|
428
|
+
interface TaggedUser {
|
|
429
|
+
id: string;
|
|
430
|
+
username: string;
|
|
431
|
+
full_name: string;
|
|
432
|
+
}
|
|
433
|
+
/** Parser config */
|
|
434
|
+
interface ParserConfig {
|
|
435
|
+
root: string;
|
|
436
|
+
findTags: (text: string) => string[];
|
|
437
|
+
parseTimestamp: (ts: number | null | undefined) => string;
|
|
438
|
+
staticVideo: boolean;
|
|
439
|
+
warnVideo: boolean;
|
|
440
|
+
warnImage: number;
|
|
441
|
+
videosDash: boolean;
|
|
442
|
+
}
|
|
443
|
+
//#endregion
|
|
444
|
+
//#region instagram/api.d.ts
|
|
445
|
+
declare class InstagramRestAPI {
|
|
446
|
+
private readonly http;
|
|
447
|
+
private readonly root;
|
|
448
|
+
private readonly getCsrf;
|
|
449
|
+
private readonly getWwwClaim;
|
|
450
|
+
private readonly setWwwClaim;
|
|
451
|
+
private readonly setCsrf;
|
|
452
|
+
/** A ref to the extractor's cursor. */
|
|
453
|
+
private getCursor;
|
|
454
|
+
private setCursor;
|
|
455
|
+
constructor(opts: {
|
|
456
|
+
http: HttpClient;
|
|
457
|
+
root: string;
|
|
458
|
+
csrfToken: {
|
|
459
|
+
value: string;
|
|
460
|
+
};
|
|
461
|
+
wwwClaim: {
|
|
462
|
+
value: string;
|
|
463
|
+
};
|
|
464
|
+
cursor: {
|
|
465
|
+
value: string | null;
|
|
466
|
+
};
|
|
467
|
+
});
|
|
468
|
+
/** Public endpoint methods */
|
|
469
|
+
/** Single post by shortcode. */
|
|
470
|
+
media(shortcode: string): AsyncGenerator<InstagramPost>;
|
|
471
|
+
/** Paginated user feed. */
|
|
472
|
+
userFeed(userId: string): AsyncGenerator<InstagramPost>;
|
|
473
|
+
/** Paginated user reels (POST endpoint). */
|
|
474
|
+
userClips(userId: string): AsyncGenerator<InstagramPost>;
|
|
475
|
+
/** Paginated tagged posts. */
|
|
476
|
+
userTagged(userId: string): AsyncGenerator<InstagramPost>;
|
|
477
|
+
/** Paginated saved posts (media wrapper). */
|
|
478
|
+
userSaved(): AsyncGenerator<InstagramPost>;
|
|
479
|
+
/** Paginated collection. */
|
|
480
|
+
userCollection(collectionId: string): AsyncGenerator<InstagramPost>;
|
|
481
|
+
/** Reels media — batch call, returns full reel objects. */
|
|
482
|
+
reelsMedia(reelIds: string[]): Promise<InstagramPost[]>;
|
|
483
|
+
/** Story tray. */
|
|
484
|
+
reelsTray(): Promise<InstagramPost[]>;
|
|
485
|
+
/** Highlights list (tray). */
|
|
486
|
+
highlightsTray(userId: string): Promise<{
|
|
487
|
+
id: string;
|
|
488
|
+
}[]>;
|
|
489
|
+
/** All highlights' media batched by ``chunkSize``. */
|
|
490
|
+
highlightsMedia(userId: string, chunkSize?: number): AsyncGenerator<InstagramPost>;
|
|
491
|
+
/** Hashtag posts (via sections). */
|
|
492
|
+
tagsMedia(tag: string): AsyncGenerator<InstagramPost>;
|
|
493
|
+
private tagsSections;
|
|
494
|
+
/** User by numeric ID. */
|
|
495
|
+
userById(userId: string): Promise<InstagramUser>;
|
|
496
|
+
/** User by username (web_profile_info). */
|
|
497
|
+
userByName(username: string): Promise<InstagramUser>;
|
|
498
|
+
/** Search user by username. */
|
|
499
|
+
userBySearch(username: string): Promise<InstagramUser>;
|
|
500
|
+
/** Scrape user ID from HTML profile page. */
|
|
501
|
+
userByWeb(username: string): Promise<{
|
|
502
|
+
id: string;
|
|
503
|
+
}>;
|
|
504
|
+
/** Resolve screen name via fallback chain: search → info → web. */
|
|
505
|
+
userByScreenName(screenName: string): Promise<InstagramUser>;
|
|
506
|
+
/** Resolve username/id to numeric user ID string. */
|
|
507
|
+
userId(screenName: string, checkPrivate?: boolean): Promise<string>;
|
|
508
|
+
/** Followers (paginated). */
|
|
509
|
+
userFollowers(userId: string): AsyncGenerator<InstagramUser>;
|
|
510
|
+
/** Following (paginated). */
|
|
511
|
+
userFollowing(userId: string): AsyncGenerator<InstagramUser>;
|
|
512
|
+
/** Internal — HTTP call */
|
|
513
|
+
private _call;
|
|
514
|
+
/** Pagination engines */
|
|
515
|
+
private _pagination;
|
|
516
|
+
private _paginationPost;
|
|
517
|
+
private _paginationSections;
|
|
518
|
+
private _paginationFollowing;
|
|
519
|
+
private _parseIntCursor;
|
|
520
|
+
}
|
|
521
|
+
//#endregion
|
|
522
|
+
//#region instagram/base.d.ts
|
|
523
|
+
interface InstagramExtractorOptions extends ExtractorOptions {
|
|
524
|
+
sessionId?: string;
|
|
525
|
+
cookies?: Record<string, string>;
|
|
526
|
+
/** Pre-seeded CSRF token (from anonymous session cookie jar). */
|
|
527
|
+
csrfToken?: string;
|
|
528
|
+
}
|
|
529
|
+
declare class Ref<T> {
|
|
530
|
+
value: T;
|
|
531
|
+
constructor(v: T);
|
|
532
|
+
}
|
|
533
|
+
declare abstract class InstagramExtractor extends Extractor {
|
|
534
|
+
readonly category = "instagram";
|
|
535
|
+
readonly root = "https://www.instagram.com";
|
|
536
|
+
api: InstagramRestAPI;
|
|
537
|
+
csrfToken: Ref<string>;
|
|
538
|
+
wwwClaim: Ref<string>;
|
|
539
|
+
cursor: Ref<string | null>;
|
|
540
|
+
protected _loggedIn: boolean;
|
|
541
|
+
protected _user: InstagramUser | null;
|
|
542
|
+
private readonly _findTags;
|
|
543
|
+
private readonly _csrfSeed;
|
|
544
|
+
constructor(opts: InstagramExtractorOptions);
|
|
545
|
+
/** Initialization */
|
|
546
|
+
protected _init(): Promise<void>;
|
|
547
|
+
/** Request override */
|
|
548
|
+
request(url: string, cfg?: RequestConfig): Promise<HttpResponse<unknown>>;
|
|
549
|
+
/** Login */
|
|
550
|
+
login(): Promise<void>;
|
|
551
|
+
/** Core pipeline */
|
|
552
|
+
items(): MessageIter;
|
|
553
|
+
/** Subclass hooks */
|
|
554
|
+
/** @virtual */
|
|
555
|
+
metadata(): Promise<Record<string, unknown>>;
|
|
556
|
+
abstract posts(): AsyncGenerator<InstagramPost>;
|
|
557
|
+
/** Cursor management */
|
|
558
|
+
protected _initCursor(): string | null;
|
|
559
|
+
protected _updateCursor(cursor: string | null): string | null;
|
|
560
|
+
/** User assignment */
|
|
561
|
+
protected _assignUser(user: InstagramUser): void;
|
|
562
|
+
}
|
|
563
|
+
//#endregion
|
|
564
|
+
//#region instagram/extractors.d.ts
|
|
565
|
+
declare class InstagramPostExtractor extends InstagramExtractor {
|
|
566
|
+
static readonly subcategory = "post";
|
|
567
|
+
static pattern: RegExp;
|
|
568
|
+
readonly subcategory = "post";
|
|
569
|
+
constructor(opts: InstagramExtractorOptions);
|
|
570
|
+
static fromURL(url: string, opts: InstagramExtractorOptions): InstagramPostExtractor | null;
|
|
571
|
+
posts(): AsyncGenerator<InstagramPost>;
|
|
572
|
+
}
|
|
573
|
+
declare class InstagramUserExtractor extends InstagramExtractor {
|
|
574
|
+
static readonly subcategory = "user";
|
|
575
|
+
static pattern: RegExp;
|
|
576
|
+
readonly subcategory = "user";
|
|
577
|
+
constructor(opts: InstagramExtractorOptions);
|
|
578
|
+
static fromURL(url: string, opts: InstagramExtractorOptions): InstagramUserExtractor | null;
|
|
579
|
+
items(): MessageIter;
|
|
580
|
+
posts(): AsyncGenerator<InstagramPost>;
|
|
581
|
+
}
|
|
582
|
+
declare class InstagramPostsExtractor extends InstagramExtractor {
|
|
583
|
+
static readonly subcategory = "posts";
|
|
584
|
+
static pattern: RegExp;
|
|
585
|
+
readonly subcategory = "posts";
|
|
586
|
+
constructor(opts: InstagramExtractorOptions);
|
|
587
|
+
static fromURL(url: string, opts: InstagramExtractorOptions): InstagramPostsExtractor | null;
|
|
588
|
+
posts(): AsyncGenerator<InstagramPost>;
|
|
589
|
+
}
|
|
590
|
+
declare class InstagramReelsExtractor extends InstagramExtractor {
|
|
591
|
+
static readonly subcategory = "reels";
|
|
592
|
+
static pattern: RegExp;
|
|
593
|
+
readonly subcategory = "reels";
|
|
594
|
+
constructor(opts: InstagramExtractorOptions);
|
|
595
|
+
static fromURL(url: string, opts: InstagramExtractorOptions): InstagramReelsExtractor | null;
|
|
596
|
+
posts(): AsyncGenerator<InstagramPost>;
|
|
597
|
+
}
|
|
598
|
+
declare class InstagramTaggedExtractor extends InstagramExtractor {
|
|
599
|
+
static readonly subcategory = "tagged";
|
|
600
|
+
static pattern: RegExp;
|
|
601
|
+
readonly subcategory = "tagged";
|
|
602
|
+
private _taggedUserId;
|
|
603
|
+
constructor(opts: InstagramExtractorOptions);
|
|
604
|
+
static fromURL(url: string, opts: InstagramExtractorOptions): InstagramTaggedExtractor | null;
|
|
605
|
+
metadata(): Promise<Record<string, unknown>>;
|
|
606
|
+
posts(): AsyncGenerator<InstagramPost>;
|
|
607
|
+
}
|
|
608
|
+
declare class InstagramStoriesExtractor extends InstagramExtractor {
|
|
609
|
+
static readonly subcategory = "stories";
|
|
610
|
+
static pattern: RegExp;
|
|
611
|
+
readonly subcategory = "stories";
|
|
612
|
+
private highlightId;
|
|
613
|
+
private mediaId;
|
|
614
|
+
constructor(opts: InstagramExtractorOptions);
|
|
615
|
+
static fromURL(url: string, opts: InstagramExtractorOptions): InstagramStoriesExtractor | null;
|
|
616
|
+
posts(): AsyncGenerator<InstagramPost>;
|
|
617
|
+
}
|
|
618
|
+
declare class InstagramHighlightsExtractor extends InstagramExtractor {
|
|
619
|
+
static readonly subcategory = "highlights";
|
|
620
|
+
static pattern: RegExp;
|
|
621
|
+
readonly subcategory = "highlights";
|
|
622
|
+
constructor(opts: InstagramExtractorOptions);
|
|
623
|
+
static fromURL(url: string, opts: InstagramExtractorOptions): InstagramHighlightsExtractor | null;
|
|
624
|
+
posts(): AsyncGenerator<InstagramPost>;
|
|
625
|
+
}
|
|
626
|
+
declare class InstagramTagExtractor extends InstagramExtractor {
|
|
627
|
+
static readonly subcategory = "tag";
|
|
628
|
+
static pattern: RegExp;
|
|
629
|
+
readonly subcategory = "tag";
|
|
630
|
+
constructor(opts: InstagramExtractorOptions);
|
|
631
|
+
static fromURL(url: string, opts: InstagramExtractorOptions): InstagramTagExtractor | null;
|
|
632
|
+
metadata(): Promise<Record<string, unknown>>;
|
|
633
|
+
posts(): AsyncGenerator<InstagramPost>;
|
|
634
|
+
}
|
|
635
|
+
declare class InstagramInfoExtractor extends InstagramExtractor {
|
|
636
|
+
static readonly subcategory = "info";
|
|
637
|
+
static pattern: RegExp;
|
|
638
|
+
readonly subcategory = "info";
|
|
639
|
+
constructor(opts: InstagramExtractorOptions);
|
|
640
|
+
static fromURL(url: string, opts: InstagramExtractorOptions): InstagramInfoExtractor | null;
|
|
641
|
+
items(): MessageIter;
|
|
642
|
+
posts(): AsyncGenerator<InstagramPost>;
|
|
643
|
+
}
|
|
644
|
+
declare class InstagramAvatarExtractor extends InstagramExtractor {
|
|
645
|
+
static readonly subcategory = "avatar";
|
|
646
|
+
static pattern: RegExp;
|
|
647
|
+
readonly subcategory = "avatar";
|
|
648
|
+
constructor(opts: InstagramExtractorOptions);
|
|
649
|
+
static fromURL(url: string, opts: InstagramExtractorOptions): InstagramAvatarExtractor | null;
|
|
650
|
+
posts(): AsyncGenerator<InstagramPost>;
|
|
651
|
+
}
|
|
652
|
+
declare class InstagramSavedExtractor extends InstagramExtractor {
|
|
653
|
+
static readonly subcategory = "saved";
|
|
654
|
+
static pattern: RegExp;
|
|
655
|
+
readonly subcategory = "saved";
|
|
656
|
+
constructor(opts: InstagramExtractorOptions);
|
|
657
|
+
static fromURL(url: string, opts: InstagramExtractorOptions): InstagramSavedExtractor | null;
|
|
658
|
+
posts(): AsyncGenerator<InstagramPost>;
|
|
659
|
+
}
|
|
660
|
+
//#endregion
|
|
661
|
+
//#region sdk.d.ts
|
|
662
|
+
interface SDKOptions {
|
|
663
|
+
/** Custom HttpClient implementation (required). */
|
|
664
|
+
http: HttpClient;
|
|
665
|
+
/**
|
|
666
|
+
* Custom Storage implementation for file output.
|
|
667
|
+
* Only needed if you plan to call ``download()``.
|
|
668
|
+
*/
|
|
669
|
+
storage?: Storage;
|
|
670
|
+
/** Logger instance. Defaults to a silent no-op logger. */
|
|
671
|
+
log?: Logger;
|
|
672
|
+
/** Pre-extracted CSRF token (optional). */
|
|
673
|
+
csrfToken?: string;
|
|
674
|
+
}
|
|
675
|
+
interface ExtractOptions {
|
|
676
|
+
/** Max posts to extract (for user/tag feeds). */
|
|
677
|
+
maxPosts?: number;
|
|
678
|
+
/** Download videos (default: true). */
|
|
679
|
+
videos?: boolean;
|
|
680
|
+
/** Max posts to extract (for user/tag feeds). */
|
|
681
|
+
limit?: number;
|
|
682
|
+
}
|
|
683
|
+
declare class InstagramSDK {
|
|
684
|
+
readonly http: HttpClient;
|
|
685
|
+
readonly storage: Storage;
|
|
686
|
+
readonly log: Logger;
|
|
687
|
+
readonly config: ConfigManager;
|
|
688
|
+
private readonly _csrfToken;
|
|
689
|
+
constructor(opts: {
|
|
690
|
+
http: HttpClient;
|
|
691
|
+
storage?: Storage;
|
|
692
|
+
log?: Logger;
|
|
693
|
+
csrfToken?: string;
|
|
694
|
+
});
|
|
695
|
+
/** High-level API */
|
|
696
|
+
/**
|
|
697
|
+
* Extract messages from an Instagram URL without downloading.
|
|
698
|
+
*
|
|
699
|
+
* Returns an async generator yielding Directory / Url / Queue messages.
|
|
700
|
+
* Each ``url`` message includes full metadata (post_id, username, dimensions, etc.).
|
|
701
|
+
*
|
|
702
|
+
* ```ts
|
|
703
|
+
* for await (const msg of instagram.extract('https://www.instagram.com/p/.../')) {
|
|
704
|
+
* if (msg.type === 'url') {
|
|
705
|
+
* console.log(msg.url, msg.metadata.media_id)
|
|
706
|
+
* }
|
|
707
|
+
* }
|
|
708
|
+
* ```
|
|
709
|
+
*/
|
|
710
|
+
extract(url: string): MessageIter;
|
|
711
|
+
/**
|
|
712
|
+
* Download all media from an Instagram URL.
|
|
713
|
+
*
|
|
714
|
+
* Uses the built-in DownloadJob + Storage to save files to disk.
|
|
715
|
+
* Requires ``storage`` to be set in constructor options.
|
|
716
|
+
*
|
|
717
|
+
* ```ts
|
|
718
|
+
* const stats = await instagram.download(
|
|
719
|
+
* 'https://www.instagram.com/p/.../',
|
|
720
|
+
* './my-downloads',
|
|
721
|
+
* )
|
|
722
|
+
* // → { posts: 1, files: 9, bytes: 4500000 }
|
|
723
|
+
* ```
|
|
724
|
+
*/
|
|
725
|
+
download(url: string, outputDir?: string): Promise<{
|
|
726
|
+
posts: number;
|
|
727
|
+
files: number;
|
|
728
|
+
bytes: number;
|
|
729
|
+
}>;
|
|
730
|
+
/** Internal */
|
|
731
|
+
/**
|
|
732
|
+
* Resolve a URL to an Extractor instance via pattern matching.
|
|
733
|
+
*/
|
|
734
|
+
private _resolve;
|
|
735
|
+
}
|
|
736
|
+
//#endregion
|
|
737
|
+
export { Extractor as A, HttpResponse as B, InstagramUser as C, ParserConfig as D, ParsedPost as E, Config as F, RequestConfig as G, MessageIter as H, ConfigValue as I, Storage as K, DirectoryMsg as L, Logger as M, noopLogger as N, TaggedUser as O, ConfigManager as P, ExtractorClass as R, InstagramPost as S, ParsedMedia as T, Metadata as U, Message as V, QueueMsg as W, InstagramRestAPI as _, InstagramHighlightsExtractor as a, InstagramCarouselItem as b, InstagramPostsExtractor as c, InstagramStoriesExtractor as d, InstagramTagExtractor as f, InstagramExtractorOptions as g, InstagramExtractor as h, InstagramAvatarExtractor as i, ExtractorOptions as j, VideoVersion as k, InstagramReelsExtractor as l, InstagramUserExtractor as m, InstagramSDK as n, InstagramInfoExtractor as o, InstagramTaggedExtractor as p, UrlMsg as q, SDKOptions as r, InstagramPostExtractor as s, ExtractOptions as t, InstagramSavedExtractor as u, Coauthor as v, MusicSticker as w, InstagramLocation as x, ImageCandidate as y, HttpClient as z };
|