Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/actions/install-dependencies/action.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,9 @@ fi
if [[ "${INSTALL_TEST_REQUIREMENTS}" == "true" ]]; then
echo "Installing test requirements"
pip install -r requirements-test.txt
fi
fi

if [[ "${INSTALL_DOCS_REQUIREMENTS}" == "true" ]]; then
echo "Installing docs requirements"
pip install -r requirements-docs.txt
fi
7 changes: 6 additions & 1 deletion .github/actions/install-dependencies/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ inputs:
description: "Should requirements-test.txt be installed"
default: "false"
required: false
docs-requirements:
description: "Should requirements-docs.txt be installed"
default: "false"
required: false
runs:
using: "composite"
steps:
Expand All @@ -17,4 +21,5 @@ runs:
shell: "bash"
env:
INSTALL_REQUIREMENTS: ${{ inputs.requirements }}
INSTALL_TEST_REQUIREMENTS: ${{ inputs.test-requirements }}
INSTALL_TEST_REQUIREMENTS: ${{ inputs.test-requirements }}
INSTALL_DOCS_REQUIREMENTS: ${{ inputs.docs-requirements }}
2 changes: 1 addition & 1 deletion .github/actions/publish-docs-with-mike/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ runs:
USER_EMAIL: ${{ inputs.email }}
VERSION_NAME: ${{ inputs.version_name }}
NEW_VERSION: ${{ inputs.new_version }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ fi

echo "::debug::Falling back to GITHUB_ACTOR"
LOGIN="${GITHUB_ACTOR:-github_action}"
set_and_exit "${LOGIN}" "${LOGIN}${NO_REPLY_SUFFIX}"
set_and_exit "${LOGIN}" "${LOGIN}${NO_REPLY_SUFFIX}"
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ else
mike retitle --message "Remove latest from title of ${PREV_LATEST}" "${PREV_LATEST}" "${PREV_LATEST}"
fi
echo "mike deploy --update-aliases --title \"${NEW_VERSION} (latest)\" \"${NEW_VERSION}\" \"latest\""
mike deploy --update-aliases --title "${NEW_VERSION} (latest)" "${NEW_VERSION}" "latest"
mike deploy --update-aliases --title "${NEW_VERSION} (latest)" "${NEW_VERSION}" "latest"
8 changes: 5 additions & 3 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
pull_request: {}

env:
PYTHON_VERSION: "3.9.14"
PYTHON_VERSION: "3.13.5"

jobs:
bandit:
Expand Down Expand Up @@ -68,7 +68,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ "3.10" ]
python-version: [ "3.13.5" ]
env:
TEST_ACCOUNTS_URL: ${{ secrets.TEST_ACCOUNTS_URL }}
steps:
Expand Down Expand Up @@ -113,6 +113,7 @@ jobs:
with:
requirements: "true"
test-requirements: "true"
docs-requirements: "true"

- name: Build Docs
run: mkdocs build --strict
Expand Down Expand Up @@ -141,8 +142,9 @@ jobs:
with:
requirements: "true"
test-requirements: "true"
docs-requirements: "true"

- name: Push documentaiton changes
- name: Push documentation changes
uses: ./.github/actions/publish-docs-with-mike
with:
version_name: dev
9 changes: 3 additions & 6 deletions docker/devbox.dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
FROM python:3.11.4-buster
FROM python:3.13-bookworm

ARG _USER="instagrapi"
ARG _UID="1001"
ARG _GID="100"
ARG _SHELL="/bin/bash"


RUN useradd -m -s "${_SHELL}" -N -u "${_UID}" "${_USER}"

ENV USER ${_USER}
Expand All @@ -15,15 +14,13 @@ ENV HOME /home/${_USER}
ENV PATH "${HOME}/.local/bin/:${PATH}"
ENV PIP_NO_CACHE_DIR "true"


RUN mkdir /app && chown ${UID}:${GID} /app

USER ${_USER}

