Skip to content

Commit f66401b

Browse files
authored
Merge branch 'master' into dependabot/pip/isort-7.0.0
2 parents 019f65a + 3ecfbd1 commit f66401b

File tree

9 files changed

+173
-36
lines changed

9 files changed

+173
-36
lines changed

.github/workflows/python-package.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ jobs:
121121
# upload artifact for dev build
122122
- name: Upload coverage results artifact
123123
if: github.ref != 'refs/heads/main'
124-
uses: actions/upload-artifact@v5
124+
uses: actions/upload-artifact@v6
125125
with:
126126
name: docs-site
127127
path: site/

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,27 @@ The instagrapi more suits for testing or research than a working business!
2525
* [InstaSurfBot](https://t.me/InstaSurfBot) telegram bot for downloading medias from Instagram ❤️
2626
* [OSINTagramBot](https://t.me/OSINTagramBot) telegram bot for OSINT on Instagram 🕵️‍♂️
2727

28+
29+
### 💰 [HikerAPI Affiliate Program](https://hikerapi.com/help/affiliate) — Up to 50% Commission!
30+
31+
Refer users to HikerAPI and earn a percentage of their API spending:
32+
33+
| Plan | Commission |
34+
|------|------------|
35+
| Start ($0.02/req) | **50%** |
36+
| Standard ($0.001/req) | **25%** |
37+
| Business ($0.00069/req) | **15%** |
38+
| Ultra ($0.0006/req) | **10%** |
39+
40+
**How it works:**
41+
1. Create your promo code in the [dashboard](https://hikerapi.com/affiliate)
42+
2. Share it with your audience (in your GitHub repositories)
43+
3. Earn commission on every request they make
44+
45+
**Payouts:** USDT (TRC-20 or ERC-20), minimum $500
46+
47+
------
48+
2849
[![Package](https://github.com/subzeroid/instagrapi/actions/workflows/python-package.yml/badge.svg?branch=master&1)](https://github.com/subzeroid/instagrapi/actions/workflows/python-package.yml)
2950
[![PyPI](https://img.shields.io/pypi/v/instagrapi)](https://pypi.org/project/instagrapi/)
3051
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/instagrapi)

instagrapi/config.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,31 @@
1010
"{dpi}; {resolution}; {manufacturer}; "
1111
"{model}; {device}; {cpu}; {locale}; {version_code})"
1212
)
13+
14+
# Default device profile (hardware/system) and app version settings.
15+
DEVICE_SETTINGS = {
16+
"android_version": 26,
17+
"android_release": "8.0.0",
18+
"dpi": "480dpi",
19+
"resolution": "1080x1920",
20+
"manufacturer": "OnePlus",
21+
"device": "devitron",
22+
"model": "6T Dev",
23+
"cpu": "qcom",
24+
}
25+
APP_SETTINGS = {
26+
"364.0.0.35.86": {
27+
"app_version": "364.0.0.35.86",
28+
"version_code": "374010953",
29+
"bloks_versioning_id": "8ccf54aad76788a6ca03ddfc33afcdcf692f2f5a3ba814ea73d5facba7fa2c2d",
30+
},
31+
"385.0.0.47.74": {
32+
"app_version": "385.0.0.47.74",
33+
"version_code": "378906843",
34+
"bloks_versioning_id": "a8973d49a9cc6a6f65a4997c10216ce2a06f65a517010e64885e92029bb19221",
35+
},
36+
}
37+
1338
# Instagram 76.0.0.15.395 (iPhone9,2; iOS 10_0_2; en_US; en-US; scale=2.61; 1080x1920) AppleWebKit/420+
1439
# Instagram 208.0.0.32.135 (iPhone; iOS 14_7_1; en_US; en-US; scale=2.61; 1080x1920) AppleWebKit/605.1.15
1540

instagrapi/mixins/auth.py

Lines changed: 86 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def get_prefill_candidates(self, login: bool = False) -> Dict:
8282
data = {
8383
"android_device_id": self.android_device_id,
8484
"client_contact_points": '[{"type":"omnistring","value":"%s","source":"last_login_attempt"}]'
85-
% self.username,
85+
% self.username,
8686
"phone_id": self.phone_id,
8787
"usages": '["account_recovery_omnibox"]',
8888
"logged_in_user_ids": "[]", # "[\"123456789\",\"987654321\"]",
@@ -188,7 +188,7 @@ def login_flow(self) -> bool:
188188
return all(check_flow)
189189

190190
def get_timeline_feed(
191-
self, reason: TIMELINE_FEED_REASON = "pull_to_refresh", max_id: str = None
191+
self, reason: TIMELINE_FEED_REASON = "pull_to_refresh", max_id: str = None
192192
) -> Dict:
193193
"""
194194
Get your timeline feed
@@ -246,7 +246,7 @@ def get_timeline_feed(
246246
)
247247

248248
def get_reels_tray_feed(
249-
self, reason: REELS_TRAY_REASON = "pull_to_refresh"
249+
self, reason: REELS_TRAY_REASON = "pull_to_refresh"
250250
) -> Dict:
251251
"""
252252
Get your reels tray feed
@@ -305,8 +305,10 @@ class LoginMixin(PreLoginFlowMixin, PostLoginFlowMixin):
305305
ig_www_claim = "" # e.g. hmac.AR2uidim8es5kYgDiNxY0UG_ZhffFFSt8TGCV5eA1VYYsMNx
306306

307307
def __init__(self):
308+
self.bloks_versioning_id = "ce555e5500576acd8e84a66018f54a05720f2dce29f0bb5a1f97f0c10d6fac48"
308309
self.user_agent = None
309310
self.settings = None
311+
self.override_app_version = False
310312

311313
def init(self) -> bool:
312314
"""
@@ -327,10 +329,6 @@ def init(self) -> bool:
327329
self.settings.get("timezone_offset", self.timezone_offset)
328330
)
329331
self.set_device(self.settings.get("device_settings"))
330-
# c7aeefd59aab78fc0a703ea060ffb631e005e2b3948efb9d73ee6a346c446bf3
331-
self.bloks_versioning_id = (
332-
"ce555e5500576acd8e84a66018f54a05720f2dce29f0bb5a1f97f0c10d6fac48"
333-
) # this param is constant and will change by Instagram app version
334332
self.set_user_agent(self.settings.get("user_agent"))
335333
self.set_uuids(self.settings.get("uuids") or {})
336334
self.set_locale(self.settings.get("locale", self.locale))
@@ -377,11 +375,11 @@ def login_by_sessionid(self, sessionid: str) -> bool:
377375
return True
378376

379377
def login(
380-
self,
381-
username: Union[str, None] = None,
382-
password: Union[str, None] = None,
383-
relogin: bool = False,
384-
verification_code: str = "",
378+
self,
379+
username: Union[str, None] = None,
380+
password: Union[str, None] = None,
381+
relogin: bool = False,
382+
verification_code: str = "",
385383
) -> bool:
386384
"""
387385
Login
@@ -603,20 +601,26 @@ def set_settings(self, settings: Dict) -> bool:
603601
self.init()
604602
return True
605603

606-
def load_settings(self, path: Union[str, Path]) -> Dict:
604+
def load_settings(self, path: Union[str, Path], override_app_version: bool = False) -> Dict:
607605
"""
608606
Load session settings
609607
610608
Parameters
611609
----------
612610
path: Path
613611
Path to storage file
612+
override_app_version: bool, optional
613+
Mismatched app_version/version_code/bloks_versioning_id may
614+
increase risk. If True, override with a known version from
615+
APP_SETTINGS (in memory). Call dump_settings() to persist.
616+
614617
615618
Returns
616619
-------
617620
Dict
618621
Current session settings as a Dict
619622
"""
623+
self.override_app_version = override_app_version
620624
with open(path, "r") as fp:
621625
self.set_settings(json.load(fp))
622626
return self.settings
@@ -652,22 +656,77 @@ def set_device(self, device: Dict = None, reset: bool = False) -> bool:
652656
bool
653657
A boolean value
654658
"""
655-
self.device_settings = device or {
656-
"app_version": "269.0.0.18.75",
657-
"android_version": 26,
658-
"android_release": "8.0.0",
659-
"dpi": "480dpi",
660-
"resolution": "1080x1920",
661-
"manufacturer": "OnePlus",
662-
"device": "devitron",
663-
"model": "6T Dev",
664-
"cpu": "qcom",
665-
"version_code": "314665256",
666-
}
667-
self.settings["device_settings"] = self.device_settings
659+
device = device or {}
660+
self.device_settings = dict(config.DEVICE_SETTINGS)
661+
self.device_settings.update(device)
662+
seed = None
663+
if self.settings:
664+
uuids = self.settings.get("uuids") or {}
665+
seed = uuids.get("uuid")
666+
self.set_app(seed=seed)
668667
if reset:
669668
self.set_uuids({})
670-
# self.settings = self.get_settings()
669+
return True
670+
671+
def set_app(self, app: Union[str, Dict] = None, seed: str = None) -> bool:
672+
"""
673+
Helper to set app version settings
674+
675+
Parameters
676+
----------
677+
app: Union[str, Dict], optional
678+
App version string or settings dict
679+
seed: str, optional
680+
Seed used for stable app selection
681+
682+
Returns
683+
-------
684+
bool
685+
A boolean value
686+
"""
687+
app_keys = ("app_version", "version_code", "bloks_versioning_id")
688+
if not getattr(self, "device_settings", None):
689+
self.device_settings = dict(config.DEVICE_SETTINGS)
690+
if not config.APP_SETTINGS:
691+
raise ValueError("APP_SETTINGS is empty")
692+
override_app_version = bool(getattr(self, "override_app_version", False))
693+
694+
def apply_settings(app_settings: Dict) -> None:
695+
for key in app_keys:
696+
val = app_settings.get(key)
697+
if val:
698+
self.device_settings[key] = val
699+
700+
def pick_by_seed() -> Dict:
701+
app_values = list(config.APP_SETTINGS.values())
702+
if seed:
703+
digest = hashlib.sha256(seed.encode("utf-8")).hexdigest()
704+
idx = int(digest, 16) % len(app_values)
705+
return app_values[idx]
706+
return random.choice(app_values)
707+
708+
if app:
709+
if isinstance(app, str):
710+
matched = config.APP_SETTINGS.get(app)
711+
if not matched:
712+
raise ValueError(f"Unknown app_version: {app}")
713+
apply_settings(matched)
714+
else:
715+
apply_settings(dict(app))
716+
else:
717+
app_version = self.device_settings.get("app_version")
718+
matched = config.APP_SETTINGS.get(app_version) if app_version else None
719+
if matched:
720+
apply_settings(matched)
721+
else:
722+
if override_app_version or not app_version:
723+
apply_settings(pick_by_seed())
724+
725+
if override_app_version:
726+
self.set_user_agent()
727+
self.bloks_versioning_id = self.device_settings.get("bloks_versioning_id")
728+
if self.settings is not None:
729+
self.settings["device_settings"] = self.device_settings
671730
return True
672731

673732
def set_user_agent(self, user_agent: str = "", reset: bool = False) -> bool:

instagrapi/mixins/private.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def base_headers(self):
166166
"X-IG-Android-ID": self.android_device_id,
167167
"X-IG-Timezone-Offset": str(self.timezone_offset),
168168
"X-IG-Connection-Type": "WIFI",
169-
"X-IG-Capabilities": "3brTvx0=", # "3brTvwE=" in instabot
169+
"X-IG-Capabilities": "3brTv10=", # "3brTvwE=" in instabot
170170
"X-IG-App-ID": self.app_id,
171171
"Priority": "u=3",
172172
"User-Agent": self.user_agent,

instagrapi/types.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,10 @@ class SharedMediaImageCandidate(TypesBaseModel):
173173

174174
estimated_scans_sizes: List[int] = []
175175
height: int
176-
scans_profile: str
176+
scans_profile: Optional[str] = None
177177
url: str
178178
width: int
179+
is_spatial_image: Optional[bool] = None
179180

180181

181182
class ScrubberSpritesheetInfo(TypesBaseModel):
@@ -349,6 +350,37 @@ class ClipsOriginalSoundInfo(TypesBaseModel):
349350
fb_downstream_use_xpost_metadata: ClipsFbDownstreamUseXpostMetadata
350351

351352

353+
class ClipsReusableTextColor(TypesBaseModel):
354+
"""Color information for reusable text in clips"""
355+
356+
count: int
357+
hex_rgba_color: str
358+
359+
360+
class ClipsReusableTextInfo(TypesBaseModel):
361+
"""Reusable text information for clips"""
362+
363+
alignment: str
364+
end_time_ms: float
365+
font_size: float
366+
height: float
367+
id: str
368+
is_animated: bool
369+
offset_x: float
370+
offset_y: float
371+
rotation_degree: float
372+
scale: float
373+
start_time_ms: float
374+
text: str
375+
text_emphasis_mode: str
376+
text_format_type: str
377+
width: float
378+
z_index: int
379+
effects: str = ""
380+
animation: str = ""
381+
colors: List[ClipsReusableTextColor] = []
382+
383+
352384
class ClipsMetadata(TypesBaseModel):
353385
"""Complete clips metadata structure for Media objects"""
354386

@@ -382,7 +414,7 @@ class ClipsMetadata(TypesBaseModel):
382414
originality_info: Optional[dict] = None
383415
reels_on_the_rise_info: Optional[dict] = None
384416
reusable_text_attribute_string: Optional[str] = None
385-
reusable_text_info: Optional[dict] = None
417+
reusable_text_info: Optional[List[ClipsReusableTextInfo]] = None
386418
shopping_info: Optional[dict] = None
387419
show_achievements: bool = False
388420
template_info: Optional[dict] = None

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,12 @@ Repository = "https://github.com/subzeroid/instagrapi"
8282
[project.optional-dependencies]
8383
test = [
8484
"flake8==7.3.0",
85-
"Pillow==11.3.0",
85+
"Pillow==12.1.0",
8686
"isort==7.0.0",
8787
"bandit==1.8.6",
8888
"mike==2.1.3",
8989
"markdown-include==0.8.1",
90-
"mkdocs-material==9.7.0",
90+
"mkdocs-material==9.7.1",
9191
"mkdocs-minify-html-plugin>=0.3.1",
9292
"mkdocstrings==0.30.1",
9393
"pytest-xdist==3.8.0",

requirements-docs.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ setuptools==68.2.2
77

88
markdown-include==0.8.1
99
mkdocs==1.6.1
10-
mkdocs-material==9.7.0
10+
mkdocs-material==9.7.1
1111
mkdocs-minify-plugin==0.8.0
1212
mkdocs-redirects==1.2.2
13-
mkdocstrings[python]==0.30.1
13+
mkdocstrings[python]==1.0.0
1414
mkdocs-autorefs>=1.0.0

requirements-test.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
flake8==7.3.0
2-
Pillow==11.3.0
2+
Pillow==12.1.0
33
isort==7.0.0
44
bandit==1.8.6
55
pytest-xdist==3.8.0

0 commit comments

Comments
 (0)