├── .github
└── workflows
│ └── typedoc.yml
├── .gitignore
├── LICENSE
├── README.md
├── examples
├── example.ts
└── getCookie.md
├── package-lock.json
├── package.json
├── src
├── config
│ └── index.ts
├── helper
│ ├── CookieHandler.ts
│ ├── Session.ts
│ └── query.ts
├── index.ts
├── types
│ ├── HighlightMediaMetadata.ts
│ ├── HighlightMetadata.ts
│ ├── LoginData.ts
│ ├── MediaConfigureOptions.ts
│ ├── PaginatedPosts.ts
│ ├── PostFeedResult.ts
│ ├── PostMetadata.ts
│ ├── PostModels.ts
│ ├── PostStoryResult.ts
│ ├── StoriesMetadata.ts
│ ├── UserGraphQlV2.ts
│ ├── UserMetadata.ts
│ ├── index.ts
│ └── searchFollow.ts
└── utils
│ └── index.ts
├── tea.yaml
├── tsconfig.json
└── typedoc.json
/.github/workflows/typedoc.yml:
--------------------------------------------------------------------------------
1 | name: Update Docs
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | jobs:
8 | Build:
9 | runs-on: ubuntu-latest
10 | outputs:
11 | package-name: ${{ steps.packageInfo.outputs.package-name }}
12 | package-version: ${{ steps.packageInfo.outputs.package-version }}
13 | commit-msg: ${{ steps.packageInfo.outputs.commit-msg }}
14 | # Steps represent a sequence of tasks that will be executed as part of the job
15 | steps:
16 | - name: Checkout Commit
17 | uses: actions/checkout@v2
18 |
19 | - name: Parsing Package Info
20 | id: packageInfo
21 | run: |
22 | echo "::set-output name=package-name::$(jq -r .name package.json)"
23 | echo "::set-output name=package-version::$(jq -r .version package.json)"
24 | echo "::set-output name=commit-msg::$(git log -1 --pretty=%B)"
25 |
26 | - name: Setup Node.js environment
27 | uses: actions/setup-node@v2.1.1
28 |
29 | - name: Install Dependencies
30 | run: yarn
31 |
32 | - name: Build
33 | run: yarn run build:all
34 |
35 | - name: Publish to Pages
36 | uses: crazy-max/ghaction-github-pages@v2
37 | with:
38 | target_branch: gh-pages
39 | build_dir: docs
40 | env:
41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | metadata
3 | meta.json
4 | stories_meta.json
5 | stories.json
6 | user.json
7 | dist
8 | h_media.json
9 | h.json
10 | nganu.js
11 | tes.js
12 | media/*
13 | docs
14 | logged_in.json
15 | Cookies.txt
16 | tes.ts
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Insta Fetcher
2 |
3 | [](http://hits.dwyl.com/Gimenz/insta-fetcher) [](https://github.com/Gimenz/insta-fetcher/blob/master/LICENSE) [](https://npmjs.com/package/insta-fetcher)  [](https://badge.fury.io/js/insta-fetcher)
4 |
5 | Fetch instagram api with full details and simplified json metadata
6 |
7 | **Read the docs [here](https://gimenz.github.io/insta-fetcher/)**
8 |
9 | ☕ Buy Me a Coffee : [Saweria](https://saweria.co/masgimenz "Saweria")
10 |
11 | # Features
12 |
13 | - [x] accountInfo
14 | - [x] addPost
15 | - [x] changeProfilePicture
16 | - [x] fetchHighlights
17 | - [x] fetchPost
18 | - [x] fetchStories
19 | - [x] fetchUser
20 | - [x] fetchUserPosts
21 | - [x] fetchUserV2
22 |
23 | # Usage
24 |
25 | ### Installation:
26 |
27 | ```bash
28 | npm i insta-fetcher
29 | ```
30 |
31 | ### recommended to set the cookie before make call to all function
32 |
33 | ```js
34 | let { igApi, getCookie } = require("insta-fetcher");
35 | // using constructor
36 | let ig = new igApi("your cookie");
37 |
38 | // you can get sesion id by using getSessionId function, it requires username & password
39 | (async () => {
40 | const session_id = await getCookie("username", "password");
41 | console.log(session_id);
42 | })();
43 | ```
44 |
45 | ## Example
46 |
47 | more example you can check at example.ts file
48 |
49 | ```js
50 | let { igApi } = require("insta-fetcher");
51 |
52 | // some example with proxy, but i never test it
53 | let ig = new igApi("your cookie", false, {
54 | proxy: {
55 | host: 'proxy-url',
56 | port: 80,
57 | auth: {username: 'my-user', password: 'my-password'}
58 | }
59 | });
60 |
61 | // Public post
62 | ig.fetchPost("https://www.instagram.com/reel/CXhW_4sp32Z/").then((res) => {
63 | console.log(res);
64 | });
65 |
66 | // User data
67 | ig.fetchUser("mg.creativestudio").then((res) => {
68 | console.log(res);
69 | });
70 |
71 | // Fetch stories
72 | ig.fetchStories("adiraas.p").then((res) => {
73 | console.log(res);
74 | });
75 |
76 | // Fetch highlights
77 | ig.fetchHighlights("adiraas.p").then((res) => {
78 | console.log(res);
79 | });
80 | ```
81 |
82 | ## My Project with this Library
83 |
84 | - https://github.com/Gimenz/nganu - simple multi-device base WhatsApp Bot
85 |
86 | # Contributing
87 |
88 | All kinds of contributions are welcome - code, tests, documentation, bug reports, new features, etc...
89 |
90 | - Send feedbacks.
91 | - Submit bug reports.
92 | - Write/Edit the documents.
93 | - Fix bugs or add new features.
94 |
--------------------------------------------------------------------------------
/examples/example.ts:
--------------------------------------------------------------------------------
1 | // an example to get cookie using getCookie function
2 |
3 | import { getCookie, igApi, isIgPostUrl, shortcodeFormatter } from '../src'
4 |
5 | // some example working with axios proxy
6 | const proxy = {
7 | host: '127.0.0.1',
8 | port: 1337,
9 | protocol: 'http'
10 | }
11 | const ig = new igApi('your Cookie', { proxy });
12 |
13 | // you can easily get ig cookie. from anywhere, termux, terminal or etc
14 | getCookie('username', 'password').then(res => {
15 | console.log(res)
16 | });
17 |
18 | //some examples of most uses funtion
19 |
20 | (async () => {
21 |
22 | // fetch a Post
23 | const post = await ig.fetchPost('https://www.instagram.com/p/CW0hkIOFip9/?utm_source=ig_web_copy_link');
24 | console.log(post);
25 |
26 | // fetch user posts, with pagination support
27 | const userPosts = await ig.fetchUserPostsV2('ketoprak_jowo');
28 | console.log(userPosts);
29 |
30 | // use end_cursor to get nextPage posts, end_cursor you can get it by fetch user posts first, if has_next_page value is true
31 | const userPostsNextPage = await ig.fetchUserPostsV2('ketoprak_jowo', userPosts.page_info.end_cursor);
32 | console.log(userPostsNextPage);
33 |
34 | // fetch Stories
35 | const stories = await ig.fetchStories('novia.mawa');
36 | console.log(stories);
37 |
38 | // fetch highlights
39 | const highlight = await ig.fetchHighlights('novia.mawa');
40 | console.log(highlight);
41 |
42 | // fetch user info
43 | const user = await ig.fetchUser('novia.mawa');
44 | console.log(user);
45 |
46 | // also you can use fetchUserV2 version, basically this is same as /?__a=1
47 | const userV2 = await ig.fetchUserV2('novia.mawa');
48 | console.log(userV2);
49 |
50 | // ig url can be extracted , you can use shortcodeFormatter
51 | const formatted = shortcodeFormatter('https://www.instagram.com/p/C3M96a2vOCV/?utm_source=ig_web_copy_link&igsh=MzRlODBiNWFlZA==');
52 | console.log(formatted);
53 |
54 | // or if you want to check wether the ig post is valid url?
55 | const check = isIgPostUrl('https://www.instagram.com/p/C3M96a2vOCV/?utm_source=ig_web_copy_link&igsh=MzRlODBiNWFlZA==');
56 | console.log(check);
57 | })();
58 |
--------------------------------------------------------------------------------
/examples/getCookie.md:
--------------------------------------------------------------------------------
1 | ### An example to get cookie
2 |
3 | _this just example to get ig cookie_
4 |
5 | - create new javascript file
6 | - copy this code
7 | - just change with your ig login credentials
8 |
9 | ```js
10 | const { getCookie } = require("insta-fetcher");
11 |
12 | (async () => {
13 | try {
14 | const cookie = await getCookie("your ig username", "your ig password");
15 | console.log(cookie);
16 | } catch (error) {
17 | console.log(error);
18 | }
19 | })();
20 | ```
21 |
22 | and then run node filename.js
23 |
24 | new method is needed full of ig cookie, you must copy all string of the result. for more example, you can check at example.ts
25 |
26 | ### With Browser
27 |
28 | if you can't understand with the getCookie() method, you can get cookie manually by using browser.
29 |
30 | just log in to instagram.com, open Dev Tools and go to the Network tab, and find at Request Header that the word match with cookie, just copy all.
31 |
32 | For mobile, you can try Kiwi Browser, it like as Desktop Browser that have Dev Tools
33 |
34 | Thanks.
35 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "insta-fetcher",
3 | "version": "1.3.25",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "insta-fetcher",
9 | "version": "1.3.25",
10 | "license": "MIT",
11 | "dependencies": {
12 | "axios": "^0.27.2",
13 | "big-integer": "^1.6.51",
14 | "form-data": "^4.0.0"
15 | },
16 | "devDependencies": {
17 | "@types/node": "^17.0.29",
18 | "typedoc": "^0.22.15",
19 | "typescript": "^4.6.3"
20 | }
21 | },
22 | "node_modules/@types/node": {
23 | "version": "17.0.29",
24 | "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz",
25 | "integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==",
26 | "dev": true
27 | },
28 | "node_modules/asynckit": {
29 | "version": "0.4.0",
30 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
31 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
32 | },
33 | "node_modules/axios": {
34 | "version": "0.27.2",
35 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
36 | "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
37 | "dependencies": {
38 | "follow-redirects": "^1.14.9",
39 | "form-data": "^4.0.0"
40 | }
41 | },
42 | "node_modules/balanced-match": {
43 | "version": "1.0.2",
44 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
45 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
46 | "dev": true
47 | },
48 | "node_modules/big-integer": {
49 | "version": "1.6.51",
50 | "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
51 | "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
52 | "engines": {
53 | "node": ">=0.6"
54 | }
55 | },
56 | "node_modules/brace-expansion": {
57 | "version": "1.1.11",
58 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
59 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
60 | "dev": true,
61 | "dependencies": {
62 | "balanced-match": "^1.0.0",
63 | "concat-map": "0.0.1"
64 | }
65 | },
66 | "node_modules/combined-stream": {
67 | "version": "1.0.8",
68 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
69 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
70 | "dependencies": {
71 | "delayed-stream": "~1.0.0"
72 | },
73 | "engines": {
74 | "node": ">= 0.8"
75 | }
76 | },
77 | "node_modules/concat-map": {
78 | "version": "0.0.1",
79 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
80 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
81 | "dev": true
82 | },
83 | "node_modules/delayed-stream": {
84 | "version": "1.0.0",
85 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
86 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
87 | "engines": {
88 | "node": ">=0.4.0"
89 | }
90 | },
91 | "node_modules/follow-redirects": {
92 | "version": "1.14.9",
93 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
94 | "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==",
95 | "funding": [
96 | {
97 | "type": "individual",
98 | "url": "https://github.com/sponsors/RubenVerborgh"
99 | }
100 | ],
101 | "engines": {
102 | "node": ">=4.0"
103 | },
104 | "peerDependenciesMeta": {
105 | "debug": {
106 | "optional": true
107 | }
108 | }
109 | },
110 | "node_modules/form-data": {
111 | "version": "4.0.0",
112 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
113 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
114 | "dependencies": {
115 | "asynckit": "^0.4.0",
116 | "combined-stream": "^1.0.8",
117 | "mime-types": "^2.1.12"
118 | },
119 | "engines": {
120 | "node": ">= 6"
121 | }
122 | },
123 | "node_modules/fs.realpath": {
124 | "version": "1.0.0",
125 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
126 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
127 | "dev": true
128 | },
129 | "node_modules/glob": {
130 | "version": "7.2.0",
131 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
132 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
133 | "dev": true,
134 | "dependencies": {
135 | "fs.realpath": "^1.0.0",
136 | "inflight": "^1.0.4",
137 | "inherits": "2",
138 | "minimatch": "^3.0.4",
139 | "once": "^1.3.0",
140 | "path-is-absolute": "^1.0.0"
141 | },
142 | "engines": {
143 | "node": "*"
144 | },
145 | "funding": {
146 | "url": "https://github.com/sponsors/isaacs"
147 | }
148 | },
149 | "node_modules/inflight": {
150 | "version": "1.0.6",
151 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
152 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
153 | "dev": true,
154 | "dependencies": {
155 | "once": "^1.3.0",
156 | "wrappy": "1"
157 | }
158 | },
159 | "node_modules/inherits": {
160 | "version": "2.0.4",
161 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
162 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
163 | "dev": true
164 | },
165 | "node_modules/jsonc-parser": {
166 | "version": "3.0.0",
167 | "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz",
168 | "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==",
169 | "dev": true
170 | },
171 | "node_modules/lunr": {
172 | "version": "2.3.9",
173 | "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
174 | "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
175 | "dev": true
176 | },
177 | "node_modules/marked": {
178 | "version": "4.0.12",
179 | "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.12.tgz",
180 | "integrity": "sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==",
181 | "dev": true,
182 | "bin": {
183 | "marked": "bin/marked.js"
184 | },
185 | "engines": {
186 | "node": ">= 12"
187 | }
188 | },
189 | "node_modules/mime-db": {
190 | "version": "1.52.0",
191 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
192 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
193 | "engines": {
194 | "node": ">= 0.6"
195 | }
196 | },
197 | "node_modules/mime-types": {
198 | "version": "2.1.35",
199 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
200 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
201 | "dependencies": {
202 | "mime-db": "1.52.0"
203 | },
204 | "engines": {
205 | "node": ">= 0.6"
206 | }
207 | },
208 | "node_modules/minimatch": {
209 | "version": "3.1.2",
210 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
211 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
212 | "dev": true,
213 | "dependencies": {
214 | "brace-expansion": "^1.1.7"
215 | },
216 | "engines": {
217 | "node": "*"
218 | }
219 | },
220 | "node_modules/once": {
221 | "version": "1.4.0",
222 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
223 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
224 | "dev": true,
225 | "dependencies": {
226 | "wrappy": "1"
227 | }
228 | },
229 | "node_modules/path-is-absolute": {
230 | "version": "1.0.1",
231 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
232 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
233 | "dev": true,
234 | "engines": {
235 | "node": ">=0.10.0"
236 | }
237 | },
238 | "node_modules/shiki": {
239 | "version": "0.10.1",
240 | "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz",
241 | "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==",
242 | "dev": true,
243 | "dependencies": {
244 | "jsonc-parser": "^3.0.0",
245 | "vscode-oniguruma": "^1.6.1",
246 | "vscode-textmate": "5.2.0"
247 | }
248 | },
249 | "node_modules/typedoc": {
250 | "version": "0.22.15",
251 | "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.15.tgz",
252 | "integrity": "sha512-CMd1lrqQbFvbx6S9G6fL4HKp3GoIuhujJReWqlIvSb2T26vGai+8Os3Mde7Pn832pXYemd9BMuuYWhFpL5st0Q==",
253 | "dev": true,
254 | "dependencies": {
255 | "glob": "^7.2.0",
256 | "lunr": "^2.3.9",
257 | "marked": "^4.0.12",
258 | "minimatch": "^5.0.1",
259 | "shiki": "^0.10.1"
260 | },
261 | "bin": {
262 | "typedoc": "bin/typedoc"
263 | },
264 | "engines": {
265 | "node": ">= 12.10.0"
266 | },
267 | "peerDependencies": {
268 | "typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x || 4.6.x"
269 | }
270 | },
271 | "node_modules/typedoc/node_modules/brace-expansion": {
272 | "version": "2.0.1",
273 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
274 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
275 | "dev": true,
276 | "dependencies": {
277 | "balanced-match": "^1.0.0"
278 | }
279 | },
280 | "node_modules/typedoc/node_modules/minimatch": {
281 | "version": "5.0.1",
282 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
283 | "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
284 | "dev": true,
285 | "dependencies": {
286 | "brace-expansion": "^2.0.1"
287 | },
288 | "engines": {
289 | "node": ">=10"
290 | }
291 | },
292 | "node_modules/typescript": {
293 | "version": "4.6.3",
294 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz",
295 | "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==",
296 | "dev": true,
297 | "bin": {
298 | "tsc": "bin/tsc",
299 | "tsserver": "bin/tsserver"
300 | },
301 | "engines": {
302 | "node": ">=4.2.0"
303 | }
304 | },
305 | "node_modules/vscode-oniguruma": {
306 | "version": "1.6.1",
307 | "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.1.tgz",
308 | "integrity": "sha512-vc4WhSIaVpgJ0jJIejjYxPvURJavX6QG41vu0mGhqywMkQqulezEqEQ3cO3gc8GvcOpX6ycmKGqRoROEMBNXTQ==",
309 | "dev": true
310 | },
311 | "node_modules/vscode-textmate": {
312 | "version": "5.2.0",
313 | "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz",
314 | "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==",
315 | "dev": true
316 | },
317 | "node_modules/wrappy": {
318 | "version": "1.0.2",
319 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
320 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
321 | "dev": true
322 | }
323 | },
324 | "dependencies": {
325 | "@types/node": {
326 | "version": "17.0.29",
327 | "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz",
328 | "integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==",
329 | "dev": true
330 | },
331 | "asynckit": {
332 | "version": "0.4.0",
333 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
334 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
335 | },
336 | "axios": {
337 | "version": "0.27.2",
338 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
339 | "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
340 | "requires": {
341 | "follow-redirects": "^1.14.9",
342 | "form-data": "^4.0.0"
343 | }
344 | },
345 | "balanced-match": {
346 | "version": "1.0.2",
347 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
348 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
349 | "dev": true
350 | },
351 | "big-integer": {
352 | "version": "1.6.51",
353 | "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
354 | "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg=="
355 | },
356 | "brace-expansion": {
357 | "version": "1.1.11",
358 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
359 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
360 | "dev": true,
361 | "requires": {
362 | "balanced-match": "^1.0.0",
363 | "concat-map": "0.0.1"
364 | }
365 | },
366 | "combined-stream": {
367 | "version": "1.0.8",
368 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
369 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
370 | "requires": {
371 | "delayed-stream": "~1.0.0"
372 | }
373 | },
374 | "concat-map": {
375 | "version": "0.0.1",
376 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
377 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
378 | "dev": true
379 | },
380 | "delayed-stream": {
381 | "version": "1.0.0",
382 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
383 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
384 | },
385 | "follow-redirects": {
386 | "version": "1.14.9",
387 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
388 | "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w=="
389 | },
390 | "form-data": {
391 | "version": "4.0.0",
392 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
393 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
394 | "requires": {
395 | "asynckit": "^0.4.0",
396 | "combined-stream": "^1.0.8",
397 | "mime-types": "^2.1.12"
398 | }
399 | },
400 | "fs.realpath": {
401 | "version": "1.0.0",
402 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
403 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
404 | "dev": true
405 | },
406 | "glob": {
407 | "version": "7.2.0",
408 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
409 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
410 | "dev": true,
411 | "requires": {
412 | "fs.realpath": "^1.0.0",
413 | "inflight": "^1.0.4",
414 | "inherits": "2",
415 | "minimatch": "^3.0.4",
416 | "once": "^1.3.0",
417 | "path-is-absolute": "^1.0.0"
418 | }
419 | },
420 | "inflight": {
421 | "version": "1.0.6",
422 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
423 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
424 | "dev": true,
425 | "requires": {
426 | "once": "^1.3.0",
427 | "wrappy": "1"
428 | }
429 | },
430 | "inherits": {
431 | "version": "2.0.4",
432 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
433 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
434 | "dev": true
435 | },
436 | "jsonc-parser": {
437 | "version": "3.0.0",
438 | "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz",
439 | "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==",
440 | "dev": true
441 | },
442 | "lunr": {
443 | "version": "2.3.9",
444 | "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
445 | "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
446 | "dev": true
447 | },
448 | "marked": {
449 | "version": "4.0.12",
450 | "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.12.tgz",
451 | "integrity": "sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==",
452 | "dev": true
453 | },
454 | "mime-db": {
455 | "version": "1.52.0",
456 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
457 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
458 | },
459 | "mime-types": {
460 | "version": "2.1.35",
461 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
462 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
463 | "requires": {
464 | "mime-db": "1.52.0"
465 | }
466 | },
467 | "minimatch": {
468 | "version": "3.1.2",
469 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
470 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
471 | "dev": true,
472 | "requires": {
473 | "brace-expansion": "^1.1.7"
474 | }
475 | },
476 | "once": {
477 | "version": "1.4.0",
478 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
479 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
480 | "dev": true,
481 | "requires": {
482 | "wrappy": "1"
483 | }
484 | },
485 | "path-is-absolute": {
486 | "version": "1.0.1",
487 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
488 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
489 | "dev": true
490 | },
491 | "shiki": {
492 | "version": "0.10.1",
493 | "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz",
494 | "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==",
495 | "dev": true,
496 | "requires": {
497 | "jsonc-parser": "^3.0.0",
498 | "vscode-oniguruma": "^1.6.1",
499 | "vscode-textmate": "5.2.0"
500 | }
501 | },
502 | "typedoc": {
503 | "version": "0.22.15",
504 | "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.15.tgz",
505 | "integrity": "sha512-CMd1lrqQbFvbx6S9G6fL4HKp3GoIuhujJReWqlIvSb2T26vGai+8Os3Mde7Pn832pXYemd9BMuuYWhFpL5st0Q==",
506 | "dev": true,
507 | "requires": {
508 | "glob": "^7.2.0",
509 | "lunr": "^2.3.9",
510 | "marked": "^4.0.12",
511 | "minimatch": "^5.0.1",
512 | "shiki": "^0.10.1"
513 | },
514 | "dependencies": {
515 | "brace-expansion": {
516 | "version": "2.0.1",
517 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
518 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
519 | "dev": true,
520 | "requires": {
521 | "balanced-match": "^1.0.0"
522 | }
523 | },
524 | "minimatch": {
525 | "version": "5.0.1",
526 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
527 | "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
528 | "dev": true,
529 | "requires": {
530 | "brace-expansion": "^2.0.1"
531 | }
532 | }
533 | }
534 | },
535 | "typescript": {
536 | "version": "4.6.3",
537 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz",
538 | "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==",
539 | "dev": true
540 | },
541 | "vscode-oniguruma": {
542 | "version": "1.6.1",
543 | "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.1.tgz",
544 | "integrity": "sha512-vc4WhSIaVpgJ0jJIejjYxPvURJavX6QG41vu0mGhqywMkQqulezEqEQ3cO3gc8GvcOpX6ycmKGqRoROEMBNXTQ==",
545 | "dev": true
546 | },
547 | "vscode-textmate": {
548 | "version": "5.2.0",
549 | "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz",
550 | "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==",
551 | "dev": true
552 | },
553 | "wrappy": {
554 | "version": "1.0.2",
555 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
556 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
557 | "dev": true
558 | }
559 | }
560 | }
561 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "insta-fetcher",
3 | "version": "1.3.36",
4 | "description": "Simplified Instagram metadata scraping",
5 | "main": "./dist/index.js",
6 | "scripts": {
7 | "build:all": "tsc && typedoc",
8 | "build": "tsc",
9 | "build:docs": "typedoc",
10 | "build:tsc": "tsc",
11 | "start": "tsc && node dist/index.js",
12 | "prepare": "npm run build-ts",
13 | "build-ts": "tsc"
14 | },
15 | "files": [
16 | "dist"
17 | ],
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/Gimenz/insta-fetcher.git"
21 | },
22 | "publishConfig": {
23 | "registry": "https://registry.npmjs.org/"
24 | },
25 | "keywords": [
26 | "instagram-scraper",
27 | "instagram-downloader",
28 | "instagram-saver",
29 | "insta-scraper",
30 | "instagram",
31 | "ig-scraper",
32 | "ig-api",
33 | "instagram-private-api",
34 | "instagram-api",
35 | "instagram-scraping"
36 | ],
37 | "author": "Muhamad Ristiyanto ",
38 | "license": "MIT",
39 | "bugs": {
40 | "url": "https://github.com/Gimenz/insta-fetcher/issues"
41 | },
42 | "homepage": "https://github.com/Gimenz/insta-fetcher",
43 | "dependencies": {
44 | "axios": "^0.27.2",
45 | "big-integer": "^1.6.51",
46 | "form-data": "^4.0.0"
47 | },
48 | "devDependencies": {
49 | "@types/node": "^17.0.29",
50 | "typedoc": "^0.22.15",
51 | "typescript": "^4.6.3"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/config/index.ts:
--------------------------------------------------------------------------------
1 | export const config = {
2 | /** Instagram Base URL */
3 | instagram_base_url: 'https://www.instagram.com',
4 | instagram_base_z4: 'https://z-p4.www.instagram.com',
5 | /** Instagram Api v1 */
6 | instagram_api_v1: 'https://i.instagram.com/api/v1',
7 | /** Instagram API Search User */
8 | instagram_search_url: 'https://www.instagram.com/web/search/topsearch/?query=',
9 | /** Android User-Agent */
10 | android: 'Instagram 177.0.0.30.119 Android (18/4.3; 320dpi; 720x1280; Xiaomi; HM 1SW; armani; qcom; en_US)',
11 | /** Desktop User-Agent */
12 | desktop: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36',
13 | /** iPhone User-Agent */
14 | iPhone: 'Instagram 123.0.0.21.114 (iPhone; CPU iPhone OS 11_4 like Mac OS X; en_US; en-US; scale=2.00; 750x1334) AppleWebKit/605.1.15'
15 | }
--------------------------------------------------------------------------------
/src/helper/CookieHandler.ts:
--------------------------------------------------------------------------------
1 | import * as fs from 'fs';
2 | import * as path from 'path';
3 | import { IgCookie } from '../types';
4 |
5 | let DIR: string = path.join(__dirname, '../config/Cookies.txt');
6 |
7 | export class CookieHandler {
8 | IgCookie: IgCookie
9 | constructor(IgCookie: string = '') {
10 | this.IgCookie = IgCookie;
11 | }
12 |
13 | /**
14 | * save session id to local directory
15 | * @param IgCookie session id
16 | * @returns
17 | */
18 | public save = (IgCookie: string = this.IgCookie): void => {
19 | if (!fs.existsSync(DIR)) {
20 | fs.writeFileSync(DIR, IgCookie, 'utf-8');
21 | } else {
22 | this.update(IgCookie)
23 | }
24 | }
25 |
26 | /**
27 | * update with new cookie if last cookie got error, e.g account locked mybe
28 | * @param {String} IgCookie
29 | * @returns
30 | */
31 | public update = (IgCookie: string = this.IgCookie): void => {
32 | if (fs.existsSync(DIR)) {
33 | fs.writeFileSync(DIR, IgCookie, 'utf-8');
34 | } else {
35 | throw new Error(
36 | "Cookie hasn't been saved before, save cookie first using save()"
37 | );
38 | }
39 | }
40 |
41 | /**
42 | * to check if cookies.txt stored in local dir
43 | * @returns {boolean} true if file has stored in local dir
44 | */
45 | public check = (): boolean => {
46 | return fs.existsSync(DIR);
47 | }
48 |
49 | /**
50 | * get a session id
51 | * @returns session id
52 | */
53 | public get = (): string => {
54 | let data: string = this.check()
55 | ? fs.readFileSync(DIR, 'utf-8').toString() || this.IgCookie
56 | : this.IgCookie;
57 | return data;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/helper/Session.ts:
--------------------------------------------------------------------------------
1 | import axios, { AxiosRequestHeaders, AxiosResponse } from "axios";
2 | import { formatCookie } from "../utils";
3 | import { config } from "../config";
4 | import { csrfToken, IgCookie, LoginData, password, username } from "../types";
5 | import { randomUUID } from "crypto";
6 |
7 | export const getCsrfToken = async (): Promise => {
8 | try {
9 | const { headers } = await axios({
10 | method: 'GET',
11 | url: 'https://www.instagram.com/accounts/login/'
12 | });
13 | let csrfToken: csrfToken = headers["set-cookie"]?.find(x => x.match(/csrftoken=(.*?);/)?.[1])?.match(/csrftoken=(.*?);/)?.[1] || '';
14 | return csrfToken
15 | } catch (error) {
16 | throw error
17 | }
18 | }
19 |
20 | /**
21 | * get session id using login method
22 | * @deprecated recommended to use getCookie() function, but you still can use this function too
23 | * @param {username} username instagram username
24 | * @param {password} password instagram password
25 | * @returns {IgCookie} session id
26 | */
27 | export const getSessionId = async (username: username, password: password): Promise => {
28 | if (typeof username !== 'string' || typeof password !== 'string') {
29 | throw new TypeError(`Expected a string, got ${typeof username !== 'string' ? typeof username : typeof password}`);
30 | }
31 |
32 | try {
33 | const csrfToken = await getCsrfToken();
34 | const genHeaders: AxiosRequestHeaders = {
35 | 'X-CSRFToken': csrfToken,
36 | 'user-agent': config.desktop,
37 | 'cache-Control': 'no-cache',
38 | 'content-type': 'application/x-www-form-urlencoded',
39 | referer: 'https://www.instagram.com/accounts/login/?source=auth_switcher',
40 | 'authority': 'www.instagram.com',
41 | 'origin': 'https://www.instagram.com',
42 | 'accept-language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7',
43 | 'sec-fetch-site': 'same-origin',
44 | 'sec-fetch-mode': 'cors',
45 | 'sec-fetch-dest': 'empty',
46 | 'x-ig-app-id': '936619743392459',
47 | 'x-ig-www-claim': 'hmac.AR3W0DThY2Mu5Fag4sW5u3RhaR3qhFD_5wvYbOJOD9qaPjIf',
48 | 'x-instagram-ajax': '1',
49 | 'x-requested-with': 'XMLHttpRequest',
50 | 'Cookie': 'csrftoken=' + csrfToken + ';'
51 | }
52 |
53 | const { headers, data }: AxiosResponse = await axios({
54 | method: 'POST',
55 | url: 'https://www.instagram.com/accounts/login/ajax/',
56 | data: `username=${username}&enc_password=#PWD_INSTAGRAM_BROWSER:0:${Date.now()}:${password}&queryParams=%7B%22source%22%3A%22auth_switcher%22%7D&optIntoOneTap=false`,
57 | headers: genHeaders
58 | });
59 |
60 | const { userId: userID, authenticated } = (data);
61 | if (authenticated) {
62 | let Cookie = formatCookie(headers['set-cookie']) || '';
63 | return Cookie;
64 | } else {
65 | throw new Error('Username or password is incorrect. Please check and try again');
66 | }
67 | } catch (error) {
68 | if (axios.isAxiosError(error)) {
69 | throw error.toJSON()
70 | } else {
71 | throw error
72 | }
73 | }
74 | }
75 |
76 | /**
77 | *
78 | * @param {username} username
79 | * @param {password} password
80 | * @param withLoginData if true, it will return logindata
81 | * @returns
82 | */
83 | export const getCookie = async (username: string, password: string, withLoginData: boolean = false) => {
84 | try {
85 | let login_headers = {
86 | "User-Agent": "Instagram 100.1.0.29.135 Android",
87 | "Content-Type": "application/x-www-form-urlencoded",
88 | "Accept-Language": "en-US,en;q=0.9",
89 | Cookie: "",
90 | }
91 | const { headers: getHeaders } = await axios.get('https://i.instagram.com/api/v1/si/fetch_headers/?challenge_type=signup')
92 | login_headers.Cookie = formatCookie(getHeaders["set-cookie"]) || ''
93 | const res = await axios.post(
94 | 'https://i.instagram.com/api/v1/accounts/login/',
95 | `username=${username}&password=${encodeURIComponent(password)}&device_id=${randomUUID()}&login_attempt_count=0`, {
96 | headers: login_headers
97 | })
98 | const cookie: IgCookie = formatCookie(res.headers['set-cookie']) || '';
99 | const result = res.data;
100 | if (withLoginData) {
101 | result['cookie'] = cookie;
102 | return result as LoginData
103 | } else return cookie
104 | } catch (error) {
105 | throw error
106 | }
107 | }
--------------------------------------------------------------------------------
/src/helper/query.ts:
--------------------------------------------------------------------------------
1 |
2 | /** Instagram Highlight query */
3 | export const highlight_ids_query = (userId: string) => {
4 | return {
5 | 'query_hash': 'c9100bf9110dd6361671f113dd02e7d6',
6 | 'variables': JSON.stringify({
7 | "user_id": userId,
8 | "include_chaining": false,
9 | "include_reel": true,
10 | "include_suggested_users": false,
11 | "include_logged_out_extras": false,
12 | "include_highlight_reels": true,
13 | "include_live_status": false
14 | })
15 | }
16 | }
17 |
18 | export const highlight_media_query = (ids: string) => {
19 | return {
20 | 'query_hash': '0a85e6ea60a4c99edc58ab2f3d17cfdf',
21 | 'variables': JSON.stringify({
22 | "reel_ids": [],
23 | "tag_names": [],
24 | "location_ids": [],
25 | "highlight_reel_ids": [ids],
26 | "precomposed_overlay": false,
27 | "show_story_viewer_list": true,
28 | "story_viewer_fetch_count": 50,
29 | "story_viewer_cursor": "",
30 | "stories_video_dash_manifest": false
31 | })
32 | }
33 | }
34 |
35 | export const post_shortcode_query = (shortcode: string) => {
36 | return {
37 | 'query_hash': '55a3c4bad29e4e20c20ff4cdfd80f5b4',
38 | 'variables': JSON.stringify({
39 | shortcode
40 | })
41 | }
42 | }
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | /* Muhamad Ristiyanto _ https://github.com/Gimenz
2 | * Created, Published at Selasa, 9 Maret 2021
3 | * Modified, Updated at Minggu, 20 Februari 2022
4 | */
5 |
6 | import fs from 'fs'
7 | import FormData from 'form-data';
8 | import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
9 | import { bufferToStream, getPostType, parseCookie, randInt, shortcodeFormatter } from './utils/index';
10 | import { username, userId, seachTerm, url, IgCookie, ProductType, MediaType, IChangedProfilePicture, ISearchFollow, IGPostMetadata, PostGraphQL } from './types';
11 | import { IGUserMetadata, UserGraphQL } from './types/UserMetadata';
12 | import { IGStoriesMetadata, ItemStories, StoriesGraphQL } from './types/StoriesMetadata';
13 | import { highlight_ids_query, highlight_media_query, post_shortcode_query } from './helper/query';
14 | import { HightlighGraphQL, ReelsIds } from './types/HighlightMetadata';
15 | import { HMedia, IHighlightsMetadata, IReelsMetadata, ReelsMediaData } from './types/HighlightMediaMetadata';
16 | import { IPostModels, IRawBody, MediaUrls } from './types/PostModels';
17 | import { config } from './config';
18 | import { getCsrfToken } from './helper/Session';
19 | import { PostFeedResult } from './types/PostFeedResult';
20 | import { PostStoryResult } from './types/PostStoryResult';
21 | import { MediaConfigureOptions } from './types/MediaConfigureOptions';
22 | import { UserGraphQlV2, Graphql } from './types/UserGraphQlV2';
23 | import { IPaginatedPosts } from './types/PaginatedPosts';
24 |
25 | export * from './utils'
26 | export * as InstagramMetadata from './types'
27 | export * from './helper/Session';
28 | export class igApi {
29 | /**
30 | * Recommended to set cookie for most all IG Request
31 | * @param IgCookie cookie you can get it by using getSessionId function, see README.md or example file
32 | * @param storeCookie
33 | * @param AxiosOpts
34 | */
35 | constructor(private IgCookie: IgCookie = '', public AxiosOpts: AxiosRequestConfig = {}) {
36 | this.IgCookie = IgCookie;
37 | this.AxiosOpts = AxiosOpts;
38 | }
39 | private accountUserId = this.IgCookie.match(/sessionid=(.*?);/)?.[1].split('%')[0] || ''
40 |
41 | private buildHeaders = (agent: string = config.android, options?: any) => {
42 | return {
43 | 'user-agent': agent,
44 | 'cookie': `${this.IgCookie}`,
45 | 'authority': 'www.instagram.com',
46 | 'content-type': 'application/x-www-form-urlencoded',
47 | 'origin': 'https://www.instagram.com',
48 | 'accept-language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7',
49 | 'sec-fetch-site': 'same-origin',
50 | 'sec-fetch-mode': 'cors',
51 | 'sec-fetch-dest': 'empty',
52 | 'x-ig-app-id': 936619743392459,
53 | 'x-ig-www-claim': 'hmac.AR3W0DThY2Mu5Fag4sW5u3RhaR3qhFD_5wvYbOJOD9qaPjIf',
54 | 'x-instagram-ajax': 1,
55 | 'x-requested-with': 'XMLHttpRequest',
56 | ...options
57 | };
58 | }
59 |
60 | /**
61 | * Make request to IG API
62 | * @param baseURL
63 | * @param url
64 | * @param agent
65 | * @param AxiosOptions
66 | */
67 | private FetchIGAPI = (baseURL: string, url: string = '', agent: string = config.android, AxiosOptions: AxiosRequestConfig = {}): Promise | undefined => {
68 | try {
69 | return axios({
70 | baseURL,
71 | url,
72 | headers: AxiosOptions.headers ? AxiosOptions.headers : this.buildHeaders(agent),
73 | method: AxiosOptions.method || 'GET',
74 | ...AxiosOptions,
75 | ...this.AxiosOpts
76 | });
77 | } catch (error) {
78 | if (axios.isAxiosError(error)) {
79 | throw error.response
80 | }
81 | }
82 | }
83 |
84 | /**
85 | * get user id by username
86 | * @param {username} username
87 | * @returns
88 | */
89 | public getIdByUsername = async (username: username): Promise => {
90 | const res = await this.fetchUserV2(username);
91 | return res?.id as userId;
92 | }
93 |
94 | public searchFollower = async (userId: userId, seachTerm: seachTerm): Promise => {
95 | const res = await this.FetchIGAPI(
96 | config.instagram_api_v1,
97 | `/friendships/${userId}/followers/?count=12&query=${seachTerm}&search_surface=follow_list_page`,
98 | config.iPhone,
99 | );
100 | return res?.data || res
101 | }
102 |
103 | public searchFollowing = async (userId: userId, seachTerm: seachTerm): Promise => {
104 | const res = await this.FetchIGAPI(
105 | config.instagram_api_v1,
106 | `/friendships/${userId}/following/?query=${seachTerm}`,
107 | config.iPhone,
108 | );
109 | return res?.data || res
110 | }
111 |
112 | private _formatSidecar = (data: IRawBody): Array => {
113 | const gql = data.items[0]
114 | let urls: MediaUrls[] = []
115 | if (gql.product_type == ProductType.CAROUSEL) {
116 | gql.carousel_media.forEach((v, i, a) => {
117 | urls.push({
118 | id: v.id,
119 | url: v.media_type == MediaType.IMAGE ? v.image_versions2.candidates[0].url : v.video_versions?.[0].url || '',
120 | type: v.media_type == MediaType.IMAGE ? 'image' : 'video',
121 | dimensions: {
122 | height: v.media_type == MediaType.IMAGE ? v.image_versions2.candidates[0].height : v.video_versions?.[0].height || 0,
123 | width: v.media_type == MediaType.IMAGE ? v.image_versions2.candidates[0].width : v.video_versions?.[0].width || 0
124 | }
125 | })
126 | })
127 | } else if (gql.product_type == ProductType.REEL) {
128 | urls.push({
129 | id: gql.id,
130 | url: gql.video_versions[0].url,
131 | type: 'video',
132 | dimensions: {
133 | height: gql.video_versions[0].height,
134 | width: gql.video_versions[0].width
135 | }
136 | })
137 | } else if (gql.product_type == ProductType.TV) {
138 | urls.push({
139 | id: gql.id,
140 | url: gql.video_versions[0].url,
141 | type: 'video',
142 | dimensions: {
143 | height: gql.video_versions[0].height,
144 | width: gql.video_versions[0].width
145 | }
146 | })
147 | } else if (gql.product_type == ProductType.SINGLE) {
148 | urls.push({
149 | id: gql.id,
150 | url: gql.media_type == MediaType.IMAGE ? gql.image_versions2.candidates[0].url : gql.video_versions?.[0].url || '',
151 | type: gql.media_type == MediaType.IMAGE ? 'image' : 'video',
152 | dimensions: {
153 | height: gql.media_type == MediaType.IMAGE ? gql.image_versions2.candidates[0].height : gql.video_versions?.[0].height || 0,
154 | width: gql.media_type == MediaType.IMAGE ? gql.image_versions2.candidates[0].width : gql.video_versions?.[0].width || 0
155 | }
156 | })
157 | }
158 | return urls
159 | }
160 |
161 | public fetchPost = async (url: url): Promise => {
162 | const post = shortcodeFormatter(url);
163 |
164 | const metadata = await this.fetchPostByMediaId(post.media_id)
165 |
166 | const item = metadata.items[0]
167 | return {
168 | username: item.user.username,
169 | name: item.user.full_name,
170 | postType: getPostType(item.product_type),
171 | media_id: item.id,
172 | shortcode: item.code,
173 | taken_at_timestamp: item.taken_at,
174 | likes: item.like_count,
175 | caption: item.caption?.text || null,
176 | media_count: item.product_type == ProductType.CAROUSEL ? item.carousel_media_count : 1,
177 | comment_count: item.comment_count,
178 | video_duration: item?.video_duration || null,
179 | music: item?.clips_metadata || null,
180 | links: this._formatSidecar(metadata),
181 | }
182 | }
183 |
184 | public fetchPostByMediaId = async (mediaId: string | number): Promise => {
185 | try {
186 | const res = await this.FetchIGAPI(
187 | config.instagram_api_v1,
188 | `/media/${mediaId.toString()}/info/`
189 | )
190 | return res?.data
191 | } catch (error) {
192 | throw error
193 | }
194 | }
195 |
196 | public fetchPostByShortcode = async (shortcode: string): Promise => {
197 | const res = await this.FetchIGAPI(
198 | config.instagram_base_url,
199 | '/graphql/query/',
200 | config.iPhone,
201 | { params: post_shortcode_query(shortcode) }
202 | )
203 | const graphql = res?.data;
204 | return graphql;
205 | }
206 |
207 | /**
208 | * fetch client account profile
209 | */
210 | public accountInfo = async (
211 | userID: string = this.accountUserId
212 | ): Promise => {
213 | try {
214 | const res = await this.FetchIGAPI(
215 | config.instagram_api_v1,
216 | `/users/${userID}/info/`
217 | );
218 | const graphql: UserGraphQL = res?.data;
219 | return graphql
220 | } catch (error) {
221 | throw error
222 | }
223 | }
224 |
225 | /**
226 | * fetch profile by username. including email, phone number
227 | * @param {username} username
228 | * @returns
229 | */
230 | public fetchUser = async (username: username): Promise => {
231 | const userID = await this.getIdByUsername(username);
232 | const res = await this.FetchIGAPI(
233 | config.instagram_api_v1,
234 | `/users/${userID}/info/`
235 | );
236 | const graphql: UserGraphQL = res?.data;
237 | return {
238 | id: graphql.user.pk,
239 | username: graphql.user.username,
240 | fullname: graphql.user.full_name,
241 | followers: graphql.user.follower_count,
242 | following: graphql.user.following_count,
243 | post_count: graphql.user.media_count,
244 | is_private: graphql.user.is_private,
245 | is_verified: graphql.user.is_verified,
246 | biography: graphql.user.biography,
247 | external_url: graphql.user.external_url,
248 | total_igtv_videos: graphql.user.total_igtv_videos,
249 | has_videos: graphql.user.has_videos,
250 | hd_profile_pic_url_info: graphql.user.hd_profile_pic_url_info,
251 | has_highlight_reels: graphql.user.has_highlight_reels,
252 | has_guides: graphql.user.has_guides,
253 | is_business: graphql.user.is_business,
254 | contact_phone_number: graphql.user.contact_phone_number,
255 | public_email: graphql.user.public_email,
256 | account_type: graphql.user.account_type,
257 | ...graphql
258 | }
259 | }
260 |
261 | /**
262 | * hmmm..?
263 | * @param username
264 | * @returns
265 | */
266 | public fetchUserV2 = async (username: username) => {
267 | const res = await this.FetchIGAPI(
268 | config.instagram_api_v1,
269 | `/users/web_profile_info/?username=${username}`,
270 | config.iPhone,
271 | );
272 | const graphql: Graphql = res?.data;
273 | return graphql.data?.user as UserGraphQlV2;
274 | }
275 |
276 | /**
277 | * simple method to check is user follow me
278 | * @param username
279 | * @returns true if user is follow me
280 | */
281 | public isFollowMe = async (username: username): Promise => {
282 | const user = await this.fetchUserV2(username);
283 | return user.follows_viewer;
284 | }
285 |
286 | /**
287 | *
288 | * @param {StoriesGraphQL} metadata
289 | * @returns {ItemStories[]}
290 | */
291 | private _parseStories = (metadata: StoriesGraphQL): Array => {
292 | const items = metadata.items;
293 | let storyList = new Array();
294 | for (let i = 0; i < items.length; i++) {
295 | if (items[i].media_type == 1) {
296 | storyList.push({
297 | type: 'image',
298 | mimetype: 'image/jpeg',
299 | url: items[i].image_versions2.candidates[0].url,
300 | taken_at: items[i].taken_at,
301 | expiring_at: items[i].expiring_at,
302 | id: items[i].id,
303 | original_width: items[i].original_width,
304 | original_height: items[i].original_height,
305 | has_audio:
306 | items[i].has_audio !== undefined ? items[i].has_audio : null,
307 | video_duration:
308 | items[i].video_duration !== undefined
309 | ? items[i].video_duration
310 | : null,
311 | caption: items[i].caption,
312 | });
313 | } else {
314 | storyList.push({
315 | type: 'video',
316 | mimetype: 'video/mp4',
317 | url: items[i].video_versions[0].url,
318 | taken_at: items[i].taken_at,
319 | expiring_at: items[i].expiring_at,
320 | id: items[i].id,
321 | original_width: items[i].original_width,
322 | original_height: items[i].original_height,
323 | has_audio:
324 | items[i].has_audio !== undefined ? items[i].has_audio : false,
325 | video_duration:
326 | items[i].video_duration !== undefined
327 | ? items[i].video_duration
328 | : null,
329 | caption: items[i].caption,
330 | });
331 | }
332 | }
333 | return storyList;
334 | }
335 |
336 | /**
337 | * fetches stories metadata
338 | * @param {string} username username target to fetch the stories, also work with private profile if you use cookie \w your account that follows target account
339 | * @returns
340 | */
341 | public fetchStories = async (username: username): Promise => {
342 | const userID = await this.getIdByUsername(username);
343 | const res = await this.FetchIGAPI(
344 | config.instagram_api_v1,
345 | `/feed/user/${userID}/reel_media/`,
346 | config.iPhone
347 | );
348 | const graphql: StoriesGraphQL = res?.data;
349 | const isFollowing = typeof graphql.user?.friendship_status !== 'undefined';
350 |
351 | if (!isFollowing && graphql.user.is_private) {
352 | throw new Error('Private profile');
353 | } else {
354 | return {
355 | username: graphql.user.username,
356 | stories_count: graphql.media_count,
357 | stories: graphql.items.length == 0 ? null : this._parseStories(graphql),
358 | graphql,
359 | };
360 | }
361 | }
362 |
363 | /**
364 | * Fetch all reels/highlight id
365 | * @param {username} username
366 | * @returns
367 | */
368 | public _getReelsIds = async (username: username): Promise => {
369 | const userID: string = await this.getIdByUsername(username);
370 | const res = await this.FetchIGAPI(
371 | config.instagram_base_url,
372 | '/graphql/query/',
373 | config.iPhone,
374 | { params: highlight_ids_query(userID) }
375 | )
376 | const graphql: HightlighGraphQL = res?.data;
377 | let items = new Array();
378 | graphql.data.user.edge_highlight_reels.edges.map((edge) => {
379 | items.push({
380 | highlight_id: edge.node.id,
381 | cover: edge.node.cover_media.thumbnail_src,
382 | title: edge.node.title
383 | })
384 | })
385 | return items;
386 | }
387 |
388 | /**
389 | * get media urls from highlight id
390 | * @param {ids} ids of highlight
391 | * @returns
392 | */
393 | public _getReels = async (ids: string): Promise => {
394 | const res = await this.FetchIGAPI(
395 | config.instagram_base_url,
396 | '/graphql/query/',
397 | config.iPhone,
398 | { params: highlight_media_query(ids) }
399 | )
400 | const graphql = res?.data;
401 | return graphql;
402 | }
403 |
404 | private formatHighlight = async (graphql: HMedia): Promise => {
405 | return graphql.data.reels_media[0].items.map((item) => ({
406 | owner: graphql.data.reels_media[0].owner,
407 | media_id: item.id,
408 | mimetype: item.is_video ? 'video/mp4' || 'video/gif' : 'image/jpeg',
409 | taken_at: item.taken_at_timestamp,
410 | type: item.is_video ? 'video' : 'image',
411 | url: item.is_video ? item.video_resources[0].src : item.display_url,
412 | dimensions: item.dimensions,
413 | }))
414 | }
415 |
416 | /**
417 | * fetches highlight metadata
418 | * @param {string} username username target to fetch the highlights, also work with private profile if you use cookie \w your account that follows target account
419 | * @returns
420 | */
421 | public fetchHighlights = async (username: username): Promise => {
422 | try {
423 | const ids = await this._getReelsIds(username);
424 | const reels = await Promise.all(ids.map(async x => this.formatHighlight(await this._getReels(x.highlight_id))))
425 |
426 | let data: IReelsMetadata[] = [];
427 | for (let i = 0; i < reels.length; i++) {
428 | data.push({
429 | title: ids[i].title,
430 | cover: ids[i].cover,
431 | media_count: reels[i].length,
432 | highlights_id: ids[i].highlight_id,
433 | highlights: reels[i]
434 | })
435 | }
436 | let json: IHighlightsMetadata = {
437 | username,
438 | highlights_count: ids.length,
439 | data: data
440 | }
441 |
442 | return json;
443 | } catch (error) {
444 | throw error
445 | }
446 | }
447 |
448 | /**
449 | * fetches user posts, with pagination
450 | * @deprecated Does not return all information about a post, use fetchUserPostsV2()
451 | * @param username
452 | * @param end_cursor get end_cursor by fetch user posts first
453 | * @returns
454 | */
455 | public fetchUserPosts = async (username: username, end_cursor = ''): Promise => {
456 | const userId = await this.getIdByUsername(username);
457 | const params = {
458 | 'query_id': '17880160963012870',
459 | 'id': userId,
460 | 'first': 12,
461 | 'after': end_cursor
462 | }
463 | const res = await this.FetchIGAPI(config.instagram_base_url, '/graphql/query/', config.android, { params })
464 |
465 | return res?.data?.data.user.edge_owner_to_timeline_media
466 | }
467 |
468 | /**
469 | * fetches user posts, with pagination
470 | * @param username
471 | * @param end_cursor get end_cursor by fetchUserPostsV2 first
472 | * @param num_posts number of posts to fetch (default 12)
473 | * @returns
474 | */
475 |
476 | public fetchUserPostsV2 = async (username: username, end_cursor = '', num_posts = 12): Promise => {
477 | const userId = await this.getIdByUsername(username);
478 | return this.fetchUserIDPostsV2(userId, end_cursor, num_posts)
479 | }
480 |
481 | /**
482 | * fetches user posts, with pagination
483 | * @param user_id user id from getIdByUsername. See fetchUserPostsV2 if using username
484 | * @param end_cursor get end_cursor by fetchUserPostsV2 first
485 | * @param num_posts number of posts to fetch (default 12)
486 | * @returns
487 | */
488 |
489 | public fetchUserIDPostsV2 = async (user_id: string, end_cursor = '', num_posts = 12): Promise => {
490 | const params = {
491 | 'query_hash': '69cba40317214236af40e7efa697781d',
492 | 'variables': {
493 | "id": user_id,
494 | "first": num_posts,
495 | "after": end_cursor
496 | }
497 | }
498 | const res = await this.FetchIGAPI(config.instagram_base_url, '/graphql/query/', config.android, { params })
499 |
500 | return res?.data?.data.user.edge_owner_to_timeline_media
501 | }
502 |
503 | private uploadPhoto = async (photo: string | Buffer) => {
504 | try {
505 | const uploadId = Date.now();
506 |
507 | const file = Buffer.isBuffer(photo)
508 | ? photo
509 | : fs.existsSync(photo)
510 | ? fs.readFileSync(photo)
511 | : photo;
512 |
513 | const uploadParams = {
514 | media_type: 1,
515 | upload_id: uploadId.toString(),
516 | upload_media_height: 1080,
517 | upload_media_width: 1080,
518 | xsharing_user_ids: JSON.stringify([]),
519 | image_compression: JSON.stringify({
520 | lib_name: 'moz',
521 | lib_version: '3.1.m',
522 | quality: '80'
523 | })
524 | }
525 |
526 | const nameEntity = `${uploadId}_0_${randInt(1000000000, 9999999999)}`
527 |
528 | const headers = {
529 | 'x-entity-type': 'image/jpeg',
530 | offset: 0,
531 | 'x-entity-name': nameEntity,
532 | 'x-instagram-rupload-params': JSON.stringify(uploadParams),
533 | 'x-entity-length': Buffer.byteLength(file),
534 | 'Content-Length': Buffer.byteLength(file),
535 | 'Content-Type': 'application/octet-stream',
536 | 'x-ig-app-id': `1217981644879628`,
537 | 'Accept-Encoding': 'gzip',
538 | 'X-Pigeon-Rawclienttime': (Date.now() / 1000).toFixed(3),
539 | 'X-IG-Connection-Speed': `${randInt(3700, 1000)}kbps`,
540 | 'X-IG-Bandwidth-Speed-KBPS': '-1.000',
541 | 'X-IG-Bandwidth-TotalBytes-B': '0',
542 | 'X-IG-Bandwidth-TotalTime-MS': '0',
543 | }
544 |
545 | const headersPhoto = this.buildHeaders(config.android, headers)
546 |
547 | const result = await this.FetchIGAPI(
548 | `${config.instagram_base_url}`,
549 | `/rupload_igphoto/fb_uploader_${nameEntity}`,
550 | config.android,
551 | { headers: headersPhoto, data: file, method: 'POST' }
552 | );
553 | return result?.data
554 | } catch (error) {
555 | throw error
556 | }
557 | }
558 |
559 | /**
560 | * Post a photo to instagram
561 | * @param photo file path or Buffer
562 | * @param type post type
563 | * @param options
564 | * @returns
565 | */
566 | public addPost = async (photo: string | Buffer, type: 'feed' | 'story' = 'feed', options: MediaConfigureOptions): Promise => {
567 | try {
568 | const dateObj = new Date()
569 | const now = dateObj
570 | .toISOString()
571 | .replace(/T/, ' ')
572 | .replace(/\..+/, ' ')
573 | const offset = dateObj.getTimezoneOffset()
574 |
575 | const responseUpload = await this.uploadPhoto(photo);
576 |
577 | const payloadForm = {
578 | upload_id: responseUpload.upload_id,
579 | timezone_offset: offset,
580 | date_time_original: now,
581 | date_time_digitalized: now,
582 | source_type: '4',
583 | // edits: {
584 | // crop_original_size: [1080, 1080],
585 | // crop_center: [0.0, -0.0],
586 | // crop_zoom: 1.0
587 | // },
588 | ...options
589 | }
590 |
591 | let headers = {
592 | 'authority': 'www.instagram.com',
593 | 'x-ig-www-claim': 'hmac.AR2-43UfYbG2ZZLxh-BQ8N0rqGa-hESkcmxat2RqMAXejXE3',
594 | 'x-instagram-ajax': 'adb961e446b7-hot',
595 | 'content-type': 'application/x-www-form-urlencoded',
596 | 'accept': '*/*',
597 | 'user-agent': config.desktop,
598 | 'x-requested-with': 'XMLHttpRequest',
599 | 'x-csrftoken': parseCookie(this.IgCookie).csrftoken,
600 | 'x-ig-app-id': '1217981644879628',
601 | 'origin': 'https://www.instagram.com',
602 | 'sec-fetch-site': 'same-origin',
603 | 'sec-fetch-mode': 'cors',
604 | 'sec-fetch-dest': 'empty',
605 | 'referer': 'https://www.instagram.com/',
606 | 'accept-language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7',
607 | 'cookie': `${this.IgCookie}`,
608 | }
609 |
610 | const result = await this.FetchIGAPI(
611 | `${config.instagram_api_v1}`,
612 | `/media/${type === 'feed' ? 'configure/' : 'configure_to_story/'}`,
613 | config.android,
614 | { data: new URLSearchParams(Object.entries(payloadForm)).toString(), method: 'POST', headers: headers }
615 | );
616 |
617 | return result?.data
618 | } catch (error) {
619 | throw error
620 | }
621 | }
622 |
623 | /**
624 | *
625 | * @param photo input must be filepath or buffer
626 | */
627 | public changeProfilePicture = async (photo: string | Buffer): Promise => {
628 | const media = Buffer.isBuffer(photo) ? bufferToStream(photo) : fs.createReadStream(photo)
629 |
630 | const form = new FormData();
631 | form.append('profile_pic', media, 'profilepic.jpg')
632 |
633 | const headers = this.buildHeaders(
634 | config.desktop,
635 | {
636 | 'X-CSRFToken': await getCsrfToken(),
637 | ...form.getHeaders()
638 | }
639 | )
640 | const result = await this.FetchIGAPI(config.instagram_base_url, '/accounts/web_change_profile_picture/', config.desktop, {
641 | method: 'post',
642 | data: form,
643 | headers
644 | })
645 |
646 | return result?.data
647 | }
648 | }
649 |
--------------------------------------------------------------------------------
/src/types/HighlightMediaMetadata.ts:
--------------------------------------------------------------------------------
1 | // Generated by https://quicktype.io
2 | //
3 | // To change quicktype's target language, run command:
4 | //
5 | // "Set quicktype target language"
6 |
7 | import { Dimensions, DisplayResource, MediaType, MimeType, PageInfo } from ".";
8 |
9 | /** Instagram Simplified Highlights reels Metadata */
10 | export interface IHighlightsMetadata {
11 | /** Instagram username */
12 | username: string;
13 | /** stories count */
14 | highlights_count: number;
15 | data: IReelsMetadata[];
16 | }
17 |
18 | export interface IReelsMetadata {
19 | title: string;
20 | cover: string;
21 | media_count: number;
22 | highlights_id: string;
23 | highlights: ReelsMediaData[];
24 | }
25 |
26 | export interface ReelsMediaData {
27 | owner: HighlightOwner
28 | media_id: string;
29 | mimetype: string;
30 | taken_at: number;
31 | type: string;
32 | /** Downloadable media url */
33 | url: string;
34 | dimensions: Dimensions;
35 |
36 | }
37 |
38 | export interface HMedia {
39 | data: ReelsData;
40 | status: string;
41 | }
42 |
43 | export interface ReelsData {
44 | reels_media: ReelsMedia[];
45 | }
46 |
47 | export interface ReelsMedia {
48 | __typename: string;
49 | id: string;
50 | latest_reel_media: null;
51 | can_reply: boolean;
52 | owner: HighlightOwner;
53 | items: HighlightItem[];
54 | }
55 |
56 | export interface HighlightItem {
57 | audience: string;
58 | edge_story_media_viewers: EdgeStoryMediaViewers;
59 | __typename: string;
60 | id: string;
61 | dimensions: Dimensions;
62 | display_resources: DisplayResource[];
63 | display_url: string;
64 | media_preview: null | string;
65 | gating_info: null;
66 | fact_check_overall_rating: null;
67 | fact_check_information: null;
68 | sensitivity_friction_info: null;
69 | taken_at_timestamp: number;
70 | expiring_at_timestamp: number;
71 | story_cta_url: null;
72 | story_view_count: null;
73 | is_video: boolean;
74 | owner: HighlightOwner;
75 | tracking_token: string;
76 | tappable_objects: any[];
77 | story_app_attribution: null;
78 | edge_media_to_sponsor_user: EdgeMediaToSponsorUser;
79 | muting_info: null;
80 | has_audio?: boolean;
81 | overlay_image_resources?: null;
82 | video_duration?: number;
83 | video_resources: VideoResource[];
84 | }
85 |
86 | export interface EdgeMediaToSponsorUser {
87 | edges: any[];
88 | }
89 |
90 | export interface EdgeStoryMediaViewers {
91 | count: number;
92 | page_info: PageInfo;
93 | edges: any[];
94 | }
95 |
96 | export interface HighlightOwner {
97 | id: string;
98 | profile_pic_url: string;
99 | username: string;
100 | followed_by_viewer: boolean;
101 | requested_by_viewer: boolean;
102 | __typename?: string;
103 | }
104 |
105 | export interface VideoResource {
106 | src: string;
107 | config_width: number;
108 | config_height: number;
109 | mime_type: string;
110 | profile: string;
111 | }
112 |
--------------------------------------------------------------------------------
/src/types/HighlightMetadata.ts:
--------------------------------------------------------------------------------
1 | import { HighlightOwner } from "./HighlightMediaMetadata";
2 |
3 | export interface ReelsIds {
4 | highlight_id: string;
5 | cover: string;
6 | title: string;
7 | }
8 |
9 | export interface HightlighGraphQL {
10 | data: IHighlightData;
11 | status: string;
12 | }
13 |
14 | export interface IHighlightData {
15 | viewer: null;
16 | user: IHighlightUser;
17 | }
18 |
19 | export interface IHighlightUser {
20 | has_public_story: boolean;
21 | edge_highlight_reels: Edge;
22 | edge_related_profiles: Edge;
23 | }
24 |
25 | export interface Edge {
26 | edges: EdgeElement[];
27 | }
28 |
29 | export interface EdgeElement {
30 | node: Node;
31 | }
32 |
33 | export interface Node {
34 | __typename: string;
35 | id: string;
36 | cover_media: CoverMedia;
37 | cover_media_cropped_thumbnail: CoverMediaCroppedThumbnail;
38 | owner: HighlightOwner;
39 | title: string;
40 | }
41 |
42 | export interface CoverMedia {
43 | thumbnail_src: string;
44 | }
45 |
46 | export interface CoverMediaCroppedThumbnail {
47 | url: string;
48 | }
--------------------------------------------------------------------------------
/src/types/LoginData.ts:
--------------------------------------------------------------------------------
1 | import { IgCookie } from ".";
2 |
3 | export interface LoginData {
4 | cookie: IgCookie
5 | logged_in_user: LoggedInUser;
6 | session_flush_nonce: any;
7 | status: string;
8 | }
9 |
10 | export interface LoggedInUser {
11 | pk: number;
12 | username: string;
13 | full_name: string;
14 | is_private: boolean;
15 | profile_pic_url: string;
16 | profile_pic_id: string;
17 | is_verified: boolean;
18 | follow_friction_type: number;
19 | growth_friction_info: GrowthFrictionInfo;
20 | has_anonymous_profile_picture: boolean;
21 | is_supervision_features_enabled: boolean;
22 | can_boost_post: boolean;
23 | is_business: boolean;
24 | account_type: number;
25 | professional_conversion_suggested_account_type: number;
26 | is_call_to_action_enabled: boolean;
27 | can_see_organic_insights: boolean;
28 | show_insights_terms: boolean;
29 | total_igtv_videos: number;
30 | has_igtv_series: boolean;
31 | reel_auto_archive: string;
32 | has_placed_orders: boolean;
33 | allowed_commenter_type: string;
34 | has_highlight_reels: boolean;
35 | nametag: Nametag;
36 | can_hide_category: boolean;
37 | can_hide_public_contacts: boolean;
38 | should_show_category: boolean;
39 | category: string;
40 | should_show_public_contacts: boolean;
41 | is_using_unified_inbox_for_direct: boolean;
42 | biz_user_inbox_state: number;
43 | wa_addressable: boolean;
44 | wa_eligibility: number;
45 | interop_messaging_user_fbid: number;
46 | can_see_primary_country_in_settings: boolean;
47 | account_badges: any[];
48 | fbid_v2: number;
49 | all_media_count: number;
50 | allow_contacts_sync: boolean;
51 | phone_number: string;
52 | country_code: number;
53 | national_number: number;
54 | }
55 |
56 | export interface GrowthFrictionInfo {
57 | has_active_interventions: boolean;
58 | interventions: Interventions;
59 | }
60 |
61 | export interface Interventions {
62 | }
63 |
64 | export interface Nametag {
65 | mode: number;
66 | gradient: number;
67 | emoji: string;
68 | selfie_sticker: number;
69 | }
70 |
--------------------------------------------------------------------------------
/src/types/MediaConfigureOptions.ts:
--------------------------------------------------------------------------------
1 | // source : https://github.com/dilame/instagram-private-api/blob/master/src/types/media.configure.options.ts
2 |
3 | export interface MediaConfigureOptions {
4 | caption?: string | '';
5 | source_type?: string;
6 | disable_comments?: boolean;
7 | edits?: {
8 | crop_original_size?: [number, number];
9 | crop_center?: [number, number];
10 | crop_zoom?: number | string;
11 | };
12 | extra?: {
13 | source_width: number;
14 | source_height: number;
15 | };
16 |
17 | width?: number;
18 | height?: number;
19 |
20 | scene_capture_type?: string;
21 | media_folder?: string;
22 | software?: string;
23 | // location
24 | geotag_enabled?: '1' | '0';
25 | posting_latitude?: string;
26 | posting_longitude?: string;
27 | media_latitude?: string;
28 | media_longitude?: string;
29 | // string is only for internal use!
30 | location?: MediaLocation | string;
31 | // string is only for internal use!
32 | usertags?: PostingUsertags | string;
33 | }
34 |
35 | export interface PostingUsertags {
36 | in: Array<{ user_id: number | string; position: [number, number] }>;
37 | }
38 |
39 | export interface MediaLocation {
40 | name: string;
41 | lat: number;
42 | lng: number;
43 | address: string;
44 | external_source: string;
45 | external_id: string;
46 | }
47 |
--------------------------------------------------------------------------------
/src/types/PaginatedPosts.ts:
--------------------------------------------------------------------------------
1 | import { PageInfo, PurpleNode } from "./PostMetadata";
2 |
3 | export interface IPaginatedPosts {
4 | count: number;
5 | page_info: PageInfo;
6 | edges: EdgeOwnerToTimelineMediaEdge[];
7 | }
8 |
9 | export interface EdgeOwnerToTimelineMediaEdge {
10 | node: PurpleNode;
11 | }
--------------------------------------------------------------------------------
/src/types/PostFeedResult.ts:
--------------------------------------------------------------------------------
1 | // Generated by https://quicktype.io
2 | //
3 | // To change quicktype's target language, run command:
4 | //
5 | // "Set quicktype target language"
6 |
7 | import { Candidate, CommentInformTreatment, ImageVersions2, MusicMetadata, SharingFrictionInfo } from ".";
8 |
9 | export interface PostFeedResult {
10 | media: Media;
11 | status: string;
12 | }
13 |
14 | export interface Media {
15 | taken_at: number;
16 | pk: string;
17 | id: string;
18 | device_timestamp: number;
19 | media_type: number;
20 | code: string;
21 | client_cache_key: string;
22 | filter_type: number;
23 | accessibility_caption: string;
24 | is_unified_video: boolean;
25 | user: IPostOwnerUser;
26 | can_viewer_reshare: boolean;
27 | caption_is_edited: boolean;
28 | like_and_view_counts_disabled: boolean;
29 | commerciality_status: string;
30 | is_paid_partnership: boolean;
31 | is_visual_reply_commenter_notice_enabled: boolean;
32 | original_media_has_visual_reply_media: boolean;
33 | comment_likes_enabled: boolean;
34 | comment_threading_enabled: boolean;
35 | has_more_comments: boolean;
36 | max_num_visible_preview_comments: number;
37 | preview_comments: any[];
38 | comments: any[];
39 | can_view_more_preview_comments: boolean;
40 | comment_count: number;
41 | hide_view_all_comment_entrypoint: boolean;
42 | image_versions2: ImageVersions2;
43 | original_width: number;
44 | original_height: number;
45 | photo_of_you: boolean;
46 | can_see_insights_as_brand: boolean;
47 | caption: null;
48 | fb_user_tags: FbUserTags;
49 | can_viewer_save: boolean;
50 | organic_tracking_token: string;
51 | sharing_friction_info: SharingFrictionInfo;
52 | comment_inform_treatment: CommentInformTreatment;
53 | product_type: string;
54 | is_in_profile_grid: boolean;
55 | profile_grid_control_enabled: boolean;
56 | deleted_reason: number;
57 | integrity_review_decision: string;
58 | music_metadata: MusicMetadata;
59 | }
60 |
61 | export interface FbUserTags {
62 | in: any[];
63 | }
64 |
65 | export interface IPostOwnerUser {
66 | pk: number;
67 | username: string;
68 | full_name: string;
69 | is_private: boolean;
70 | profile_pic_url: string;
71 | profile_pic_id: string;
72 | has_anonymous_profile_picture: boolean;
73 | can_boost_post: boolean;
74 | can_see_organic_insights: boolean;
75 | show_insights_terms: boolean;
76 | reel_auto_archive: string;
77 | is_unpublished: boolean;
78 | allowed_commenter_type: string;
79 | has_highlight_reels: boolean;
80 | interop_messaging_user_fbid: string;
81 | fbid_v2: string;
82 | }
83 |
--------------------------------------------------------------------------------
/src/types/PostMetadata.ts:
--------------------------------------------------------------------------------
1 | import { MediaType, Typename, User } from '.';
2 |
3 | export interface IGPostMetadata {
4 | /** an Instagram Username */
5 | username: string;
6 | /** Instagram Full Name */
7 | name: string;
8 | /** media id */
9 | media_id: string;
10 | /** post shortcode */
11 | shortcode: string;
12 | /** a timestamp of posted media */
13 | taken_at_timestamp: number;
14 | /** the number of user who like a instagram post */
15 | likes: number;
16 | /** an caption from instagram post */
17 | caption: string;
18 | /** total media */
19 | media_count: number;
20 | /** comment count */
21 | comment_count: number;
22 | /** media urls */
23 | links: links[];
24 | }
25 |
26 | export interface links {
27 | type: string;
28 | /** url of downloadable media */
29 | url: string;
30 | dimensions: Dimensions;
31 | }
32 |
33 | export interface PostGraphQL {
34 | data?: PostData;
35 | extensions?: Extensions;
36 | status?: string;
37 | }
38 |
39 | export interface PostData {
40 | shortcode_media?: ShortcodeMedia;
41 | }
42 |
43 | export interface ShortcodeMedia extends ViewerInfo {
44 | [x: string]: any;
45 | __typename: string;
46 | id: string;
47 | shortcode: string;
48 | dimensions: Dimensions;
49 | gating_info: null;
50 | fact_check_overall_rating: null;
51 | fact_check_information: null;
52 | sensitivity_friction_info: null;
53 | sharing_friction_info: SharingFrictionInfo;
54 | media_overlay_info: null;
55 | media_preview: null;
56 | video_url: string;
57 | display_url: string;
58 | display_resources: DisplayResource[];
59 | is_video: boolean;
60 | tracking_token: string;
61 | upcoming_event: null;
62 | edge_media_to_tagged_user: EdgeMediaToTaggedUser;
63 | edge_media_to_caption: EdgeMediaToCaptionClass;
64 | can_see_insights_as_brand: boolean;
65 | caption_is_edited: boolean;
66 | has_ranked_comments: boolean;
67 | like_and_view_counts_disabled: boolean;
68 | edge_media_to_parent_comment: EdgeMediaToParentCommentClass;
69 | edge_media_to_hoisted_comment: EdgeMediaToCaptionClass;
70 | edge_media_preview_comment: EdgeMediaPreview;
71 | comments_disabled: boolean;
72 | commenting_disabled_for_viewer: boolean;
73 | taken_at_timestamp: number;
74 | edge_media_preview_like: EdgeMediaPreview;
75 | edge_media_to_sponsor_user: EdgeMediaToCaptionClass;
76 | is_affiliate: boolean;
77 | is_paid_partnership: boolean;
78 | location: null;
79 | owner: ShortcodeMediaOwner;
80 | is_ad: boolean;
81 | edge_web_media_to_related_media: EdgeMediaToCaptionClass;
82 | coauthor_producers: any[];
83 | edge_sidecar_to_children: EdgeSidecarToChildren;
84 | edge_related_profiles: EdgeMediaToCaptionClass;
85 | accessibility_caption: null;
86 | dash_info: DashInfo;
87 | has_audio: boolean;
88 | video_view_count: number;
89 | video_play_count: null;
90 | encoding_status: null;
91 | is_published: boolean;
92 | product_type: string;
93 | title: string;
94 | video_duration: number;
95 | thumbnail_src: string;
96 | clips_music_attribution_info: null;
97 | }
98 |
99 | export interface ViewerInfo {
100 | viewer_has_liked: boolean;
101 | viewer_has_saved: boolean;
102 | viewer_has_saved_to_collection: boolean;
103 | viewer_in_photo_of_you: boolean;
104 | viewer_can_reshare: boolean;
105 | }
106 |
107 | export interface DashInfo {
108 | is_dash_eligible: boolean;
109 | video_dash_manifest: string;
110 | number_of_qualities: number;
111 | }
112 |
113 | /**
114 | * Media pixels dimensions
115 | */
116 | export interface Dimensions {
117 | height: number;
118 | width: number;
119 | }
120 |
121 | export interface DisplayResource {
122 | src: string;
123 | config_width: number;
124 | config_height: number;
125 | }
126 |
127 | export interface EdgeMediaPreview {
128 | count: number;
129 | edges: EdgeMediaPreviewCommentEdge[];
130 | }
131 |
132 | export interface EdgeMediaToParentCommentClass {
133 | count: number;
134 | page_info: PageInfo;
135 | edges: EdgeMediaPreviewCommentEdge[];
136 | }
137 |
138 | export interface PurpleNode extends ViewerInfo {
139 | __typename: Typename;
140 | id: string;
141 | text: string;
142 | created_at: number;
143 | did_report_as_spam: boolean;
144 | edge_liked_by: EdgeFollowedByClass;
145 | is_restricted_pending: boolean;
146 | edge_threaded_comments?: EdgeMediaToParentCommentClass;
147 | shortcode: string;
148 | dimensions: Dimensions;
149 | display_url: string;
150 | edge_media_to_tagged_user: EdgeMediaToTaggedUser;
151 | fact_check_overall_rating: null;
152 | fact_check_information: null;
153 | gating_info: null;
154 | sensitivity_friction_info: any;
155 | sharing_friction_info: SharingFrictionInfo;
156 | media_overlay_info: null;
157 | media_preview: null | string;
158 | owner: User;
159 | is_video: boolean;
160 | has_upcoming_event: boolean;
161 | accessibility_caption: null | string;
162 | edge_media_to_caption: EdgeMediaToCaptionClass;
163 | comments_disabled: boolean;
164 | taken_at_timestamp: number;
165 | location: Location | null;
166 | thumbnail_src: string;
167 | thumbnail_resources: DisplayResource[];
168 | coauthor_producers: any[];
169 | dash_info?: DashInfo;
170 | has_audio?: boolean;
171 | tracking_token?: string;
172 | video_url?: string;
173 | video_view_count?: number;
174 | felix_profile_grid_crop?: null;
175 | product_type?: string;
176 | clips_music_attribution_info?: ClipsMusicAttributionInfo;
177 | edge_sidecar_to_children?: EdgeSidecarToChildren;
178 | pinned_for_users: any[];
179 | nft_asset_info: any;
180 | edge_media_to_sponsor_user: EdgeMediaToCaptionClass;
181 | is_affiliate: boolean;
182 | is_paid_partnership: boolean;
183 | }
184 |
185 | export interface EdgeMediaPreviewCommentEdge {
186 | node: PurpleNode;
187 | }
188 |
189 | export interface PageInfo {
190 | has_next_page: boolean;
191 | end_cursor: string;
192 | }
193 |
194 | export interface EdgeFollowedByClass {
195 | count: number;
196 | }
197 |
198 | export interface NodeOwner {
199 | id: string;
200 | is_verified: boolean;
201 | profile_pic_url: string;
202 | username: string;
203 | }
204 |
205 | export interface EdgeMediaToCaptionClass {
206 | edges: EdgeMediaToCaptionEdge[];
207 | }
208 |
209 | export interface EdgeMediaToCaptionEdge {
210 | node: FluffyNode;
211 | }
212 |
213 | export interface FluffyNode {
214 | text: string;
215 | }
216 |
217 | export interface EdgeMediaToTaggedUser {
218 | edges: EdgeMediaToTaggedUserEdge[];
219 | }
220 |
221 | export interface EdgeMediaToTaggedUserEdge {
222 | node: TentacledNode;
223 | }
224 |
225 | export interface TentacledNode {
226 | user: UserNode;
227 | x: number;
228 | y: number;
229 | }
230 |
231 | export interface UserNode {
232 | full_name: string;
233 | followed_by_viewer: boolean;
234 | id: string;
235 | is_verified: boolean;
236 | profile_pic_url: string;
237 | username: string;
238 | }
239 |
240 | export interface EdgeSidecarToChildren {
241 | edges: EdgeSidecarToChildrenEdge[];
242 | }
243 |
244 | export interface EdgeSidecarToChildrenEdge {
245 | __typename: string;
246 | node: StickyNode;
247 | }
248 |
249 | export interface StickyNode {
250 | __typename: string;
251 | id: string;
252 | shortcode: string;
253 | dimensions: Dimensions;
254 | gating_info: null;
255 | fact_check_overall_rating: null;
256 | fact_check_information: null;
257 | sensitivity_friction_info: null;
258 | sharing_friction_info: SharingFrictionInfo;
259 | media_overlay_info: null;
260 | media_preview: string;
261 | display_url: string;
262 | video_url: string;
263 | display_resources: DisplayResource[];
264 | accessibility_caption: string;
265 | is_video: boolean;
266 | tracking_token: string;
267 | upcoming_event: null;
268 | owner: User;
269 | has_upcoming_event: boolean;
270 | dash_info?: DashInfo;
271 | has_audio?: boolean;
272 | video_view_count?: number;
273 | }
274 |
275 | export interface SharingFrictionInfo {
276 | should_have_sharing_friction: boolean;
277 | bloks_app_url: null;
278 | }
279 |
280 | export interface ShortcodeMediaOwner {
281 | id: string;
282 | is_verified: boolean;
283 | profile_pic_url: string;
284 | username: string;
285 | blocked_by_viewer: boolean;
286 | restricted_by_viewer: boolean;
287 | followed_by_viewer: boolean;
288 | full_name: string;
289 | has_blocked_viewer: boolean;
290 | is_embeds_disabled: boolean;
291 | is_private: boolean;
292 | is_unpublished: boolean;
293 | requested_by_viewer: boolean;
294 | pass_tiering_recommendation: boolean;
295 | edge_owner_to_timeline_media: EdgeFollowedByClass;
296 | edge_followed_by: EdgeFollowedByClass;
297 | }
298 |
299 | export interface ClipsMusicAttributionInfo {
300 | artist_name: string;
301 | song_name: string;
302 | uses_original_audio: boolean;
303 | should_mute_audio: boolean;
304 | should_mute_audio_reason: string;
305 | audio_id: string;
306 | }
307 |
308 | export interface Extensions {
309 | is_final?: boolean;
310 | }
--------------------------------------------------------------------------------
/src/types/PostModels.ts:
--------------------------------------------------------------------------------
1 | // Generated by https://quicktype.io
2 | //
3 | // To change quicktype's target language, run command:
4 | //
5 | // "Set quicktype target language"
6 |
7 | import { Dimensions, postType, SharingFrictionInfo } from '.';
8 |
9 | export interface IPostModels {
10 | /** an Instagram Username */
11 | username: string;
12 | /** Instagram Full Name */
13 | name: string;
14 | /** Instagram Post type */
15 | postType: string;
16 | /** media id */
17 | media_id: string;
18 | /** post shortcode */
19 | shortcode: string;
20 | /** a timestamp of posted media */
21 | taken_at_timestamp: number;
22 | /** the number of user who like a instagram post */
23 | likes: number;
24 | /** an caption from instagram post */
25 | caption: string | null;
26 | /** total media */
27 | media_count: number;
28 | /** comment count */
29 | comment_count: number;
30 | /** if post is video */
31 | video_duration: number | null;
32 | /** music info will show if post is Reel */
33 | music?: ClipsMetadata | null;
34 | /** media urls */
35 | links: MediaUrls[];
36 | }
37 |
38 | export interface MediaUrls {
39 | /** Media ID */
40 | id: string;
41 | type: string;
42 | /** url of downloadable media */
43 | url: string;
44 | dimensions: Dimensions;
45 | }
46 |
47 | export interface IRawBody {
48 | items: Item[];
49 | num_results: number;
50 | more_available: boolean;
51 | auto_load_more_enabled: boolean;
52 | }
53 |
54 | export interface Item {
55 | taken_at: number;
56 | pk: number;
57 | id: string;
58 | device_timestamp: number;
59 | media_type: number;
60 | code: string;
61 | client_cache_key: string;
62 | filter_type: number;
63 | is_unified_video: boolean;
64 | user: User;
65 | can_viewer_reshare: boolean;
66 | caption_is_edited: boolean;
67 | like_and_view_counts_disabled: boolean;
68 | featured_products_cta: null;
69 | commerciality_status: string;
70 | is_paid_partnership: boolean;
71 | is_visual_reply_commenter_notice_enabled: boolean;
72 | original_media_has_visual_reply_media: boolean;
73 | comment_likes_enabled: boolean;
74 | comment_threading_enabled: boolean;
75 | has_more_comments: boolean;
76 | max_num_visible_preview_comments: number;
77 | carousel_media_count: number;
78 | carousel_media: CarouselMedia[];
79 | next_max_id: number;
80 | preview_comments: Comment[];
81 | comments: Comment[];
82 | can_view_more_preview_comments: boolean;
83 | comment_count: number;
84 | hide_view_all_comment_entrypoint: boolean;
85 | inline_composer_display_condition: string;
86 | image_versions2: ImageVersions2;
87 | original_width: number;
88 | original_height: number;
89 | like_count: number;
90 | has_liked: boolean;
91 | top_likers: any[];
92 | facepile_top_likers: any[];
93 | photo_of_you: boolean;
94 | can_see_insights_as_brand: boolean;
95 | mashup_info: MashupInfo;
96 | is_dash_eligible: number;
97 | video_dash_manifest: string;
98 | video_codec: string;
99 | number_of_qualities: number;
100 | video_versions: VideoVersion[];
101 | has_audio: boolean;
102 | video_duration: number;
103 | view_count: number;
104 | caption: Caption;
105 | can_viewer_save: boolean;
106 | organic_tracking_token: string;
107 | sharing_friction_info: SharingFrictionInfo;
108 | comment_inform_treatment: CommentInformTreatment;
109 | product_type: string;
110 | is_in_profile_grid: boolean;
111 | profile_grid_control_enabled: boolean;
112 | deleted_reason: number;
113 | integrity_review_decision: string;
114 | music_metadata: MusicMetadata;
115 | clips_metadata: ClipsMetadata;
116 | media_cropping_info: MediaCroppingInfo;
117 | has_translation: boolean;
118 | caption_position: number;
119 | is_reel_media: boolean;
120 | expiring_at: number;
121 | can_reshare: boolean;
122 | can_reply: boolean;
123 | story_static_models: any[];
124 | supports_reel_reactions: boolean;
125 | can_send_custom_emojis: boolean;
126 | show_one_tap_fb_share_tooltip: boolean;
127 | }
128 |
129 | export interface Caption {
130 | pk: number;
131 | user_id: number;
132 | text: string;
133 | type: number;
134 | created_at: number;
135 | created_at_utc: number;
136 | content_type: string;
137 | status: string;
138 | bit_flags: number;
139 | did_report_as_spam: boolean;
140 | share_enabled: boolean;
141 | user: User;
142 | is_covered: boolean;
143 | media_id: number;
144 | private_reply_status: number;
145 | }
146 |
147 | export interface User {
148 | pk: number;
149 | username: string;
150 | full_name: string;
151 | is_private: boolean;
152 | profile_pic_url: string;
153 | profile_pic_id: string;
154 | friendship_status: FriendshipStatus | false;
155 | is_verified: boolean;
156 | follow_friction_type: number;
157 | has_anonymous_profile_picture: boolean;
158 | is_unpublished: boolean;
159 | is_favorite: boolean;
160 | latest_reel_media: number;
161 | has_highlight_reels: boolean;
162 | live_broadcast_id: null;
163 | live_broadcast_visibility: null;
164 | can_boost_post: boolean;
165 | can_see_organic_insights: boolean;
166 | show_insights_terms: boolean;
167 | reel_auto_archive: string;
168 | allowed_commenter_type: string;
169 | interop_messaging_user_fbid: string;
170 | fbid_v2: string;
171 | account_badges: any[];
172 | }
173 |
174 | export interface FriendshipStatus {
175 | following: boolean;
176 | outgoing_request: boolean;
177 | is_bestie: boolean;
178 | is_restricted: boolean;
179 | is_feed_favorite: boolean;
180 | followed_by: boolean;
181 | blocking: boolean;
182 | muting: boolean;
183 | is_private: boolean;
184 | incoming_request: boolean;
185 | }
186 |
187 | export interface CarouselMedia {
188 | id: string;
189 | media_type: number;
190 | image_versions2: ImageVersions2;
191 | original_width: number;
192 | original_height: number;
193 | pk: number;
194 | carousel_parent_id: string;
195 | can_see_insights_as_brand: boolean;
196 | usertags?: Usertags;
197 | commerciality_status: string;
198 | sharing_friction_info: SharingFrictionInfo;
199 | comment_inform_treatment: CommentInformTreatment;
200 | video_versions?: VideoVersion[];
201 | video_duration?: number;
202 | is_dash_eligible?: number;
203 | video_dash_manifest?: string;
204 | video_codec?: string;
205 | number_of_qualities?: number;
206 | }
207 |
208 | export interface CommentInformTreatment {
209 | should_have_inform_treatment: boolean;
210 | text: string;
211 | }
212 |
213 | export interface ClipsMetadata {
214 | music_info: MusicInfo;
215 | original_sound_info: OriginalSoundInfo;
216 | audio_type: string;
217 | music_canonical_id: string;
218 | featured_label: null;
219 | mashup_info: MashupInfo;
220 | nux_info: null;
221 | viewer_interaction_settings: null;
222 | branded_content_tag_info: BrandedContentTagInfo;
223 | shopping_info: null;
224 | additional_audio_info: AdditionalAudioInfo;
225 | is_shared_to_fb: boolean;
226 | breaking_content_info: null;
227 | challenge_info: null;
228 | reels_on_the_rise_info: null;
229 | breaking_creator_info: null;
230 | asset_recommendation_info: null;
231 | contextual_highlight_info: null;
232 | clips_creation_entry_point: string;
233 | audio_ranking_info: AudioRankingInfo;
234 | }
235 |
236 | export interface AdditionalAudioInfo {
237 | additional_audio_username: null;
238 | audio_reattribution_info: AudioReattributionInfo;
239 | }
240 |
241 | export interface AudioReattributionInfo {
242 | should_allow_restore: boolean;
243 | }
244 |
245 | export interface AudioRankingInfo {
246 | best_audio_cluster_id: string;
247 | }
248 |
249 | export interface BrandedContentTagInfo {
250 | can_add_tag: boolean;
251 | }
252 |
253 | export interface MashupInfo {
254 | mashups_allowed: boolean;
255 | can_toggle_mashups_allowed: boolean;
256 | has_been_mashed_up: boolean;
257 | formatted_mashups_count: null;
258 | original_media: null;
259 | non_privacy_filtered_mashups_media_count: null;
260 | }
261 |
262 | export interface MusicInfo {
263 | music_asset_info: MusicAssetInfo;
264 | music_consumption_info: MusicConsumptionInfo;
265 | push_blocking_test: null;
266 | }
267 |
268 | export interface MusicAssetInfo {
269 | audio_cluster_id: string;
270 | id: string;
271 | title: string;
272 | subtitle: string;
273 | display_artist: string;
274 | artist_id: string;
275 | cover_artwork_uri: string;
276 | cover_artwork_thumbnail_uri: string;
277 | progressive_download_url: string;
278 | reactive_audio_download_url: null;
279 | fast_start_progressive_download_url: string;
280 | highlight_start_times_in_ms: number[];
281 | is_explicit: boolean;
282 | dash_manifest: null;
283 | has_lyrics: boolean;
284 | audio_asset_id: string;
285 | duration_in_ms: number;
286 | dark_message: null;
287 | allows_saving: boolean;
288 | territory_validity_periods: TerritoryValidityPeriods;
289 | }
290 |
291 | export interface TerritoryValidityPeriods {}
292 |
293 | export interface MusicConsumptionInfo {
294 | ig_artist: CoauthorProducer;
295 | placeholder_profile_pic_url: string;
296 | should_mute_audio: boolean;
297 | should_mute_audio_reason: string[];
298 | is_bookmarked: boolean;
299 | overlap_duration_in_ms: number;
300 | audio_asset_start_time_in_ms: number;
301 | allow_media_creation_with_music: boolean;
302 | is_trending_in_clips: boolean;
303 | formatted_clips_media_count: null;
304 | streaming_services: null;
305 | display_labels: null;
306 | }
307 |
308 | export interface CoauthorProducer {
309 | pk: number;
310 | username: string;
311 | full_name: string;
312 | is_private: boolean;
313 | profile_pic_url: string;
314 | profile_pic_id?: string;
315 | is_verified: boolean;
316 | follow_friction_type: number;
317 | friendship_status?: CoauthorProducerFriendshipStatus;
318 | }
319 |
320 | export interface CoauthorProducerFriendshipStatus {
321 | following: boolean;
322 | followed_by: boolean;
323 | blocking: boolean;
324 | muting: boolean;
325 | is_private: boolean;
326 | incoming_request: boolean;
327 | outgoing_request: boolean;
328 | is_bestie: boolean;
329 | is_restricted: boolean;
330 | is_feed_favorite: boolean;
331 | }
332 |
333 | export interface OriginalSoundInfo {
334 | audio_asset_id: number;
335 | progressive_download_url: string;
336 | dash_manifest: string;
337 | ig_artist: IgArtist;
338 | should_mute_audio: boolean;
339 | original_media_id: number;
340 | hide_remixing: boolean;
341 | duration_in_ms: number;
342 | time_created: number;
343 | original_audio_title: string[];
344 | consumption_info: ConsumptionInfo;
345 | allow_creator_to_rename: boolean;
346 | can_remix_be_shared_to_fb: boolean;
347 | formatted_clips_media_count: null;
348 | audio_parts: any[];
349 | is_explicit: boolean;
350 | original_audio_subtype: string;
351 | is_audio_automatically_attributed: boolean;
352 | }
353 |
354 | export interface ConsumptionInfo {
355 | is_bookmarked: boolean;
356 | should_mute_audio_reason: string;
357 | is_trending_in_clips: boolean;
358 | }
359 |
360 | export interface IgArtist {
361 | pk: number;
362 | username: string;
363 | full_name: string;
364 | is_private: boolean;
365 | profile_pic_url: string;
366 | profile_pic_id: string;
367 | is_verified: boolean;
368 | follow_friction_type: number;
369 | friendship_status?: IgArtistFriendshipStatus;
370 | }
371 |
372 | export interface IgArtistFriendshipStatus {
373 | following: boolean;
374 | followed_by: boolean;
375 | blocking: boolean;
376 | muting: boolean;
377 | is_private: boolean;
378 | incoming_request: boolean;
379 | outgoing_request: boolean;
380 | is_bestie: boolean;
381 | is_restricted: boolean;
382 | is_feed_favorite: boolean;
383 | }
384 |
385 | export interface Usertags {
386 | in: In[];
387 | }
388 |
389 | export interface In {
390 | user: InUser;
391 | position: number[];
392 | start_time_in_video_in_sec: null;
393 | duration_in_video_in_sec: null;
394 | }
395 |
396 | export interface InUser {
397 | pk: number;
398 | username: string;
399 | full_name: string;
400 | is_private: boolean;
401 | profile_pic_url: string;
402 | profile_pic_id: string;
403 | is_verified: boolean;
404 | follow_friction_type: number;
405 | }
406 |
407 | export interface VideoVersion {
408 | type: number;
409 | width: number;
410 | height: number;
411 | url: string;
412 | id: string;
413 | }
414 |
415 | export interface Location {
416 | pk: number;
417 | short_name: string;
418 | facebook_places_id: number;
419 | external_source: string;
420 | name: string;
421 | address: string;
422 | city: string;
423 | has_viewer_saved: boolean;
424 | lng: number;
425 | lat: number;
426 | is_eligible_for_guides: boolean;
427 | }
428 |
429 | export interface ImageVersions2 {
430 | candidates: FirstFrame[];
431 | additional_candidates: AdditionalCandidates;
432 | animated_thumbnail_spritesheet_info_candidates: AnimatedThumbnailSpritesheetInfoCandidates;
433 | }
434 |
435 | export interface AdditionalCandidates {
436 | igtv_first_frame: FirstFrame;
437 | first_frame: FirstFrame;
438 | }
439 |
440 | export interface FirstFrame {
441 | width: number;
442 | height: number;
443 | url: string;
444 | }
445 |
446 | export interface AnimatedThumbnailSpritesheetInfoCandidates {
447 | default: Default;
448 | }
449 |
450 | export interface Default {
451 | video_length: number;
452 | thumbnail_width: number;
453 | thumbnail_height: number;
454 | thumbnail_duration: number;
455 | sprite_urls: string[];
456 | thumbnails_per_row: number;
457 | total_thumbnail_num_per_sprite: number;
458 | max_thumbnails_per_sprite: number;
459 | sprite_width: number;
460 | sprite_height: number;
461 | rendered_width: number;
462 | file_size_kb: number;
463 | }
464 |
465 | export interface Candidate {
466 | width: number;
467 | height: number;
468 | url: string;
469 | }
470 |
471 | export interface MusicMetadata {
472 | music_canonical_id: string;
473 | audio_type: null;
474 | music_info: null;
475 | original_sound_info: null;
476 | }
477 |
478 | export interface MediaCroppingInfo {
479 | feed_preview_crop: null;
480 | square_crop: SquareCrop;
481 | }
482 |
483 | export interface SquareCrop {
484 | crop_bottom: number;
485 | crop_left: number;
486 | crop_right: number;
487 | crop_top: number;
488 | }
489 |
490 | export interface CommentInformTreatment {
491 | should_have_inform_treatment: boolean;
492 | text: string;
493 | }
494 |
495 | export interface Comment {
496 | pk: number;
497 | user_id: number;
498 | text: string;
499 | type: number;
500 | created_at: number;
501 | created_at_utc: number;
502 | content_type: string;
503 | status: string;
504 | bit_flags: number;
505 | did_report_as_spam: boolean;
506 | share_enabled: boolean;
507 | user: CommentUser;
508 | is_covered: boolean;
509 | media_id: number;
510 | has_liked_comment: boolean;
511 | comment_like_count: number;
512 | private_reply_status: number;
513 | parent_comment_id?: number;
514 | }
515 |
516 | export interface CommentUser {
517 | pk: number;
518 | username: string;
519 | full_name: string;
520 | is_private: boolean;
521 | profile_pic_url: string;
522 | profile_pic_id: string;
523 | is_verified: boolean;
524 | follow_friction_type: number;
525 | }
526 |
527 | export interface ItemUser {
528 | pk: number;
529 | username: string;
530 | full_name: string;
531 | is_private: boolean;
532 | profile_pic_url: string;
533 | profile_pic_id: string;
534 | friendship_status: FriendshipStatus;
535 | is_verified: boolean;
536 | follow_friction_type: number;
537 | has_anonymous_profile_picture: boolean;
538 | is_unpublished: boolean;
539 | is_favorite: boolean;
540 | latest_reel_media: number;
541 | has_highlight_reels: boolean;
542 | live_broadcast_id: null;
543 | live_broadcast_visibility: null;
544 | }
545 |
546 | export interface FriendshipStatus {
547 | following: boolean;
548 | outgoing_request: boolean;
549 | is_bestie: boolean;
550 | is_restricted: boolean;
551 | is_feed_favorite: boolean;
552 | }
553 |
--------------------------------------------------------------------------------
/src/types/PostStoryResult.ts:
--------------------------------------------------------------------------------
1 | // Generated by https://quicktype.io
2 | //
3 | // To change quicktype's target language, run command:
4 | //
5 | // "Set quicktype target language"
6 |
7 | import { CommentInformTreatment, ImageVersions2, SharingFrictionInfo, User } from ".";
8 |
9 | export interface PostStoryResult {
10 | media: StoryMedia;
11 | status: string;
12 | }
13 |
14 | export interface StoryMedia {
15 | taken_at: number;
16 | pk: string;
17 | id: string;
18 | device_timestamp: number;
19 | media_type: number;
20 | code: string;
21 | client_cache_key: string;
22 | filter_type: number;
23 | is_unified_video: boolean;
24 | user: User;
25 | caption_is_edited: boolean;
26 | like_and_view_counts_disabled: boolean;
27 | commerciality_status: string;
28 | is_paid_partnership: boolean;
29 | is_visual_reply_commenter_notice_enabled: boolean;
30 | original_media_has_visual_reply_media: boolean;
31 | comment_likes_enabled: boolean;
32 | comment_threading_enabled: boolean;
33 | has_more_comments: boolean;
34 | max_num_visible_preview_comments: number;
35 | preview_comments: any[];
36 | comments: any[];
37 | can_view_more_preview_comments: boolean;
38 | comment_count: number;
39 | hide_view_all_comment_entrypoint: boolean;
40 | image_versions2: ImageVersions2;
41 | original_width: number;
42 | original_height: number;
43 | caption_position: number;
44 | is_reel_media: boolean;
45 | timezone_offset: number;
46 | like_count: number;
47 | has_liked: boolean;
48 | likers: any[];
49 | photo_of_you: boolean;
50 | can_see_insights_as_brand: boolean;
51 | caption: null;
52 | can_viewer_save: boolean;
53 | organic_tracking_token: string;
54 | expiring_at: number;
55 | sharing_friction_info: SharingFrictionInfo;
56 | comment_inform_treatment: CommentInformTreatment;
57 | product_type: string;
58 | is_in_profile_grid: boolean;
59 | profile_grid_control_enabled: boolean;
60 | deleted_reason: number;
61 | integrity_review_decision: string;
62 | music_metadata: null;
63 | can_reshare: boolean;
64 | can_reply: boolean;
65 | story_is_saved_to_archive: boolean;
66 | story_static_models: any[];
67 | viewers: any[];
68 | viewer_count: number;
69 | fb_viewer_count: null;
70 | viewer_cursor: null;
71 | total_viewer_count: number;
72 | multi_author_reel_names: any[];
73 | supports_reel_reactions: boolean;
74 | can_send_custom_emojis: boolean;
75 | show_one_tap_fb_share_tooltip: boolean;
76 | has_shared_to_fb: number;
77 | has_shared_to_fb_dating: number;
78 | source_type: number;
79 | }
--------------------------------------------------------------------------------
/src/types/StoriesMetadata.ts:
--------------------------------------------------------------------------------
1 | import { CommentInformTreatment, FriendshipStatus, ImageVersions2, Item, MediaType, MimeType, SharingFrictionInfo, User } from '.';
2 |
3 | /** Instagram Simplified Stories Metadata */
4 | export interface IGStoriesMetadata {
5 | /** Instagram username */
6 | username: string;
7 | /** stories count */
8 | stories_count: number;
9 | stories: ItemStories[] | null;
10 | graphql: StoriesGraphQL;
11 | }
12 |
13 | /** an Array of simplified StoriesMetadata */
14 | export interface ItemStories {
15 | type: string;
16 | mimetpye: MimeType;
17 | /** Downloadable media url */
18 | url: string;
19 | /** a timestamp of posted media */
20 | taken_at: number;
21 | /** a timestamp of expire stories */
22 | expiring_at: number;
23 | /** stories media id */
24 | id: number;
25 | /** media pixels weight */
26 | original_width: number;
27 | /** media pixels height */
28 | original_height: number;
29 | /** has audio */
30 | has_audio: boolean;
31 | /** video duration */
32 | video_duration: number;
33 | /** stories caption */
34 | caption: string;
35 | }
36 |
37 | export interface StoriesGraphQL {
38 | id: number;
39 | latest_reel_media: number;
40 | expiring_at: number;
41 | seen: number;
42 | can_reply: boolean;
43 | can_gif_quick_reply: boolean;
44 | can_reshare: boolean;
45 | reel_type: string;
46 | ad_expiry_timestamp_in_millis: null;
47 | is_cta_sticker_available: null;
48 | user: User;
49 | items: Item[];
50 | prefetch_count: number;
51 | has_besties_media: boolean;
52 | media_count: number;
53 | media_ids: number[];
54 | has_fan_club_media: boolean;
55 | status: string;
56 | }
--------------------------------------------------------------------------------
/src/types/UserGraphQlV2.ts:
--------------------------------------------------------------------------------
1 | import { PageInfo } from ".";
2 |
3 | export interface Graphql {
4 | data?: Data;
5 | status?: string;
6 | }
7 |
8 | export interface Data {
9 | user?: UserGraphQlV2;
10 | }
11 |
12 | export interface UserGraphQlV2 {
13 | ai_agent_type?: null;
14 | biography?: string;
15 | bio_links?: BioLink[];
16 | fb_profile_biolink?: null;
17 | biography_with_entities?: BiographyWithEntities;
18 | blocked_by_viewer?: boolean;
19 | restricted_by_viewer?: boolean;
20 | country_block?: boolean;
21 | eimu_id?: string;
22 | external_url?: string;
23 | external_url_linkshimmed?: string;
24 | edge_followed_by?: EdgeFollow;
25 | fbid?: string;
26 | followed_by_viewer?: boolean;
27 | edge_follow?: EdgeFollow;
28 | follows_viewer?: boolean;
29 | full_name?: string;
30 | group_metadata?: null;
31 | has_ar_effects?: boolean;
32 | has_clips?: boolean;
33 | has_guides?: boolean;
34 | has_chaining?: boolean;
35 | has_channel?: boolean;
36 | has_blocked_viewer?: boolean;
37 | highlight_reel_count?: number;
38 | has_requested_viewer?: boolean;
39 | hide_like_and_view_counts?: boolean;
40 | id?: string;
41 | is_business_account?: boolean;
42 | is_professional_account?: boolean;
43 | is_supervision_enabled?: boolean;
44 | is_guardian_of_viewer?: boolean;
45 | is_supervised_by_viewer?: boolean;
46 | is_supervised_user?: boolean;
47 | is_embeds_disabled?: boolean;
48 | is_joined_recently?: boolean;
49 | guardian_id?: null;
50 | business_address_json?: null;
51 | business_contact_method?: string;
52 | business_email?: null;
53 | business_phone_number?: null;
54 | business_category_name?: null;
55 | overall_category_name?: null;
56 | category_enum?: null;
57 | category_name?: null;
58 | is_private?: boolean;
59 | is_verified?: boolean;
60 | is_verified_by_mv4b?: boolean;
61 | is_regulated_c18?: boolean;
62 | edge_mutual_followed_by?: EdgeMutualFollowedBy;
63 | pinned_channels_list_count?: number;
64 | profile_pic_url?: string;
65 | profile_pic_url_hd?: string;
66 | requested_by_viewer?: boolean;
67 | should_show_category?: boolean;
68 | should_show_public_contacts?: boolean;
69 | show_account_transparency_details?: boolean;
70 | transparency_label?: null;
71 | transparency_product?: null;
72 | username?: string;
73 | connected_fb_page?: null;
74 | pronouns?: any[];
75 | edge_owner_to_timeline_media?: EdgeOwnerToTimelineMedia;
76 | }
77 |
78 | export interface BioLink {
79 | title?: string;
80 | lynx_url?: string;
81 | url?: string;
82 | link_type?: string;
83 | }
84 |
85 | export interface BiographyWithEntities {
86 | raw_text?: string;
87 | entities?: any[];
88 | }
89 |
90 | export interface EdgeFollow {
91 | count?: number;
92 | }
93 |
94 | export interface EdgeMutualFollowedBy {
95 | count?: number;
96 | edges?: EdgeUser[];
97 | }
98 |
99 | export interface EdgeUser {
100 | node?: NodeUsername;
101 | }
102 |
103 | export interface NodeUsername {
104 | username?: string;
105 | }
106 |
107 | export interface EdgeOwnerToTimelineMedia {
108 | count?: number;
109 | page_info?: PageInfo;
110 | edges?: any[];
111 | }
112 |
--------------------------------------------------------------------------------
/src/types/UserMetadata.ts:
--------------------------------------------------------------------------------
1 | export interface IGUserMetadata {
2 | /** Instagram user id */
3 | id: number;
4 | /** Instagram username */
5 | username: string;
6 | /** full name of instagram account */
7 | fullname: string;
8 | /** followers count */
9 | followers: number;
10 | /** following count */
11 | following: number;
12 | /** total post */
13 | post_count: number;
14 | /** is_private? */
15 | is_private: boolean;
16 | is_verified: boolean;
17 | /** full instagram bio */
18 | biography: string;
19 | /** external url given by user */
20 | external_url: string;
21 | /** total of an IGTV videos if has igtv post */
22 | total_igtv_videos: number;
23 | has_videos: boolean;
24 | /** url of instagram profile picture at HD / Original Quality */
25 | hd_profile_pic_url_info: HDProfilePic;
26 | has_highlight_reels: boolean;
27 | has_guides: boolean;
28 | is_business: boolean;
29 | /** contact phone number if user set their phone number to public */
30 | contact_phone_number: string;
31 | /** contact email */
32 | public_email: string;
33 | /** account type e.g Business | Personal .etc */
34 | account_type: number;
35 | }
36 |
37 | export interface UserGraphQL {
38 | user: UserDetails;
39 | status: string;
40 | }
41 |
42 | export interface UserDetails {
43 | pk: number;
44 | username: string;
45 | full_name: string;
46 | is_private: boolean;
47 | profile_pic_url: string;
48 | profile_pic_id: string;
49 | is_verified: boolean;
50 | follow_friction_type: number;
51 | has_anonymous_profile_picture: boolean;
52 | media_count: number;
53 | geo_media_count: number;
54 | follower_count: number;
55 | following_count: number;
56 | following_tag_count: number;
57 | biography: string;
58 | external_url: string;
59 | external_lynx_url: string;
60 | show_fb_link_on_profile: boolean;
61 | primary_profile_link_type: number;
62 | has_biography_translation: boolean;
63 | total_igtv_videos: number;
64 | has_videos: boolean;
65 | total_ar_effects: number;
66 | usertags_count: number;
67 | is_favorite: boolean;
68 | is_interest_account: boolean;
69 | has_chaining: boolean;
70 | hd_profile_pic_versions: HDProfilePic[];
71 | hd_profile_pic_url_info: HDProfilePic;
72 | mutual_followers_count: number;
73 | profile_context: string;
74 | profile_context_links_with_user_ids: ProfileContextLinksWithUserID[];
75 | profile_context_mutual_follow_ids: number[];
76 | has_highlight_reels: boolean;
77 | has_guides: boolean;
78 | can_be_reported_as_fraud: boolean;
79 | is_eligible_for_smb_support_flow: boolean;
80 | smb_support_partner: null;
81 | direct_messaging: string;
82 | address_street: string;
83 | business_contact_method: string;
84 | category: string;
85 | city_id: number;
86 | city_name: string;
87 | contact_phone_number: string;
88 | is_call_to_action_enabled: boolean;
89 | latitude: number;
90 | longitude: number;
91 | public_email: string;
92 | public_phone_country_code: string;
93 | public_phone_number: string;
94 | zip: string;
95 | instagram_location_id: string;
96 | is_business: boolean;
97 | professional_conversion_suggested_account_type: number;
98 | account_type: number;
99 | can_hide_category: boolean;
100 | can_hide_public_contacts: boolean;
101 | should_show_category: boolean;
102 | should_show_public_contacts: boolean;
103 | interop_messaging_user_fbid: number;
104 | account_badges: any[];
105 | include_direct_blacklist_status: boolean;
106 | is_potential_business: boolean;
107 | show_post_insights_entry_point: boolean;
108 | request_contact_enabled: boolean;
109 | is_bestie: boolean;
110 | has_unseen_besties_media: boolean;
111 | show_account_transparency_details: boolean;
112 | auto_expand_chaining: boolean;
113 | highlight_reshare_disabled: boolean;
114 | is_memorialized: boolean;
115 | open_external_url_with_in_app_browser: boolean;
116 | }
117 |
118 | export interface HDProfilePic {
119 | width: number;
120 | height: number;
121 | url: string;
122 | }
123 |
124 | export interface ProfileContextLinksWithUserID {
125 | start: number;
126 | end: number;
127 | username: string;
128 | }
129 |
--------------------------------------------------------------------------------
/src/types/index.ts:
--------------------------------------------------------------------------------
1 | export * from './HighlightMediaMetadata'
2 | export * from './HighlightMetadata'
3 | export * from './MediaConfigureOptions'
4 | export * from './PostFeedResult'
5 | export * from './PostMetadata'
6 | export * from './PostModels'
7 | export * from './PostStoryResult'
8 | export * from './StoriesMetadata'
9 | export * from './UserGraphQlV2'
10 | export * from './UserMetadata'
11 | export * from './PaginatedPosts'
12 | export * from './LoginData'
13 | export * from './searchFollow'
14 |
15 | /** instagram username */
16 | export type username = string;
17 | /** instagram user pk */
18 | export type userId = string;
19 | /** term to search for a user, it can be their name or username */
20 | export type seachTerm = string;
21 | /** instagram password */
22 | export type password = string;
23 | /** Instagram Cookie */
24 | export type IgCookie = string;
25 | /** instagram post url can be post, reel, tv */
26 | export type url = string;
27 | /** Media Type */
28 | export enum MediaType {
29 | IMAGE = 1,
30 | VIDEO = 2,
31 | CAROUSEL = 8
32 | }
33 | export enum ProductType {
34 | CAROUSEL = 'carousel_container',
35 | REEL = 'clips',
36 | TV = 'igtv',
37 | SINGLE = 'feed'
38 | }
39 |
40 | export enum Typename {
41 | GraphImage = "GraphImage",
42 | GraphSidecar = "GraphSidecar",
43 | GraphVideo = "GraphVideo",
44 | }
45 |
46 | export enum IGPostType {
47 | 'carousel_container' = 'p',
48 | 'clips' = 'reel',
49 | 'igtv' = 'tv',
50 | 'feed' = 'p'
51 | }
52 | /** Mime Type */
53 | export type MimeType = 'image/jpeg' | 'image/png' | 'video/mp4' | 'video/gif';
54 | /** csrf token */
55 | export type csrfToken = string;
56 | /** instagram post type */
57 | export type postType = 'p' | 'reel' | 'tv'
58 | /** a formatted shortcode */
59 | export interface formattedShortcode {
60 | type: postType | string,
61 | shortcode: string;
62 | url: string;
63 | media_id: number | string
64 | }
65 |
66 | export interface IChangedProfilePicture {
67 | changed_profile: boolean
68 | id: number,
69 | has_profile_pic: boolean,
70 | profile_pic_url: string
71 | profile_pic_url_hd: string
72 | status: string
73 | }
--------------------------------------------------------------------------------
/src/types/searchFollow.ts:
--------------------------------------------------------------------------------
1 | import { User } from "./PostModels";
2 |
3 | export interface ISearchFollow {
4 | users?: UserFollow[];
5 | big_list?: boolean;
6 | page_size?: number;
7 | has_more?: boolean;
8 | should_limit_list_of_followers?: boolean;
9 | use_clickable_see_more?: boolean;
10 | show_spam_follow_request_tab?: boolean;
11 | status?: string;
12 | }
13 |
14 | export type UserFollow = User & {
15 | pk_id?: string;
16 | third_party_downloads_enabled?: number;
17 | strong_id__?: string;
18 | }
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | import { Readable } from 'stream';
2 | import { formattedShortcode, IGPostType, postType, ProductType } from '../types/index';
3 | import bigInt from 'big-integer';
4 | import { createHmac } from 'crypto';
5 |
6 | // https://stackoverflow.com/questions/16758316/where-do-i-find-the-instagram-media-id-of-a-image
7 | // https://gist.github.com/sclark39/9daf13eea9c0b381667b61e3d2e7bc11
8 | const lower = 'abcdefghijklmnopqrstuvwxyz';
9 | const upper = lower.toUpperCase();
10 | const numbers = '0123456789'
11 | const ig_alphabet = upper + lower + numbers + '-_'
12 | const bigint_alphabet = numbers + lower
13 | /**
14 | * convert instagram shortcode into media_id
15 | * @param shortcode
16 | * @returns
17 | */
18 | export const shortcodeToMediaID = (shortcode: string) => {
19 | const o = shortcode.replace(/\S/g, m => {
20 | var c = ig_alphabet.indexOf(m)
21 | var b = bigint_alphabet.charAt(c)
22 | return (b != "") ? b : `<${c}>`
23 | })
24 | return bigInt(o, 64).toString(10)
25 | }
26 |
27 | export const shortcodeFromMediaID = (media_id: string) => {
28 | var o = bigInt(media_id).toString(64)
29 | return o.replace(/<(\d+)>|(\w)/g, (_m: any, m1: string, m2: string) => {
30 | return ig_alphabet.charAt((m1)
31 | ? parseInt(m1)
32 | : bigint_alphabet.indexOf(m2))
33 | });
34 | }
35 |
36 | /** Instagram post regex */
37 | export const IGPostRegex = /(?:https?:\/\/)?(?:www\.)?(?:instagram\.com(?:\/.+?)?\/(p|reel(?:s|)|tv)\/)([\w-]+)(?:\/)?(\?.*)?$/gim
38 |
39 | /**
40 | * format instagram long url to get shortcode
41 | * @param url a instagram post url
42 | * @returns {formattedShortcode}
43 | */
44 | export const shortcodeFormatter = (url: string): formattedShortcode => {
45 | const splitted = /(?:https?:\/\/)?(?:www\.)?(?:instagram\.com(?:\/.+?)?\/(p|reel(?:s|)|tv)\/)([\w-]+)(?:\/)?(\?.*)?$/gim.exec(url) || '';
46 | return {
47 | type: splitted[1],
48 | shortcode: splitted[2],
49 | url: 'https://www.instagram.com/' + splitted[1] + '/' + splitted[2],
50 | media_id: shortcodeToMediaID(splitted[2])
51 | }
52 | };
53 |
54 | /**
55 | * is Instagram Url?
56 | * @param url instagram post url
57 | * @returns
58 | */
59 | export const isIgPostUrl = (url: string): boolean => {
60 | return /(?:https?:\/\/)?(?:www\.)?(?:instagram\.com(?:\/.+?)?\/(p|reel(?:s|)|tv)\/)([\w-]+)(?:\/)?(\?.*)?$/gim.test(url);
61 | }
62 |
63 | /**
64 | * get instagram post type
65 | * @param type product_type
66 | * @returns
67 | */
68 | export const getPostType = (type: string): postType => {
69 | return type == ProductType.CAROUSEL
70 | ? IGPostType.carousel_container
71 | : type == ProductType.REEL
72 | ? IGPostType.clips
73 | : type == ProductType.SINGLE
74 | ? IGPostType.feed
75 | : type == ProductType.TV
76 | ? IGPostType.igtv
77 | : IGPostType.feed
78 | }
79 |
80 | /** get random number in range */
81 | export const randInt = (min: number, max: number, q = 0.001): number => {
82 | return Math.floor((Math.random() * (min - max)) / q) * q
83 | }
84 |
85 | // https://stackoverflow.com/questions/13230487/converting-a-buffer-into-a-readablestream-in-node-js
86 | export const bufferToStream = (buffer: Buffer) => {
87 | const readable = new Readable()
88 | readable._read = () => { } // _read is required but you can noop it
89 | readable.push(buffer)
90 | readable.push(null)
91 | return readable
92 | }
93 |
94 | export const formatCookie = (setCookie: string[] | undefined) => {
95 | return setCookie?.map(x => x.match(/(.*?=.*?);/)?.[1])?.join('; ');
96 | }
97 |
98 | export const parseCookie = (str: string) => {
99 | return str.split(';')
100 | .map(v => v.trim().split('='))
101 | .reduce((acc: any, v) => {
102 | acc[decodeURIComponent(v[0])] = decodeURIComponent(v[1]);
103 | delete acc['']
104 | return acc;
105 | }, {});
106 | }
--------------------------------------------------------------------------------
/tea.yaml:
--------------------------------------------------------------------------------
1 | # https://tea.xyz/what-is-this-file
2 | ---
3 | version: 1.0.0
4 | codeOwners:
5 | - '0xBf3Ea78f403cA79E4D7F75C9cc0aF84EFc8A5a98'
6 | quorum: 1
7 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2016",
4 | "module": "commonjs",
5 | "rootDir": "src",
6 | "baseUrl": "src",
7 | "declaration": true,
8 | "outDir": "./dist",
9 | "esModuleInterop": true,
10 | "forceConsistentCasingInFileNames": true,
11 | "strict": true,
12 | "skipLibCheck": true,
13 | "typeRoots": ["./node_modules/@types"]
14 | },
15 | "include": ["src/**/*.*"],
16 | "exclude": ["node_modules"]
17 | }
18 |
--------------------------------------------------------------------------------
/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/index.ts"],
3 | "excludePrivate": true,
4 | "excludeProtected": true,
5 | "excludeExternals": true,
6 | "includeVersion": true,
7 | "out": "docs"
8 | }
--------------------------------------------------------------------------------