Compare commits

...
23 Commits
Author SHA1 Message Date
Alexander Graf 3338260f5d Release of version 4.16 2026-10-26 22:31:03 +01:00
Alexander Graf 49b0df42b4 Merge branch 'upcoming/v4.16' 2026-10-26 22:30:31 +01:00
Alexander Graf 756f097626 Prevent user_id setter 2026-10-26 22:12:33 +01:00
Vassilis Papadimas 9e0158de54 fix get_iphone_json: send derived bearer token and correct user_id (#2771) 2026-10-26 22:06:39 +01:00
Alexander Graf d035c9b7c7 Update dependencies 2026-10-26 21:54:49 +01:00
Alexander Graf 00a6784029 Fix Profile.from_id() 2026-10-26 21:44:16 +01:00
Alexander Graf 09dea80d2b Release of version 4.15.5 2026-10-24 16:26:56 +02:00
Alexander Graf 56493a8a78 First Release Candidate for Version 4.16 2026-10-24 16:21:33 +02:00
Alexander Graf a7119ef1e3 Merge branch 'master' into upcoming/v4.16 2026-10-24 16:05:19 +02:00
André Koch-Kramer bf3f6e2bfb Remove PolarisFeedShareMenu relay provider from NodeIterator 2026-10-24 15:14:18 +02:00
Alexander Graf 5b27110476 NodeIterator: keep first_item besides first_node to spare wrapper invocations
The NodeIterator is sometimes invocated with node wrappers that are heavy to
invocate, e.g. because they trigger requests. Storing the resulting item
besides the node allows to avoid those extra requests.

In the FrozenNodeIterator, the node is still saved, rather than the item.
2026-10-24 12:03:46 +02:00
Alexander Graf 221cd7f8bc Add versionchanged directive for Profile.mediacount 2026-10-24 11:22:10 +02:00
Alexander Graf 328e93b0bc Annotate Profile.mediacount as Optional 2026-10-23 23:40:53 +02:00
Alexander Graf 653efed311 Query Post metadata through api/graphql when not logged in 2026-10-23 23:40:31 +02:00
Alexander Graf 133e5c442c Fetch clips play count only when Post.video_play_count is accessed 2026-10-23 23:40:13 +02:00
Alexander Graf 28d991f765 Fix Profile.mediacount from the logged-out profile page 2026-10-23 23:39:34 +02:00
Alexander Graf fa6baebc66 Raise LoginRequiredException in Profile.get_posts() for private profiles when not logged in 2026-10-23 23:36:53 +02:00
Alexander Graf c0e47314c2 Fix Profile.get_posts() when not logged in 2026-10-23 23:33:28 +02:00
Alexander Graf e628a8d04a Allow api/graphql queries when not logged in 2026-10-23 23:27:30 +02:00
Alexander Graf ca44660707 Fix Post.get_likes() with api/v1/media/{id}/likers endpoint 2026-10-23 22:03:54 +02:00
Alexander Graf e93795223a Add AI Policy 2026-10-23 21:16:27 +02:00
Alexander Graf 7d26ad6ab8 Minor improvements to contributing guidelines 2026-10-23 21:16:11 +02:00
Alexander Graf 5432c4cce1 Update copyright years 2026-10-21 22:56:21 +02:00
12 changed files with 317 additions and 240 deletions
+3
View File
@@ -20,5 +20,8 @@ describe:
- Further considerations
- Is it based on master (bugfix), upcoming/v4.X (new feature), or another pull request?
- Does it preserve backward compatibility and existing behavior?
- If generative AI was involved, ensure it follows our AI policy.
(also see https://instaloader.github.io/contributing.html)
-->
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
cache: 'pipenv'
- name: "Install Dependencies"
run: |
python -m pip install pipenv==2026.8.0
python -m pip install pipenv==2026.10.3
pipenv --python `python --version | grep -Eo '3\.[0-9]+'` sync --dev
- name: "Build Documentation"
run: pipenv --python `python --version | grep -Eo '3\.[0-9]+'` run make -C docs html SPHINXOPTS="-W -n"
+2 -1
View File
@@ -22,9 +22,10 @@ jobs:
cache: 'pipenv'
- name: Install Dependencies
run: |
python -m pip install pipenv==2026.8.0
python -m pip install pipenv==2026.10.3
pipenv --python `python --version | grep -Eo '3\.[0-9]+'` sync --dev
- name: PyLint
if: matrix.python-version != '3.10'
run: pipenv --python `python --version | grep -Eo '3\.[0-9]+'` run pylint instaloader
- name: MyPy
run: pipenv --python `python --version | grep -Eo '3\.[0-9]+'` run mypy -m instaloader
+2 -1
View File
@@ -1,6 +1,7 @@
The MIT License (MIT)
Copyright (c) 2016-2020 Alexander Graf and André Koch-Kramer.
Copyright (c) 2016-2026 Alexander Graf, André Koch-Kramer and the Instaloader
contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Generated
+178 -178
View File
@@ -24,11 +24,11 @@
},
"certifi": {
"hashes": [
"sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775",
"sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55"
"sha256:a9895e6e2758b371e0545e321a3a8fd1fcfd9829ada8824a936dfb16aaaf36cd",
"sha256:e9b54de76e530bb6cf0ccd036787103acb58fd42ba930ea8bf948ddbaa2f61d1"
],
"markers": "python_version >= '3.7'",
"version": "==2026.7.22"
"version": "==2026.10.23"
},
"charset-normalizer": {
"hashes": [
@@ -216,6 +216,14 @@
"markers": "python_version >= '3.9'",
"version": "==3.20"
},
"jeepney": {
"hashes": [
"sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683",
"sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732"
],
"markers": "python_version >= '3.7'",
"version": "==0.9.0"
},
"lz4": {
"hashes": [
"sha256:0846e6e78f374156ccf21c631de80967e03cc3c01c373c665789dc0c5431e7fc",
@@ -281,52 +289,52 @@
},
"pycryptodomex": {
"hashes": [
"sha256:0428f19f13452c6b89bbaf2c530f84f369873811dfa77f0cee0da4f40fb0474f",
"sha256:0afd3f4cb2bd690cbf2b24e5d330e883cd5d8dcf3370aafc2aed16f676fff91e",
"sha256:3b6276fe007464502df796710fb57dcfeb813b6ccac0eabaf85100be1ad358f2",
"sha256:408fb76e0af11937381532c992d9f7c0dcf987878cbe61d772b0e788343e81c5",
"sha256:42c8221e3a4ca04b070cb388fca004815f6544951bfb2cc6c7958e293b7caf64",
"sha256:556e063b52f338bd924fe5c40692cc1f50cb0453bd1d6580b7ffff2eade1a894",
"sha256:55f22d72250d7923aac3c2442ec6a1dd8774d2efa3bdcb0f68d5e137d372268e",
"sha256:582efdf767d72c12538949b876a64b9a7af30f2cff063c06dd63ece32c4e5c1d",
"sha256:5be79564e05ed620a63f353ea50e0d474eb598f70cda1b28c2ca8e9e2f02c139",
"sha256:5fa46af1281be707e0ec5878aea0f77d58d8d4b465f63f7385a71ae0080bfff9",
"sha256:6a62122fb4c85befcc01ec3a1ae5b2ba81689481aba1d383b4e21e34f18900dd",
"sha256:72742921e388856044163e711643244b6d5c7062846dc0676b1f9f0743846ab3",
"sha256:770db9a5b9d30d8a48486bc163870763f3fe0f983c780403cd15c332618fa51c",
"sha256:78bb214b8016aade97a357071d753a5c11687bce2ba693da48218c3472ece287",
"sha256:793b9f5ba7e9147a6a6d8e284854e3711e12f43d4ef57a26b3415b2455a9801a",
"sha256:7ffcedf4210d8c206fe9852ccde9f78ec9ce35e8039f0a989900ffe710e7a5db",
"sha256:8293a92e6f71d6de57364432ff0ba48244959a81c632574eb5586e7e67f5de59",
"sha256:88d37b28b450c06a03bd5570467c601fe8c7dbe493ca39771716f56fdbe35d6e",
"sha256:8a2a634c86c0a59b28b0d51bbf7e5d1feed00dc7ebdc789fe968f771f1430b47",
"sha256:8d6c5e01e4fb1ddd20cc24d4d8706643dd78b5279453dabcf10ba4e0683bf9b2",
"sha256:908f92fbc307b642b65580d0295698f423b057018d87ae43d441f1d1a00674a2",
"sha256:96b60c0f36ab7c11a826c116633b08afeac58b9b9c066a5ad7cd373ed996363c",
"sha256:99c19dcd9846d6bf9886eb758c6d8e06c5bfd8a0c83802551f1aa56e80fe13dc",
"sha256:abf768c285d289c4a0e0678f055663162c9d6257c79f5904fbd2692ade94da1c",
"sha256:b4f7f9c737ca1af9a79962d3289eaa6521869915ee9fbb9168e578277126691b",
"sha256:b5d0afc29fc461d599379f814f5ba378e58c69418588034619d76747bc2b5d5d",
"sha256:b6690bfae043c81108e28e31dc7e3afa8cb1b1eb0ba590fdbff2b66e4c6913e7",
"sha256:bb393480b5845ef4acbc9f713e4c473ad08be81bc3cdb5ef017cd02bdafd36e1",
"sha256:c2f42f24d7112ebb93d3aed581d011c82c20101da7d7a6248145c530e99bd2eb",
"sha256:c55e6c42f9eb43d90c15792bf69bc09cb3e13a5e55a30eecb555695a02b0d4c0",
"sha256:c7055400f773856cd219680d15525c6fb147237534cbe5394a5f92f57f7efaed",
"sha256:c7b8ad51baf3505dd3d94ec974855359d15769e45c58c2b89c6d4612b1f7ed94",
"sha256:da9996407d03684221a4e1603b70fad97d8772185e5f75addcd97fcbc4c3281f",
"sha256:dc685ab0b420597fe9a3187555c14d5b4d87c1518a99646397018457dc2a70c8",
"sha256:e42a2e9531c40315290278d9eee93ea5031eda3c83969f5709ada51a1c7491b4",
"sha256:e635c7ac056f2a47d79e2bf7042fb3fc6d175f47796a954388a3cec1f2e082a4",
"sha256:e8a7463d346015b42a0fb9c9179ebb7cccfd86bf40199c6796b546ac7be0b85c",
"sha256:eb14a078429434b017f1fb26a75a8fcd62c12befb6b3d37ca39353dc2b5843fd",
"sha256:ef2bd306328a8447d4d2af6037efddd67ef16630876ed3ec84babd16ca558941",
"sha256:f6af77f15a91bb6c16607067cfd201330cf5dfefe1c715e955be1fb06d368613",
"sha256:f96e10f0edff9d4b6b253e0a78f7c819749521d3ffe6af0139e08fcd35384405",
"sha256:fab40542a863cc142a763aa92630d613925fe3e937bea3ba5fb735e0c42d4f96",
"sha256:ff8c1a125b2a7a2933219e9e523aabca31c920839c3c10968b56ec9a76c81d1e"
"sha256:03e2027f81fe6b700e7ff614d79111559bfb05ed8c4a9de9d2152d1a0a0768de",
"sha256:09081666ffc599976c0b8b29caf2cf82212c0f05bed233c8f8ed53e4f6e1d356",
"sha256:147c742f73bbe8791d8c454b9972330d7ea501de94e8172957af375f9bdb4a7f",
"sha256:347c37708688414d9b3ba69e3a60df4c82f3d9f9d0fcc1d645f85252d997207b",
"sha256:3bbcc1807502da4b5d66c94357a99589c8547aa9ad2f9ecfa537b2e9a347538b",
"sha256:455596da1c6a1d534051c1883761f9c0122a8126375827dd7cb7f0bf83c63a3a",
"sha256:48d9058dd4c8f3af83e048b6ff83d9c6300841c42579f77fdfab19e49156a512",
"sha256:514d685de4b0227d35d7114047fbd575bf162bff373e07af665aa41eee089dd0",
"sha256:569fdbeff936cbd5beb852b3969dc2f58fb255bd221b3f7a8999c035c30ec958",
"sha256:5966f829f64c833cc72a8694cfee05ad50446a44167842c92dec4ebf6b84d72c",
"sha256:5b37b86a3771d6aa21cccf9f8448460e4be11e68bb8e699133ce632cb986f521",
"sha256:6159dc74824c591b4c294f8f96b74a71c3b5e9f637dab2f2da14cfa32dc24d47",
"sha256:637b4bbc8165921b13d2b9d706e3697a9c6077d7564bfb61a3b7005182b2a7ac",
"sha256:6773f8c65b6e3d7524f4e18542ac2aa8856979785792ca0359d69bca27a269c6",
"sha256:77a48a855776101a61b932ddedbf522e1ead9e20b321bec0f64dd7434ac4fcc3",
"sha256:77ef934c2b2eab3c57a431daf858fcbf272134691bcc8d729787d17ad4cbf758",
"sha256:794f32227a480ab3b39971ac4a53dfa8ed444e28c0ddecbdc35f26d038bb46da",
"sha256:7a81e9be7084af3591912475b22c5d0646a9160f3974b6b7300138781fffdc0d",
"sha256:7f30261641dac5ae60e0af2fb11ad7c87200575b0ce403f7531576b0f38a52be",
"sha256:82eb0dd8a95be97f03527b108ee49f9b86a7c534fa47fa7a510be3eab8ea9acd",
"sha256:8321c315c4418dfe45a811b792380438ec81185deaaf202dbcd77711b4f51796",
"sha256:8f27725ec41d6722bd4f729a403a38238d844127f39cf462991e693b9c9c2608",
"sha256:9a732b9f5603b153dcdc071d6b342f192981907519827f2c1e4aeac41e2b34c2",
"sha256:9b94a8c647c1f80b4c82c7ac9642dda94a71abbb4efa29ad652c410ad7a39879",
"sha256:9bb353c764c144a9fc03302ef3763ad0c3e75bc7ca41f445cc98455f36da6c59",
"sha256:9dd5104a1d8ccf725a3c1b40b21d5ed47530b6499abba30955c174d895c1be2f",
"sha256:9fd3b792942e3b0937f9e39a1c56030cc41bbea058fb5a8af652ff6fd02a553e",
"sha256:a692d2484ca8fa2c69f45c63f2b30cd00b8512834e3a522fc297d981dde5b34c",
"sha256:b1c7a61b0b644e9780aa9f6eee301fb77c813b1e41262f6f4f387de0558e8926",
"sha256:b299a1c10e45e1b71b34b048d555d3a8f366240942af89be5db379f88edb9542",
"sha256:b3eda6b9416ef35b232403caa2bc6e25cc87530448d505a45d859210eab74051",
"sha256:bd06ab1d9cf90e8b198daae3b364e9ac23a640d210bb8faddad6627cf2e33be7",
"sha256:bf9c87112ee78e21be984c5873c17615d7b3f7305ba01f472931dc77a70ffb26",
"sha256:c20fb5e8cf874dc182091d6df122b8b588501d23e7b500acf662c49899afdd0f",
"sha256:cc64f4e1fc07a155ef31eb9815183a6a8eb13dfd6876ab049c01125223aa0c40",
"sha256:cdec09935db4cbd74da5b577ea7d9959c73374060b22abf7d505429c0da7ed63",
"sha256:e87928d8f37952ba53d215836cb3d89c63c1367f037d055c3a5b3f4403f4c6b6",
"sha256:edc1deb28fceab6b78e12bae506eaef62ee2fc1b3cabc96f7932f0d51e368acd",
"sha256:eeac2c9acbd2d9f0ca493fdf692ce8245ca37cbebee08c496025868d4b8ef70f",
"sha256:f3ed97cdde1d96894057778095238bad3dd94d3e46dc07d6d618e6d4b7700cce",
"sha256:f87d74a804ca949f46a6babe70247a789f6401f229566e90174c4b7033b87cc5",
"sha256:fd487cc20730dc9d294e000126be86a02079485fa6cb723d8f01eddf86e96f5a",
"sha256:fe19e03b81aefdeaa579afc6262fc03504fce93455129d6ef0da79ddb48ca47d"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'",
"version": "==3.24.0"
"markers": "python_version >= '2.7' and python_version != '3.0' and python_version != '3.1' and python_version != '3.2' and python_version != '3.3' and python_version != '3.4' and python_version != '3.5' and python_version != '3.6'",
"version": "==3.24.1"
},
"requests": {
"hashes": [
@@ -364,66 +372,66 @@
},
"ast-serialize": {
"hashes": [
"sha256:09cc4d3103c1fc97f6845ba307af1db9cde5226bef47f8843220dde83f2276ba",
"sha256:0f93a70fa9826c04ea9f2c3a880f87f4cca09a828144ed5084682abd28110980",
"sha256:10b59afc108eb285146acb23d1b5ec0fc58bb3c09cb2ab8876402df06c373c3b",
"sha256:119d1b0cadaba4a6e475f9bbe79eecc79351e373142eabe7c353f0250d70aebb",
"sha256:1858887be56a64a2aea899423dfe43787c34c75c18b0d7497de8e618d54b2790",
"sha256:243054a05a5190f5d087b5c8b16423e7f1cefa4991bac26e9c8ace18074b75b6",
"sha256:3398e458047d21c9bc1b323fe5aab77c608dc9ddb65b2d44deebaff503a1f1eb",
"sha256:3d6ed63d4fc1ec867b8cb522d58c36df0e8f05e487bea0ffd102043a37636d72",
"sha256:410233de149ab8414cb27c6fc73e9d2baa35d6f971672d540d752060d980ffb4",
"sha256:45a9e6b700bbd973d49942668a5cdbeffa693f2e250b8a5409abd1fa9d351854",
"sha256:4655ef993e69e01bb47d2d99647de9bbb74af03938438656832cd010d95de348",
"sha256:50a9eaedf1db4857dad7cc47dd757ed70bfcc40b89d44d516c4a2f0d5033bd76",
"sha256:5285a390caf1c44368ae270f037f797b91427d138b7d43cad0f1fda4c83518d9",
"sha256:536d783c4d91331f094e0a892221e619be5ffbe6fb6640885f14d7f226ec90ca",
"sha256:5bbf582286c9dc6b4c544ef645dc99e4b3aa09db28892bc60344141f6926641f",
"sha256:5ef62601db3ce5c23445132262a193075e211fb2fc87b46b7550dd351fac0976",
"sha256:5fc136cd08001b817ad0b3e7426f50a7d2b8982dc7c6491f0af78af4c3dd8672",
"sha256:610a41351de68199de9a1434499083b4256c0df7658ec1cfc0a0a7b20b08d317",
"sha256:6485e681625ed7a094221f16a7ff2ef154946112266a05cf83bde50c959ef345",
"sha256:657a7354ea16ed4d29f8127ed477c6fee3915c111d135f020ca835a991438e90",
"sha256:6add54b495e37ae3cf3a1f0d5eaba364814eb72e93026adc41b7791e4b0d45d3",
"sha256:6e25cd319fb0d7b39fcac666784ec86708ccbc78d07a698b1400cf5ed40c045b",
"sha256:6ff65f40f49d5e1a1a043ba366081d59a4e26a9f5c1b07eb1170e172115da7ca",
"sha256:72e871f6995a066c1b19104f8a6b5832b1163adb9a8267c2aa4711fbb0f4d1f3",
"sha256:7b1ad06513022cfa1337744959255af0ef16119d2beb1e547b67f37ad9433d4a",
"sha256:7d9fbe5a3e8acddfc2fddff3dbbc7ea0e9798b3df3428f851b8abc52a3806f31",
"sha256:82866f3523d53ffca8d2a69a750bec52908b69f728012e40959bebce2620453c",
"sha256:89a2bc39a820bc7785b60c53a5742b4e8dd4c1a599294e2dd68fae545883d44a",
"sha256:8a32f184ce3e4b1d0b06d642a1243281cf55b99e0323680b1b8f904029fd7700",
"sha256:8d6711adf11136c77e3a35517de9488a5081d1012874fae99c2876b64f4daace",
"sha256:9649cd903db0dc047906c6dd740784a2ba665d54f7e43ba31457edbce76c9493",
"sha256:98d91cd3a6cb76a39512ee090a539d1e3206b732ad8150eb38918cffa1ddf515",
"sha256:99e33c93efb5254a70c525b46038212371dfe5693d48eb2d0d5f17d936a263d7",
"sha256:9a0cbab9796e6ce841197feeba4008faa96b4cc7741129542fd81c882d7a4f01",
"sha256:9e855adfa5bb982b2e6fe09056b2d584f6dd4fce085d91a07d1155683751b6b5",
"sha256:9eb9de7e59621acdb3e66984f374272b33d56d15a04763e2fd0604211e1c8303",
"sha256:a1d8267f83c613ea0a31f2518df074bd62e98a4b3a4892f6a529d74e08e02dba",
"sha256:a513bc6f60980d01767f7cbe39b17ce0373e722824a74ce28d6cea49ee3c8460",
"sha256:a5628a12acc875fe7a167910f18d101dd101c2a7b1e6c2b6f7289ffaff25805c",
"sha256:a5cac246474d2a703147d1605a6ac5ba0fa9e0a443cf1cf42513adf4df02686f",
"sha256:a9cd24a26126088693ca054547ea0a391398a29cf1a3a2bec1009b4b6acc8b82",
"sha256:aa6c17a2b7f07e81fa8cfcc4aa7c832b3e57733853aebea113ab502f9b0963db",
"sha256:af699e81fd7ce80b8b03945826d8ea23dd36d072f10d4613402da597ba4ee9c6",
"sha256:b3cd105995942cc6163a229674a86161ba1305f646493efd59bd6723a357ee14",
"sha256:b4282695f1d51a3c6ef76560351bad5af880eff7d755aefea325bffb9bf68c25",
"sha256:b9a2310845302f1a6bd45ae8a67d5760211103a8d66410b854bfa440d107e093",
"sha256:bac5a99a2c91dd823be9b8c44645694fccbb0750773cc5b27889a9f6f22fce89",
"sha256:c30b609e8fea426b310543126de876592236a25aa8ebd59f1e2b323dd52a4085",
"sha256:c42d2d65f388d1960c5796231eb9bf5a988c46228633eb489605c4549ad16c52",
"sha256:c9e2a592706fd791c2271ce9c8f4e38c98d3ea0b4a86b511e09a4fe3ac44ab37",
"sha256:cbe239bee4bd609186daf60b95b7b0f47146c7f7f55f6da83807d747d6fe753f",
"sha256:d3d516da3463071d27e64caf54d88cba25cf4ad4afcc807e0bcf67743719f03e",
"sha256:e62126ac2be2d9340ac1b3ee7a0466a883ecbed634cff0929c88ca0b671483b7",
"sha256:e73255c9227fd74eac8a9b55c4049e8ad7b66d1f690bf827c98a86b2e594def7",
"sha256:f4ac042e95a575432c1730ca4cb9183066a2074886a599f46c1f1b0955fb8198",
"sha256:f896fa38e0af38821e1ab1425c5dee89e359623e165765bdeae7d0eb6909e76d",
"sha256:fafe1471e8aca6c87b4913b7b54ff97197adf702fbe28692284b929dfa62ff96"
"sha256:02686b281ec9b8e9614f6f0db27e12e4cac515f336c5d05b678bc9eb73ff2af5",
"sha256:032b09d86c785c3984e975378b7861f2a68ac44e22ba7b07b93a536b2524eeb8",
"sha256:0d764913374ba21df8cd618045b371ed104ce55c6276de7c59e554a4f5ba26fd",
"sha256:121e1d08d58b75c15491cc3003609cbad71ac2b0016043c36d30a6b2032b6605",
"sha256:1b158f1c9e3a0d386913924c57995d6df78224868a4d0f215bdd41587c97b34a",
"sha256:2015fd0165e463aac3b1aadc6a1fa1e5820c14ca950821f4fe02f8a3f6a388d6",
"sha256:23d768369b89d551077dc173da6892fad00443338417523b6732f4e8ba4a7ed5",
"sha256:2876444a5f87a7c76f371af3c07c2fda563a08bc8af52568df812e8aba4bf568",
"sha256:29422d7bcd9e7f39411571c36cec45ce8a7a9b3ad4b2e7aa64497c15a9e397f6",
"sha256:2bad302ae2427454ef9dab71bd5c3ad67188860c39d36daee38f72031edb39c4",
"sha256:2f9a9ce8b0994f757b941f7f7fe384a6666b4162b941ebc5c248081baea18e47",
"sha256:30cf89b6a6844542d116c758725d13de5b97b9410a51ee577715f761270d0c1c",
"sha256:3e129d44b0cffbea24a7f40117ce49e30993c3d119e584d4817ebd6f87246456",
"sha256:401cc84e8888d4d76f2c8d296fa006ed1a5ff993b6aff90dd777c03973efd025",
"sha256:43e8ddd63e80fc280c2f790157386f27f9b9f6ccb9c4f8e803b863cbfb085769",
"sha256:48f11d96c9ec71119612f8e79a8c55c12f2b136716d68347433c561d27a25f43",
"sha256:4bcf1d5f4eefecaa325a34ecf079b2741189e7d0821523f92cb343a389a67489",
"sha256:4e385b17d5bde892a6184003a9aff3518387908b73f8f5ea539313c07c8c0ede",
"sha256:4f98da562e5901d69c7dd30885594c5438f859edf354e9ac7517d188fb026c3a",
"sha256:523d45bab16ddaf1399c04c4fe81bbf180f81e33c2f7bcbe76be56b0f7311ab4",
"sha256:5d99910e6b9a9b9360bcca2ae99aee36cc912ce058df2a57d1c33099b6cb2593",
"sha256:5db12d843d931b9d1f1519ce66b9cbfe72d8563b75c1204d255322254d1964dd",
"sha256:638333fb8ae72c62753f9e794fda20290883ddc65b0d85e26e08f8bb227567ad",
"sha256:68f8829d114dab6c9db4a8bbb8d0e342958faee1b5e15a29022678df639960f8",
"sha256:6eb0be64c9b8f1ed26637eef345abe75ea90351c92c85a8aec7838b3af971011",
"sha256:6ffb0f548a7dc126067fdfb7b2325ab5dfcdeecc29faf5e0f0461c96d6ebfa3d",
"sha256:732aaae9e498c973fc63fd7f308009b57c4afa6ff59d0b674d894e57d0bca01a",
"sha256:75d7750fe98f6f35a96c43aba8d98a2e623e22c778a0c17ab9ede92eb10f5d82",
"sha256:77a6201b69ce42e919f2fd9a559138d5410b5d8afff7c3a6b1f500b0481ff7d8",
"sha256:7a5c38bdb93669c596f94fb7204dd6ebe4fadb19058ac9a2faf2948c2a175f96",
"sha256:7f2427bddfca208e84de700044fadf9aef2769a70bae740a1bdabb89ee9e1117",
"sha256:7f3e8a3eff69af640db985360fef35073fb46956dfc3e5c614cf00920d2746dd",
"sha256:847cad4c22953823f5e76d0b126c6f9da670cfa45b1df41b9324e22189d77611",
"sha256:87427913c325adc811e81e7c9a757b061f47ef1e29114ac479aa0953a2687a98",
"sha256:885a62ec6481ce58ab24c6357360d7a82023b62dd7e5e7ceccf59e9662a3272b",
"sha256:8899c038b1c15ae8b98e379057fb3ef398ceb0b21d1737a8156dd5a0923b7e51",
"sha256:88df960e67184a71874e5b2ee014f87d1254a0dbc1f903c7bd7b1ab7733ecaef",
"sha256:8c8ebd419811c435812d242fb2a173e57dfede198c9ac9a0a584666ebc9b9331",
"sha256:9221e09496fb942901993c1812ee87950cc0ecbb514c7c0f1f5fa6d78f701ed8",
"sha256:929eda0c419e622ab49df3a4c45f81c57dcc10874bbad55d0470a4a03324dac3",
"sha256:9f99786e0d62082a5b121b3437f3167562133711df22128de1e9886f57f0b226",
"sha256:a01b515b25a03184eff4acef25b981ae007916379682e908fc8785b342a0bf3e",
"sha256:a789cbe14d0a0e9ec9b32a456e5abc81ad8799479c3cfd88a29e3442262aebe6",
"sha256:a8ab2c2585b2e22e48cd4aff2136fce4eab4ced569b85f150ef9a5a5d6f34d49",
"sha256:aca07de3ca8e3d9f2b716c3c31f4f384fe4bd2d03e09912417cff7a3e08036f7",
"sha256:acf4e9f055d75058ab01536da330648746f2f82b7697a85230547f2d5ebe895c",
"sha256:ad88921f95b92bc144d9ad059a0e16f8c1ae69f5239f2d3c6536fd2774f73dfe",
"sha256:bf53a3ba1cbe45399fc1e4ccd684b8f2a11cca450f89706b79122f478534c6f5",
"sha256:c652d9f5d52d8b81eff3ff2c95c9dd0f281de45f6ad5d3fa95527550c396454a",
"sha256:ca9acc67f796aa2554fa3037dccc022a4b08b38b2ad153edfac9c9bb7cb1f3c6",
"sha256:cc34c670747d85d4232834665e247009413eaebe47c69eaf60a5c439aaecaed9",
"sha256:d9c1a920b2aa0c1e016bed7721689717034ca0dba64ac3a3ff243b003d4e8dd8",
"sha256:ddf7cbc9c8abf70102c4a088efe154bb86bfb825b0a10e556d2b15972cf99bd7",
"sha256:e14c4de98f965647a74e6eaf37e20207124e45451ccd36e84a6f6ebab45e0372",
"sha256:eb41e1906502ac80d24ff343f45008552a3f5b5158607959fe6a07dbfc6eb037",
"sha256:f8b17e2921e56621bcb46792bd3e0b82ca3b85de78d5936e7b8174ba1758b0aa",
"sha256:fb8021f4dc3296de18737e3b8b34994411da725374d74a0b9eb32a738f2a23d0"
],
"markers": "python_version >= '3.7'",
"version": "==0.12.1"
"version": "==0.13.1"
},
"astroid": {
"hashes": [
@@ -443,11 +451,11 @@
},
"certifi": {
"hashes": [
"sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775",
"sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55"
"sha256:a9895e6e2758b371e0545e321a3a8fd1fcfd9829ada8824a936dfb16aaaf36cd",
"sha256:e9b54de76e530bb6cf0ccd036787103acb58fd42ba930ea8bf948ddbaa2f61d1"
],
"markers": "python_version >= '3.7'",
"version": "==2026.7.22"
"version": "==2026.10.23"
},
"charset-normalizer": {
"hashes": [
@@ -638,11 +646,11 @@
},
"docutils": {
"hashes": [
"sha256:4db53b1fde9abecbb74d91230d32ab626d94f6badfc575d6db9194a49df29968",
"sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de"
"sha256:25d013af9bf23bc1c7b2b093dff4208166c53a94786c9e447808335ef1185fea",
"sha256:746f5060322511280a1e50eb76846ed6bf2342984b2ac04dc42caa1a8d78799e"
],
"markers": "python_version >= '3.9'",
"version": "==0.22.4"
"version": "==0.23"
},
"idna": {
"hashes": [
@@ -854,14 +862,6 @@
"markers": "python_version >= '3.9'",
"version": "==0.16.0"
},
"macholib": {
"hashes": [
"sha256:da1a3fa8266e30f0ce7e97c6a54eefaae8edd1e5f86f3eb8b95457cae90265ea",
"sha256:f408c93ab2e995cd2c46e34fe328b130404be143469e41bc366c807448979362"
],
"markers": "sys_platform == 'darwin'",
"version": "==1.16.4"
},
"markupsafe": {
"hashes": [
"sha256:007e1ffd9bf65bb6ee96df7b258fc632a4868dd5566037986c64781f35a36e98",
@@ -1130,11 +1130,11 @@
},
"platformdirs": {
"hashes": [
"sha256:63743c02414e755de4e31b8f68125c1407495b86c5a006e203c01ff8b9924250",
"sha256:78bfb9db2a8471ed7eebe3c3c932da413911042994e699b384fbb4493fa872d7"
"sha256:05831adf87d392760f4b5c3a0a95579ab5a10b18b9b9bd43680dcb47544788a0",
"sha256:53d3ec4280b815c1e0b02edad7f9ee8fda1ba9c0865dd9c2e6e63849ce82fc1e"
],
"markers": "python_version >= '3.10'",
"version": "==4.12.4"
"markers": "python_version >= '3.11'",
"version": "==4.13.5"
},
"prettytable": {
"hashes": [
@@ -1196,25 +1196,25 @@
"sha256:f82d0fb89f21c3ed6f482ee16f341bc59e8a31dbabb9bae9ef04e53ade4dc0d9"
],
"index": "pypi",
"markers": "python_version < '3.16' and python_version >= '3.8'",
"markers": "python_version >= '3.8' and python_version < '3.16'",
"version": "==6.22.3"
},
"pyinstaller-hooks-contrib": {
"hashes": [
"sha256:4d825786ad7a9b7dbcc52d612748a34562fe273461bcfd88f4d549c594bbf8f9",
"sha256:6d21d65323ea4467753afc21f52d7d0e69416ae8101dd88269bf273ad48db084"
"sha256:2748767901acb5cecd1304652b6c7add5bffcff1d71d01207fe24a5d42942a56",
"sha256:fb3e67dd64122561724c48ad0366ac9e8c16e638b63bf7d85de03bf3fdbf06c3"
],
"markers": "python_version >= '3.8'",
"version": "==2026.8"
"version": "==2026.9"
},
"pylint": {
"hashes": [
"sha256:235f13dc418c0041c649b42a5c35c99f2ffc6ca8b6a7574958eac5335906a68a",
"sha256:e34c8636edc7d60a2eaadca4ad6c18a49e202361987a26e81b2a17fa92be28e1"
"sha256:9928603068edfa0d1a3c167f174b099d4b97c3db75d32d0fcdd029770b4713a9",
"sha256:a85357cae24f33ad8d86c8f3daaa92c600ae4012b54a57299cee76000e9364cf"
],
"index": "pypi",
"markers": "python_full_version >= '3.10.0'",
"version": "==4.1.2"
"version": "==4.1.3"
},
"pywin32-ctypes": {
"hashes": [
@@ -1244,11 +1244,11 @@
},
"setuptools": {
"hashes": [
"sha256:51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670",
"sha256:f4695c21257f0d9b537ec2692c941d02ee143b7cc1276941349a546573b2ef73"
"sha256:3ff8b3b5492a0aa66960f4419365a86b84e013070d4313e4d4a6894f5d64d6bc",
"sha256:ca140b45d5325a9478f880e351484f62fef15f336462e449ca0c03c873d589c2"
],
"markers": "python_version >= '3.10'",
"version": "==84.0.0"
"version": "==84.2.1"
},
"snowballstemmer": {
"hashes": [
@@ -1260,21 +1260,21 @@
},
"sphinx": {
"hashes": [
"sha256:7741722357dd75f8190766926071fed3bdc211c74dd2d7d4df5404da95930ddb",
"sha256:c84fdd4e782504495fe4f2c0b3413d6c2bf388589bb352d439b2a3bb99991978"
"sha256:4c3ec13b612712c0d3ce4cbdd9e3eb91e68577e07a8e31f32f21cf178453578c",
"sha256:90470459f3cab15d9dfed146c71cf77694b0445df17b2e0e69059cb9f7fc9ee4"
],
"index": "pypi",
"markers": "python_version >= '3.12'",
"version": "==9.1.0"
"markers": "python_version >= '3.13'",
"version": "==9.2.0"
},
"sphinx-autodoc-typehints": {
"hashes": [
"sha256:f5bac0996e76a2007fa26bc5393bb065ceb6cb4d062283fb5c69830c791c9716",
"sha256:f5db988060f68a231dbc230df97d81421e54a0860778a63216b9f71958a9afdd"
"sha256:b0ad1f96503d69b63c2a1c043f12e2a727c9549e6503d4adbf2125dbf5ff50ed",
"sha256:de41ed4001f4818bb6d37c22fd10ee44a93e6c8e945c6c7e3984e28a9df87d1c"
],
"index": "pypi",
"markers": "python_version >= '3.12'",
"version": "==3.13.9"
"version": "==3.17.2"
},
"sphinxcontrib-applehelp": {
"hashes": [
@@ -1311,11 +1311,11 @@
},
"sphinxcontrib-jsmath": {
"hashes": [
"sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178",
"sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"
"sha256:15ca92fe0eec82f0baf91a7efcc51ffacdb605924be6327683a52ebdacb6744c",
"sha256:551f780cf9687f9c3c74f0cf9f18aca06e0d6958853453f3803fe4d357c5b924"
],
"markers": "python_version >= '3.5'",
"version": "==1.0.1"
"markers": "python_version >= '3.9'",
"version": "==2.0.0"
},
"sphinxcontrib-qthelp": {
"hashes": [
@@ -1407,11 +1407,11 @@
},
"tomlkit": {
"hashes": [
"sha256:177a05aece5a8ca5266fd3c448abb47b8d352f09d477d3ca8332db4d89b24304",
"sha256:e25bbf38843005246210a12982776f27f99cb9be67160e14434d0c0d21ee1e97"
"sha256:05562412163a3037b94497385fb7f9204c637bc605af7a48199e41cf2272f437",
"sha256:83e32755ba1d20d9340bd069ee97e9f6232ba2346b63ffcba425de01f7e327a6"
],
"markers": "python_version >= '3.9'",
"version": "==0.15.1"
"version": "==0.15.2"
},
"types-requests": {
"hashes": [
@@ -1440,38 +1440,38 @@
},
"wcwidth": {
"hashes": [
"sha256:0a47e03d8293590ecce66c45dc20ff7b4b885e3c78093722239585eca0d77ab2",
"sha256:0cd4f7f2e53905dcb110d213a4c8529b6733fa3d232d8c717f946cc69a10349b",
"sha256:138e1f8898e431b2f2d7881f8ca8d75591c1d3c21aa53f54e989bd6b39811da2",
"sha256:196b47cf32f9df27ccda6dc513237f3c2429c4c659db428d60a5bc443d10f270",
"sha256:1bf361c8705576760623b4724ae564666d73b016f9a778bcfd1c7345378ef4ec",
"sha256:2a9746de704242bd4fdaabb31dd46b82f694a56a8d21081ad89b679a89da9fec",
"sha256:33df042f96c61ed3cd5fb3742fba427553a635bc578799857a48aa79f774a0b9",
"sha256:42dbcb76ce8af39e2c9db410ac3f9bdf4e47eb41d6f44525952f172d3d98f724",
"sha256:48719a9bc76c2f84238693fe5013571fa5beffa3621cf228f1f3a9e30dae84b8",
"sha256:5175609bf8cc7398a5f48aa35207bd64ebf9f45e4c70df65f7fdc7a988041a3c",
"sha256:59dab4049cbd982b478bca098528df2c79a9160636a3a163ffebffcbd7d1b892",
"sha256:674b518af28d38ee645ff97b74f5760abee5fad4bac74413bfc4b881ef2ce724",
"sha256:67d901a4ad99249eb775b4ee4769ca97fa405d35a75f46e83166910a47003f04",
"sha256:734aa9405b321d1042301aa19c943c4731ee9e3460e4f8feea3299c064c97a14",
"sha256:751bef0ab404b6a1dc028b56b4b85d46486be1c55833f80da533e42dc691f389",
"sha256:7ef5a940bd5e30bac6e721f1a48fce0cd7bb3ece19e9c5d139e72c76c35cfd07",
"sha256:89ca642c5bf0101157a09366be69fad0379db1f700ae39a920e103234573670e",
"sha256:8b4e381590b9b7390e07e22b2c0c1bb96ce50e1d2243c866d9387600362d51ed",
"sha256:97b878d1e158da5ed9ac5aac53fa3a55e282103af6a09ec353865613d1a31a76",
"sha256:9e542f1f8475b78452a295495d7a5bc3ead565112e9446a64dc93462a41c2a79",
"sha256:ae0800c5339423cc53d33a266ad264b42ba8aaa16d4464f6e6b1bee607f50b17",
"sha256:ae0ef90b90f6af38b54f1fe6d58662ec33b3cb4b8391958a62416d654231727b",
"sha256:b9c6ab615e03723b7f8760ea2f27758d656e7e13b51515c9dca5c3e8b04612fa",
"sha256:bb08ceb501d6aaf94066c3ee122dd825b152df40ff0bd0df4dc27126233b948e",
"sha256:c3d80f39ba4653a595edae9aa46a509d14883790a8fc23c5db221ceb207f64b7",
"sha256:e5f669ae8c3d969c72032f9cdee019674b666e522d45e1e2099a2e9dda4a341d",
"sha256:eda88ffdc97c0fbf193d407114f2c7a54b379f67f6e52a7531ee3b9fe749eca7",
"sha256:ee1fd0db9d9fd711a70f3e7765e0e04c05d26982fa05361456163062549d7da4",
"sha256:f2f7b3bba5a5d5f31fc350fd36ce5b84b693c83b7eb95ee630b720da5a5ce06f"
"sha256:093469e01d881bff3db93ff3f56c364dc87c441ea01f9f41c22de0c0bdf5c6ef",
"sha256:12786620375dc83fabf4b2b2aa52416fef2bc6094522ea29c8a53c75b0dfe9b6",
"sha256:14410eb73178cc492aa9bf22f7c12e3bf930e5470b7220cf6f530efbfa2e03f3",
"sha256:17619066f95c10f44d7ae08ee456602456bc66cc9d5e91966ec73d799acebc5f",
"sha256:29c0685f5f5f8815b88308fdcbe2cd12a92996a21a5b1e18352d165174ef7a6d",
"sha256:2b58fc8cf2de1bf9cdb68b8beaa5be198742414a7c8cd97aa51ec039783ffa49",
"sha256:2cca7b5d0b9d0ae49068d3ce806e965326a987f555b62eaa322223396e10d01b",
"sha256:4831662c396dd4c59a016ec53c0ac96738006d653a00482777d9a2e2ea323d62",
"sha256:79e09e9824c88f5e275ca99e921685567a5c5c1bb6165c16e27ddd1adab33a95",
"sha256:87e4101789415a6cf55ec4c53eceeb4782c2654c88692941cb588f19dca1959f",
"sha256:8f892713ab5795d3abae181e9c02db0eb24de4084f9ee080535369d3d98d7bb5",
"sha256:901eace6d2dd25ebb917d0ce5db18e5c537e1504c905cf32f0d006c12098b05d",
"sha256:9c4b0dd04cca520792100f6110d10be262c94b285a281d1759c551f159214633",
"sha256:9e5090d253f5df99659cddfd3ed90dd21f6ff51989b0421331a63fb2681cbe27",
"sha256:a1526cd25c6420e5153bb7d764c7509e692215ee3ad9b725db1ad665d47eae09",
"sha256:a8c9ce14c6b4a499e61de6de7e9e456de11be8bc991554e2ab2ed4feb40b9664",
"sha256:ab1e5190fb82476e75fbf963e9d59b4fb1c1e1f4ced82069a0c989016aa959f7",
"sha256:b185c8b927b23af2721be1783499d1cfa5c028b098b0858951b4ae224477f1c2",
"sha256:b52f265a694dda6b3ad9050c8bd89158ad519109ef7c5eb110b906cc49f25763",
"sha256:b7969c9aa258d536df54c8ac8af5cad0c74a6268c9972e1fb60a5f29feffb66d",
"sha256:befbf46467100e43fd8c8cc0c031a0105f13f5418c3be95fdcf0c47214487967",
"sha256:c36954849aafae1092d6f9de9548c5280c1d6841637a27ca288b2241c802c4ab",
"sha256:d68f09093c9bec9226a52edc47487042ed4f64c5df91d06f00419495071c0279",
"sha256:d76b7c715c5ca0103b28915f699f1020ae21f06f1d22cdd85a7a97f7b1536eed",
"sha256:d8905f1390d828d745fdd1904374c90386d902d3cfa9ee88e9875099f75a4e17",
"sha256:e05458491759aa42b7b85f36345b3e6df082d6d2d9bf616299668fd598e0209d",
"sha256:f279f32c8e206a9092fa350e53ca0c2bd8072e45b1c9fd31bb6d476b59b591c4",
"sha256:f28d77153303450ee13ebbe888297e75cf532c754555b6cabafc9bdda16c421c",
"sha256:fd8d57d3cdfe570e3265c8fab1885c24e34ef40889c0759c0c304a19e9835954"
],
"markers": "python_version >= '3.9'",
"version": "==0.9.2"
"version": "==0.9.4"
}
}
}
+1 -1
View File
@@ -53,7 +53,7 @@ bundled_packages = ' '.join(list(locked_packages) + ['psutil', 'pyinstaller'])
os.makedirs('dist/licenses', exist_ok=True)
# install dependencies, invoke PyInstaller and collect licenses
commands = ["pip install pipenv==2026.8.0",
commands = ["pip install pipenv==2026.10.3",
f"pipenv --python {sys.version_info.major}.{sys.version_info.minor} sync --dev",
"pipenv run pyinstaller --log-level=DEBUG instaloader.spec",
f"pipenv run pip-licenses --packages {bundled_packages} --with-license-file "
+1 -1
View File
@@ -15,7 +15,7 @@ sys.path.insert(0, os.path.abspath('..'))
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = 'Instaloader'
copyright = '2023, Alexander Graf and Andre Koch-Kramer'
copyright = '2016-2026, Alexander Graf, Andre Koch-Kramer and the Instaloader contributors'
author = 'Alexander Graf and Andre Koch-Kramer'
# -- General configuration ---------------------------------------------------
+14 -1
View File
@@ -80,7 +80,7 @@ Improvements of the Instaloader source or its documentation can be proposed as a
review, validate, or selectively merge them.
- Be mindful of backward compatibility: changes should preserve existing intended
behavior whenever possible.
behavior whenever feasible.
- All Pull Requests are analyzed by `Pylint <https://www.pylint.org/>`__ for
error and syntax checking of the source and
@@ -100,6 +100,19 @@ Improvements of the Instaloader source or its documentation can be proposed as a
agrees that the change might be an improvement, or if you want to discuss
your basic proposal, before working on a pull request.
AI Policy
---------
- If generative AI was used to create notable portions of a contribution, the
author must disclose which parts were AI-assisted (e.g. research, testing,
coding, or documentation).
- The author must carefully review and understand the contribution before
submitting it.
- If the maintainers need more effort to review the contribution than it took
to create it, please do not submit it.
Proposing Features
------------------
+1 -1
View File
@@ -1,7 +1,7 @@
"""Download pictures (or videos) along with their captions and other metadata from Instagram."""
__version__ = '4.16b1'
__version__ = '4.16'
try:
+43 -10
View File
@@ -9,6 +9,7 @@ import textwrap
import time
import urllib.parse
import uuid
from base64 import b64encode
from contextlib import contextmanager, suppress
from datetime import datetime, timedelta
from functools import partial
@@ -102,7 +103,6 @@ class InstaloaderContext:
self.request_timeout = request_timeout
self._session = self.get_anonymous_session()
self.username: Optional[str] = None
self.user_id = None
self.sleep = sleep
self.quiet = quiet
self.max_connection_attempts = max_connection_attempts
@@ -132,11 +132,9 @@ class InstaloaderContext:
def anonymous_copy(self):
session = self._session
username = self.username
user_id = self.user_id
iphone_headers = self.iphone_headers
self._session = self.get_anonymous_session()
self.username = None
self.user_id = None
self.iphone_headers = default_iphone_headers()
try:
yield self
@@ -144,9 +142,22 @@ class InstaloaderContext:
self._session.close()
self.username = username
self._session = session
self.user_id = user_id
self.iphone_headers = iphone_headers
@property
def user_id(self) -> Optional[str]:
"""ID of the user this session is logged in as.
Derived from the ``ds_user_id`` cookie of the current session, so it is set for every
logged-in session, and ``None`` if not logged in."""
return self._session.cookies.get_dict().get('ds_user_id') or None
@user_id.setter
def user_id(self, user_id: Optional[str]) -> None:
# The setter is only provided for backwards-compatibility with pre-4.16.
if user_id != self.user_id:
raise AttributeError("user_id cannot be set to a different value.")
@property
def is_logged_in(self) -> bool:
"""True, if this Instaloader instance is logged in."""
@@ -354,7 +365,6 @@ class InstaloaderContext:
session.headers.update({'X-CSRFToken': login.cookies['csrftoken']})
self._session = session
self.username = user
self.user_id = resp_json['userId']
def two_factor_login(self, two_factor_code):
"""Second step of login if 2FA is enabled.
@@ -605,7 +615,7 @@ class InstaloaderContext:
return token_from_cookies() or ''
def _web_api_tokens(self) -> Dict[str, str]:
"""The tokens that the web app sends along with its api/graphql queries, from the logged-in start page."""
"""The tokens that the web app sends along with its api/graphql queries, from the start page."""
sessionid = self._session.cookies.get_dict().get("sessionid", "")
if sessionid not in self._web_api_tokens_cache:
html = self._get_page(self._session, "")
@@ -616,11 +626,13 @@ class InstaloaderContext:
("av", r'"IG_USER_EIMU":"?(\d+)'),
]:
match = re.search(pattern, html)
if match is None:
if match is not None:
tokens[name] = match.group(1)
# Logged out, the start page has no fb_dtsg, and the web app sends its queries without.
elif name != "fb_dtsg" or self.is_logged_in:
raise BadResponseException(
"The start page did not contain the token {}.".format(name)
)
tokens[name] = match.group(1)
self._web_api_tokens_cache[sessionid] = tokens
return self._web_api_tokens_cache[sessionid]
@@ -658,7 +670,7 @@ class InstaloaderContext:
:param variables: Variables for the Query.
:param referer: HTTP Referer, or None.
:param web_api: Query the web app's ``api/graphql`` endpoint, as the web app does, rather than
``graphql/query``. Requires login.
``graphql/query``.
:return: The server's response dictionary.
.. versionchanged:: 4.16
@@ -726,12 +738,33 @@ class InstaloaderContext:
.. versionadded:: 4.2.1"""
with copy_session(self._session, self.request_timeout) as tempsession:
# Set headers to simulate an API request from iPad
tempsession.headers['ig-intended-user-id'] = str(self.user_id)
# ig-intended-user-id should name the logged-in user; self.user_id is derived
# from the ds_user_id cookie, so it is set for any logged-in session. Without a
# logged-in user, omit the header rather than sending the literal string "None".
if self.user_id is not None:
tempsession.headers['ig-intended-user-id'] = self.user_id
tempsession.headers['x-pigeon-rawclienttime'] = '{:.6f}'.format(time.time())
# Add headers obtained from previous iPad request
tempsession.headers.update(self.iphone_headers)
# The mobile API requires an Authorization bearer token for most
# endpoints (reels_media, users/info, ...); without it they answer
# with empty data or a "fail" status. A token is handed out via
# the ig-set-authorization response header, but only by the few
# endpoints that still accept cookie-only requests (e.g.
# media/<id>/info/), so relying on having seen one makes success
# depend on request order. The token is deterministically derived
# from the session cookies, so construct it if none is known yet.
if 'authorization' not in tempsession.headers and self.user_id is not None:
sessionid = tempsession.cookies.get_dict().get('sessionid')
if sessionid:
token = b64encode(json.dumps(
{'ds_user_id': self.user_id,
'sessionid': sessionid},
separators=(',', ':')).encode()).decode()
tempsession.headers['authorization'] = 'Bearer IGT:2:{}'.format(token)
# Extract key information from cookies if we haven't got it already from a previous request
header_cookies_mapping = {'x-mid': 'mid',
'ig-u-ds-user-id': 'ds_user_id',
+14 -5
View File
@@ -104,6 +104,7 @@ class NodeIterator(Iterator[T]):
else:
self._data = self._query()
self._first_node: Optional[Dict] = None
self._first_item: Optional[T] = None
self._is_first = is_first
def _query(self, after: Optional[str] = None) -> Dict:
@@ -114,11 +115,11 @@ class NodeIterator(Iterator[T]):
return self._query_query_hash(self._query_hash, after)
def _query_doc_id(self, doc_id: str, after: Optional[str] = None) -> Dict:
pagination_variables: Dict[str, Any] = {'__relay_internal__pv__PolarisFeedShareMenurelayprovider': False}
pagination_variables: Dict[str, Any] = {}
if after is not None:
pagination_variables['after'] = after
pagination_variables['before'] = None
pagination_variables['first'] = 12
pagination_variables['first'] = NodeIterator._graphql_page_length
pagination_variables['last'] = None
data = self._edge_extractor(
self._context.doc_id_graphql_query(
@@ -156,10 +157,10 @@ class NodeIterator(Iterator[T]):
item = self._node_wrapper(node)
if self._is_first is not None:
if self._is_first(item, self.first_item):
self._first_node = node
self._first_node, self._first_item = node, item
else:
if self._first_node is None:
self._first_node = node
self._first_node, self._first_item = node, item
return item
if self._data.get('page_info', {}).get('has_next_page'):
query_response = self._query(self._data['page_info']['end_cursor'])
@@ -206,7 +207,15 @@ class NodeIterator(Iterator[T]):
.. versionchanged:: 4.9.2
What is considered the first item can be overridden.
"""
return self._node_wrapper(self._first_node) if self._first_node is not None else None
if self._first_item is None:
# Restore _first_item from _first_node. Needed after thawing, since
# FrozenNodeIterator stores the node, not the item.
self._first_item = (
self._node_wrapper(self._first_node)
if self._first_node is not None
else None
)
return self._first_item
@staticmethod
def page_length() -> int:
+57 -40
View File
@@ -279,7 +279,7 @@ class Post:
return None
@staticmethod
def _normalize_post_data(media: Dict[str, Any], context: 'InstaloaderContext') -> Dict[str, Any]:
def _normalize_post_data(media: Dict[str, Any]) -> Dict[str, Any]:
"""Normalize a Polaris media item to a legacy-compatible node, preserving the source structure."""
media_types = {1: "GraphImage", 2: "GraphVideo", 8: "GraphSidecar"}
media_type = media.get("media_type")
@@ -306,10 +306,6 @@ class Post:
pic_json["video_duration"] = media.get("video_duration")
pic_json["video_view_count"] = media.get("view_count")
pic_json["video_play_count"] = media.get("play_count")
if media_type == 2 and pic_json["video_view_count"] is None:
pic_json["video_play_count"] = Post._fetch_play_count_from_clips(
context, media["user"]["pk"], media["code"]
)
caption = media.get("caption")
caption_text = caption.get("text") if isinstance(caption, dict) else None
pic_json["edge_media_to_caption"] = (
@@ -419,12 +415,14 @@ class Post:
"shortcode": self.shortcode,
"__relay_internal__pv__PolarisAIGMMediaWebLabelEnabledrelayprovider": False,
},
# As the logged-out web app does.
web_api=not self._context.is_logged_in,
)
web_info = (resp.get("data") or {}).get("xdt_api__v1__media__shortcode__web_info") or {}
items = web_info.get("items")
if not items:
raise BadResponseException("Fetching Post metadata failed.")
self._full_metadata_dict = Post._normalize_post_data(items[0], self._context)
self._full_metadata_dict = Post._normalize_post_data(items[0])
if self.shortcode != self._full_metadata_dict['shortcode']:
self._node.update(self._full_metadata_dict)
raise PostChangedException
@@ -697,7 +695,11 @@ class Post:
.. versionadded:: 4.14.3"""
if self.is_video:
return self._field('video_play_count')
play_count = self._field('video_play_count')
# Not logged in, the clips connection is null.
if play_count is None and self.video_view_count is None and self._context.is_logged_in:
play_count = Post._fetch_play_count_from_clips(self._context, str(self.owner_id), self.shortcode)
return play_count
return None
@property
@@ -879,19 +881,9 @@ class Post:
if self.likes == 0:
# Avoid doing additional requests if there are no comments
return
likes_edges = self._field('edge_media_preview_like', 'edges')
if self.likes == len(likes_edges):
# If the Post's metadata already contains all likes, don't do GraphQL requests to obtain them
yield from (Profile(self._context, like['node']) for like in likes_edges)
return
yield from NodeIterator(
self._context,
'1cb6ec562846122743b61e492c85999f',
lambda d: d['data']['shortcode_media']['edge_liked_by'],
lambda n: Profile(self._context, n),
{'shortcode': self.shortcode},
'https://www.instagram.com/p/{0}/'.format(self.shortcode),
)
data = self._context.get_json(f"api/v1/media/{self.mediaid}/likers/", {})
for user in data["users"]:
yield Profile(self._context, user)
@property
def is_sponsored(self) -> bool:
@@ -1035,16 +1027,24 @@ class Profile:
"""
if profile_id in context.profile_id_cache:
return context.profile_id_cache[profile_id]
# Resolve the current username from the user id, then load the full profile.
# The GraphQL user query previously used here started responding with HTTP 400.
try:
user = context.get_json(
"api/v1/users/{0}/info/".format(profile_id), params={}
).get('user')
user = context.doc_id_graphql_query(
'27937681195819736',
{
"id": str(profile_id),
"render_surface": "PROFILE",
"__relay_internal__pv__PolarisCannesGuardianExperienceEnabledrelayprovider": True,
"__relay_internal__pv__PolarisCASB976ProfileEnabledrelayprovider": False,
"__relay_internal__pv__PolarisRepostsConsumptionEnabledrelayprovider": False,
"__relay_internal__pv__PolarisWebSchoolsEnabledrelayprovider": False,
"enable_integrity_filters": True,
},
web_api=True,
).get('data', {}).get('user')
except QueryReturnedNotFoundException:
user = None
if user and user.get('username'):
profile = cls.from_username(context, user['username'])
profile = cls(context, cls._normalize_profile_data(user))
else:
raise ProfileNotExistsException("No profile found, the user may have blocked you (ID: " +
str(profile_id) + ").")
@@ -1147,6 +1147,9 @@ class Profile:
normalized['id'] = normalized['pk']
if 'edge_owner_to_timeline_media' not in normalized and 'media_count' in normalized:
normalized['edge_owner_to_timeline_media'] = {'count': normalized['media_count']}
# The logged-out profile page has all_media_count instead.
if 'edge_owner_to_timeline_media' not in normalized and 'all_media_count' in normalized:
normalized['edge_owner_to_timeline_media'] = {'count': normalized['all_media_count']}
if 'edge_felix_video_timeline' not in normalized:
normalized['edge_felix_video_timeline'] = {'count': 0}
if 'edge_followed_by' not in normalized and 'follower_count' in normalized:
@@ -1232,7 +1235,11 @@ class Profile:
return self._metadata('followed_by_viewer')
@property
def mediacount(self) -> int:
def mediacount(self) -> Optional[int]:
"""Number of posts, or None if unavailable (e.g. when not logged in).
.. versionchanged:: 4.16
Returns None if unavailable (e.g. when not logged in)."""
return self._metadata('edge_owner_to_timeline_media', 'count')
@property
@@ -1385,28 +1392,38 @@ class Profile:
"""Retrieve all posts from a profile.
:rtype: NodeIterator[Post]
:raises PrivateProfileNotFollowedException: When logged in and the profile is private and not followed."""
self._obtain_metadata()
:raises PrivateProfileNotFollowedException: When logged in and the profile is private and not followed.
:raises LoginRequiredException: When not logged in and the profile is private."""
if not self._context.is_logged_in:
# As the logged-out web app, take the first posts from the profile page, and query further ones
# (PolarisLoggedOutDesktopWWWProfilePostsTabContentQuery_connection) by the page's "id" of the
# profile, which is not its user ID.
page = self._context.get_page_data(f"{self.username}/")
# The page shows no posts of a private profile, rather than an error.
if any((data.get("xig_user_by_username") or {}).get("is_private") for data in page):
raise LoginRequiredException(f"Login required to access the posts of private profile {self.username}.")
user = next((data["xig_user_by_username"] for data in page
if "polaris_ordered_timeline_connection" in (data.get("xig_user_by_username") or {})),
None)
if user is None:
raise BadResponseException(f"The page of profile {self.username} did not contain its posts.")
return NodeIterator(
context=self._context,
edge_extractor=lambda d: d["data"]["user"]["edge_owner_to_timeline_media"],
node_wrapper=lambda n: Post(self._context, n, self),
edge_extractor=lambda d: d["data"]["node"]["polaris_ordered_timeline_connection"],
# The nodes lack most of the post's metadata, as in get_reels().
node_wrapper=lambda n: Post.from_shortcode(self._context, n["code"]),
query_variables={
"data": {
"count": 12,
"include_relationship_info": True,
"latest_besties_reel_media": True,
"latest_reel_media": True,
},
"id": self.userid,
"id": user["id"],
"__relay_internal__pv__PolarisSEOIsCrawlerrelayprovider": False,
},
query_referer="https://www.instagram.com/{0}/".format(self.username),
is_first=Profile._make_is_newest_checker(),
doc_id="7950326061742207",
doc_id="28904005159232689",
query_hash=None,
first_data=self._metadata("edge_owner_to_timeline_media"),
first_data=user["polaris_ordered_timeline_connection"],
web_api=True,
)
self._obtain_metadata()
# Instagram answers with an empty timeline rather than an error in that case. Unlike followed_by_viewer,
# which defaults to False, friendship_status tells whether the follow state is actually known.
if (self.is_private and self.username != (self._context.username or '').lower() and