COPY --chown=${UID}:${GID} ./requirements* /app/
COPY --chown=${UID}:${GID} ./util /app/util/
WORKDIR /app

RUN pip install -r requirements.txt -r requirements-test.txt
RUN pip install -r requirements.txt -r requirements-test.txt -r requirements-docs.txt

CMD bash
CMD bash
2 changes: 1 addition & 1 deletion docker/lock_requirements.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ pip install -r requirements.txt
printf "# THIS IS AN AUTOGENERATED LOCKFILE. DO NOT EDIT MANUALLY.\n" > requirements.lock
pip freeze --disable-pip-version-check --all >> requirements.lock

echo "Rebuild containers to verify there are no conflicts."
echo "Rebuild containers to verify there are no conflicts."
6 changes: 3 additions & 3 deletions docker/run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ while [[ $# -gt 0 ]]; do
case $arg in
--format-code)
BLACK_ACTION="--quiet"
ISORT_ACTION="--recursive"
ISORT_ACTION=""
;;
-h|--help)
usage
Expand All @@ -36,8 +36,8 @@ done

python -m unittest tests.FakeClientTestCase tests.ClientPublicTestCase

echo "Running iSort..."
echo "Running isort..."
isort ${ISORT_ACTION} instagrapi

echo "Running flake8..."
flake8 instagrapi --count --exit-zero --statistics
flake8 instagrapi --count --exit-zero --statistics
32 changes: 30 additions & 2 deletions instagrapi/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,39 @@
# QUERY_HASH_COMMENTS = '33ba35852cb50da46f5b5e889df7d159'
# QUERY_HASH_TAGGED_MEDIAS = 'be13233562af2d229b008d2976b998b5'

LOGIN_EXPERIMENTS = "ig_android_reg_nux_headers_cleanup_universe,ig_android_device_detection_info_upload,ig_android_nux_add_email_device,ig_android_gmail_oauth_in_reg,ig_android_device_info_foreground_reporting,ig_android_device_verification_fb_signup,ig_android_direct_main_tab_universe_v2,ig_android_passwordless_account_password_creation_universe,ig_android_direct_add_direct_to_android_native_photo_share_sheet,ig_growth_android_profile_pic_prefill_with_fb_pic_2,ig_account_identity_logged_out_signals_global_holdout_universe,ig_android_quickcapture_keep_screen_on,ig_android_device_based_country_verification,ig_android_login_identifier_fuzzy_match,ig_android_reg_modularization_universe,ig_android_security_intent_switchoff,ig_android_device_verification_separate_endpoint,ig_android_suma_landing_page,ig_android_sim_info_upload,ig_android_smartlock_hints_universe,ig_android_fb_account_linking_sampling_freq_universe,ig_android_retry_create_account_universe,ig_android_caption_typeahead_fix_on_o_universe"
LOGIN_EXPERIMENTS = (
"ig_android_reg_nux_headers_cleanup_universe,"
"ig_android_device_detection_info_upload,"
"ig_android_nux_add_email_device,"
"ig_android_gmail_oauth_in_reg,"
"ig_android_device_info_foreground_reporting,"
"ig_android_device_verification_fb_signup,"
"ig_android_direct_main_tab_universe_v2,"
"ig_android_passwordless_account_password_creation_universe,"
"ig_android_direct_add_direct_to_android_native_photo_share_sheet,"
"ig_growth_android_profile_pic_prefill_with_fb_pic_2,"
"ig_account_identity_logged_out_signals_global_holdout_universe,"
"ig_android_quickcapture_keep_screen_on,"
"ig_android_device_based_country_verification,"
"ig_android_login_identifier_fuzzy_match,"
"ig_android_reg_modularization_universe,"
"ig_android_security_intent_switchoff,"
"ig_android_device_verification_separate_endpoint,"
"ig_android_suma_landing_page,"
"ig_android_sim_info_upload,"
"ig_android_smartlock_hints_universe,"
"ig_android_fb_account_linking_sampling_freq_universe,"
"ig_android_retry_create_account_universe,"
"ig_android_caption_typeahead_fix_on_o_universe"
)

SUPPORTED_CAPABILITIES = [
{
"value": "119.0,120.0,121.0,122.0,123.0,124.0,125.0,126.0,127.0,128.0,129.0,130.0,131.0,132.0,133.0,134.0,135.0,136.0,137.0,138.0,139.0,140.0,141.0,142.0",
"value": (
"119.0,120.0,121.0,122.0,123.0,124.0,125.0,126.0,127.0,128.0,"
"129.0,130.0,131.0,132.0,133.0,134.0,135.0,136.0,137.0,138.0,"
"139.0,140.0,141.0,142.0"
),
"name": "SUPPORTED_SDK_VERSIONS",
},
{"value": "14", "name": "FACE_TRACKER_VERSION"},
Expand Down
2 changes: 1 addition & 1 deletion instagrapi/extractors.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from .types import (
Account,
Broadcast,
Collection,
Comment,
DirectMedia,
Expand All @@ -29,7 +30,6 @@
StoryMedia,
StoryMention,
Track,
Broadcast,
User,
UserShort,
Usertag,
Expand Down
7 changes: 3 additions & 4 deletions instagrapi/mixins/account.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import json
from json.decoder import JSONDecodeError
from pathlib import Path
from typing import Dict

import json
import requests

from instagrapi.exceptions import ClientError, ClientLoginRequired
Expand Down Expand Up @@ -105,7 +105,7 @@ def change_password(
return False

def remove_bio_links(self, link_ids: list[int]) -> dict:
signed_body={
signed_body = {
"signed_body": "SIGNATURE." + json.dumps(
{
"_uid": self.user_id,
Expand All @@ -114,8 +114,7 @@ def remove_bio_links(self, link_ids: list[int]) -> dict:
}
)
}
return self.private_request('accounts/remove_bio_links/', data = signed_body, with_signature = False)

return self.private_request('accounts/remove_bio_links/', data=signed_body, with_signature=False)

def set_external_url(self, external_url) -> dict:
"""
Expand Down
6 changes: 4 additions & 2 deletions instagrapi/mixins/album.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ def album_download(self, media_pk: int, folder: Path = "") -> List[Path]:
media_pk: int
PK for the album you want to download
folder: Path, optional
Directory in which you want to download the album, default is "" and will download the files to working directory.
Directory in which you want to download the album, default is ""
and will download the files to working directory.

Returns
-------
Expand Down Expand Up @@ -62,7 +63,8 @@ def album_download_by_urls(self, urls: List[str], folder: Path = "") -> List[Pat
urls: List[str]
List of URLs to download media from
folder: Path, optional
Directory in which you want to download the album, default is "" and will download the files to working directory.
Directory in which you want to download the album, default is ""
and will download the files to working directory.

Returns
-------
Expand Down
24 changes: 14 additions & 10 deletions instagrapi/mixins/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ def get_timeline_feed(
}
data = {
"has_camera_permission": "1",
"feed_view_info": "[]", # e.g. [{"media_id":"2634223601739446191_7450075998","version":24,"media_pct":1.0,"time_info":{"10":63124,"25":63124,"50":63124,"75":63124},"latest_timestamp":1628253523186}]
"feed_view_info": "[]", # e.g. [{"media_id":"2634223601739446191_7450075998","version":24,
# "media_pct":1.0,"time_info":{"10":63124,"25":63124,"50":63124,"75":63124},"latest_timestamp":1628253523186}]
"phone_id": self.phone_id,
"reason": reason,
"battery_level": 100, # Random battery level is not simulating real bahaviour
Expand Down Expand Up @@ -265,7 +266,8 @@ def get_reels_tray_feed(
"timezone_offset": str(self.timezone_offset),
"tray_session_id": self.tray_session_id,
"request_id": self.request_id,
# "latest_preloaded_reel_ids": "[]", # [{"reel_id":"6009504750","media_count":"15","timestamp":1628253494,"media_ids":"[\"2634301737009283814\",\"2634301789371018685\",\"2634301853921370532\",\"2634301920174570551\",\"2634301973895112725\",\"2634302037581608844\",\"2634302088273817272\",\"2634302822117736694\",\"2634303181452199341\",\"2634303245482345741\",\"2634303317473473894\",\"2634303382971517344\",\"2634303441062726263\",\"2634303502039423893\",\"2634303754729475501\"]"},{"reel_id":"4357392188","media_count":"4","timestamp":1628250613,"media_ids":"[\"2634142331579781054\",\"2634142839803515356\",\"2634150786575125861\",\"2634279566740346641\"]"},{"reel_id":"5931631205","media_count":"7","timestamp":1628253023,"media_ids":"[\"2633699694927154768\",\"2634153361241413763\",\"2634196788830183839\",\"2634219197377323622\",\"2634294221109889541\",\"2634299705648894876\",\"2634299760434939842\"]"}],
# "latest_preloaded_reel_ids": "[]", # Long JSON array with reel data
# Example: [{"reel_id":"6009504750","media_count":"15","timestamp":1628253494,"media_ids":"..."}]
"page_size": 50,
# "_csrftoken": self.token,
"_uuid": self.uuid,
Expand All @@ -280,7 +282,6 @@ def get_reels_tray_feed(
class LoginMixin(PreLoginFlowMixin, PostLoginFlowMixin):
username = None
password = None
authorization = "" # Bearer IGT:2:<base64:authorization_data>
authorization_data = {} # decoded authorization header
last_login = None
relogin_attempt = 0
Expand All @@ -298,7 +299,8 @@ class LoginMixin(PreLoginFlowMixin, PostLoginFlowMixin):
country_code = 1 # Phone code, default USA
locale = "en_US"
timezone_offset: int = -14400 # New York, GMT-4 in seconds
ig_u_rur = "" # e.g. CLN,49897488153,1666640702:01f7bdb93090f4f773516fc2cf1424178a58a2295b4c754090ba02cb0a834e2d1f731e20
# Example: CLN,49897488153,1666640702:01f7bdb93090f4f773516fc2cf1424178a58a2295b4c754090ba02cb0a834e2d1f731e20
ig_u_rur = ""
ig_www_claim = "" # e.g. hmac.AR2uidim8es5kYgDiNxY0UG_ZhffFFSt8TGCV5eA1VYYsMNx

def __init__(self):
Expand All @@ -325,7 +327,9 @@ def init(self) -> bool:
)
self.set_device(self.settings.get("device_settings"))
# c7aeefd59aab78fc0a703ea060ffb631e005e2b3948efb9d73ee6a346c446bf3
self.bloks_versioning_id = "ce555e5500576acd8e84a66018f54a05720f2dce29f0bb5a1f97f0c10d6fac48" # this param is constant and will change by Instagram app version
self.bloks_versioning_id = (
"ce555e5500576acd8e84a66018f54a05720f2dce29f0bb5a1f97f0c10d6fac48"
) # this param is constant and will change by Instagram app version
self.set_user_agent(self.settings.get("user_agent"))
self.set_uuids(self.settings.get("uuids") or {})
self.set_locale(self.settings.get("locale", self.locale))
Expand Down Expand Up @@ -397,11 +401,9 @@ def login(
bool
A boolean value
"""

if username and password:
self.username = username
self.password = password

if self.username is None or self.password is None:
raise BadCredentials("Both username and password must be provided.")

Expand All @@ -426,8 +428,9 @@ def login(
enc_password = self.password_encrypt(self.password)
data = {
"jazoest": generate_jazoest(self.phone_id),
"country_codes": '[{"country_code":"%d","source":["default"]}]'
% int(self.country_code),
"country_codes": '[{"country_code":"%d","source":["default"]}]' % int(
self.country_code
),
"phone_id": self.phone_id,
"enc_password": enc_password,
"username": username,
Expand Down Expand Up @@ -882,7 +885,8 @@ def authorization(self) -> str:
return ""

def dump_instaman(self):
# helen9151hernandez:AgcXb0GJhAP|Instagram 200.0.0.24.121 Android (24/7.0; 640dpi; 1440x2392; Samsung; SGH-T849; SGH-T849; hi3660; pt_BR; 304101669)|097e7efb59ba976b;03c1746f-77cd-4ac6-8f7e-175b0ba0dc17;c4155719-9d80-466c-b3f7-f98f0a14a372;7fa9e7c7-75e1-498f-8d0f-8f56fe7a4f45|X-MID=YaHXxQABAAFcCc6aAC_OQ53CVDbd;IG-U-DS-USER-ID=50511821576;IG-U-RUR=FRC,50511821576,1669532533:01f705b9f6a7411dc1e985485b1fe39dd317e97b2cf166f380148836d9c2e5233cac5476;Authorization=Bearer IGT:2:eyJkc191c2VyX2lkIjoiNTA1MTE4MjE1NzYiLCJzZXNzaW9uaWQiOiI1MDUxMTgyMTU3NiUzQWtyaEVSbHF2VW8wbnRXJTNBMjQiLCJzaG91bGRfdXNlX2hlYWRlcl9vdmVyX2Nvb2tpZXMiOnRydWV9;X-IG-WWW-Claim=hmac.AR300vJeNkurM8IGnekSoFtSKJmXazjxOawhWNC3d1Gw1OiX;||
# Example format: helen9151hernandez:AgcXb0GJhAP|Instagram 200.0.0.24.121 Android...
# Long string with user credentials and device info
uuids = ";".join(
[
self.android_device_id.replace("android-", ""),
Expand Down
1 change: 0 additions & 1 deletion instagrapi/mixins/media.py
Original file line number Diff line number Diff line change
Expand Up @@ -1154,7 +1154,6 @@ def media_unpin(self, media_pk):
"""
return self.media_pin(media_pk, True)


def media_create_livestream(self, title="Instagram Live"):
"""
Create a new live broadcast.
Expand Down
4 changes: 2 additions & 2 deletions instagrapi/mixins/photo.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
StoryLocation,
StoryMedia,
StoryMention,
StorySticker,
StoryPoll,
StorySticker,
Usertag,
)
from instagrapi.utils import date_time_original, dumps
Expand Down Expand Up @@ -699,7 +699,7 @@ def photo_configure_to_story(
"count": 0,
"font_size": 39.0,
"text": o
}
}
for o in poll.options
],
**poll_extra,
Expand Down
9 changes: 3 additions & 6 deletions instagrapi/mixins/signup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import base64
import random
import time
from datetime import datetime
from uuid import uuid4

from instagrapi.extractors import extract_user_short
Expand Down Expand Up @@ -127,9 +125,8 @@ def accounts_create(
day: int = None,
**kwargs,
) -> dict:
timestamp = datetime.now().strftime("%s")
nonce = f'{username}|{timestamp}|\xb9F"\x8c\xa2I\xaaz|\xf6xz\x86\x92\x91Y\xa5\xaa#f*o%\x7f'
sn_nonce = base64.encodebytes(nonce.encode()).decode().strip()
# timestamp = datetime.now().strftime("%s") # Unused variable
# nonce = f'{username}|{timestamp}|\xb9F"\x8c\xa2I\xaaz|\xf6xz\x86\x92\x91Y\xa5\xaa#f*o%\x7f' # Unused variable
data = {
"is_secondary_account_creation": "true",
"jazoest": str(int(random.randint(22300, 22399))), # "22341",
Expand All @@ -149,7 +146,7 @@ def accounts_create(
"one_tap_opt_in": "true",
**kwargs,
}
return self.private_request("accounts/create/", data, domain= "www.instagram.com")
return self.private_request("accounts/create/", data, domain="www.instagram.com")

def challenge_flow(self, data):
data = self.challenge_api(data)
Expand Down
Loading
Loading