├── .github └── CONTRIBUTING.md ├── .gitignore ├── Dockerfile ├── InstagramAPI ├── __init__.py └── src │ ├── Checkpoint.py │ ├── Constants.py │ ├── Instagram.py │ ├── InstagramException.py │ ├── InstagramRegistration.py │ ├── SignatureUtils.py │ ├── Utils │ ├── Compat.py │ ├── Settings.py │ ├── Utils.py │ ├── __init__.py │ └── php.py │ ├── __init__.py │ ├── data │ ├── .gitkeep │ └── backup │ │ └── .gitkeep │ └── http │ ├── HttpInterface.py │ ├── Response │ ├── AccountCreationResponse.py │ ├── ChallengeResponse.py │ ├── CheckEmailResponse.py │ ├── CheckUsernameResponse.py │ ├── CommentResponse.py │ ├── ConfigureResponse.py │ ├── ConfigureVideoResponse.py │ ├── ExploreResponse.py │ ├── ExposeResponse.py │ ├── FollowerResponse.py │ ├── FollowingResponse.py │ ├── LocationResponse.py │ ├── LoginResponse.py │ ├── LogoutResponse.py │ ├── MediaCommentsResponse.py │ ├── MediaInfoResponse.py │ ├── MediaLikersResponse.py │ ├── MegaphoneLogResponse.py │ ├── Objects │ │ ├── Caption.py │ │ ├── Comment.py │ │ ├── Experiment.py │ │ ├── Explore.py │ │ ├── FeedAysf.py │ │ ├── FriendshipStatus.py │ │ ├── HdProfilePicUrlInfo.py │ │ ├── In.py │ │ ├── Inbox.py │ │ ├── Item.py │ │ ├── Location.py │ │ ├── Param.py │ │ ├── Position.py │ │ ├── Suggestion.py │ │ ├── Tray.py │ │ ├── User.py │ │ ├── Usertag.py │ │ ├── VideoVersions.py │ │ ├── _Message.py │ │ └── __init__.py │ ├── PendingInboxResponse.py │ ├── ProfileResponse.py │ ├── RankedRecipientsResponse.py │ ├── RecentRecipientsResponse.py │ ├── ReelsTrayFeedResponse.py │ ├── Response.py │ ├── SyncResponse.py │ ├── TagFeedResponse.py │ ├── TimelineFeedResponse.py │ ├── UploadJobVideoResponse.py │ ├── UploadPhotoResponse.py │ ├── UploadVideoResponse.py │ ├── UserFeedResponse.py │ ├── UsernameInfoResponse.py │ ├── UsernameSuggestionsResponse.py │ ├── UsertagsResponse.py │ ├── V2InboxResponse.py │ ├── __init__.py │ └── autoCompleteUserListResponse.py │ ├── UserAgent.py │ ├── __init__.py │ └── devices.csv ├── LICENSE ├── MANIFEST.in ├── README.md ├── README.rst ├── examples ├── assets │ └── instagram.png ├── checkpoint.py ├── registrationTool.py ├── uploadPhoto.py └── uploadVideo.py ├── requirements.txt └── setup.py /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Steps for creating good issues or pull requests. 2 | 3 | **Pull requests are highly welcome** but (*please read below*) 4 | 5 | I might never be able merge some pull requests because of code maintenance issue, 6 | I try very hard to make this repo an exact replica of the [PHP](https://github.com/mgp25/Instagram-API) side from the 7 | 8 | - The project name :) 9 | - Variable names 10 | - Folder structure (every *.php file has its *.py sister) 11 | - Class names and Order of functions in a class 12 | - Funtion/Method signature 13 | - Package names 14 | 15 | - ** the project doesn't follow PEP standards if it will take out similarity** 16 | 17 | this makes the php wiki 100% applicable. 18 | 19 | this has been achieved by bringing changes to this side in the same order of commits as they are made on the php side. 20 | 21 | For example, 22 | At the time of updating this guidelines, this project is believed (by me :) ) to be ~exactly similar to the php project at this [commit](https://github.com/mgp25/Instagram-API/commit/7c37130890287287b0d2a6823cfbd9caffaf2a03), 23 | that is this [commit](https://github.com/danleyb2/Instagram-API/commit/be1d4357d896af9581c1be96a74136eebc12667a) on this project. (try opening the above commits in two new tabs and compare) 24 | 25 | 26 | So if your PR is about a change that is already on the **PHP** project but made at a later commit like say [this](https://github.com/mgp25/Instagram-API/commit/c03d72e01425f63ec8386d833fd4410f6aac9c7c), 27 | the maintainers wont be able to **merge** because we believe (it's true :) ) it will be replicated to this side when it's reached and we dont want to get a very hard time then. if you think otherwise, please raise an issue. 28 | 29 | 30 | **But you are always free to fork and do anything you want to your fork** 31 | 32 | Here is a video on an easy way to help do the translations 33 | https://www.youtube.com/watch?v=ExFAUFcUN5I 34 | 35 | Thank you. 36 | 37 | 38 | ## Links to external documentation, mailing lists, or a code of conduct. 39 | ## Community and behavioral expectations. 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.dat 3 | 4 | sigs/sigs 5 | 6 | sigs/sigKeys 7 | 8 | 9 | *.DS_Store 10 | 11 | .idea 12 | 13 | backup/ 14 | 15 | # Byte-compiled / optimized / DLL files 16 | __pycache__/ 17 | *.py[cod] 18 | *$py.class 19 | 20 | # C extensions 21 | *.so 22 | 23 | # Distribution / packaging 24 | .Python 25 | env/ 26 | build/ 27 | develop-eggs/ 28 | dist/ 29 | downloads/ 30 | eggs/ 31 | .eggs/ 32 | lib/ 33 | lib64/ 34 | parts/ 35 | sdist/ 36 | var/ 37 | wheels/ 38 | *.egg-info/ 39 | .installed.cfg 40 | *.egg 41 | 42 | # PyInstaller 43 | # Usually these files are written by a python script from a template 44 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 45 | *.manifest 46 | *.spec 47 | 48 | # Installer logs 49 | pip-log.txt 50 | pip-delete-this-directory.txt 51 | 52 | # Unit test / coverage reports 53 | htmlcov/ 54 | .tox/ 55 | .coverage 56 | .coverage.* 57 | .cache 58 | nosetests.xml 59 | coverage.xml 60 | *,cover 61 | .hypothesis/ 62 | 63 | # Translations 64 | *.mo 65 | *.pot 66 | 67 | # Django stuff: 68 | *.log 69 | local_settings.py 70 | 71 | # Flask stuff: 72 | instance/ 73 | .webassets-cache 74 | 75 | # Scrapy stuff: 76 | .scrapy 77 | 78 | # Sphinx documentation 79 | docs/_build/ 80 | 81 | # PyBuilder 82 | target/ 83 | 84 | # Jupyter Notebook 85 | .ipynb_checkpoints 86 | 87 | # pyenv 88 | .python-version 89 | 90 | # celery beat schedule file 91 | celerybeat-schedule 92 | 93 | # dotenv 94 | .env 95 | 96 | # virtualenv 97 | .venv/ 98 | venv/ 99 | ENV/ 100 | 101 | # Spyder project settings 102 | .spyderproject 103 | 104 | # Rope project settings 105 | .ropeproject 106 | 107 | # Backup files 108 | *~ -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:2.7 2 | RUN mkdir /app 3 | WORKDIR /app 4 | ADD requirements.txt /app/ 5 | RUN pip install -r requirements.txt 6 | ADD . /app/ 7 | -------------------------------------------------------------------------------- /InstagramAPI/__init__.py: -------------------------------------------------------------------------------- 1 | from .src import * 2 | -------------------------------------------------------------------------------- /InstagramAPI/src/Checkpoint.py: -------------------------------------------------------------------------------- 1 | import json 2 | import pycurl 3 | from collections import OrderedDict 4 | 5 | import os 6 | import re 7 | 8 | from InstagramAPI.src.Utils import Settings, json_decode 9 | 10 | try: 11 | from io import BytesIO 12 | except ImportError: 13 | from StringIO import StringIO as BytesIO 14 | 15 | 16 | class Checkpoint(object): 17 | def __init__(self, username, settingsPath=None, debug=False): 18 | self.username = None 19 | self.settingsPath = None 20 | self.settings = None 21 | self.userAgent = None 22 | self.debug = None 23 | 24 | self.username = username 25 | self.debug = debug 26 | 27 | if not settingsPath: 28 | self.settingsPath = os.path.join( 29 | os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data'), 30 | username, 31 | '' 32 | ) 33 | if not os.path.isdir(self.settingsPath): os.mkdir(self.settingsPath, 0o777) 34 | 35 | self.settings = Settings(self.settingsPath + 'settings-' + username + '.dat') 36 | self.userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_3_3 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Mobile/13G34 Instagram 8.5.2 (iPhone5,2; iPhone OS 9_3_3; es_ES; es-ES; scale=2.00; 640x1136)' 37 | 38 | def doCheckpoint(self): 39 | token = self.checkpointFirstStep() 40 | self.checkpointSecondStep(token) 41 | 42 | return token 43 | 44 | def checkpointFirstStep(self): 45 | response = self.request("https://i.instagram.com/integrity/checkpoint/checkpoint_logged_out_main/" + 46 | str(self.settings.get('username_id')) + "/?next=instagram%3A%2F%2Fcheckpoint%2Fdismiss") 47 | 48 | # Fixme str value of null is '' in php ,str value of None is 'None' in python 49 | match = re.search(r'^Set-Cookie: csrftoken=([^;]+)', response[0], re.MULTILINE) 50 | 51 | if match: 52 | token = match.group(1) 53 | return token 54 | 55 | return None 56 | 57 | def checkpointSecondStep(self, token): 58 | post = OrderedDict([ 59 | ('csrfmiddlewaretoken', token), # fixme php version is the matched array at this point 60 | ('email', 'Verificar por correo electronico') # google translates to Verify by email 61 | ]) 62 | 63 | headers = [ 64 | 'Origin: https://i.instagram.com', 65 | 'Connection: keep-alive', 66 | 'Proxy-Connection: keep-alive', 67 | 'Accept-Language: es-es', 68 | 69 | 'Referer: https://i.instagram.com/integrity/checkpoint/checkpoint_logged_out_main/' + 70 | str(self.settings.get('username_id')) + '/?next=instagram%3A%2F%2Fcheckpoint%2Fdismiss', 71 | 72 | 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' 73 | ] 74 | 75 | self.request( 76 | 'https://i.instagram.com/integrity/checkpoint/checkpoint_logged_out_main/' + 77 | str(self.settings.get('username_id')) + '/?next=instagram%3A%2F%2Fcheckpoint%2Fdismiss', 78 | headers, 79 | post 80 | ) 81 | 82 | return token 83 | 84 | def checkpointThird(self, code, token): 85 | post = OrderedDict([ 86 | ('csrfmiddlewaretoken', token), 87 | ('response_code', code) 88 | ]) 89 | 90 | headers = [ 91 | 'Origin: https://i.instagram.com', 92 | 'Connection: keep-alive', 93 | 'Proxy-Connection: keep-alive', 94 | 'Accept-Language: es-es', 95 | 96 | 'Referer: https://i.instagram.com/integrity/checkpoint/checkpoint_logged_out_main/' + 97 | str(self.settings.get('username_id')) + '/?next=instagram%3A%2F%2Fcheckpoint%2Fdismiss', 98 | 99 | 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' 100 | ] 101 | 102 | self.request( 103 | 'https://i.instagram.com/integrity/checkpoint/checkpoint_logged_out_main/' + 104 | str(self.settings.get('username_id')) + 105 | '/?next=instagram%3A%2F%2Fcheckpoint%2Fdismiss', 106 | headers, 107 | post 108 | ) 109 | 110 | def request(self, endpoint, headers=None, post=None, first=True): 111 | buffer = BytesIO() 112 | 113 | ch = pycurl.Curl() 114 | 115 | ch.setopt(pycurl.URL, endpoint) 116 | ch.setopt(pycurl.USERAGENT, self.userAgent) 117 | ch.setopt(pycurl.WRITEFUNCTION, buffer.write) 118 | ch.setopt(pycurl.FOLLOWLOCATION, True) 119 | ch.setopt(pycurl.HEADER, True) 120 | if headers: 121 | ch.setopt(pycurl.HTTPHEADER, headers) 122 | 123 | ch.setopt(pycurl.VERBOSE, self.debug) 124 | ch.setopt(pycurl.SSL_VERIFYPEER, False) 125 | ch.setopt(pycurl.SSL_VERIFYHOST, False) 126 | ch.setopt(pycurl.COOKIEFILE, self.settingsPath + self.username + '-cookies.dat') 127 | ch.setopt(pycurl.COOKIEJAR, self.settingsPath + self.username + '-cookies.dat') 128 | 129 | if post: 130 | import urllib 131 | ch.setopt(pycurl.POST, len(post)) 132 | ch.setopt(pycurl.POSTFIELDS, urllib.urlencode(post)) 133 | 134 | ch.perform() 135 | resp = buffer.getvalue() 136 | header_len = ch.getinfo(pycurl.HEADER_SIZE) 137 | header = resp[0: header_len] 138 | body = resp[header_len:] 139 | ch.close() 140 | 141 | if self.debug: 142 | import urllib 143 | print("REQUEST: " + endpoint) 144 | if post is not None: 145 | if not isinstance(post, list): 146 | print('DATA: ' + urllib.unquote_plus(json.dumps(post))) 147 | print("RESPONSE: " + body + "\n") 148 | 149 | return [header, json_decode(body)] 150 | -------------------------------------------------------------------------------- /InstagramAPI/src/Constants.py: -------------------------------------------------------------------------------- 1 | class Constants(object): 2 | """ 3 | Constant declarations. 4 | """ 5 | API_URL = 'https://i.instagram.com/api/v1/' 6 | VERSION = '9.2.0' 7 | IG_SIG_KEY = '012a54f51c49aa8c5c322416ab1410909add32c966bbaa0fe3dc58ac43fd7ede' 8 | EXPERIMENTS = 'ig_android_ad_holdout_16m5_universe,ig_android_progressive_jpeg,ig_creation_growth_holdout,ig_android_oppo_app_badging,ig_android_ad_remove_username_from_caption_universe,ig_android_enable_share_to_whatsapp,ig_android_direct_drawing_in_quick_cam_universe,ig_android_ad_always_send_ad_attribution_id_universe,ig_android_universe_video_production,ig_android_direct_plus_button,ig_android_ads_heatmap_overlay_universe,ig_android_http_stack_experiment_2016,ig_android_infinite_scrolling,ig_fbns_blocked,ig_android_post_auto_retry_v7_21,ig_fbns_push,ig_android_video_playback_bandwidth_threshold,ig_android_direct_link_preview,ig_android_direct_typing_indicator,ig_android_preview_capture,ig_android_feed_pill,ig_android_profile_link_iab,ig_android_story_caption,ig_android_network_cancellation,ig_android_histogram_reporter,ig_android_anrwatchdog,ig_android_search_client_matching,ig_android_follow_request_text_buttons,ig_android_feed_zoom,ig_android_drafts_universe,ig_android_disable_comment,ig_android_user_detail_endpoint,ig_android_os_version_blocking,ig_android_blocked_list,ig_android_event_creation,ig_android_high_res_upload_2,ig_android_2fac,ig_android_mark_reel_seen_on_Swipe_forward,ig_android_comment_redesign,ig_android_ad_sponsored_label_universe,ig_android_mentions_dismiss_rule,ig_android_disable_chroma_subsampling,ig_android_share_spinner,ig_android_video_reuse_surface,ig_explore_v3_android_universe,ig_android_media_favorites,ig_android_nux_holdout,ig_android_insta_video_universe,ig_android_search_null_state,ig_android_universe_reel_video_production,liger_instagram_android_univ,ig_android_direct_emoji_picker,ig_feed_holdout_universe,ig_android_direct_send_auto_retry_universe,ig_android_samsung_app_badging,ig_android_disk_usage,ig_android_business_promotion,ig_android_direct_swipe_to_inbox,ig_android_feed_reshare_button_nux,ig_android_react_native_boost_post,ig_android_boomerang_feed_attribution,ig_fbns_shared,ig_fbns_dump_ids,ig_android_react_native_universe,ig_show_promote_button_in_feed,ig_android_ad_metadata_behavior_universe,ig_android_video_loopcount_int,ig_android_inline_gallery_backoff_hours_universe,ig_android_rendering_controls,ig_android_profile_photo_as_media,ig_android_async_stack_image_cache,ig_video_max_duration_qe_preuniverse,ig_video_copyright_whitelist,ig_android_render_stories_with_content_override,ig_android_ad_intent_to_highlight_universe,ig_android_swipe_navigation_x_angle_universe,ig_android_disable_comment_public_test,ig_android_profile,ig_android_direct_blue_tab,ig_android_enable_share_to_messenger,ig_android_fetch_reel_tray_on_resume_universe,ig_android_promote_again,ig_feed_event_landing_page_channel,ig_ranking_following,ig_android_pending_request_search_bar,ig_android_feed_ufi_redesign,ig_android_pending_edits_dialog_universe,ig_android_business_conversion_flow_universe,ig_android_show_your_story_when_empty_universe,ig_android_ad_drop_cookie_early,ig_android_app_start_config,ig_android_fix_ise_two_phase,ig_android_ppage_toggle_universe,ig_android_pbia_normal_weight_universe,ig_android_profanity_filter,ig_ios_su_activity_feed,ig_android_search,ig_android_boomerang_entry,ig_android_mute_story,ig_android_inline_gallery_universe,ig_android_ad_remove_one_tap_indicator_universe,ig_android_view_count_decouple_likes_universe,ig_android_contact_button_redesign_v2,ig_android_periodic_analytics_upload_v2,ig_android_send_direct_typing_indicator,ig_android_ad_holdout_16h2m1_universe,ig_android_react_native_comment_moderation_settings,ig_video_use_sve_universe,ig_android_inline_gallery_no_backoff_on_launch_universe,ig_android_immersive_viewer,ig_android_discover_people_icon,ig_android_profile_follow_back_button,is_android_feed_seen_state,ig_android_dense_feed_unit_cards,ig_android_drafts_video_universe,ig_android_exoplayer,ig_android_add_to_last_post,ig_android_ad_remove_cta_chevron_universe,ig_android_ad_comment_cta_universe,ig_android_ad_chevron_universe,ig_android_ad_comment_cta_universe,ig_android_search_event_icon,ig_android_channels_home,ig_android_feed,ig_android_dv2_realtime_private_share,ig_android_non_square_first,ig_android_video_interleaved_v2,ig_android_video_cache_policy,ig_android_react_native_universe_kill_switch,ig_android_video_captions_universe,ig_android_follow_search_bar,ig_android_last_edits,ig_android_two_step_capture_flow,ig_android_video_download_logging,ig_android_share_link_to_whatsapp,ig_android_facebook_twitter_profile_photos,ig_android_swipeable_filters_blacklist,ig_android_ad_pbia_profile_tap_universe,ig_android_use_software_layer_for_kc_drawing_universe,ig_android_react_native_ota,ig_android_direct_mutually_exclusive_experiment_universe,ig_android_following_follower_social_context' 9 | LOGIN_EXPERIMENTS = 'ig_android_reg_login_btn_active_state,ig_android_ci_opt_in_at_reg,ig_android_one_click_in_old_flow,ig_android_merge_fb_and_ci_friends_page,ig_android_non_fb_sso,ig_android_mandatory_full_name,ig_android_reg_enable_login_password_btn,ig_android_reg_phone_email_active_state,ig_android_analytics_data_loss,ig_fbns_blocked,ig_android_contact_point_triage,ig_android_reg_next_btn_active_state,ig_android_prefill_phone_number,ig_android_show_fb_social_context_in_nux,ig_android_one_tap_login_upsell,ig_fbns_push,ig_android_phoneid_sync_interval' 10 | SIG_KEY_VERSION = '4' 11 | 12 | ANDROID_VERSION = 18 13 | ANDROID_RELEASE = '4.3' 14 | -------------------------------------------------------------------------------- /InstagramAPI/src/Instagram.py: -------------------------------------------------------------------------------- 1 | import json 2 | import locale 3 | import re 4 | import time 5 | import urllib 6 | from collections import OrderedDict 7 | from distutils.version import LooseVersion 8 | 9 | try: 10 | from io import BytesIO 11 | except ImportError: 12 | from StringIO import StringIO as BytesIO 13 | 14 | from .Utils import * 15 | from .http import HttpInterface, UserAgent 16 | from .http.Response import * 17 | 18 | from .InstagramException import InstagramException 19 | from .Constants import Constants 20 | from .SignatureUtils import SignatureUtils 21 | 22 | locale.setlocale(locale.LC_NUMERIC, '') 23 | 24 | 25 | class Instagram: 26 | def __init__(self, username, password, debug=False, IGDataPath=None, truncatedDebug=False): 27 | 28 | """ 29 | Default class constructor. 30 | :type username: str 31 | :param username: Your Instagram username. 32 | :type password: str 33 | :param password: Your Instagram password. 34 | :param debug: Debug on or off, False by default. 35 | :param IGDataPath: Default folder to store data, you can change it. 36 | """ 37 | self.username = None # // Instagram username 38 | self.password = None # // Instagram password 39 | self.debug = None # // Debug 40 | self.truncatedDebug = None 41 | 42 | self.uuid = None # // UUID 43 | self.device_id = None # // Device ID 44 | self.username_id = None # // Username ID 45 | self.token = None # // _csrftoken 46 | self.isLoggedIn = False # // Session status 47 | self.rank_token = None # // Rank token 48 | self.IGDataPath = None # // Data storage path 49 | self.customPath = False 50 | self.http = None 51 | self.settings = None 52 | self.proxy = None # Full Proxy 53 | self.proxyHost = None # Proxy Host and Port 54 | self.proxyAuth = None # Proxy User and Pass 55 | 56 | self.debug = debug 57 | self.truncatedDebug = truncatedDebug 58 | self.device_id = SignatureUtils.generateDeviceId(hashlib.md5((username + password).encode("utf-8"))) 59 | 60 | if IGDataPath is not None: 61 | self.IGDataPath = IGDataPath 62 | self.customPath = True 63 | else: 64 | self.IGDataPath = os.path.join( 65 | os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data'), 66 | username, 67 | '' 68 | ) 69 | if not os.path.isdir(self.IGDataPath): 70 | os.mkdir(self.IGDataPath, 0o777) 71 | 72 | self.checkSettings(username) 73 | 74 | self.http = HttpInterface(self) 75 | 76 | self.setUser(username, password) 77 | 78 | def setUser(self, username, password): 79 | """ 80 | Set the user. Manage multiple accounts. 81 | 82 | :type username: str 83 | :param username: Your Instagram username. 84 | :type password: str 85 | :param password: Your Instagram password. 86 | : 87 | """ 88 | self.username = username 89 | self.password = password 90 | 91 | self.checkSettings(username) 92 | 93 | self.uuid = SignatureUtils.generateUUID(True) 94 | 95 | if os.path.isfile(self.IGDataPath + self.username + '-cookies.dat') and \ 96 | (self.settings.get('username_id') != None) and \ 97 | (self.settings.get('token') != None): 98 | self.isLoggedIn = True 99 | self.username_id = self.settings.get('username_id') 100 | self.rank_token = self.username_id + '_' + self.uuid 101 | self.token = self.settings.get('token') 102 | else: 103 | self.isLoggedIn = False 104 | 105 | def checkSettings(self, username): 106 | if not self.customPath: 107 | self.IGDataPath = os.path.join( 108 | os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data'), 109 | username, 110 | '' 111 | ) 112 | 113 | if not os.path.isdir(self.IGDataPath): os.mkdir(self.IGDataPath, 0o777) 114 | 115 | self.settings = Settings( 116 | os.path.join(self.IGDataPath, 'settings-' + username + '.dat') 117 | ) 118 | if self.settings.get('version') is None: 119 | self.settings.set('version', Constants.VERSION) 120 | 121 | if (self.settings.get('user_agent') is None) or ( 122 | LooseVersion(self.settings.get('version')) < LooseVersion(Constants.VERSION)): 123 | userAgent = UserAgent(self) 124 | ua = userAgent.buildUserAgent() 125 | self.settings.set('version', Constants.VERSION) 126 | self.settings.set('user_agent', ua) 127 | 128 | def setProxy(self, proxy, port=None, username=None, password=None): 129 | """ 130 | Set the proxy. 131 | 132 | :type proxy: str 133 | :param proxy: Full proxy string. Ex: user:pass@192.168.0.0:8080 134 | Use $proxy = "" to clear proxy 135 | :type port: int 136 | :param port: Port of proxy 137 | :type username: str 138 | :param username: Username for proxy 139 | :type password: str 140 | :param password: Password for proxy 141 | 142 | :raises: InstagramException 143 | """ 144 | self.proxy = proxy 145 | 146 | if proxy == '': 147 | return 148 | 149 | proxy = parse_url(proxy) 150 | 151 | if port and isinstance(port, int): 152 | proxy['port'] = int(port) 153 | 154 | if username and password: 155 | proxy['user'] = username 156 | proxy['pass'] = password 157 | 158 | if proxy['host'] and proxy['port'] and isinstance(proxy['port'], int): 159 | self.proxyHost = proxy['host'] + ':' + proxy['port'] 160 | else: 161 | raise InstagramException('Proxy host error. Please check ip address and port of proxy.') 162 | 163 | if proxy['user'] and proxy['pass']: 164 | self.proxyAuth = proxy['user'] + ':' + proxy['pass'] 165 | 166 | def login(self, force=False): 167 | """ 168 | Login to Instagram. 169 | 170 | :type force: bool 171 | :param force: Force login to Instagram, this will create a new session 172 | :return: Login data 173 | :rtype List: 174 | """ 175 | if (not self.isLoggedIn) or force: 176 | self.syncFeatures(True) 177 | fetch = self.http.request( 178 | 'si/fetch_headers/?challenge_type=signup&guid=' + SignatureUtils.generateUUID(False), None, True) 179 | header = fetch[0] 180 | response = ChallengeResponse(fetch[1]) 181 | 182 | if not header or not response.isOk(): 183 | raise InstagramException("Couldn't get challenge, check your connection") 184 | # return response #FIXME unreachable code 185 | 186 | match = re.search(r'^Set-Cookie: csrftoken=([^;]+)', fetch[0], re.MULTILINE) 187 | if match: 188 | self.token = match.group(1) 189 | else: 190 | raise InstagramException('Missing csfrtoken') 191 | 192 | data = OrderedDict([ 193 | ('username', self.username), 194 | ('guid', self.uuid), 195 | ('device_id', self.device_id), 196 | ('password', self.password), 197 | ('login_attempt_count', 0) 198 | ]) 199 | 200 | login = self.http.request('accounts/login/', SignatureUtils.generateSignature(json.dumps(data)), True) 201 | response = LoginResponse(login[1]) 202 | 203 | if not response.isOk(): raise InstagramException(response.getMessage()) 204 | 205 | self.isLoggedIn = True 206 | self.username_id = response.getUsernameId() 207 | self.settings.set('username_id', self.username_id) 208 | self.rank_token = self.username_id + '_' + self.uuid 209 | match = re.search(r'^Set-Cookie: csrftoken=([^;]+)', login[0], re.MULTILINE) 210 | if match: self.token = match.group(1) 211 | self.settings.set('token', self.token) 212 | 213 | self.syncFeatures() 214 | self.autoCompleteUserList() 215 | self.timelineFeed() 216 | self.getRankedRecipients() 217 | self.getRecentRecipients() 218 | self.megaphoneLog() 219 | self.getv2Inbox() 220 | self.getRecentActivity() 221 | self.getReelsTrayFeed() 222 | self.explore() 223 | 224 | return response 225 | 226 | check = self.timelineFeed() 227 | 228 | if check.getMessage() == 'login_required': 229 | self.login(True) 230 | 231 | self.autoCompleteUserList() 232 | self.getReelsTrayFeed() 233 | self.getRankedRecipients() 234 | # push register 235 | self.getRecentRecipients() 236 | # push register 237 | self.megaphoneLog() 238 | self.getv2Inbox() 239 | self.getRecentActivity() 240 | self.explore() 241 | 242 | def syncFeatures(self, prelogin=False): 243 | if prelogin: 244 | data = json.dumps( 245 | OrderedDict([ 246 | ('id', SignatureUtils.generateUUID(True)), 247 | ('experiments', Constants.LOGIN_EXPERIMENTS) 248 | ]) 249 | ) 250 | return SyncResponse(self.http.request('qe/sync/', SignatureUtils.generateSignature(data), True)[1]) 251 | else: 252 | 253 | data = json.dumps( 254 | OrderedDict([ 255 | ('_uuid', self.uuid), 256 | ('_uid', self.username_id), 257 | ('_csrftoken', self.token), 258 | ('id', self.username_id), 259 | ('experiments', Constants.EXPERIMENTS) 260 | ]) 261 | ) 262 | return SyncResponse(self.http.request('qe/sync/', SignatureUtils.generateSignature(data))[1]) 263 | 264 | def autoCompleteUserList(self): 265 | return autoCompleteUserListResponse(self.http.request('friendships/autocomplete_user_list/?version=2')[1]) 266 | 267 | def pushRegister(self, gcmToken): 268 | deviceToken = json.dumps( 269 | OrderedDict([ 270 | ('k', gcmToken), 271 | ('v', 0), 272 | ('t', 'fbns-b64') 273 | ]) 274 | ) 275 | data = json.dumps( 276 | OrderedDict([ 277 | ('_uuid', self.uuid), 278 | ('guid', self.uuid), 279 | ('phone_id', SignatureUtils.generateUUID(True)), 280 | ('device_type', 'android_mqtt'), 281 | ('device_token', deviceToken), 282 | ('is_main_push_channel', True), 283 | ('_csrftoken', self.token), 284 | ('users', self.username_id) 285 | ]) 286 | ) 287 | return self.http.request( 288 | 'push/register/?platform=10&device_type=android_mqtt', 289 | SignatureUtils.generateSignature(data) 290 | )[1] 291 | 292 | def timelineFeed(self): 293 | return TimelineFeedResponse(self.http.request('feed/timeline/')[1]) 294 | 295 | def megaphoneLog(self): 296 | data = OrderedDict([ 297 | ('type', 'feed_aysf'), 298 | ('action', 'seen'), 299 | ('reason', ''), 300 | ('_uuid', self.uuid), 301 | ('device_id', self.device_id), 302 | ('_csrftoken', self.token), 303 | ('uuid', hashlib.md5(str(int(time.time())).encode("utf-8")).hexdigest()) 304 | ]) 305 | 306 | return MegaphoneLogResponse(self.http.request('megaphone/log/', compat_urllib_parse.urlencode(data))[1]) 307 | 308 | def getPendingInbox(self): 309 | """ 310 | Pending Inbox 311 | 312 | :rtype: object 313 | :return: Pending Inbox Data 314 | """ 315 | pendingInbox = PendingInboxResponse(self.http.request('direct_v2/pending_inbox/?')[1]) 316 | 317 | if not pendingInbox.isOk(): 318 | raise InstagramException(pendingInbox.getMessage() + "\n") 319 | # return FIXME unreachable code 320 | 321 | return pendingInbox 322 | 323 | def getRankedRecipients(self): 324 | """ 325 | Ranked recipients. 326 | 327 | :rtype:list 328 | :return: Ranked recipients Data 329 | """ 330 | ranked_recipients = RankedRecipientsResponse( 331 | self.http.request('direct_v2/ranked_recipients/?show_threads=true')[1] 332 | ) 333 | 334 | if not ranked_recipients.isOk(): 335 | raise InstagramException(ranked_recipients.getMessage() + "\n") 336 | # return todo unreachable code 337 | 338 | return ranked_recipients 339 | 340 | def getRecentRecipients(self): 341 | """ 342 | Recent recipients. 343 | 344 | :rtype: list 345 | :return: Ranked recipients Data 346 | """ 347 | recent_recipients = RecentRecipientsResponse(self.http.request('direct_share/recent_recipients/')[1]) 348 | 349 | if not recent_recipients.isOk(): 350 | raise InstagramException(recent_recipients.getMessage() + "\n") 351 | # return todo unreachable code 352 | 353 | return recent_recipients 354 | 355 | def explore(self): 356 | """ 357 | Explore Tab 358 | 359 | :rtype: object 360 | :return: Explore data 361 | """ 362 | explore = ExploreResponse(self.http.request('discover/explore/')[1]) 363 | 364 | if not explore.isOk(): 365 | raise InstagramException(explore.getMessage() + "\n") 366 | 367 | # return todo unreachable code 368 | return explore 369 | 370 | def expose(self): 371 | data = json.dumps( 372 | OrderedDict([ 373 | ('_uuid', self.uuid), 374 | ('_uid', self.username_id), 375 | ('id', self.username_id), 376 | ('_csrftoken', self.token), 377 | ('experiment', 'ig_android_profile_contextual_feed') 378 | ]) 379 | ) 380 | return ExposeResponse(self.http.request('qe/expose/', SignatureUtils.generateSignature(data))[1]) 381 | 382 | def logout(self): 383 | """ 384 | Logout of Instagram. 385 | 386 | :rtype: bool 387 | :return: Returns true if logged out correctly 388 | """ 389 | logout = LogoutResponse(self.http.request('accounts/logout/')[1]) 390 | 391 | if logout.isOk(): 392 | return True 393 | else: 394 | return False 395 | 396 | def uploadPhoto(self, photo, caption=None, upload_id=None, customPreview=None, location=None, filter_=None): 397 | """ 398 | Upload photo to Instagram. 399 | 400 | :type photo: str 401 | :param photo: Path to your photo 402 | :type caption: str 403 | :param caption: Caption to be included in your photo. 404 | :rtype: object 405 | :return: Upload data 406 | """ 407 | return self.http.uploadPhoto(photo, caption, upload_id, customPreview, location, filter_) 408 | 409 | def uploadPhotoStory(self, photo, caption=None, upload_id=None, customPreview=None): 410 | 411 | return self.http.uploadPhoto(photo, caption, upload_id, customPreview, None, None, True) 412 | 413 | def uploadVideo(self, video, caption=None, customPreview=None): 414 | """ 415 | Upload video to Instagram. 416 | 417 | :type video: str 418 | :param photo: Path to your video 419 | :type caption: str 420 | :param caption: Caption to be included in your video. 421 | :rtype: object 422 | :return: Upload data 423 | """ 424 | return self.http.uploadVideo(video, caption), customPreview 425 | 426 | def direct_share(self, media_id, recipients, text=None): 427 | self.http.direct_share(media_id, recipients, text) 428 | 429 | def direct_message(self, recipients, text): 430 | """ 431 | Send direct message to user by inbox. 432 | 433 | :type recipients: list|int 434 | :param recipients: Users id 435 | :type text: str 436 | :param text: Text message 437 | 438 | :return: void 439 | """ 440 | self.http.direct_message(recipients, text) 441 | 442 | def directThread(self, threadId): 443 | """ 444 | Direct Thread Data 445 | 446 | :type threadId: str 447 | :param threadId: Thread Id 448 | :rtype: object 449 | :return: Direct Thread Data 450 | """ 451 | directThread = self.http.request("direct_v2/threads/" + str(threadId) + "/?")[1] 452 | 453 | if directThread['status'] != 'ok': 454 | raise InstagramException(directThread['message'] + "\n") 455 | # return Fixme unreachable code 456 | 457 | return directThread 458 | 459 | def directThreadAction(self, threadId, threadAction): 460 | """ 461 | Direct Thread Action 462 | 463 | :type threadId: str 464 | :param threadId: Thread Id 465 | :type threadAction: str 466 | :param threadAction: Thread Action 'approve' OR 'decline' OR 'block' 467 | :rtype: object 468 | :return: Direct Thread Action Data 469 | """ 470 | data = json.dumps( 471 | OrderedDict([ 472 | ('_uuid', self.uuid), 473 | ('_uid', self.username_id), 474 | ('_csrftoken', self.token) 475 | ]) 476 | ) 477 | return self.http.request( 478 | "direct_v2/threads/" + str(threadId) + "/" + str(threadAction) + "/", 479 | self.generateSignature(data) # todo Unresolved reference 480 | )[1] 481 | 482 | def configureVideo(self, upload_id, video, caption='', customPreview=None): 483 | 484 | self.uploadPhoto(video, caption, upload_id, customPreview) 485 | size = Image.open(video).size[0] 486 | 487 | post = json.dumps( 488 | OrderedDict([ 489 | ('upload_id', upload_id), 490 | ('source_type', 3), 491 | ('poster_frame_index', 0), 492 | ('length', 0.00), 493 | ('audio_muted', False), 494 | ('filter_type', '0'), 495 | ('video_result', 'deprecated'), 496 | ('clips', OrderedDict([ 497 | ('length', Utils.getSeconds(video)), 498 | ('source_type', '3'), 499 | ('camera_position', 'back') 500 | ])), 501 | ('extra', OrderedDict([ 502 | ('source_width', 960), 503 | ('source_height', 1280) 504 | ])), 505 | 506 | ('device', OrderedDict([ 507 | ('manufacturer', self.settings.get('manufacturer')), 508 | ('model', self.settings.get('model')), 509 | ('android_version', Constants.ANDROID_VERSION), 510 | ('android_release', Constants.ANDROID_RELEASE) 511 | ])), 512 | ('_csrftoken', self.token), 513 | ('_uuid', self.uuid), 514 | ('_uid', self.username_id), 515 | ('caption', caption) 516 | 517 | ]) 518 | 519 | ) 520 | 521 | post = post.replace('"length":0', '"length":0.00') 522 | 523 | return ConfigureVideoResponse( 524 | self.http.request('media/configure/?video=1', SignatureUtils.generateSignature(post))[1]) 525 | 526 | def configure(self, upload_id, photo, caption='', location=None, filter_=None): 527 | caption = caption if caption else '' 528 | size = Image.open(photo).size[0] 529 | 530 | post = OrderedDict([ 531 | ('upload_id', upload_id), 532 | ('camera_model', self.settings.get('model').replace(" ", "")), 533 | ('source_type', 3), 534 | ('date_time_original', time.strftime('%Y:%m:%d %H:%M:%S')), 535 | ('camera_make', self.settings.get('manufacturer')), 536 | ('edits', OrderedDict([ 537 | ('crop_original_size', [size, size]), 538 | ('crop_zoom', 1.3333334), 539 | ('crop_center', [0.0, -0.0]) 540 | ])), 541 | ('extra', OrderedDict([ 542 | ('source_width', size), 543 | ('source_height', size) 544 | ])), 545 | 546 | ('device', OrderedDict([ 547 | ('manufacturer', self.settings.get('manufacturer')), 548 | ('model', self.settings.get('model')), 549 | ('android_version', Constants.ANDROID_VERSION), 550 | ('android_release', Constants.ANDROID_RELEASE) 551 | ])), 552 | ('_csrftoken', self.token), 553 | ('_uuid', self.uuid), 554 | ('_uid', self.username_id), 555 | ('caption', caption) 556 | 557 | ]) 558 | if location: 559 | loc = OrderedDict([ 560 | (str(location.getExternalIdSource()) + '_id', location.getExternalId()), 561 | ('name', location.getName()), 562 | ('lat', location.getLatitude()), 563 | ('lng', location.getLongitude()), 564 | ('address', location.getAddress()), 565 | ('external_source', location.getExternalIdSource()) 566 | ]) 567 | post['location'] = json.dumps(loc) 568 | post['geotag_enabled'] = True 569 | post['media_latitude'] = location.getLatitude() 570 | post['posting_latitude'] = location.getLatitude() 571 | post['media_longitude'] = location.getLongitude() 572 | post['posting_longitude'] = location.getLongitude() 573 | post['altitude'] = mt_rand(10, 800) 574 | 575 | if filter_: 576 | post['edits']['filter_type'] = Utils.getFilterCode(filter) 577 | 578 | post = json.dumps(post) 579 | post = post.replace('"crop_center":[0,0]', '"crop_center":[0.0,-0.0]') 580 | 581 | return ConfigureResponse(self.http.request('media/configure/', SignatureUtils.generateSignature(post))[1]) 582 | 583 | def configureToReel(self, upload_id, photo): 584 | 585 | size = Image.open(photo).size[0] 586 | 587 | post = json.dumps( 588 | OrderedDict([ 589 | ('upload_id', upload_id), 590 | ('source_type', 3), 591 | ('edits', OrderedDict([ 592 | ('crop_original_size', [size, size]), 593 | ('crop_zoom', 1.3333334), 594 | ('crop_center', [0.0, 0.0]) 595 | ])), 596 | ('extra', OrderedDict([ 597 | ('source_width', size), 598 | ('source_height', size) 599 | ])), 600 | 601 | ('device', OrderedDict([ 602 | ('manufacturer', self.settings.get('manufacturer')), 603 | ('model', self.settings.get('model')), 604 | ('android_version', Constants.ANDROID_VERSION), 605 | ('android_release', Constants.ANDROID_RELEASE) 606 | ])), 607 | ('_csrftoken', self.token), 608 | ('_uuid', self.uuid), 609 | ('_uid', self.username_id), 610 | 611 | ]) 612 | ) 613 | post = post.replace('"crop_center":[0,0]', '"crop_center":[0.0,0.0]') 614 | 615 | return ConfigureResponse( 616 | self.http.request('media/configure_to_reel/', SignatureUtils.generateSignature(post))[1]) 617 | 618 | def editMedia(self, mediaId, captionText=''): 619 | """ 620 | Edit media. 621 | :type mediaId: str 622 | :param mediaId: Media id 623 | :type captionText: str 624 | :param captionText: Caption text 625 | :rtype: object 626 | :return: edit media data 627 | """ 628 | data = json.dumps( 629 | OrderedDict([ 630 | ('_uuid', self.uuid), 631 | ('_uid', self.username_id), 632 | ('_csrftoken', self.token), 633 | ('caption_text', captionText) 634 | ]) 635 | ) 636 | # Unresolved Reference MediaResponse 637 | return MediaResponse( 638 | self.http.request("media/" + mediaId + "/edit_media/", SignatureUtils.generateSignature(data))[1]['media'] 639 | ) 640 | 641 | def removeSelftag(self, mediaId): 642 | """ 643 | Remove yourself from a tagged media. 644 | :type mediaId: str 645 | :param mediaId: Media id 646 | :rtype: object 647 | :return: edit media data 648 | """ 649 | data = json.dumps( 650 | OrderedDict([ 651 | ('_uuid', self.uuid), 652 | ('_uid', self.username_id), 653 | ('_csrftoken', self.token) 654 | ]) 655 | ) 656 | 657 | # Unresolved Reference MediaResponse 658 | return MediaResponse( 659 | self.http.request("usertags/" + mediaId + "/remove/", SignatureUtils.generateSignature(data))[1] 660 | ) 661 | 662 | def mediaInfo(self, mediaId): 663 | """ 664 | Media info 665 | :type mediaId: str 666 | :param mediaId: Media id 667 | :rtype: object 668 | :return: delete request data 669 | """ 670 | data = json.dumps( 671 | OrderedDict([ 672 | ('_uuid', self.uuid), 673 | ('_uid', self.username_id), 674 | ('_csrftoken', self.token), 675 | ('media_id', mediaId) 676 | ]) 677 | ) 678 | return MediaInfoResponse( 679 | self.http.request("media/" + mediaId + "/info/", SignatureUtils.generateSignature(data))[1]) 680 | 681 | def deleteMedia(self, mediaId): 682 | """ 683 | Delete photo or video. 684 | :type mediaId: str 685 | :param mediaId: Media id 686 | :rtype: object 687 | :return: delete request data 688 | """ 689 | data = json.dumps( 690 | OrderedDict([ 691 | ('_uuid', self.uuid), 692 | ('_uid', self.username_id), 693 | ('_csrftoken', self.token), 694 | ('media_id', mediaId) 695 | ]) 696 | ) 697 | return self.http.request("media/" + mediaId + "/delete/", SignatureUtils.generateSignature(data))[1] 698 | 699 | def comment(self, mediaId, commentText): 700 | """ 701 | Comment media. 702 | :type mediaId: str 703 | :param mediaId: Media id 704 | :type commentText: str 705 | :param commentText: Comment Text 706 | :rtype: object 707 | :return: comment media data 708 | """ 709 | data = json.dumps( 710 | OrderedDict([ 711 | ('_uuid', self.uuid), 712 | ('_uid', self.username_id), 713 | ('_csrftoken', self.token), 714 | ('comment_text', commentText) 715 | ]) 716 | ) 717 | return CommentResponse( 718 | self.http.request("media/" + mediaId + "/comment/", SignatureUtils.generateSignature(data))[1] 719 | ) 720 | 721 | def deleteComment(self, mediaId, commentId): 722 | """ 723 | Delete Comment. 724 | :type mediaId: str 725 | :param mediaId: Media ID 726 | :type commentId: str 727 | :param commentId: Comment ID 728 | :rtype: object 729 | :return: Delete comment data 730 | """ 731 | data = json.dumps( 732 | OrderedDict([ 733 | ('_uuid', self.uuid), 734 | ('_uid', self.username_id), 735 | ('_csrftoken', self.token) 736 | ]) 737 | ) 738 | return \ 739 | self.http.request("media/" + mediaId + "/comment/" + commentId + "/delete/", 740 | SignatureUtils.generateSignature(data))[1] 741 | 742 | def deleteCommentsBulk(self, mediaId, commentIds): 743 | """ 744 | Delete Comment Bulk. 745 | 746 | :type mediaId: str 747 | :param mediaId: Media ID 748 | :type commentIds: list 749 | :param commentIds: List of comments to delete 750 | :rtype: object 751 | :return: Delete Comment Bulk Data 752 | """ 753 | if not isinstance(commentIds, list): 754 | commentIds = [commentIds] 755 | 756 | string = [] 757 | for commentId in commentIds: 758 | string.append(str(commentId)) 759 | 760 | comment_ids_to_delete = ','.join(string) 761 | 762 | data = json.dumps( 763 | OrderedDict([ 764 | ('_uuid', self.uuid), 765 | ('_uid', self.username_id), 766 | ('_csrftoken', self.token), 767 | ('comment_ids_to_delete', comment_ids_to_delete) 768 | ]) 769 | ) 770 | return self.http.request("media/" + mediaId + "/comment/bulk_delete/", 771 | SignatureUtils.generateSignature(data))[1] 772 | 773 | def changeProfilePicture(self, photo): 774 | """ 775 | Sets account to public. 776 | :type photo: str 777 | :param photo: Path to photo 778 | """ 779 | self.http.changeProfilePicture(photo) 780 | 781 | def removeProfilePicture(self): 782 | """ 783 | Remove profile picture. 784 | :rtype: object 785 | :return: status request data 786 | """ 787 | data = json.dumps( 788 | OrderedDict([('_uuid', self.uuid), ('_uid', self.username_id), ('_csrftoken', self.token)]) 789 | ) 790 | return self.http.request('accounts/remove_profile_picture/', SignatureUtils.generateSignature(data))[1] 791 | 792 | def setPrivateAccount(self): 793 | """ 794 | Sets account to private. 795 | 796 | :rtype: object 797 | :return: status request data 798 | """ 799 | data = json.dumps( 800 | OrderedDict([ 801 | ('_uuid', self.uuid), 802 | ('_uid', self.username_id), 803 | ('_csrftoken', self.token) 804 | ]) 805 | ) 806 | return self.http.request('accounts/set_private/', SignatureUtils.generateSignature(data))[1] 807 | 808 | def setPublicAccount(self): 809 | """ 810 | Sets account to public. 811 | :rtype: object 812 | :return: status request data 813 | """ 814 | data = json.dumps( 815 | OrderedDict([ 816 | ('_uuid', self.uuid), 817 | ('_uid', self.username_id), 818 | ('_csrftoken', self.token) 819 | ]) 820 | ) 821 | return self.http.request('accounts/set_public/', SignatureUtils.generateSignature(data))[1] 822 | 823 | def getProfileData(self): 824 | """ 825 | Get personal profile data. 826 | :rtype: object 827 | :return: 828 | """ 829 | data = json.dumps( 830 | OrderedDict([ 831 | ('_uuid', self.uuid), 832 | ('_uid', self.username_id), 833 | ('_csrftoken', self.token) 834 | ]) 835 | ) 836 | return ProfileResponse( 837 | self.http.request('accounts/current_user/?edit=true', SignatureUtils.generateSignature(data))[1]) 838 | 839 | def editProfile(self, url, phone, first_name, biography, email, gender): 840 | """ 841 | Edit profile. 842 | :type url: str 843 | :param url: Url - website. "" for nothing 844 | :type phone: str 845 | :param phone: Phone number. "" for nothing 846 | :type first_name: str 847 | :param first_name: Name. "" for nothing 848 | :type email: str 849 | :param email: Email. Required. 850 | :type gender: int 851 | :param gender: Gender. male = 1 , female = 0 852 | :rtype: object 853 | :return: edit profile data 854 | """ 855 | data = json.dumps( 856 | OrderedDict([ 857 | ('_uuid', self.uuid), 858 | ('_uid', self.username_id), 859 | ('_csrftoken', self.token), 860 | ('external_url', url), 861 | ('phone_number', phone), 862 | ('username', self.username), 863 | ('first_name', first_name), 864 | ('biography', biography), 865 | ('email', email), 866 | ('gender', gender) 867 | ]) 868 | ) 869 | 870 | return ProfileResponse(self.http.request('accounts/edit_profile/', SignatureUtils.generateSignature(data))[1]) 871 | 872 | def changePassword(self, oldPassword, newPassword): 873 | """ 874 | Change Password. 875 | 876 | :type oldPassword: str 877 | :param oldPassword: Old Password 878 | :type newPassword: str 879 | :param newPassword: New Password 880 | :rtype: object 881 | :return: Change Password Data 882 | """ 883 | 884 | data = json.dumps( 885 | OrderedDict([ 886 | ('_uuid', self.uuid), 887 | ('_uid', self.username_id), 888 | ('_csrftoken', self.token), 889 | ('old_password', oldPassword), 890 | ('new_password1', newPassword), 891 | ('new_password2', newPassword) 892 | ]) 893 | ) 894 | return self.http.request('accounts/change_password/', SignatureUtils.generateSignature(data))[1] 895 | 896 | def getUsernameInfo(self, usernameId): 897 | """ 898 | Get username info. 899 | :param usernameId: Username id 900 | :rtype: object 901 | :return: Username data 902 | """ 903 | return UsernameInfoResponse(self.http.request("users/" + str(usernameId) + "/info/")[1]) 904 | 905 | def getSelfUsernameInfo(self): 906 | """ 907 | Get self username info. 908 | :rtype: object 909 | :return: Username data 910 | """ 911 | return self.getUsernameInfo(self.username_id) 912 | 913 | def getRecentActivity(self): 914 | """ 915 | Get recent activity. 916 | :rtype: object 917 | :return: Recent activity data 918 | """ 919 | activity = self.http.request('news/inbox/')[1] 920 | 921 | if activity['status'] != 'ok': 922 | raise InstagramException(activity['message'] + "\n") 923 | 924 | return activity 925 | 926 | def getFollowingRecentActivity(self): 927 | """ 928 | Get recent activity from accounts followed. 929 | 930 | :rtype: object 931 | :return: Recent activity data of follows 932 | """ 933 | activity = self.http.request('news/?')[1] 934 | if activity['status'] != 'ok': 935 | raise InstagramException(activity['message'] + "\n") 936 | 937 | return activity 938 | 939 | def getv2Inbox(self): 940 | """ 941 | I dont know this yet. 942 | :rtype: object 943 | :return: v2 inbox data 944 | """ 945 | inbox = V2InboxResponse(self.http.request('direct_v2/inbox/?')[1]) 946 | 947 | if not inbox.isOk(): 948 | raise InstagramException(inbox.getMessage() + "\n") 949 | 950 | return inbox 951 | 952 | def getUserTags(self, usernameId): 953 | """ 954 | Get user tags. 955 | :type usernameId: str 956 | :param usernameId: 957 | :rtype: object 958 | :return: user tags data 959 | """ 960 | tags = UsertagsResponse(self.http.request("usertags/" + str(usernameId) + "/feed/?rank_token=" + self.rank_token 961 | + "&ranked_content=true&")[1]) 962 | if not tags.isOk(): 963 | raise InstagramException(tags.getMessage() + "\n") 964 | 965 | return tags 966 | 967 | def getSelfUserTags(self): 968 | """ 969 | Get self user tags. 970 | :rtype: object 971 | :return: self user tags data 972 | """ 973 | return self.getUserTags(self.username_id) 974 | 975 | def tagFeed(self, tag): 976 | """ 977 | Get tagged media. 978 | :type tag: str 979 | :param tag: 980 | :rtype: object 981 | :return: 982 | """ 983 | userFeed = TagFeedResponse( 984 | self.http.request("feed/tag/" + tag + "/?rank_token=" + self.rank_token + "&ranked_content=true&")[1]) 985 | 986 | if not userFeed.isOk(): 987 | raise InstagramException(userFeed.getMessage() + "\n") 988 | 989 | return userFeed 990 | 991 | def getMediaLikers(self, mediaId): 992 | """ 993 | Get media likers. 994 | :type mediaId: str 995 | :param mediaId: 996 | :rtype: object 997 | :return: 998 | """ 999 | likers = MediaLikersResponse(self.http.request("media/" + mediaId + "/likers/")[1]) 1000 | if not likers.isOk(): 1001 | raise InstagramException(likers.getMessage() + "\n") 1002 | # return #fixme unreachable code 1003 | 1004 | return likers 1005 | 1006 | def getGeoMedia(self, usernameId): 1007 | """ 1008 | Get user locations media. 1009 | :type usernameId: str 1010 | :param usernameId: Username id 1011 | :rtype: object 1012 | :return: Geo Media data 1013 | """ 1014 | locations = self.http.request("maps/user/" + str(usernameId) + "/")[1] 1015 | 1016 | if locations['status'] != 'ok': 1017 | raise InstagramException(locations['message'] + "\n") 1018 | 1019 | return locations 1020 | 1021 | def getSelfGeoMedia(self): 1022 | """ 1023 | Get self user locations media. 1024 | :rtype: object 1025 | :return: Geo Media data 1026 | """ 1027 | return self.getGeoMedia(self.username_id) 1028 | 1029 | def searchLocation(self, latitude, longitude, query=None): 1030 | locationQuery = OrderedDict([ 1031 | ('rank_token', self.rank_token), 1032 | ('latitude', latitude), 1033 | ('longitude', longitude) 1034 | ]) 1035 | 1036 | if query: 1037 | locationQuery['timestamp'] = int(time.time()) 1038 | else: 1039 | locationQuery['search_query'] = query # TODO possible bug, query is None 1040 | 1041 | locations = LocationResponse(self.http.request("location_search/?" + urllib.urlencode(locationQuery))[1]) 1042 | 1043 | if not locations.isOk(): 1044 | raise InstagramException(locations.getMessage() + "\n") 1045 | # return fixme unreachable code 1046 | 1047 | return locations 1048 | 1049 | def fbUserSearch(self, query): 1050 | """ 1051 | facebook user search. 1052 | :type query: str 1053 | :param query: 1054 | :rtype: object 1055 | :return: query data 1056 | """ 1057 | query = urllib.quote(query) 1058 | query = \ 1059 | self.http.request("fbsearch/topsearch/?context=blended&query=" + query + "&rank_token=" + self.rank_token)[ 1060 | 1] 1061 | 1062 | if query['status'] != 'ok': 1063 | raise InstagramException(query['message'] + "\n") 1064 | 1065 | return query 1066 | 1067 | def searchUsers(self, query): 1068 | """ 1069 | Search users. 1070 | :type query: str 1071 | :param query: 1072 | :rtype: object 1073 | :return: query data 1074 | """ 1075 | query = self.http.request( 1076 | 'users/search/?ig_sig_key_version=' + Constants.SIG_KEY_VERSION \ 1077 | + "&is_typeahead=true&query=" + query + "&rank_token=" + self.rank_token)[1] 1078 | 1079 | if query['status'] != 'ok': 1080 | raise InstagramException(query['message'] + "\n") 1081 | 1082 | return query 1083 | 1084 | def searchUsername(self, usernameName): 1085 | """ 1086 | Search exact username 1087 | 1088 | :type usernameName: str 1089 | :param usernameName: username as STRING not an id 1090 | 1091 | :rtype: object 1092 | :return: query data 1093 | """ 1094 | query = UsernameInfoResponse(self.http.request("users/" + usernameName + "/usernameinfo/")[1]) 1095 | 1096 | if not query.isOk(): 1097 | raise InstagramException(query.getMessage() + "\n") 1098 | 1099 | return query 1100 | 1101 | def getUsernameId(self, username): 1102 | return self.searchUsername(username).getUsernameId() 1103 | 1104 | def syncFromAdressBook(self, contacts): 1105 | """ 1106 | Search users using addres book. 1107 | :type contacts: list 1108 | :param contacts: 1109 | :rtype: object 1110 | :return: 1111 | """ 1112 | data = OrderedDict([( 1113 | ('contacts=', json.dumps(contacts)) 1114 | )]) 1115 | return self.http.request('address_book/link/?include=extra_display_name,thumbnails', data)[1] 1116 | 1117 | def searchTags(self, query): 1118 | """ 1119 | Search tags. 1120 | :type query: str 1121 | :param query: 1122 | :rtype: object 1123 | :return: query data 1124 | """ 1125 | query = self.http.request("tags/search/?is_typeahead=true&q=" + query + "&rank_token=" + self.rank_token)[1] 1126 | 1127 | if query['status'] != 'ok': 1128 | raise InstagramException(query['message'] + "\n") 1129 | 1130 | return query 1131 | 1132 | def getTimeline(self, maxid=None): 1133 | """ 1134 | Get timeline data. 1135 | :rtype: object 1136 | :return: timeline data 1137 | """ 1138 | timeline = self.http.request( 1139 | "feed/timeline/?rank_token=" + self.rank_token + "&ranked_content=true" + 1140 | (("&max_id=" + str(maxid)) if maxid is not None else '') 1141 | )[1] 1142 | 1143 | if timeline['status'] != 'ok': 1144 | raise InstagramException(timeline['message'] + "\n") 1145 | 1146 | return timeline 1147 | 1148 | def getReelsTrayFeed(self): 1149 | feed = ReelsTrayFeedResponse(self.http.request('feed/reels_tray/')[1]) 1150 | if not feed.isOk(): 1151 | raise InstagramException(feed.getMessage() + "\n") 1152 | # return todo Unreachable code 1153 | 1154 | return feed 1155 | 1156 | def getUserFeed(self, usernameId, maxid=None, minTimestamp=None): 1157 | """ 1158 | Get user feed. 1159 | :type usernameId: str 1160 | :param usernameId: Username id 1161 | :type maxid: str 1162 | :param maxid: Max Id 1163 | :type minTimestamp: str 1164 | :param minTimestamp: Min timestamp 1165 | :rtype: object 1166 | :return: User feed data 1167 | :raises: InstagramException 1168 | """ 1169 | userFeed = UserFeedResponse(self.http.request("feed/user/" + str(usernameId) + "/?rank_token=" + self.rank_token 1170 | + (("&max_id=" + str(maxid)) if maxid is not None else '') \ 1171 | + (("&min_timestamp=" + str( 1172 | minTimestamp)) if minTimestamp is not None else '') \ 1173 | + "&ranked_content=true" 1174 | )[1]) 1175 | 1176 | if not userFeed.isOk(): 1177 | raise InstagramException(userFeed.getMessage() + "\n") 1178 | 1179 | return userFeed 1180 | 1181 | def getHashtagFeed(self, hashtagString, maxid=''): 1182 | """ 1183 | Get hashtag feed. 1184 | :type hashtagString: str 1185 | :param hashtagString: Hashtag string, not including the # 1186 | :rtype: object 1187 | :return: Hashtag feed data 1188 | """ 1189 | if maxid == '': 1190 | endpoint = "feed/tag/" + hashtagString + "/?rank_token=" + self.rank_token + "&ranked_content=true&" 1191 | else: 1192 | endpoint = "feed/tag/" + hashtagString + "/?max_id=" \ 1193 | + maxid + "&rank_token=" + self.rank_token + "&ranked_content=true&" 1194 | hashtagFeed = self.http.request(endpoint)[1] 1195 | if hashtagFeed['status'] != 'ok': 1196 | raise InstagramException(hashtagFeed['message'] + "\n") 1197 | 1198 | return hashtagFeed 1199 | 1200 | def searchFBLocation(self, query): 1201 | """ 1202 | Get locations. 1203 | :type query: str 1204 | :param query: search query 1205 | :rtype: object 1206 | :return: Location location data 1207 | """ 1208 | query = urllib.quote(query) 1209 | endpoint = "fbsearch/places/?rank_token=" + self.rank_token + "&query=" + query 1210 | 1211 | locationFeed = self.http.request(endpoint)[1] 1212 | 1213 | if locationFeed['status'] != 'ok': 1214 | raise InstagramException(locationFeed['message'] + "\n") 1215 | 1216 | return locationFeed 1217 | 1218 | def getLocationFeed(self, locationId, maxid=''): 1219 | """ 1220 | Get location feed. 1221 | :type locationId: str 1222 | :param locationId: location id 1223 | :rtype: object 1224 | :return: Location feed data 1225 | """ 1226 | if maxid is '': 1227 | endpoint = "feed/location/" + locationId + "/?rank_token=" + self.rank_token + "&ranked_content=true&" 1228 | else: 1229 | endpoint = "feed/location/" + locationId + "/?max_id=" \ 1230 | + maxid + "&rank_token=" + self.rank_token + "&ranked_content=true&" 1231 | 1232 | locationFeed = self.http.request(endpoint)[1] 1233 | 1234 | if locationFeed['status'] != 'ok': 1235 | raise InstagramException(locationFeed['message'] + "\n") 1236 | 1237 | return locationFeed 1238 | 1239 | def getSelfUserFeed(self, max_id=None): 1240 | """ 1241 | Get self user feed. 1242 | :rtype: object 1243 | :return: User feed data 1244 | """ 1245 | return self.getUserFeed(self.username_id, max_id) 1246 | 1247 | def getPopularFeed(self): 1248 | """ 1249 | Get popular feed. 1250 | :rtype: object 1251 | :return: popular feed data 1252 | """ 1253 | popularFeed = self.http.request("feed/popular/?people_teaser_supported=1&rank_token=" \ 1254 | + self.rank_token + "&ranked_content=true&")[1] 1255 | 1256 | if popularFeed['status'] != 'ok': 1257 | raise InstagramException(popularFeed['message'] + "\n") 1258 | 1259 | return popularFeed 1260 | 1261 | def getUserFollowings(self, usernameId, maxid=''): 1262 | """ 1263 | Get user followings. 1264 | :type usernameId: str 1265 | :param usernameId: Username id 1266 | 1267 | :rtype: object 1268 | :return: followers data 1269 | """ 1270 | return FollowingResponse(self.http.request( 1271 | "friendships/" + usernameId + "/following/?max_id=" + maxid + "&ig_sig_key_version=" 1272 | + Constants.SIG_KEY_VERSION + "&rank_token=" + self.rank_token)[1]) 1273 | 1274 | def getUserFollowers(self, usernameId, maxid=''): 1275 | """ 1276 | Get user followers. 1277 | :type usernameId: str 1278 | :param usernameId: Username id 1279 | 1280 | :rtype: object 1281 | :return: followers data 1282 | """ 1283 | return FollowerResponse(self.http.request( 1284 | "friendships/" + usernameId + "/followers/?max_id=" + maxid 1285 | + "&ig_sig_key_version=" + Constants.SIG_KEY_VERSION + "&rank_token=" + self.rank_token)[1]) 1286 | 1287 | def getSelfUserFollowers(self): 1288 | """ 1289 | Get self user followers. 1290 | 1291 | :rtype: object 1292 | :return: followers data 1293 | """ 1294 | return self.getUserFollowers(self.username_id) 1295 | 1296 | def getSelfUsersFollowing(self): 1297 | """ 1298 | Get self users we are following. 1299 | 1300 | :rtype: object 1301 | :return: users we are following data 1302 | """ 1303 | return self.getUserFollowings(self.username_id) 1304 | 1305 | def like(self, mediaId): 1306 | """ 1307 | Like photo or video. 1308 | 1309 | :type mediaId: str 1310 | :param mediaId: Media id 1311 | :rtype: object 1312 | :return: status request 1313 | """ 1314 | data = json.dumps( 1315 | OrderedDict([ 1316 | ('_uuid', self.uuid), 1317 | ('_uid', self.username_id), 1318 | ('_csrftoken', self.token), 1319 | ('media_id', mediaId) 1320 | ]) 1321 | ) 1322 | return self.http.request("media/" + mediaId + "/like/", SignatureUtils.generateSignature(data))[1] 1323 | 1324 | def unlike(self, mediaId): 1325 | """ 1326 | Unlike photo or video. 1327 | 1328 | :type mediaId: str 1329 | :param mediaId: Media id 1330 | :rtype: object 1331 | :return: status request 1332 | """ 1333 | data = json.dumps( 1334 | OrderedDict([ 1335 | ('_uuid', self.uuid), 1336 | ('_uid', self.username_id), 1337 | ('_csrftoken', self.token), 1338 | ('media_id', mediaId) 1339 | ]) 1340 | ) 1341 | return self.http.request("media/" + mediaId + "/unlike/", SignatureUtils.generateSignature(data))[1] 1342 | 1343 | def getMediaComments(self, mediaId, maxid=''): 1344 | """ 1345 | Get media comments. 1346 | :type mediaId: str 1347 | :param mediaId: Media id 1348 | :rtype: object 1349 | :return: Media comments data 1350 | """ 1351 | return MediaCommentsResponse(self.http.request("media/" + str(mediaId) + "/comments/?max_id=" + str(maxid) 1352 | + "&ig_sig_key_version=" + Constants.SIG_KEY_VERSION)[1]) 1353 | 1354 | def setNameAndPhone(self, name='', phone=''): 1355 | """ 1356 | Set name and phone (Optional). 1357 | :type name: str 1358 | :param name: 1359 | :type phone: str 1360 | :param phone: 1361 | :rtype: object 1362 | :return: Set status data 1363 | """ 1364 | data = json.dumps( 1365 | OrderedDict([ 1366 | ('_uuid', self.uuid), 1367 | ('_uid', self.username_id), 1368 | ('first_name', name), 1369 | ('phone_number', phone), 1370 | ('_csrftoken', self.token) 1371 | ]) 1372 | ) 1373 | 1374 | return self.http.request("accounts/set_phone_and_name/", SignatureUtils.generateSignature(data))[1] 1375 | 1376 | def getDirectShare(self): 1377 | """ 1378 | Get direct share. 1379 | 1380 | :rtype: object 1381 | :return: Direct share data 1382 | """ 1383 | return self.http.request('direct_share/inbox/?')[1] 1384 | 1385 | def backup(self): 1386 | """ 1387 | Backups all your uploaded photos :). 1388 | """ 1389 | go = False 1390 | while True: 1391 | if not go: 1392 | myUploads = self.getSelfUserFeed() 1393 | else: 1394 | myUploads = self.getSelfUserFeed(myUploads.getNextMaxId() if myUploads.getNextMaxId() else None) 1395 | # fixme local variable `myUploads` might be referenced before assignment 1396 | if not os.path.isdir(self.IGDataPath + 'backup/'): 1397 | os.mkdir(self.IGDataPath + 'backup/') 1398 | 1399 | for item in myUploads.getItems(): 1400 | dir_name = self.IGDataPath + 'backup/' + self.username + "-" + time.strftime('%Y-%m-%d') 1401 | if not os.path.isdir(dir_name): 1402 | os.mkdir(dir_name) 1403 | 1404 | if item.getVideoVersions(): 1405 | file_put_contents( 1406 | os.path.join(dir_name, item.getMediaId() + '.mp4'), 1407 | urllib.urlopen(item.getVideoVersions()[0].getUrl()).read() 1408 | ) # todo test and remove below 1409 | else: 1410 | file_put_contents( 1411 | os.path.join(dir_name, item.getMediaId() + '.jpg'), 1412 | urllib.urlopen(item.getImageVersions()[0].getUrl()).read() 1413 | ) # todo test and remove below 1414 | 1415 | # urllib.urlretrieve( 1416 | # item['image_versions2']['candidates'][0]['url'], 1417 | # self.IGDataPath + 'backup/' + self.username + "-" + time.strftime('%Y-%m-%d') + '/' + item['id'] + '.jpg' 1418 | # ) 1419 | go = True 1420 | if not myUploads.getNextMaxId(): 1421 | break 1422 | 1423 | def follow(self, userId): 1424 | """ 1425 | Follow. 1426 | 1427 | :param userId: 1428 | :type userId: str 1429 | :rtype: object 1430 | :return: Friendship status data 1431 | """ 1432 | 1433 | data = json.dumps( 1434 | OrderedDict([ 1435 | ('_uuid', self.uuid), 1436 | ('_uid', self.username_id), 1437 | ('user_id', userId), 1438 | ('_csrftoken', self.token) 1439 | 1440 | ]) 1441 | ) 1442 | 1443 | return self.http.request("friendships/create/" + userId + "/", SignatureUtils.generateSignature(data))[1] 1444 | 1445 | def unfollow(self, userId): 1446 | """ 1447 | Unfollow. 1448 | 1449 | :param userId: 1450 | :type userId: str 1451 | :rtype: object 1452 | :return: Friendship status data 1453 | """ 1454 | data = json.dumps( 1455 | OrderedDict([ 1456 | ('_uuid', self.uuid), 1457 | ('_uid', self.username_id), 1458 | ('user_id', userId), 1459 | ('_csrftoken', self.token) 1460 | ]) 1461 | ) 1462 | 1463 | return self.http.request("friendships/destroy/" + userId + "/", SignatureUtils.generateSignature(data))[1] 1464 | 1465 | def block(self, userId): 1466 | """ 1467 | Block. 1468 | 1469 | :param userId: 1470 | :type userId: str 1471 | :rtype: object 1472 | :return: Friendship status data 1473 | """ 1474 | 1475 | data = json.dumps( 1476 | OrderedDict([ 1477 | ('_uuid', self.uuid), 1478 | ('_uid', self.username_id), 1479 | ('user_id', userId), 1480 | ('_csrftoken', self.token) 1481 | ]) 1482 | ) 1483 | 1484 | return self.http.request("friendships/block/" + userId + "/", SignatureUtils.generateSignature(data))[1] 1485 | 1486 | def unblock(self, userId): 1487 | """ 1488 | Unblock. 1489 | 1490 | :param userId: 1491 | :type userId: str 1492 | :rtype: object 1493 | :return: Friendship status data 1494 | """ 1495 | 1496 | data = json.dumps( 1497 | OrderedDict([ 1498 | ('_uuid', self.uuid), 1499 | ('_uid', self.username_id), 1500 | ('user_id', userId), 1501 | ('_csrftoken', self.token) 1502 | ]) 1503 | ) 1504 | 1505 | return self.http.request("friendships/unblock/" + userId + "/", SignatureUtils.generateSignature(data))[1] 1506 | 1507 | def userFriendship(self, userId): 1508 | """ 1509 | Show User Friendship. 1510 | 1511 | :type userId: str 1512 | :param userId: 1513 | :rtype: object 1514 | :return: Friendship relationship data 1515 | """ 1516 | 1517 | data = json.dumps( 1518 | OrderedDict([ 1519 | ('_uuid', self.uuid), 1520 | ('_uid', self.username_id), 1521 | ('user_id', userId), 1522 | ('_csrftoken', self.token) 1523 | ]) 1524 | ) 1525 | 1526 | return self.http.request("friendships/show/" + userId + "/", SignatureUtils.generateSignature(data))[1] 1527 | 1528 | def getLikedMedia(self, maxid=None): 1529 | """ 1530 | Get liked media. 1531 | 1532 | :rtype: object 1533 | :return: Liked media data 1534 | """ 1535 | endpoint = 'feed/liked/?' + (('max_id=' + str(maxid) + '&') if maxid is not None else '') 1536 | return self.http.request(endpoint)[1] 1537 | 1538 | def verifyPeer(self, enable): 1539 | self.http.verifyPeer(enable) 1540 | 1541 | def verifyHost(self, enable): 1542 | self.http.verifyHost(enable) 1543 | -------------------------------------------------------------------------------- /InstagramAPI/src/InstagramException.py: -------------------------------------------------------------------------------- 1 | class InstagramException(Exception): 2 | def __init__(self, *args, **kwargs): 3 | Exception.__init__(self, *args, **kwargs) 4 | -------------------------------------------------------------------------------- /InstagramAPI/src/InstagramRegistration.py: -------------------------------------------------------------------------------- 1 | import json 2 | import pycurl 3 | import re 4 | from collections import OrderedDict 5 | 6 | from InstagramAPI.src import InstagramException 7 | from InstagramAPI.src.SignatureUtils import SignatureUtils 8 | from InstagramAPI.src.http.Response import ChallengeResponse 9 | from InstagramAPI.src.http.Response.AccountCreationResponse import AccountCreationResponse 10 | from InstagramAPI.src.http.Response.CheckEmailResponse import CheckEmailResponse 11 | from InstagramAPI.src.http.Response.CheckUsernameResponse import CheckUsernameResponse 12 | from InstagramAPI.src.http.Response.UsernameSuggestionsResponse import UsernameSuggestionsResponse 13 | 14 | try: 15 | from StringIO import StringIO as BytesIO 16 | except ImportError: 17 | from io import BytesIO 18 | 19 | from .Constants import Constants 20 | from .Utils import * 21 | 22 | 23 | class InstagramRegistration(object): 24 | def __init__(self, debug=False, IGDataPath=None): 25 | 26 | self.debug = None 27 | self.IGDataPath = None 28 | self.username = None 29 | self.uuid = None 30 | self.waterfall_id = None 31 | self.token = None 32 | self.userAgent = None 33 | self.settings = None 34 | self.proxy = None # Full Proxy 35 | self.proxyHost = None # Proxy Host and Port 36 | self.proxyAuth = None # Proxy User and Pass 37 | 38 | self.username = '' 39 | self.debug = debug 40 | self.uuid = SignatureUtils.generateUUID(True) 41 | self.waterfall_id = SignatureUtils.generateUUID(True) 42 | 43 | if IGDataPath is not None: 44 | self.IGDataPath = IGDataPath 45 | else: 46 | self.IGDataPath = os.path.join( 47 | os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data'), 48 | '' 49 | ) 50 | 51 | self.userAgent = 'Instagram ' + Constants.VERSION + ' Android (18/4.3; 320dpi; 720x1280; Xiaomi; HM 1SW; armani; qcom; en_US)' 52 | 53 | def setProxy(self, proxy, port=None, username=None, password=None): 54 | """ 55 | Set the proxy. 56 | 57 | :type proxy: str 58 | :param proxy: Full proxy string. Ex: user:pass@192.168.0.0:8080 59 | Use $proxy = "" to clear proxy 60 | :type port: int 61 | :param port: Port of proxy 62 | :type username: str 63 | :param username: Username for proxy 64 | :type password: str 65 | :param password: Password for proxy 66 | 67 | :raises: InstagramException 68 | """ 69 | self.proxy = proxy 70 | 71 | if proxy == '': 72 | return 73 | 74 | proxy = parse_url(proxy) 75 | 76 | if port and isinstance(port, int): 77 | proxy['port'] = int(port) 78 | 79 | if username and password: 80 | proxy['user'] = username 81 | proxy['pass'] = password 82 | 83 | if proxy['host'] and proxy['port'] and isinstance(proxy['port'], int): 84 | self.proxyHost = proxy['host'] + ':' + proxy['port'] 85 | else: 86 | raise InstagramException('Proxy host error. Please check ip address and port of proxy.') 87 | 88 | if proxy['user'] and proxy['pass']: 89 | self.proxyAuth = proxy['user'] + ':' + proxy['pass'] 90 | 91 | def checkUsername(self, username): 92 | """ 93 | Checks if the username is already taken (exists). 94 | :type username: str 95 | :param username: 96 | :rtype: object 97 | :return: Username availability data 98 | """ 99 | data = json.dumps( 100 | OrderedDict([ 101 | ('_uuid', self.uuid), 102 | ('username', username), 103 | ('_csrftoken', 'missing'), 104 | ]) 105 | ) 106 | 107 | self.username = username 108 | self.settings = Settings(os.path.join(self.IGDataPath, self.username, 'settings-' + username + '.dat')) 109 | return CheckUsernameResponse(self.request('users/check_username/', SignatureUtils.generateSignature(data))[1]) 110 | 111 | def checkEmail(self, email): 112 | 113 | data = json.dumps( 114 | OrderedDict([ 115 | ('qe_id', SignatureUtils.generateUUID(True)), 116 | ('waterfall_id', SignatureUtils.generateUUID(True)), 117 | ('email', email), 118 | ('_csrftoken', 'missing'), 119 | ]) 120 | ) 121 | 122 | return CheckEmailResponse(self.request('users/check_email/', SignatureUtils.generateSignature(data))[1]) 123 | 124 | def usernameSuggestions(self, email, name): 125 | data = json.dumps( 126 | OrderedDict([ 127 | ('name', SignatureUtils.generateUUID(True)), 128 | ('waterfall_id', SignatureUtils.generateUUID(True)), 129 | ('email', email), 130 | ('_csrftoken', 'missing'), 131 | ]) 132 | ) 133 | 134 | return UsernameSuggestionsResponse( 135 | self.request('accounts/username_suggestions/', SignatureUtils.generateSignature(data))[1]) 136 | 137 | def createAccount(self, username, password, email, name=''): 138 | """ 139 | Register account. 140 | :type username: str 141 | :param username: 142 | :type password: str 143 | :param password: 144 | :type email: str 145 | :param email: 146 | 147 | :rtype: object 148 | :return: Registration data 149 | """ 150 | 151 | token = self.getCsfrtoken() 152 | data = json.dumps( 153 | OrderedDict([ 154 | ('allow_contacts_sync', 'true'), 155 | ('phone_id', self.uuid), 156 | ('_csrftoken', token), 157 | ('username', username), 158 | ('first_name', name), 159 | ('guid', self.uuid), 160 | ('device_id', SignatureUtils.generateDeviceId(hashlib.md5(username + password).hexdigest())), 161 | ('email', email), 162 | ('force_sign_up_code', ''), 163 | ('waterfall_id', self.waterfall_id), 164 | ('qs_stamp', ''), 165 | ('password', password), 166 | ]) 167 | ) 168 | 169 | result = self.request('accounts/create/', SignatureUtils.generateSignature(data)) 170 | header = result[0] 171 | response = AccountCreationResponse(result[1]) 172 | 173 | if response.isAccountCreated(): 174 | self.username_id = response.getUsernameId() 175 | self.settings.set('username_id', self.username_id) 176 | match = re.search(r'^Set-Cookie: csrftoken=([^;]+)', header, re.MULTILINE) 177 | token = match.group(1) if match else '' 178 | self.settings.set('token', token) 179 | 180 | return response 181 | 182 | def getCsfrtoken(self): 183 | 184 | fetch = self.request('si/fetch_headers/', None, True) 185 | 186 | header = fetch[0] 187 | response = ChallengeResponse(fetch[1]) 188 | 189 | if not header or not response.isOk(): 190 | raise InstagramException("Couldn't get challenge, check your connection") 191 | # return response #fixme unreachable code 192 | 193 | match = re.search(r'^Set-Cookie: csrftoken=([^;]+)', fetch[0], re.MULTILINE) 194 | 195 | if not match: 196 | raise InstagramException("Missing csfrtoken") 197 | # return $response #fixme unreachable code 198 | 199 | token = match.group(1) 200 | return token[22:] 201 | 202 | def request(self, endpoint, post=None): 203 | buffer = BytesIO() 204 | 205 | ch = pycurl.Curl() 206 | ch.setopt(pycurl.URL, Constants.API_URL + endpoint) 207 | ch.setopt(pycurl.USERAGENT, self.userAgent) 208 | ch.setopt(pycurl.WRITEFUNCTION, buffer.write) 209 | ch.setopt(pycurl.FOLLOWLOCATION, True) 210 | ch.setopt(pycurl.HEADER, True) 211 | ch.setopt(pycurl.VERBOSE, False) 212 | ch.setopt(pycurl.COOKIEFILE, os.path.join(self.IGDataPath, self.username, self.username + "-cookies.dat")) 213 | ch.setopt(pycurl.COOKIEJAR, os.path.join(self.IGDataPath, self.username, self.username + "-cookies.dat")) 214 | 215 | if post is not None: 216 | ch.setopt(pycurl.POST, True) 217 | ch.setopt(pycurl.POSTFIELDS, post) 218 | 219 | if self.proxy: 220 | ch.setopt(pycurl.PROXY, self.proxyHost) 221 | if self.proxyAuth: 222 | ch.setopt(pycurl.PROXYUSERPWD, self.proxyAuth) 223 | 224 | ch.perform() 225 | resp = buffer.getvalue() 226 | header_len = ch.getinfo(pycurl.HEADER_SIZE) 227 | header = resp[0: header_len] 228 | body = resp[header_len:] 229 | 230 | ch.close() 231 | 232 | if self.debug: 233 | print("REQUEST: " + endpoint) 234 | if post is not None: 235 | if not isinstance(post, list): 236 | print("DATA: " + str(post)) 237 | print("RESPONSE: " + body) 238 | 239 | return [header, json_decode(body)] 240 | -------------------------------------------------------------------------------- /InstagramAPI/src/SignatureUtils.py: -------------------------------------------------------------------------------- 1 | import hmac 2 | 3 | from .Constants import Constants 4 | from .Utils import * 5 | 6 | 7 | class SignatureUtils: 8 | @staticmethod 9 | def generateSignature(data): 10 | hash = hmac.new(Constants.IG_SIG_KEY.encode("utf-8"), data.encode("utf-8"), hashlib.sha256).hexdigest() 11 | 12 | return 'ig_sig_key_version=' + Constants.SIG_KEY_VERSION + \ 13 | '&signed_body=' + hash + '.' + compat_urllib_parse.quote_plus(data) 14 | 15 | @staticmethod 16 | def generateDeviceId(seed): 17 | # // Neutralize username/password -> device correlation 18 | volatile_seed = '%d' % os.stat(os.path.dirname(os.path.realpath(__file__))).st_mtime 19 | 20 | return 'android-' + str(hashlib.md5((str(seed) + str(volatile_seed)).encode("utf-8")).hexdigest())[16:] 21 | 22 | @staticmethod 23 | def generateUUID(type): 24 | uuid = '%04x%04x-%04x-%04x-%04x-%04x%04x%04x' % ( 25 | mt_rand(0, 0xffff), mt_rand(0, 0xffff), 26 | mt_rand(0, 0xffff), 27 | mt_rand(0, 0x0fff) | 0x4000, 28 | mt_rand(0, 0x3fff) | 0x8000, 29 | mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff) 30 | ) 31 | 32 | return uuid if type else uuid.replace('-', '') 33 | -------------------------------------------------------------------------------- /InstagramAPI/src/Utils/Compat.py: -------------------------------------------------------------------------------- 1 | # From https://github.com/rg3/youtube-dl/blob/master/youtube_dl/compat.py 2 | 3 | try: 4 | import urllib.parse as compat_urllib_parse 5 | except ImportError: # Python 2 6 | import urllib as compat_urllib_parse 7 | 8 | __all__ = ['compat_urllib_parse'] 9 | -------------------------------------------------------------------------------- /InstagramAPI/src/Utils/Settings.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | 3 | import os 4 | 5 | 6 | class Settings: 7 | def __init__(self, path): 8 | 9 | self.path = path 10 | self.sets = OrderedDict([]) 11 | 12 | if (os.path.isfile(path)): 13 | with open(path, 'rb') as fp: 14 | for line in fp.readlines(): 15 | line = line.decode("utf-8") 16 | line = line.strip(' ') 17 | if line[0] == '#': continue; 18 | kv = line.split('=', 2) 19 | self.sets[kv[0]] = kv[1].strip("\r\n ") 20 | 21 | def get(self, key, default=None): 22 | if key == 'sets': 23 | return self.sets 24 | 25 | return self.sets.get(key, default) 26 | 27 | def set(self, key, value): 28 | if key == 'sets': 29 | return 30 | 31 | self.sets[key] = value 32 | self.Save() 33 | 34 | def Save(self): 35 | if os.path.isfile(self.path): 36 | os.unlink(self.path) 37 | 38 | with open(self.path, 'wb') as fp: 39 | fp.seek(0) 40 | fp.writelines([(key + '=' + value + "\n").encode("utf-8") for (key, value) in self.sets.items()]) 41 | 42 | def __set(self, prop, value): 43 | self.set(prop, value) 44 | 45 | def __get(self, prop): 46 | return self.get(prop) 47 | -------------------------------------------------------------------------------- /InstagramAPI/src/Utils/Utils.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import os 3 | from PIL import Image 4 | from tempfile import mkdtemp 5 | 6 | from .php import * 7 | 8 | 9 | class Utils: 10 | @staticmethod 11 | def getSeconds(file): 12 | """ 13 | Length of the file in Seconds 14 | 15 | :type file: str 16 | :param file: path to the file name 17 | :return: length of the file in seconds 18 | """ 19 | ffmpeg = Utils.checkFFMPEG() 20 | if ffmpeg: 21 | time = exec_php([ffmpeg, '-i', file, '2>&1', '|', 'grep', 'Duration', '|', 'cut', '-d', '-f', '4'])[1] 22 | duration = time.split(":") 23 | seconds = duration[0] * 3600 + duration[1] * 60 + round(duration[2]) 24 | return seconds 25 | 26 | return mt_rand(15, 300) 27 | 28 | @staticmethod 29 | def checkFFMPEG(): 30 | """ 31 | Check for ffmpeg/avconv dependencies 32 | 33 | :rtype: str/bool 34 | :return: name of the library if present, false otherwise 35 | """ 36 | try: 37 | return_value = exec_php(['ffmpeg', '-version', '2>&1'])[0] 38 | if return_value == 0: return "ffmpeg" 39 | 40 | return_value = exec_php(['avconv', '-version', '2>&1'])[0] 41 | if return_value == 0: return "avconv" 42 | except Exception: 43 | pass 44 | 45 | return False 46 | 47 | @staticmethod 48 | def createVideoIcon(file): 49 | """ 50 | Creating a video icon/thumbnail 51 | 52 | :type file: str 53 | :param file: path to the file name 54 | :rtype: image 55 | :return: icon/thumbnail for the video 56 | """ 57 | # should install ffmpeg for the method to work successfully 58 | ffmpeg = Utils.checkFFMPEG() 59 | 60 | if ffmpeg: 61 | # generate thumbnail 62 | preview = os.path.join(mkdtemp(), hashlib.md5(file) + '.jpg') 63 | 64 | try: 65 | os.unlink(preview) 66 | except Exception: 67 | pass 68 | 69 | # capture video preview 70 | command = [ffmpeg, '-i', file, '-f', 'mjpeg', '-ss', '00:00:01', '-vframes', '1', preview, '2>&1'] 71 | exec_php(command) 72 | return file_get_contents(preview) 73 | 74 | @staticmethod 75 | def createIconGD(file, size=100, raw=True): 76 | """ 77 | Implements the actual logic behind creating the icon/thumbnail 78 | 79 | :type file: str 80 | :param file: path to the file name 81 | :rtype: image 82 | :return: icon/thumbnail for the video 83 | """ 84 | image = Image.open(file) 85 | width, height = image.size 86 | 87 | if width > height: 88 | y = 0 89 | x = (width - height) / 2 90 | smallestSide = height 91 | else: 92 | x = 0 93 | y = (height - width) / 2 94 | smallestSide = width 95 | 96 | # image_p = Image.new('RGB',(size, size)) 97 | # image = Image.frombytes('RGBa',(size,size),file_get_contents(file)) 98 | 99 | image.thumbnail((size, size)) 100 | 101 | ##todo convert to jpeg 102 | i = image.tobytes() 103 | image.close() 104 | # image_p.close() 105 | return i 106 | 107 | @staticmethod 108 | def formatBytes(bytes_, precision=2): 109 | import math 110 | units = ('B', 'kB', 'mB', 'gB', 'tB') 111 | bytes_ = max(bytes_, 0) 112 | pow_ = math.floor((math.log(bytes_) if bytes_ else 0) / math.log(1024)) 113 | pow_ = min(pow_, len(units) - 1) 114 | bytes_ /= math.pow(1024, pow_) 115 | return str(round(bytes_, precision)) + ' ' + units[int(pow_)] 116 | 117 | @staticmethod 118 | def colouredString(string, colour): 119 | colours = dict() 120 | 121 | colours['black'] = '0;30' 122 | colours['dark_gray'] = '1;30' 123 | colours['blue'] = '0;34' 124 | colours['light_blue'] = '1;34' 125 | colours['green'] = '0;32' 126 | colours['light_green'] = '1;32' 127 | colours['cyan'] = '0;36' 128 | colours['light_cyan'] = '1;36' 129 | colours['red'] = '0;31' 130 | colours['light_red'] = '1;31' 131 | colours['purple'] = '0;35' 132 | colours['light_purple'] = '1;35' 133 | colours['brown'] = '0;33' 134 | colours['yellow'] = '1;33' 135 | colours['light_gray'] = '0;37' 136 | colours['white'] = '1;37' 137 | 138 | colored_string = "" 139 | 140 | if colour in colours: 141 | colored_string += "\033[" + colours[colour] + "m" 142 | 143 | colored_string += string + "\033[0m" 144 | return colored_string 145 | 146 | @staticmethod 147 | def getFilterCode(): 148 | 149 | filters = [] 150 | filters[108] = "Charmes" 151 | filters[116] = "Ashby" 152 | filters[117] = "Helena" 153 | filters[115] = "Brooklyn" 154 | filters[105] = "Dogpatch" 155 | filters[113] = "Skyline" 156 | filters[107] = "Ginza" 157 | filters[118] = "Maven" 158 | filters[16] = "Kelvin" 159 | filters[14] = "1977" 160 | filters[20] = "Walden" 161 | filters[19] = "Toaster" 162 | filters[18] = "Sutro" 163 | filters[22] = "Brannan" 164 | filters[3] = "Earlybird" 165 | filters[106] = "Vesper" 166 | filters[109] = "Stinson" 167 | filters[15] = "Nashville" 168 | filters[21] = "Hefe" 169 | filters[10] = "Inkwell" 170 | filters[2] = "Lo-Fi" 171 | filters[28] = "Willow" 172 | filters[27] = "Sierra" 173 | filters[1] = "X Pro II" 174 | filters[25] = "Valencia" 175 | filters[26] = "Hudson" 176 | filters[23] = "Rise" 177 | filters[17] = "Mayfair" 178 | filters[24] = "Amaro" 179 | filters[608] = "Perpetua" 180 | filters[612] = "Aden" 181 | filters[603] = "Ludwig" 182 | filters[616] = "Crema" 183 | filters[605] = "Slumber" 184 | filters[613] = "Juno" 185 | filters[614] = "Reyes" 186 | filters[615] = "Lark" 187 | filters[111] = "Moon" 188 | filters[114] = "Gingham" 189 | filters[112] = "Clarendon" 190 | filters[0] = "Normal" 191 | 192 | return filters.index(filter) 193 | -------------------------------------------------------------------------------- /InstagramAPI/src/Utils/__init__.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.Utils.Utils import * 2 | from .Settings import Settings 3 | from .Compat import * 4 | from .php import * 5 | -------------------------------------------------------------------------------- /InstagramAPI/src/Utils/php.py: -------------------------------------------------------------------------------- 1 | def file_get_contents(file): 2 | with open(file, 'rb') as fFile: 3 | return fFile.read() 4 | 5 | 6 | def file_put_contents(file, contents): 7 | with open(file, 'w') as fFile: 8 | fFile.write(contents) ##todo return result 9 | fFile.flush() 10 | 11 | 12 | def mt_rand(low=0, high=0x7fffffff): 13 | import random 14 | return random.randint(low, high) 15 | 16 | 17 | def exec_php(cmd): 18 | from subprocess import Popen, PIPE, STDOUT 19 | p = Popen(cmd, shell=False, stdout=PIPE, stderr=STDOUT) 20 | return [p.wait(), p.stdout.readlines()] 21 | 22 | 23 | def parse_url(url): 24 | import urlparse 25 | r = urlparse.urlparse(url)._asdict() # Fixme Access to a protected member _asdict() of a class 26 | r['host'] = r['netloc'] 27 | return r 28 | 29 | 30 | def json_decode(json_string): 31 | import json 32 | try: 33 | return json.loads(json_string) 34 | except ValueError: 35 | return None 36 | -------------------------------------------------------------------------------- /InstagramAPI/src/__init__.py: -------------------------------------------------------------------------------- 1 | from .Checkpoint import Checkpoint 2 | from .Constants import Constants 3 | from .Instagram import Instagram 4 | from .InstagramException import InstagramException 5 | from .InstagramRegistration import InstagramRegistration 6 | from .SignatureUtils import SignatureUtils 7 | from .Utils import * 8 | from .http import * 9 | 10 | __all__ = ["Constants", "Instagram", "Checkpoint", "InstagramException", "InstagramRegistration", "http", "Utils"] 11 | -------------------------------------------------------------------------------- /InstagramAPI/src/data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danleyb2/Instagram-API/3435dc6855e1cccf2c85a41839d15ca930563b21/InstagramAPI/src/data/.gitkeep -------------------------------------------------------------------------------- /InstagramAPI/src/data/backup/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danleyb2/Instagram-API/3435dc6855e1cccf2c85a41839d15ca930563b21/InstagramAPI/src/data/backup/.gitkeep -------------------------------------------------------------------------------- /InstagramAPI/src/http/HttpInterface.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import hmac 3 | import json 4 | import locale 5 | import math 6 | import pycurl 7 | import time 8 | from collections import OrderedDict 9 | 10 | try: 11 | from io import BytesIO 12 | except ImportError: 13 | from StringIO import StringIO as BytesIO 14 | 15 | from InstagramAPI.src.InstagramException import InstagramException 16 | from InstagramAPI.src.Constants import Constants 17 | 18 | from InstagramAPI.src.Utils import * 19 | from InstagramAPI.src.http.Response import * 20 | 21 | 22 | class HttpInterface(object): 23 | def __init__(self, parent): 24 | self.parent = None 25 | self.userAgent = None 26 | self.verifyPeer = False 27 | self.verifyHost = False 28 | 29 | self.parent = parent 30 | self.userAgent = self.parent.settings.get('user_agent') 31 | 32 | def request(self, endpoint, post=None, login=False): 33 | buffer = BytesIO() 34 | if (not self.parent.isLoggedIn) and not login: 35 | raise InstagramException("Not logged in\n") 36 | 37 | headers = [ 38 | 'Connection: close', 39 | 'Accept: */*', 40 | 'X-IG-Capabilities: 3QI=', 41 | 'Content-type: application/x-www-form-urlencoded; charset=UTF-8', 42 | 'Cookie2: $Version=1', 43 | 'Accept-Language: en-US' 44 | ] 45 | 46 | ch = pycurl.Curl() 47 | 48 | ch.setopt(pycurl.URL, Constants.API_URL + endpoint) 49 | ch.setopt(pycurl.USERAGENT, self.userAgent) 50 | ch.setopt(pycurl.WRITEFUNCTION, buffer.write) 51 | ch.setopt(pycurl.FOLLOWLOCATION, True) 52 | ch.setopt(pycurl.HEADER, True) 53 | ch.setopt(pycurl.HTTPHEADER, headers) 54 | ch.setopt(pycurl.VERBOSE, False) 55 | ch.setopt(pycurl.SSL_VERIFYPEER, self.verifyPeer) 56 | ch.setopt(pycurl.SSL_VERIFYHOST, self.verifyHost) 57 | ch.setopt(pycurl.COOKIEFILE, self.parent.IGDataPath + self.parent.username + '-cookies.dat') 58 | ch.setopt(pycurl.COOKIEJAR, self.parent.IGDataPath + self.parent.username + '-cookies.dat') 59 | 60 | if post: 61 | ch.setopt(pycurl.POST, True) 62 | ch.setopt(pycurl.POSTFIELDS, post) 63 | 64 | if self.parent.proxy: 65 | ch.setopt(pycurl.PROXY, self.parent.proxyHost) 66 | if self.parent.proxyAuth: 67 | ch.setopt(pycurl.PROXYUSERPWD, self.parent.proxyAuth) 68 | 69 | ch.perform() 70 | resp = buffer.getvalue().decode("utf-8") 71 | header_len = ch.getinfo(pycurl.HEADER_SIZE) 72 | header = resp[0: header_len] 73 | body = resp[header_len:] 74 | 75 | 76 | if self.parent.debug: 77 | if post: 78 | print(Utils.colouredString('POST: ', 'light_blue') + endpoint) 79 | else: 80 | print(Utils.colouredString('GET: ', 'light_blue') + endpoint) 81 | 82 | if post is not None: 83 | if not isinstance(post, list): 84 | print('DATA: ' + compat_urllib_parse.unquote_plus(post)) 85 | 86 | bytes = Utils.formatBytes(ch.getinfo(pycurl.SIZE_DOWNLOAD)) 87 | httpCode = ch.getinfo(pycurl.HTTP_CODE) 88 | print(Utils.colouredString("← " + str(httpCode) + " \t " + bytes, 'green')) 89 | 90 | if self.parent.truncatedDebug and len(body) > 1000: 91 | print(Utils.colouredString('RESPONSE: ', 'cyan') + body[0:1000] + "...\n") 92 | else: 93 | print(Utils.colouredString('RESPONSE: ', 'cyan') + body + "\n") 94 | 95 | ch.close() 96 | return [header, json.loads(body)] 97 | 98 | def uploadPhoto(self, photo, caption=None, upload_id=None, customPreview=None, location=None, filter_=None, 99 | reel_flag=False): 100 | 101 | endpoint = Constants.API_URL + 'upload/photo/' 102 | boundary = self.parent.uuid 103 | 104 | if upload_id is not None and customPreview is None: 105 | fileToUpload = Utils.createVideoIcon(photo) 106 | elif customPreview is not None: 107 | fileToUpload = file_get_contents(customPreview) 108 | else: 109 | upload_id = locale.format("%.*f", (0, round(float('%.2f' % time.time()) * 1000)), grouping=False) 110 | fileToUpload = file_get_contents(photo) 111 | 112 | bodies = [ 113 | OrderedDict([ 114 | ('type', 'form-data'), 115 | ('name', 'upload_id'), 116 | ('data', upload_id) 117 | ]), 118 | OrderedDict([ 119 | ('type', 'form-data'), 120 | ('name', '_uuid'), 121 | ('data', self.parent.uuid) 122 | ]), 123 | OrderedDict([ 124 | ('type', 'form-data'), 125 | ('name', '_csrftoken'), 126 | ('data', self.parent.token) 127 | ]), 128 | 129 | OrderedDict([ 130 | ('type', 'form-data'), 131 | ('name', 'image_compression'), 132 | ('data', '{"lib_name":"jt","lib_version":"1.3.0","quality":"70"}') 133 | ]), 134 | 135 | OrderedDict([ 136 | ('type', 'form-data'), 137 | ('name', 'photo'), 138 | ('data', fileToUpload), 139 | ('filename', 'pending_media_' + locale.format("%.*f", (0, round(float('%.2f' % time.time()) * 1000)), 140 | grouping=False) + '.jpg'), 141 | ('headers', [ 142 | 'Content-Transfer-Encoding: binary', 143 | 'Content-type: application/octet-stream', 144 | ]) 145 | ]), 146 | ] 147 | 148 | data = self.buildBody(bodies, boundary) 149 | headers = [ 150 | 'Connection: close', 151 | 'Accept: */*', 152 | 'Content-type: multipart/form-data; boundary=' + boundary, 153 | 'Content-Length: ' + str(len(data)), 154 | 'Cookie2: $Version=1', 155 | 'Accept-Language: en-US', 156 | 'Accept-Encoding: gzip', 157 | ] 158 | 159 | buffer = BytesIO() 160 | ch = pycurl.Curl() 161 | 162 | ch.setopt(pycurl.URL, endpoint) 163 | ch.setopt(pycurl.USERAGENT, self.userAgent) 164 | ch.setopt(pycurl.WRITEFUNCTION, buffer.write) 165 | ch.setopt(pycurl.FOLLOWLOCATION, True) 166 | ch.setopt(pycurl.HEADER, True) 167 | ch.setopt(pycurl.VERBOSE, self.parent.debug) 168 | ch.setopt(pycurl.SSL_VERIFYPEER, self.verifyPeer) 169 | ch.setopt(pycurl.SSL_VERIFYHOST, self.verifyHost) 170 | ch.setopt(pycurl.HTTPHEADER, headers) 171 | ch.setopt(pycurl.COOKIEFILE, self.parent.IGDataPath + self.parent.username + "-cookies.dat") 172 | ch.setopt(pycurl.COOKIEJAR, self.parent.IGDataPath + self.parent.username + "-cookies.dat") 173 | ch.setopt(pycurl.POST, True) 174 | ch.setopt(pycurl.POSTFIELDS, data) 175 | 176 | if self.parent.proxy: 177 | ch.setopt(pycurl.PROXY, self.parent.proxyHost) 178 | if self.parent.proxyAuth: 179 | ch.setopt(pycurl.PROXYUSERPWD, self.parent.proxyAuth) 180 | 181 | ch.perform() 182 | resp = buffer.getvalue() 183 | header_len = ch.getinfo(pycurl.HEADER_SIZE) 184 | 185 | header = resp[0: header_len] 186 | upload = UploadPhotoResponse(json.loads(resp[header_len:])) 187 | 188 | ch.close() 189 | 190 | if not upload.isOk(): 191 | raise InstagramException(upload.getMessage()) 192 | 193 | if self.parent.debug: 194 | print('RESPONSE: ' + resp[header_len:] + "\n") 195 | 196 | if reel_flag: 197 | configure = self.parent.configureToReel(upload.getUploadId(), photo) 198 | else: 199 | configure = self.parent.configure(upload.getUploadId(), photo, caption, location, filter_) 200 | 201 | if not configure.isOk(): 202 | raise InstagramException(configure.getMessage()) 203 | 204 | self.parent.expose() 205 | 206 | return configure 207 | 208 | def uploadVideo(self, video, caption=None, customPreview=None): 209 | 210 | videoData = file_get_contents(video) 211 | 212 | endpoint = Constants.API_URL + 'upload/video/' 213 | boundary = self.parent.uuid 214 | upload_id = str(int(round(float('%.2f' % time.time()) * 1000))) 215 | bodies = [ 216 | OrderedDict([ 217 | ('type', 'form-data'), 218 | ('name', 'upload_id'), 219 | ('data', upload_id) 220 | ]), 221 | OrderedDict([ 222 | ('type', 'form-data'), 223 | ('name', '_csrftoken'), 224 | ('data', self.parent.token) 225 | ]), 226 | OrderedDict([ 227 | ('type', 'form-data'), 228 | ('name', 'media_type'), 229 | ('data', 2) 230 | ]), 231 | OrderedDict([ 232 | ('type', 'form-data'), 233 | ('name', '_uuid'), 234 | ('data', self.parent.uuid) 235 | ]), 236 | ] 237 | 238 | data = self.buildBody(bodies, boundary) 239 | headers = [ 240 | 'Connection: close', 241 | 'Accept: */*', 242 | 'Host: i.instagram.com', 243 | 'Content-type: multipart/form-data; boundary=' + boundary, 244 | 'Accept-Language: en-en', 245 | ] 246 | 247 | buffer = BytesIO() 248 | ch = pycurl.Curl() 249 | ch.setopt(pycurl.URL, endpoint) 250 | ch.setopt(pycurl.USERAGENT, self.userAgent) 251 | ch.setopt(pycurl.WRITEFUNCTION, buffer.write) 252 | ch.setopt(pycurl.FOLLOWLOCATION, True) 253 | ch.setopt(pycurl.HEADER, True) 254 | ch.setopt(pycurl.VERBOSE, self.parent.debug) 255 | ch.setopt(pycurl.SSL_VERIFYPEER, False) 256 | ch.setopt(pycurl.SSL_VERIFYHOST, False) 257 | ch.setopt(pycurl.HTTPHEADER, headers) 258 | ch.setopt(pycurl.COOKIEFILE, self.parent.IGDataPath + self.parent.username + "-cookies.dat") 259 | ch.setopt(pycurl.COOKIEJAR, self.parent.IGDataPath + self.parent.username + "-cookies.dat") 260 | ch.setopt(pycurl.POST, True) 261 | ch.setopt(pycurl.POSTFIELDS, data) 262 | 263 | if self.parent.proxy: 264 | ch.setopt(pycurl.PROXY, self.parent.proxyHost) 265 | if self.parent.proxyAuth: 266 | ch.setopt(pycurl.PROXYUSERPWD, self.parent.proxyAuth) 267 | 268 | ch.perform() 269 | resp = buffer.getvalue() 270 | header_len = ch.getinfo(pycurl.HEADER_SIZE) 271 | 272 | header = resp[0: header_len] 273 | body = UploadJobVideoResponse(json.loads(resp[header_len:])) 274 | 275 | uploadUrl = body.getVideoUploadUrl() 276 | job = body.getVideoUploadJob() 277 | 278 | request_size = int(math.floor(len(videoData) / 4.0)) 279 | 280 | lastRequestExtra = (len(videoData) - (request_size * 4)) 281 | 282 | for a in range(4): 283 | start = (a * request_size) 284 | end = (a + 1) * request_size + (lastRequestExtra if a == 3 else 0) 285 | 286 | headers = [ 287 | 'Connection: keep-alive', 288 | 'Accept: */*', 289 | 'Host: upload.instagram.com', 290 | 'Cookie2: $Version=1', 291 | 'Accept-Encoding: gzip, deflate', 292 | 'Content-Type: application/octet-stream', 293 | 'Session-ID: ' + str(upload_id), 294 | 'Accept-Language: en-en', 295 | 'Content-Disposition: attachment; filename="video.mov"', 296 | 'Content-Length: ' + str(end - start), 297 | 'Content-Range: ' + 'bytes ' + str(start) + '-' + str(end - 1) + '/' + str(len(videoData)), 298 | 'job: ' + job, 299 | ] 300 | 301 | buffer = BytesIO() 302 | ch = pycurl.Curl() 303 | ch.setopt(pycurl.URL, uploadUrl) 304 | ch.setopt(pycurl.USERAGENT, self.userAgent) 305 | ch.setopt(pycurl.CUSTOMREQUEST, 'POST') 306 | ch.setopt(pycurl.WRITEFUNCTION, buffer.write) 307 | ch.setopt(pycurl.FOLLOWLOCATION, True) 308 | ch.setopt(pycurl.HEADER, True) 309 | ch.setopt(pycurl.VERBOSE, False) 310 | ch.setopt(pycurl.HTTPHEADER, headers) 311 | ch.setopt(pycurl.COOKIEFILE, self.parent.IGDataPath + self.parent.username + "-cookies.dat") 312 | ch.setopt(pycurl.COOKIEJAR, self.parent.IGDataPath + self.parent.username + "-cookies.dat") 313 | ch.setopt(pycurl.POST, True) 314 | ch.setopt(pycurl.POSTFIELDS, videoData[start:end]) 315 | 316 | if self.parent.proxy: 317 | ch.setopt(pycurl.PROXY, self.parent.proxyHost) 318 | if self.parent.proxyAuth: 319 | ch.setopt(pycurl.PROXYUSERPWD, self.parent.proxyAuth) 320 | 321 | ch.perform() 322 | result = buffer.getvalue() 323 | header_len = ch.getinfo(pycurl.HEADER_SIZE) 324 | body = result[header_len:] 325 | # array.append([body]) todo fix 326 | 327 | ch.perform() 328 | resp = buffer.getvalue() 329 | header_len = ch.getinfo(pycurl.HEADER_SIZE) 330 | 331 | header = resp[0: header_len] 332 | upload = UploadVideoResponse(json.loads(resp[header_len:])) 333 | 334 | ch.close() 335 | 336 | if self.parent.debug: 337 | print('RESPONSE: ' + resp[header_len:] + "\n") 338 | 339 | configure = self.parent.configureVideo(upload['upload_id'], video, caption, customPreview) 340 | self.parent.expose() 341 | 342 | return configure[1] 343 | 344 | def changeProfilePicture(self, photo): 345 | 346 | if photo is None: 347 | print("Photo not valid") 348 | return 349 | 350 | uData = json.dumps( 351 | OrderedDict([ 352 | ('_csrftoken', self.parent.token), 353 | ('_uuid', self.parent.uuid), 354 | ('_uid', self.parent.username_id) 355 | ]) 356 | ) 357 | endpoint = Constants.API_URL + 'accounts/change_profile_picture/' 358 | boundary = self.parent.uuid 359 | bodies = [ 360 | OrderedDict([ 361 | ('type', 'form-data'), 362 | ('name', 'ig_sig_key_version'), 363 | ('data', Constants.SIG_KEY_VERSION) 364 | ]), 365 | OrderedDict([ 366 | ('type', 'form-data'), 367 | ('name', 'signed_body'), 368 | ('data', hmac.new(Constants.IG_SIG_KEY, uData, hashlib.sha256).hexdigest() + uData)]), 369 | OrderedDict([ 370 | ('type', 'form-data'), 371 | ('name', 'profile_pic'), 372 | ('data', file_get_contents(photo)), 373 | ('filename', 'profile_pic'), 374 | ('headers', [ 375 | 'Content-type: application/octet-stream', 376 | 'Content-Transfer-Encoding: binary', 377 | ]) 378 | ]), 379 | ] 380 | 381 | data = self.buildBody(bodies, boundary) 382 | headers = [ 383 | 'Proxy-Connection: keep-alive', 384 | 'Connection: keep-alive', 385 | 'Accept: */*', 386 | 'Content-type: multipart/form-data; boundary=' + boundary, 387 | 'Accept-Language: en-en', 388 | 'Accept-Encoding: gzip, deflate', 389 | ] 390 | 391 | buffer = BytesIO() 392 | ch = pycurl.Curl() 393 | ch.setopt(pycurl.URL, endpoint) 394 | ch.setopt(pycurl.USERAGENT, self.userAgent) 395 | ch.setopt(pycurl.WRITEFUNCTION, buffer.write) 396 | ch.setopt(pycurl.FOLLOWLOCATION, True) 397 | ch.setopt(pycurl.HEADER, True) 398 | ch.setopt(pycurl.VERBOSE, self.parent.debug) 399 | ch.setopt(pycurl.SSL_VERIFYPEER, self.verifyPeer) 400 | ch.setopt(pycurl.SSL_VERIFYHOST, self.verifyHost) 401 | ch.setopt(pycurl.HTTPHEADER, headers) 402 | ch.setopt(pycurl.COOKIEFILE, self.parent.IGDataPath + self.parent.username + "-cookies.dat") 403 | ch.setopt(pycurl.COOKIEJAR, self.parent.IGDataPath + self.parent.username + "-cookies.dat") 404 | ch.setopt(pycurl.POST, True) 405 | ch.setopt(pycurl.POSTFIELDS, data) 406 | 407 | if self.parent.proxy: 408 | ch.setopt(pycurl.PROXY, self.parent.proxyHost) 409 | if self.parent.proxyAuth: 410 | ch.setopt(pycurl.PROXYUSERPWD, self.parent.proxyAuth) 411 | 412 | ch.perform() 413 | 414 | resp = buffer.getvalue() 415 | header_len = ch.getinfo(pycurl.HEADER_SIZE) 416 | header = resp[:header_len] 417 | upload = json.loads(resp[header_len:]) 418 | 419 | ch.close() 420 | 421 | def direct_share(self, media_id, recipients, text=None): 422 | if not isinstance(recipients, list): 423 | recipients = [recipients] 424 | 425 | string = [] 426 | for recipient in recipients: 427 | string.append('"' + recipient + '"') 428 | 429 | recipient_users = ','.join(string) 430 | 431 | endpoint = Constants.API_URL + 'direct_v2/threads/broadcast/media_share/?media_type=photo' 432 | boundary = self.parent.uuid 433 | bodies = [ 434 | OrderedDict([ 435 | ('type', 'form-data'), 436 | ('name', 'media_id'), 437 | ('data', media_id) 438 | ]), 439 | OrderedDict([ 440 | ('type', 'form-data'), 441 | ('name', 'recipient_users'), 442 | ('data', "[[" + recipient_users + "]]") 443 | ]), 444 | 445 | OrderedDict([ 446 | ('type', 'form-data'), 447 | ('name', 'client_context'), 448 | ('data', self.parent.uuid) 449 | ]), 450 | 451 | OrderedDict([ 452 | ('type', 'form-data'), 453 | ('name', 'thread_ids'), 454 | ('data', '["0"]') 455 | ]), 456 | 457 | OrderedDict([ 458 | ('type', 'form-data'), 459 | ('name', 'text'), 460 | ('data', '' if text is None else text) 461 | ]), 462 | 463 | ] 464 | 465 | data = self.buildBody(bodies, boundary) 466 | headers = [ 467 | 'Proxy-Connection: keep-alive', 468 | 'Connection: keep-alive', 469 | 'Accept: */*', 470 | 'Content-type: multipart/form-data boundary=' + boundary, 471 | 'Accept-Language: en-en', 472 | ] 473 | 474 | buffer = BytesIO() 475 | ch = pycurl.Curl() 476 | ch.setopt(pycurl.URL, endpoint) 477 | ch.setopt(pycurl.USERAGENT, self.userAgent) 478 | ch.setopt(pycurl.WRITEFUNCTION, buffer.write) 479 | ch.setopt(pycurl.FOLLOWLOCATION, True) 480 | ch.setopt(pycurl.HEADER, True) 481 | ch.setopt(pycurl.VERBOSE, self.parent.debug) 482 | ch.setopt(pycurl.SSL_VERIFYPEER, self.verifyPeer) 483 | ch.setopt(pycurl.SSL_VERIFYHOST, self.verifyHost) 484 | ch.setopt(pycurl.HTTPHEADER, headers) 485 | ch.setopt(pycurl.COOKIEFILE, self.parent.IGDataPath + self.parent.username + "-cookies.dat") 486 | ch.setopt(pycurl.COOKIEJAR, self.parent.IGDataPath + self.parent.username + "-cookies.dat") 487 | ch.setopt(pycurl.POST, True) 488 | ch.setopt(pycurl.POSTFIELDS, data) 489 | 490 | if self.parent.proxy: 491 | ch.setopt(pycurl.PROXY, self.parent.proxyHost) 492 | if self.parent.proxyAuth: 493 | ch.setopt(pycurl.PROXYUSERPWD, self.parent.proxyAuth) 494 | 495 | ch.perform() 496 | resp = buffer.getvalue() 497 | header_len = ch.getinfo(pycurl.HEADER_SIZE) 498 | header = resp[0:header_len] 499 | upload = json.loads(resp[header_len:]) 500 | ch.close() 501 | 502 | def direct_message(self, recipients, text): 503 | if not isinstance(recipients, list): 504 | recipients = [recipients] 505 | 506 | string = [] 507 | for recipient in recipients: 508 | string.append('"' + recipient + '"') 509 | 510 | recipient_users = ','.join(string) 511 | 512 | endpoint = Constants.API_URL + 'direct_v2/threads/broadcast/text/' 513 | boundary = self.parent.uuid 514 | bodies = [ 515 | OrderedDict([ 516 | ('type', 'form-data'), 517 | ('name', 'recipient_users'), 518 | ('data', "[[" + recipient_users + "]]") 519 | ]), 520 | 521 | OrderedDict([ 522 | ('type', 'form-data'), 523 | ('name', 'client_context'), 524 | ('data', self.parent.uuid) 525 | ]), 526 | 527 | OrderedDict([ 528 | ('type', 'form-data'), 529 | ('name', 'thread_ids'), 530 | ('data', '["0"]') 531 | ]), 532 | 533 | OrderedDict([ 534 | ('type', 'form-data'), 535 | ('name', 'text'), 536 | ('data', '' if text is None else text) 537 | ]), 538 | 539 | ] 540 | 541 | data = self.buildBody(bodies, boundary) 542 | headers = [ 543 | 'Proxy-Connection: keep-alive', 544 | 'Connection: keep-alive', 545 | 'Accept: */*', 546 | 'Content-type: multipart/form-data; boundary=' + boundary, 547 | 'Accept-Language: en-en', 548 | ] 549 | 550 | buffer = BytesIO() 551 | ch = pycurl.Curl() 552 | ch.setopt(pycurl.URL, endpoint) 553 | ch.setopt(pycurl.USERAGENT, self.userAgent) 554 | ch.setopt(pycurl.WRITEFUNCTION, buffer.write) 555 | ch.setopt(pycurl.FOLLOWLOCATION, True) 556 | ch.setopt(pycurl.HEADER, True) 557 | ch.setopt(pycurl.VERBOSE, self.parent.debug) 558 | ch.setopt(pycurl.SSL_VERIFYPEER, self.verifyPeer) 559 | ch.setopt(pycurl.SSL_VERIFYHOST, self.verifyHost) 560 | ch.setopt(pycurl.HTTPHEADER, headers) 561 | ch.setopt(pycurl.COOKIEFILE, self.parent.IGDataPath + self.parent.username + "-cookies.dat") 562 | ch.setopt(pycurl.COOKIEJAR, self.parent.IGDataPath + self.parent.username + "-cookies.dat") 563 | ch.setopt(pycurl.POST, True) 564 | ch.setopt(pycurl.POSTFIELDS, data) 565 | 566 | if self.parent.proxy: 567 | ch.setopt(pycurl.PROXY, self.parent.proxyHost) 568 | if self.parent.proxyAuth: 569 | ch.setopt(pycurl.PROXYUSERPWD, self.parent.proxyAuth) 570 | 571 | ch.perform() 572 | resp = buffer.getvalue() 573 | header_len = ch.getinfo(pycurl.HEADER_SIZE) 574 | header = resp[0:header_len] 575 | upload = json.loads(resp[header_len:]) 576 | ch.close() 577 | 578 | def buildBody(self, bodies, boundary): 579 | body = '' 580 | for b in bodies: 581 | body += ('--' + boundary + "\r\n") 582 | body += ('Content-Disposition: ' + b['type'] + '; name="' + b['name'] + '"') 583 | if 'filename' in b: 584 | ext = os.path.splitext(b['filename'])[1][1:] 585 | body += ('; filename="' + 'pending_media_' + locale.format("%.*f", ( 586 | 0, round(float('%.2f' % time.time()) * 1000)), grouping=False) + '.' + ext + '"') 587 | if 'headers' in b and isinstance(b['headers'], list): 588 | for header in b['headers']: 589 | body += ("\r\n" + header) 590 | body += ("\r\n\r\n" + str(b['data']) + "\r\n") 591 | body += ('--' + boundary + '--') 592 | 593 | return body 594 | 595 | def verifyPeer(self, enable): 596 | self.verifyPeer = enable 597 | 598 | def verifyHost(self, enable): 599 | self.verifyHost = enable 600 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/AccountCreationResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.HdProfilePicUrlInfo import HdProfilePicUrlInfo 2 | from .Response import Response 3 | 4 | 5 | class AccountCreationResponse(Response): 6 | def __init__(self, response): 7 | 8 | self.username = None 9 | self.has_anonymous_profile_picture = None 10 | self.allow_contacts_sync = None 11 | self.nux_private_first_page = None 12 | self.profile_pic_url = None 13 | self.full_name = None 14 | self.pk = None 15 | self.hd_profile_pic_url_info = None 16 | self.nux_private_enabled = None 17 | self.is_private = None 18 | self.account_created = False 19 | self.feedback_title = '' 20 | self.feedback_message = '' 21 | self.spam = False 22 | self.feedback_action = '' 23 | self.feedback_url = '' 24 | self.errors = None 25 | 26 | if (self.STATUS_OK == response['status']) and ('errors' not in response): 27 | 28 | self.username = response['created_user']['username'] 29 | self.has_anonymous_profile_picture = response['created_user']['has_anonymous_profile_picture'] 30 | self.allow_contacts_sync = response['created_user']['allow_contacts_sync'] 31 | self.nux_private_first_page = response['created_user']['nux_private_first_page'] 32 | self.profile_pic_url = response['created_user']['profile_pic_url'] 33 | self.full_name = response['created_user']['full_name'] 34 | self.pk = response['created_user']['pk'] 35 | self.hd_profile_pic_url_info = HdProfilePicUrlInfo(response['created_user']['hd_profile_pic_url_info']) 36 | self.nux_private_enabled = response['created_user']['nux_private_enabled'] 37 | self.is_private = response['created_user']['is_private'] 38 | self.account_created = response['account_created'] 39 | else: 40 | if 'message' in response: 41 | self.setMessage(response['message']) 42 | 43 | if 'errors' in response: 44 | self.errors = response['errors'] 45 | 46 | if not self.errors: 47 | self.feedback_title = response['feedback_title'] 48 | self.feedback_message = response['feedback_message'] 49 | self.spam = response['spam'] 50 | self.feedback_action = response['feedback_action'] 51 | self.feedback_url = response['feedback_url'] 52 | 53 | self.setStatus(response['status']) 54 | 55 | def hasAnonymousProfilePicture(self): 56 | return self.has_anonymous_profile_picture 57 | 58 | def allowContactsSync(self): 59 | return self.allow_contacts_sync 60 | 61 | def nuxPrivateFirstPage(self): 62 | return self.nux_private_first_page 63 | 64 | def getProfilePicUrl(self): 65 | return self.profile_pic_url 66 | 67 | def getFullName(self): 68 | return self.full_name 69 | 70 | def getUsernameId(self): 71 | return self.pk 72 | 73 | def getHdProfilePicUrlInfo(self): 74 | return self.hd_profile_pic_url_info 75 | 76 | def isNuxPrivateEnabled(self): 77 | return self.nux_private_enabled 78 | 79 | def isPrivate(self): 80 | return self.is_private 81 | 82 | def isAccountCreated(self): 83 | return self.account_created 84 | 85 | def getFeedbackTitle(self): 86 | return self.feedback_title 87 | 88 | def getFeedbackMessage(self): 89 | return self.feedback_message 90 | 91 | def isSpam(self): 92 | return self.spam 93 | 94 | def getFeedbackAction(self): 95 | return self.feedback_action 96 | 97 | def getFeedbackUrl(self): 98 | return self.feedback_url 99 | 100 | def getErrors(self): 101 | return self.errors 102 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/ChallengeResponse.py: -------------------------------------------------------------------------------- 1 | from .Response import Response 2 | 3 | 4 | class ChallengeResponse(Response): 5 | def __init__(self, response): 6 | 7 | if self.STATUS_OK == response['status']: 8 | pass 9 | else: 10 | self.setMessage(response['message']) 11 | 12 | self.setStatus(response['status']) 13 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/CheckEmailResponse.py: -------------------------------------------------------------------------------- 1 | from .Response import Response 2 | 3 | 4 | class CheckEmailResponse(Response): 5 | def __init__(self, response): 6 | 7 | self.username = None 8 | self.confirmed = None 9 | self.status = None 10 | self.valid = None 11 | self.username_suggestions = None 12 | 13 | if self.STATUS_OK == response['status']: 14 | self.confirmed = response['confirmed'] 15 | self.available = response['available'] 16 | self.valid = response['valid'] 17 | if 'username_suggestions' in response: 18 | self.username_suggestions = response['username_suggestions'] 19 | 20 | else: 21 | self.setMessage(response['message']) 22 | 23 | self.setStatus(response['status']) 24 | 25 | def isConfirmed(self): 26 | return self.confirmed 27 | 28 | def isAvailable(self): 29 | return self.available 30 | 31 | def isValid(self): 32 | return self.valid 33 | 34 | def getUsernameSuggestions(self): 35 | return self.username_suggestions 36 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/CheckUsernameResponse.py: -------------------------------------------------------------------------------- 1 | from .Response import Response 2 | 3 | 4 | class CheckUsernameResponse(Response): 5 | def __init__(self, response): 6 | 7 | self.username = None 8 | self.available = None 9 | self.status = None 10 | self.error = False 11 | 12 | if self.STATUS_OK == response['status']: 13 | self.username = response['username'] 14 | self.available = response['available'] 15 | if 'error' in response: 16 | self.error = response['error'] 17 | 18 | else: 19 | self.setMessage(response['message']) 20 | 21 | self.setStatus(response['status']) 22 | 23 | def getUsername(self): 24 | 25 | return self.username 26 | 27 | def isAvailable(self): 28 | return self.available 29 | 30 | def getError(self): 31 | return self.error 32 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/CommentResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.Comment import Comment 2 | from .Response import Response 3 | 4 | 5 | class CommentResponse(Response): 6 | def __init__(self, response): 7 | self.comment = None 8 | 9 | if self.STATUS_OK == response['status']: 10 | if 'comment' in response and response['comment']: 11 | self.comments = Comment(response['comment']) 12 | 13 | else: 14 | self.setMessage(response['message']) 15 | self.setStatus(response['status']) 16 | 17 | def getComment(self): 18 | return self.comment 19 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/ConfigureResponse.py: -------------------------------------------------------------------------------- 1 | from .Response import Response 2 | 3 | 4 | class ConfigureResponse(Response): 5 | def __init__(self, response): 6 | self.upload_id = None 7 | self.media_id = None 8 | self.image_url = None 9 | self.media_code = None 10 | 11 | if self.STATUS_OK == response['status']: 12 | self.upload_id = response['upload_id'] 13 | self.media_id = response['media']['id'] 14 | 15 | # TODO see fix at danleyb2/Instagram-API#20 16 | self.image_url = response['media']['image_versions2']['candidates']['0']['url'] 17 | self.media_code = response['media']['code'] 18 | else: 19 | self.setMessage(response['message']) 20 | 21 | self.setStatus(response['status']) 22 | 23 | def getUploadId(self): 24 | return self.upload_id 25 | 26 | def getMediaId(self): 27 | return self.media_id 28 | 29 | def getImageUrl(self): 30 | return self.image_url 31 | 32 | def getMediaCode(self): 33 | return self.media_code 34 | 35 | def getMediaUrl(self): 36 | return 'https://www.instagram.com/p/' + self.getMediaCode() + '/' 37 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/ConfigureVideoResponse.py: -------------------------------------------------------------------------------- 1 | from .Response import Response 2 | 3 | 4 | class ConfigureVideoResponse(Response): 5 | def __init__(self, response): 6 | self.upload_id = None 7 | self.media_id = None 8 | self.image_url = None 9 | self.video_version = None 10 | 11 | if self.STATUS_OK == response['status']: 12 | self.upload_id = response['upload_id'] 13 | self.media_id = response['media']['id'] 14 | self.image_url = response['media']['image_versions2']['candidates']['0']['url'] 15 | self.video_url = response['media']['video_versions'][0]['url'] 16 | else: 17 | self.setMessage(response['message']) 18 | 19 | self.setStatus(response['status']) 20 | 21 | def getUploadId(self): 22 | return self.upload_id 23 | 24 | def getMediaId(self): 25 | return self.media_id 26 | 27 | def getImageUrl(self): 28 | return self.image_url 29 | 30 | def getVideoUrl(self): 31 | return self.video_url 32 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/ExploreResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.Item import Item 2 | from .Response import Response 3 | 4 | 5 | class ExploreResponse(Response): 6 | def __init__(self, response): 7 | self.num_results = None 8 | self.auto_load_more_enabled = None 9 | self.items = None 10 | self.more_available = None 11 | self.next_max_id = None 12 | self.max_id = None 13 | 14 | if self.STATUS_OK == response['status']: 15 | self.num_results = response['num_results'] 16 | self.auto_load_more_enabled = response['auto_load_more_enabled'] 17 | self.more_available = response['more_available'] 18 | self.next_max_id = response['next_max_id'] 19 | self.max_id = response['max_id'] 20 | items = [] 21 | for item in response['items']: 22 | if 'media' in item and item['media']: 23 | items.append(Item(item['media'])) 24 | 25 | self.items = items 26 | else: 27 | self.setMessage(response['message']) 28 | 29 | self.setStatus(response['status']) 30 | 31 | def getExpires(self): 32 | return self.expires 33 | 34 | def getUsers(self): 35 | return self.users 36 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/ExposeResponse.py: -------------------------------------------------------------------------------- 1 | from .Response import Response 2 | 3 | 4 | class ExposeResponse(Response): 5 | def __init__(self, response): 6 | 7 | if self.STATUS_OK == response['status']: 8 | pass 9 | else: 10 | self.setMessage(response['message']) 11 | self.setStatus(response['status']) 12 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/FollowerResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.User import User 2 | from .Response import Response 3 | 4 | 5 | class FollowerResponse(Response): 6 | def __init__(self, response): 7 | self.followers = None 8 | self.next_max_id = None 9 | 10 | if self.STATUS_OK == response['status']: 11 | users = [] 12 | for user in response['users']: 13 | users.append(User(user)) 14 | 15 | self.followers = users 16 | self.next_max_id = response['next_max_id'] \ 17 | if ('next_max_id' in response and response['next_max_id']) \ 18 | else None 19 | else: 20 | self.setMessage(response['message']) 21 | self.setStatus(response['status']) 22 | 23 | def getFollowings(self): 24 | return self.followers 25 | 26 | def getNextMaxId(self): 27 | return self.next_max_id 28 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/FollowingResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.User import User 2 | from .Response import Response 3 | 4 | 5 | class FollowingResponse(Response): 6 | def __init__(self, response): 7 | self.followings = None 8 | self.next_max_id = None 9 | 10 | if self.STATUS_OK == response['status']: 11 | users = [] 12 | for user in response['users']: 13 | users.append(User(user)) 14 | self.followings = users 15 | self.next_max_id = response['next_max_id'] \ 16 | if ('next_max_id' in response and response['next_max_id']) \ 17 | else None 18 | else: 19 | self.setMessage(response['message']) 20 | self.setStatus(response['status']) 21 | 22 | def getFollowings(self): 23 | return self.followings 24 | 25 | def getNextMaxId(self): 26 | return self.next_max_id 27 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/LocationResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.Location import Location 2 | from .Response import Response 3 | 4 | 5 | class LocationResponse(Response): 6 | def __init__(self, response): 7 | self.venues = None 8 | self.request_id = None 9 | 10 | if self.STATUS_OK == response['status']: 11 | locations = [] 12 | for location in response['venues']: 13 | locations.append(Location(location)) 14 | 15 | self.venues = locations 16 | else: 17 | self.setMessage(response['message']) 18 | 19 | self.setStatus(response['status']) 20 | 21 | def getVenues(self): 22 | return self.venues 23 | 24 | def getRequestId(self): 25 | return self.request_id 26 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/LoginResponse.py: -------------------------------------------------------------------------------- 1 | from .Response import Response 2 | 3 | 4 | class LoginResponse(Response): 5 | def __init__(self, response): 6 | 7 | self.username = None 8 | self.has_anonymous_profile_picture = None 9 | self.profile_pic_url = None 10 | self.profile_pic_id = None 11 | self.full_name = None 12 | self.pk = None 13 | self.is_private = None 14 | 15 | if 'logged_in_user' in response and 'username' in response['logged_in_user']: 16 | self.username = response['logged_in_user']['username'] 17 | self.has_anonymous_profile_picture = response['logged_in_user']['has_anonymous_profile_picture'] 18 | self.profile_pic_url = response['logged_in_user']['profile_pic_url'] 19 | self.full_name = response['logged_in_user']['full_name'] 20 | self.pk = response['logged_in_user']['pk'] 21 | self.is_private = response['logged_in_user']['is_private'] 22 | else: 23 | self.setMessage(response['message']) 24 | 25 | self.setStatus(response['status']) 26 | 27 | def getUsername(self): 28 | return self.username 29 | 30 | def getHasAnonymousProfilePicture(self): 31 | return self.has_anonymous_profile_picture 32 | 33 | def getProfilePicUrl(self): 34 | return self.profile_pic_url 35 | 36 | def getProfilePicId(self): 37 | return self.profile_pic_id 38 | 39 | def getFullName(self): 40 | return self.full_name 41 | 42 | def getUsernameId(self): 43 | return str(self.pk) 44 | 45 | def getIsPrivate(self): 46 | return self.is_private 47 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/LogoutResponse.py: -------------------------------------------------------------------------------- 1 | from .Response import Response 2 | 3 | 4 | class LogoutResponse(Response): 5 | def __init__(self, response): 6 | 7 | if self.STATUS_OK == response['status']: 8 | pass 9 | else: 10 | self.setMessage(response['message']) 11 | 12 | self.setStatus(response['status']) 13 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/MediaCommentsResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.Item import Item 2 | from .Response import Response 3 | 4 | 5 | class MediaCommentsResponse(Response): 6 | def __init__(self, response): 7 | self.item = None 8 | 9 | if self.STATUS_OK == response['status']: 10 | if 'media' in response and response['media']: 11 | self.item = Item(response['media']) 12 | else: 13 | self.setMessage(response['message']) 14 | self.setStatus(response['status']) 15 | 16 | def getItem(self): 17 | return self.taken_at # Unresolved reference attribute 18 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/MediaInfoResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.Comment import Comment 2 | from .Objects.User import User 3 | from .Response import Response 4 | 5 | 6 | class MediaInfoResponse(Response): 7 | def __init__(self, response): 8 | 9 | self.taken_at = None 10 | self.image_url = None 11 | self.like_count = None 12 | self.likers = None 13 | self.comments = None 14 | 15 | if self.STATUS_OK == response['status']: 16 | 17 | self.taken_at = response['items'][0]['taken_at'] 18 | self.image_url = response['items'][0]['image_versions2']['candidates']['0'][ 19 | 'url'] # FIXME list indices must be integers, not str 20 | self.like_count = response['items'][0]['like_count'] 21 | likers = [] 22 | 23 | for liker in response['items'][0]['likers']: 24 | likers.append(User(liker)) 25 | 26 | self.likers = likers 27 | comments = [] 28 | 29 | for comment in response['items'][0]['comments']: 30 | comments.append(Comment(comment)) 31 | 32 | self.comments = comments 33 | 34 | else: 35 | self.setMessage(response['message']) 36 | 37 | self.setStatus(response['status']) 38 | self.setFullResponse(response) 39 | 40 | def getTakenTime(self): 41 | return self.taken_at 42 | 43 | def getImageUrl(self): 44 | return self.image_url 45 | 46 | def getLikeCount(self): 47 | return self.like_count 48 | 49 | def getLikers(self): 50 | return self.likers 51 | 52 | def getComments(self): 53 | return self.comments 54 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/MediaLikersResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.User import User 2 | from .Response import Response 3 | 4 | 5 | class MediaLikersResponse(Response): 6 | def __init__(self, response): 7 | 8 | self.user_count = None 9 | self.likers = None 10 | 11 | if self.STATUS_OK == response['status']: 12 | users = [] 13 | for user in response['users']: 14 | users.append(User(user)) 15 | 16 | self.likers = users 17 | self.user_count = response['user_count'] 18 | else: 19 | self.setMessage(response['message']) 20 | 21 | self.setStatus(response['status']) 22 | 23 | def getLikers(self): 24 | return self.likers 25 | 26 | def getLikeCounter(self): 27 | return self.user_count 28 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/MegaphoneLogResponse.py: -------------------------------------------------------------------------------- 1 | from .Response import Response 2 | 3 | 4 | class MegaphoneLogResponse(Response): 5 | def __init__(self, response): 6 | self.success = None 7 | 8 | if self.STATUS_OK == response['status']: 9 | self.success = response['success'] 10 | else: 11 | self.setMessage(response['message']) 12 | self.setStatus(response['status']) 13 | 14 | def isSuccess(self): 15 | return self.success 16 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/Caption.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.User import User 2 | 3 | 4 | class Caption(object): 5 | def __init__(self, data): 6 | self.status = None 7 | self.user_id = None 8 | self.created_at_utc = None 9 | self.created_at = None 10 | self.bit_flags = None 11 | self.user = None 12 | self.content_type = None 13 | self.text = None 14 | self.media_id = None 15 | self.pk = None 16 | self.type = None 17 | 18 | self.status = data['status'] 19 | self.user_id = data['user_id'] 20 | self.created_at_utc = data['created_at_utc'] 21 | self.created_at = data['created_at'] 22 | self.bit_flags = data['bit_flags'] 23 | self.user = User(data['user']) 24 | self.content_type = data['content_type'] 25 | self.text = data['text'] 26 | self.media_id = data['media_id'] 27 | self.pk = data['pk'] 28 | self.type = data['type'] 29 | 30 | def getStatus(self): 31 | return self.status 32 | 33 | def getUserId(self): 34 | return self.user_id 35 | 36 | def getCreatedAtUtc(self): 37 | return self.created_at_utc 38 | 39 | def getCreatedAt(self): 40 | return self.created_at 41 | 42 | def getBitFlags(self): 43 | return self.bit_flags 44 | 45 | def getUser(self): 46 | return self.user 47 | 48 | def getContentType(self): 49 | return self.content_type 50 | 51 | def getText(self): 52 | return self.text 53 | 54 | def getMediaId(self): 55 | return self.media_id 56 | 57 | def getUsernameId(self): 58 | return self.pk 59 | 60 | def getType(self): 61 | return self.type 62 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/Comment.py: -------------------------------------------------------------------------------- 1 | from .User import User 2 | 3 | 4 | class Comment(object): 5 | def __init__(self, commentData): 6 | self.status = None 7 | self.username_id = None 8 | self.created_at_utc = None 9 | self.created_at = None 10 | self.bit_flags = None 11 | self.user = None 12 | self.comment = None 13 | self.pk = None 14 | self.type = None 15 | self.media_id = None 16 | 17 | self.status = commentData['status'] 18 | if 'user_id' in commentData and commentData['user_id']: 19 | self.username_id = commentData['user_id'] 20 | self.created_at_utc = commentData['created_at_utc'] 21 | self.created_at = commentData['created_at'] 22 | if 'bit_flags' in commentData and commentData['bit_flags']: 23 | self.bit_flags = commentData['bit_flags'] 24 | self.user = User(commentData['user']) 25 | self.comment = commentData['text'] 26 | self.pk = commentData['pk'] 27 | if 'type' in commentData and commentData['type']: 28 | self.type = commentData['type'] 29 | if 'media_id' in commentData and commentData['media_id']: 30 | self.media_id = commentData['media_id'] 31 | 32 | def getStatus(self): 33 | return self.status 34 | 35 | def getUsernameId(self): 36 | return self.username_id 37 | 38 | def getCreatedAtUtc(self): 39 | return self.created_at_utc 40 | 41 | def created_at(self): 42 | return self.created_at 43 | 44 | def getBitFlags(self): 45 | return self.bit_flags 46 | 47 | def getUser(self): 48 | return self.user 49 | 50 | def getComment(self): 51 | return self.comment 52 | 53 | def getCommentId(self): 54 | return self.pk 55 | 56 | def getType(self): 57 | return self.type 58 | 59 | def getMediaId(self): 60 | return self.media_id 61 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/Experiment.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.Param import Param 2 | 3 | 4 | class Experiment(object): 5 | def __init__(self, data): 6 | self.params = None 7 | self.group = None 8 | self.name = None 9 | 10 | params = [] 11 | for param in data['params']: 12 | params.append(Param(param)) 13 | 14 | self.params = params 15 | self.group = data['group'] 16 | self.name = data['name'] 17 | 18 | def getParams(self): 19 | return self.params 20 | 21 | def getGroup(self): 22 | return self.group 23 | 24 | def getName(self): 25 | return self.name 26 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/Explore.py: -------------------------------------------------------------------------------- 1 | class Explore(object): 2 | def __init__(self, data): 3 | self.explanation = None 4 | self.actor_id = None 5 | self.source_token = None 6 | 7 | self.explanation = data['explanation'] 8 | if 'actor_id' in data: 9 | self.actor_id = data['actor_id'] 10 | if 'source_token' in data: 11 | self.source_token = data['source_token'] 12 | 13 | def getExplanation(self): 14 | return self.explanation 15 | 16 | def getActorId(self): 17 | return self.actor_id 18 | 19 | def getSourceToken(self): 20 | return self.source_token 21 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/FeedAysf.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.Suggestion import Suggestion 2 | 3 | 4 | class FeedAysf(object): 5 | def __init__(self, data): 6 | self.landing_site_type = None 7 | self.uuid = None 8 | self.view_all_text = None 9 | self.feed_position = None 10 | self.landing_site_title = None 11 | self.is_dismissable = None 12 | self.suggestions = None 13 | self.should_refill = None 14 | self.display_new_unit = None 15 | self.fetch_user_details = None 16 | self.title = None 17 | 18 | self.landing_site_type = data['landing_site_type'] 19 | self.uuid = data['uuid'] 20 | self.view_all_text = data['view_all_text'] 21 | self.feed_position = data['feed_position'] 22 | self.landing_site_title = data['landing_site_title'] 23 | self.is_dismissable = data['is_dismissable'] 24 | suggestions = [] 25 | if 'suggestions' in data and len(data['suggestions']): 26 | for suggestion in data['suggestions']: 27 | suggestions.append(Suggestion(suggestion)) 28 | 29 | self.suggestions = suggestions 30 | self.should_refill = data['should_refill'] 31 | self.display_new_unit = data['display_new_unit'] 32 | self.fetch_user_details = data['fetch_user_details'] 33 | self.title = data['title'] 34 | 35 | def getLandingSiteType(self): 36 | return self.landing_site_type 37 | 38 | def getUuid(self): 39 | return self.uuid 40 | 41 | def getViewAllText(self): 42 | return self.view_all_text 43 | 44 | def getFeedPosition(self): 45 | return self.feed_position 46 | 47 | def getLandingSiteTitle(self): 48 | return self.landing_site_title 49 | 50 | def isDismissable(self): 51 | return self.is_dismissable 52 | 53 | def getSuggestions(self): 54 | return self.suggestions 55 | 56 | def shouldRefill(self): 57 | return self.should_refill 58 | 59 | def displayNewUnit(self): 60 | return self.display_new_unit 61 | 62 | def fetchUserDetails(self): 63 | return self.fetch_user_details 64 | 65 | def getTitle(self): 66 | return self.title 67 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/FriendshipStatus.py: -------------------------------------------------------------------------------- 1 | class FriendshipStatus(object): 2 | def __init__(self, data): 3 | self.following = None 4 | self.incoming_request = None 5 | self.outgoing_request = None 6 | self.is_private = None 7 | 8 | self.following = data['following'] 9 | if 'source_token' in data: 10 | self.incoming_request = data['incoming_request'] 11 | if 'source_token' in data: 12 | self.outgoing_request = data['outgoing_request'] 13 | if 'is_private' in data: 14 | self.is_private = data['is_private'] 15 | 16 | def getFollowing(self): 17 | return self.following 18 | 19 | def getIncomingRequest(self): 20 | return self.incoming_request 21 | 22 | def getOutgoingRequest(self): 23 | return self.outgoing_request 24 | 25 | def isPrivate(self): 26 | return self.is_private 27 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/HdProfilePicUrlInfo.py: -------------------------------------------------------------------------------- 1 | class HdProfilePicUrlInfo(object): 2 | def __init__(self, response): 3 | self.url = None 4 | self.width = None 5 | self.height = None 6 | 7 | self.url = response['url'] 8 | self.width = response['width'] 9 | self.height = response['height'] 10 | 11 | def getUrl(self): 12 | return self.url 13 | 14 | def getWidth(self): 15 | return self.width 16 | 17 | def getHeight(self): 18 | return self.height 19 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/In.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.Position import Position 2 | from InstagramAPI.src.http.Response.Objects.User import User 3 | 4 | 5 | class In(object): 6 | def __init__(self, data): 7 | self.position = None 8 | self.user = None 9 | 10 | self.position = Position(data['position']) 11 | self.user = User(data['user']) 12 | 13 | def getPosition(self): 14 | return self.position 15 | 16 | def getUser(self): 17 | return self.user 18 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/Inbox.py: -------------------------------------------------------------------------------- 1 | class Inbox(object): 2 | def __init__(self, data): 3 | self.unseen_count = None 4 | self.has_older = None 5 | self.unseen_count_ts = None 6 | self.threads = None 7 | 8 | self.unseen_count = data['unseen_count'] 9 | self.has_older = data['has_older'] 10 | self.unseen_count_ts = data['unseen_count_ts'] 11 | self.threads = data['threads'] 12 | 13 | def getUnseenCount(self): 14 | return self.unseen_count 15 | 16 | def hasOlder(self): 17 | return self.has_older 18 | 19 | def getUnseenCountTs(self): 20 | return self.unseen_count_ts 21 | 22 | def getThreads(self): 23 | return self.threads 24 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/Item.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.Caption import Caption 2 | from InstagramAPI.src.http.Response.Objects.Comment import Comment 3 | from InstagramAPI.src.http.Response.Objects.Explore import Explore 4 | from InstagramAPI.src.http.Response.Objects.HdProfilePicUrlInfo import HdProfilePicUrlInfo 5 | from InstagramAPI.src.http.Response.Objects.User import User 6 | from InstagramAPI.src.http.Response.Objects.Usertag import Usertag 7 | from InstagramAPI.src.http.Response.Objects.VideoVersions import VideoVersions 8 | 9 | 10 | class Item(object): 11 | PHOTO = 1 12 | VIDEO = 2 13 | 14 | def __init__(self, item): 15 | 16 | self.taken_at = None 17 | self.pk = None 18 | self.id = None 19 | self.device_timestamp = None 20 | self.media_type = None 21 | self.code = None 22 | self.client_cache_key = None 23 | self.filter_type = None 24 | self.image_versions2 = None 25 | self.original_width = None 26 | self.original_height = None 27 | self.view_count = 0 28 | self.organic_tracking_token = None 29 | self.has_more_comments = None 30 | self.max_num_visible_preview_comments = None 31 | self.comments = None 32 | self.comment_count = 0 33 | self.caption = None 34 | self.caption_is_edited = None 35 | self.photo_of_you = None 36 | self.video_versions = None 37 | self.has_audio = False 38 | self.video_duration = '' 39 | self.user = None 40 | self.likers = '' 41 | self.like_count = 0 42 | self.preview = '' 43 | self.has_liked = False 44 | self.explore_context = '' 45 | self.explore_source_token = '' 46 | self.explore = '' 47 | self.impression_token = '' 48 | self.usertags = None 49 | 50 | self.taken_at = item['taken_at'] 51 | self.pk = item['pk'] 52 | self.id = item['id'] 53 | self.device_timestamp = item['device_timestamp'] 54 | self.media_type = item['media_type'] 55 | self.code = item['code'] 56 | self.client_cache_key = item['client_cache_key'] 57 | self.filter_type = item['filter_type'] 58 | images = [] 59 | if 'image_versions2' in item \ 60 | and 'candidates' in item['image_versions2'] \ 61 | and len(item['image_versions2']['candidates']): 62 | 63 | for image in item['image_versions2']['candidates']: 64 | images.append(HdProfilePicUrlInfo(image)) 65 | 66 | self.image_versions2 = images 67 | self.original_width = item['original_width'] 68 | self.original_height = item['original_height'] 69 | if 'view_count' in item and item['view_count']: 70 | self.view_count = item['view_count'] 71 | 72 | self.organic_tracking_token = item['organic_tracking_token'] 73 | if 'has_more_comments' in item: 74 | self.has_more_comments = item['has_more_comments'] 75 | if 'max_num_visible_preview_comments' in item: 76 | self.max_num_visible_preview_comments = item['max_num_visible_preview_comments'] 77 | comments = [] 78 | if 'comments' in item and len(item['comments']): 79 | for comment in item['comments']: 80 | comments.append(Comment(comment)) 81 | 82 | self.comments = comments 83 | if 'comment_count' in item: 84 | self.comment_count = item['comment_count'] 85 | if item['caption']: 86 | self.caption = Caption(item['caption']) 87 | self.caption_is_edited = item['caption_is_edited'] 88 | self.photo_of_you = item['photo_of_you'] 89 | if 'video_versions' in item and item['video_versions']: 90 | videos = [] 91 | for video in item['video_versions']: 92 | videos.append(VideoVersions(video)) 93 | self.video_versions = videos 94 | 95 | if 'has_audio' in item and item['has_audio']: 96 | self.has_audio = item['has_audio'] 97 | 98 | if 'video_duration' in item and item['video_duration']: 99 | self.video_duration = item['video_duration'] 100 | self.user = User(item['user']) 101 | likers = [] 102 | if 'likers' in item and len(item['likers']): 103 | for liker in item['likers']: 104 | likers.append(User(liker)) 105 | self.likers = likers 106 | if 'like_count' in item and item['like_count']: 107 | self.like_count = item['like_count'] 108 | if 'preview' in item and item['preview']: 109 | self.preview = item['preview'] 110 | if 'has_liked' in item and item['has_liked']: 111 | self.has_liked = item['has_liked'] 112 | if 'explore_context' in item and item['explore_context']: 113 | self.explore_context = item['explore_context'] 114 | if 'explore_source_token' in item and item['explore_source_token']: 115 | self.explore_source_token = item['explore_source_token'] 116 | if 'explore' in item and item['explore']: 117 | self.explore = Explore(item['explore']) 118 | if 'impression_token' in item and item['impression_token']: 119 | self.impression_token = item['impression_token'] 120 | if 'usertags' in item and item['usertags']: 121 | self.usertags = Usertag(item['usertags']) 122 | 123 | def getTakenAt(self): 124 | return self.taken_at 125 | 126 | def getUsernameId(self): 127 | return self.user.getUsernameId() 128 | 129 | def getMediaId(self): 130 | return self.id 131 | 132 | def getDeviceTimestamp(self): 133 | return self.device_timestamp 134 | 135 | def isVideo(self): 136 | return self.media_type == self.VIDEO 137 | 138 | def isPhoto(self): 139 | return self.media_type == self.PHOTO 140 | 141 | def getCode(self): 142 | return self.code 143 | 144 | def getClientCacheKey(self): 145 | return self.client_cache_key 146 | 147 | def getFilterType(self): 148 | return self.filter_type 149 | 150 | def getImageVersions(self): 151 | return self.image_versions2 152 | 153 | def getOriginalWidth(self): 154 | return self.original_width 155 | 156 | def getOriginalHeight(self): 157 | return self.original_height 158 | 159 | def getViewCount(self): 160 | return self.view_count 161 | 162 | def getOrganicTrackingToken(self): 163 | return self.organic_tracking_token 164 | 165 | def hasMoreComments(self): 166 | return self.has_more_comments 167 | 168 | def getMaxNumVisiblePreviewComments(self): 169 | return self.max_num_visible_preview_comments 170 | 171 | def getComments(self): 172 | return self.comments 173 | 174 | def getCommentCount(self): 175 | return self.comment_count 176 | 177 | def getCaption(self): 178 | return self.caption 179 | 180 | def isCaptionEdited(self): 181 | return self.caption_is_edited 182 | 183 | def isPhotoOfYou(self): 184 | return self.photo_of_you 185 | 186 | def getVideoVersions(self): 187 | return self.video_versions 188 | 189 | def hasAudio(self): 190 | return self.has_audio 191 | 192 | def getVideoDuration(self): 193 | return self.video_duration 194 | 195 | def getUser(self): 196 | return self.user 197 | 198 | def getMediaLikers(self): 199 | return self.likers 200 | 201 | def getLikeCount(self): 202 | return self.like_count 203 | 204 | def getPreview(self): 205 | return self.preview 206 | 207 | def hasLiked(self): 208 | return self.has_liked 209 | 210 | def getExploreContext(self): 211 | return self.explore_context 212 | 213 | def getExploreSourceToken(self): 214 | return self.explore_source_token 215 | 216 | def getExplore(self): 217 | return self.explore 218 | 219 | def getImpressionToken(self): 220 | return self.impression_token 221 | 222 | def getUsertags(self): 223 | return self.usertags 224 | 225 | def getlikers(self): 226 | return self.likers 227 | 228 | def getPk(self): 229 | return self.pk 230 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/Location.py: -------------------------------------------------------------------------------- 1 | class Location(object): 2 | def __init__(self, location): 3 | self.name = None 4 | self.external_id_source = None 5 | self.address = None 6 | self.lat = None 7 | self.lng = None 8 | self.external_id = None 9 | 10 | self.name = location['name'] 11 | self.external_id_source = location['external_id_source'] 12 | if 'address' in location and location['address']: 13 | self.address = location['address'] 14 | self.lat = location['lat'] 15 | self.lng = location['lng'] 16 | self.external_id = location['external_id'] 17 | 18 | def getName(self): 19 | return self.name 20 | 21 | def getExternalIdSource(self): 22 | return self.external_id_source 23 | 24 | def getAddress(self): 25 | return self.address 26 | 27 | def getLatitude(self): 28 | return self.lat 29 | 30 | def getLongitude(self): 31 | return self.lng 32 | 33 | def getExternalId(self): 34 | return self.external_id 35 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/Param.py: -------------------------------------------------------------------------------- 1 | class Param(object): 2 | def __init__(self, data): 3 | self.name = None 4 | self.value = None 5 | 6 | self.name = data['name'] 7 | self.value = data['value'] 8 | 9 | def getName(self): 10 | return self.name 11 | 12 | def getValue(self): 13 | return self.value 14 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/Position.py: -------------------------------------------------------------------------------- 1 | class Position(object): 2 | def __init__(self, data): 3 | self.pos1 = None 4 | self.pos2 = None 5 | 6 | self.pos1 = data[0] 7 | self.pos2 = data[1] 8 | 9 | def getPos1(self): 10 | return self.pos1 11 | 12 | def getPos2(self): 13 | return self.pos2 14 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/Suggestion.py: -------------------------------------------------------------------------------- 1 | class Suggestion(object): 2 | def __init__(self, data): 3 | self.media_infos = None 4 | self.social_context = None 5 | self.algorithm = None 6 | self.thumbnail_urls = None 7 | self.value = None 8 | self.caption = None 9 | self.user = None 10 | self.large_urls = None 11 | self.media_ids = None 12 | self.icon = None 13 | 14 | self.media_infos = data['media_infos'] 15 | self.social_context = data['social_context'] 16 | self.algorithm = data['algorithm'] 17 | self.thumbnail_urls = data['thumbnail_urls'] 18 | self.value = data['value'] 19 | self.caption = data['caption'] 20 | self.user = User(data['user']) 21 | self.large_urls = data['large_urls'] 22 | self.media_ids = data['media_ids'] 23 | self.icon = data['icon'] 24 | 25 | def getMediaInfo(self): 26 | return self.media_infos 27 | 28 | def getSocialContext(self): 29 | return self.social_context 30 | 31 | def getalgorithm(self): 32 | return self.algorithm 33 | 34 | def getThumbnailUrls(self): 35 | return self.thumbnail_urls 36 | 37 | def getValue(self): 38 | return self.value 39 | 40 | def getCaption(self): 41 | return self.caption 42 | 43 | def getUser(self): 44 | return self.user 45 | 46 | def getLargeUrls(self): 47 | return self.large_urls 48 | 49 | def getMediaIds(self): 50 | return self.media_ids 51 | 52 | def getIcon(self): 53 | return self.icon 54 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/Tray.py: -------------------------------------------------------------------------------- 1 | class Tray(object): 2 | def __init__(self, items, user, can_reply, expiring_at): 3 | self.items = None 4 | self.user = None 5 | self.can_reply = None 6 | self.expiring_at = None 7 | 8 | self.items = items 9 | self.user = user 10 | self.can_reply = can_reply 11 | self.expiring_at = expiring_at 12 | 13 | def getItems(self): 14 | return self.items 15 | 16 | def getUsers(self): 17 | return self.users 18 | 19 | def canReply(self): 20 | return self.can_reply 21 | 22 | def getExpiringAt(self): 23 | return self.expiring_at 24 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/User.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.FriendshipStatus import FriendshipStatus 2 | 3 | 4 | class User(object): 5 | def __init__(self, userData): 6 | self.username = None 7 | self.has_anonymous_profile_picture = False 8 | self.is_favorite = False 9 | self.profile_pic_url = None 10 | self.full_name = None 11 | self.pk = None 12 | self.is_verified = False 13 | self.is_private = False 14 | self.coeff_weight = 0 15 | self.friendship_status = None 16 | 17 | self.username = userData['username'] 18 | self.profile_pic_url = userData['profile_pic_url'] 19 | self.full_name = userData['full_name'] 20 | self.pk = userData['pk'] 21 | if 'is_verified' in userData and userData['is_verified']: 22 | self.is_verified = userData['is_verified'] 23 | self.is_private = userData['is_private'] 24 | if 'has_anonymous_profile_picture' in userData and userData['has_anonymous_profile_picture']: 25 | self.has_anonymous_profile_picture = userData['has_anonymous_profile_picture'] 26 | if 'is_favorite' in userData and userData['is_favorite']: 27 | self.is_favorite = userData['is_favorite'] 28 | if 'coeff_weight' in userData and userData['coeff_weight']: 29 | self.coeff_weight = userData['coeff_weight'] 30 | if 'friendship_status' in userData and userData['friendship_status']: 31 | self.friendship_status = FriendshipStatus(userData['friendship_status']) 32 | 33 | def getUsername(self): 34 | return self.username 35 | 36 | def getProfilePicUrl(self): 37 | return self.profile_pic_url 38 | 39 | def getFullName(self): 40 | return self.full_name 41 | 42 | def getUsernameId(self): 43 | return self.pk 44 | 45 | def isVerified(self): 46 | return self.is_verified 47 | 48 | def isPrivate(self): 49 | return self.is_private 50 | 51 | def hasAnonymousProfilePicture(self): 52 | return self.has_anonymous_profile_picture 53 | 54 | def isFavorite(self): 55 | return self.is_favorite 56 | 57 | def getCoeffWeight(self): 58 | return self.coeff_weight 59 | 60 | def getFriendshipStatus(self): 61 | return self.friendship_status 62 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/Usertag.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.In import In 2 | 3 | 4 | class Usertag(object): 5 | def __init__(self, data): 6 | self._in = None 7 | self.photo_of_you = None 8 | 9 | ins = [] 10 | for _in in data['in']: 11 | ins.append(In(_in)) 12 | 13 | self._in = ins 14 | 15 | def getIn(self): 16 | return self._in 17 | 18 | def getPhotoOfYou(self): 19 | return self.photo_of_you 20 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/VideoVersions.py: -------------------------------------------------------------------------------- 1 | class VideoVersions(object): 2 | def __init__(self, response): 3 | self.url = None 4 | self.type = None 5 | self.width = None 6 | self.height = None 7 | 8 | self.url = response['url'] 9 | self.type = response['type'] 10 | self.width = response['width'] 11 | self.height = response['height'] 12 | 13 | def getUrl(self): 14 | return self.url 15 | 16 | def getType(self): 17 | return self.type 18 | 19 | def getWidth(self): 20 | return self.width 21 | 22 | def getHeight(self): 23 | return self.height 24 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/_Message.py: -------------------------------------------------------------------------------- 1 | class _Message(object): 2 | def __init__(self, data): 3 | self.key = None 4 | self.time = None 5 | 6 | self.key = data['key'] 7 | self.time = data['time'] 8 | 9 | def getKey(self): 10 | return self.key 11 | 12 | def getTime(self): 13 | return self.time 14 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Objects/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danleyb2/Instagram-API/3435dc6855e1cccf2c85a41839d15ca930563b21/InstagramAPI/src/http/Response/Objects/__init__.py -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/PendingInboxResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.Inbox import Inbox 2 | from .Response import Response 3 | 4 | 5 | class PendingInboxResponse(Response): 6 | def __init__(self, response): 7 | self.seq_id = None 8 | self.pending_requests_total = None 9 | self.inbox = None 10 | 11 | if self.STATUS_OK == response['status']: 12 | self.seq_id = response['seq_id'] 13 | self.pending_requests_total = response['pending_requests_total'] 14 | self.inbox = Inbox(response['inbox']) 15 | else: 16 | self.setMessage(response['message']) 17 | self.setStatus(response['status']) 18 | 19 | def getSeqId(self): 20 | return self.seq_id 21 | 22 | def getPendingRequestsTotal(self): 23 | return self.pending_requests_total 24 | 25 | def getInbox(self): 26 | return self.inbox 27 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/ProfileResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.HdProfilePicUrlInfo import HdProfilePicUrlInfo 2 | from .Response import Response 3 | 4 | 5 | class ProfileResponse(Response): 6 | def __init__(self, response): 7 | self.username = None 8 | self.phone_number = None 9 | self.has_anonymous_profile_picture = None 10 | self.hd_profile_pic_versions = None 11 | self.gender = None 12 | self.birthday = None 13 | self.needs_email_confirm = None 14 | self.national_number = None 15 | self.profile_pic_url = None 16 | self.profile_pic_id = None 17 | self.biography = None 18 | self.full_name = None 19 | self.pk = None 20 | self.country_code = None 21 | self.hd_profile_pic_url_info = None 22 | self.email = None 23 | self.is_private = None 24 | self.external_url = None 25 | 26 | if self.STATUS_OK == response['status']: 27 | for p, v in response['user'].iteritems(): 28 | setattr(self, p, v) 29 | 30 | self.hd_profile_pic_url_info = HdProfilePicUrlInfo(self.hd_profile_pic_url_info) 31 | if self.hd_profile_pic_versions: 32 | profile_pics_vers = [] 33 | for profile_pic in self.hd_profile_pic_versions: 34 | profile_pics_vers.append(HdProfilePicUrlInfo(profile_pic)) 35 | self.hd_profile_pic_versions = profile_pics_vers 36 | else: 37 | self.setMessage(response['message']) 38 | 39 | self.setStatus(response['status']) 40 | 41 | def getUsername(self): 42 | return self.username 43 | 44 | def getPhoneNumber(self): 45 | return self.phone_number 46 | 47 | def hasAnonymousProfilePicture(self): 48 | return self.has_anonymous_profile_picture 49 | 50 | def getHdProfilePicVersions(self): 51 | return self.hd_profile_pic_versions 52 | 53 | def getGender(self): 54 | return self.gender 55 | 56 | def getBirthday(self): 57 | return self.birthday 58 | 59 | def needsEmailConfirm(self): 60 | return self.needs_email_confirm 61 | 62 | def getNationalNumber(self): 63 | return self.national_number 64 | 65 | def getProfilePicUrl(self): 66 | return self.profile_pic_url 67 | 68 | def getProfilePicId(self): 69 | return self.profile_pic_id 70 | 71 | def getBiography(self): 72 | return self.biography 73 | 74 | def getFullName(self): 75 | return self.full_name 76 | 77 | def getUsernameId(self): 78 | return self.pk 79 | 80 | def getCountryCode(self): 81 | return self.country_code 82 | 83 | def getHdProfilePicUrlInfo(self): 84 | return self.hd_profile_pic_url_info 85 | 86 | def getEmail(self): 87 | return self.email 88 | 89 | def isPrivate(self): 90 | return self.is_private 91 | 92 | def getExternalUrl(self): 93 | return self.external_url 94 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/RankedRecipientsResponse.py: -------------------------------------------------------------------------------- 1 | from .Response import Response 2 | 3 | 4 | class RankedRecipientsResponse(Response): 5 | def __init__(self, response): 6 | self.expires = None 7 | self.ranked_recipients = None 8 | 9 | if self.STATUS_OK == response['status']: 10 | self.expires = response['expires'] 11 | self.ranked_recipients = response['ranked_recipients'] 12 | else: 13 | self.setMessage(response['message']) 14 | self.setStatus(response['status']) 15 | 16 | def getExpires(self): 17 | return self.expires 18 | 19 | def getRankedRecipients(self): 20 | return self.ranked_recipients 21 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/RecentRecipientsResponse.py: -------------------------------------------------------------------------------- 1 | from .Response import Response 2 | 3 | 4 | class RecentRecipientsResponse(Response): 5 | def __init__(self, response): 6 | self.expiration_interval = None 7 | self.recent_recipients = None 8 | 9 | if self.STATUS_OK == response['status']: 10 | self.expiration_interval = response['expiration_interval'] 11 | self.recent_recipients = response['recent_recipients'] 12 | else: 13 | self.setMessage(response['message']) 14 | self.setStatus(response['status']) 15 | 16 | def getExpirationInterval(self): 17 | return self.expiration_interval 18 | 19 | def getRecentRecipients(self): 20 | return self.recent_recipients 21 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/ReelsTrayFeedResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.Item import Item 2 | from InstagramAPI.src.http.Response.Objects.Tray import Tray 3 | from .Response import Response 4 | 5 | 6 | class ReelsTrayFeedResponse(Response): 7 | def __init__(self, response): 8 | 9 | self.trays = None 10 | 11 | if self.STATUS_OK == response['status']: 12 | trays = [] 13 | if 'tray' in response and isinstance(response['tray'], list): 14 | for tray in response['tray']: 15 | items = [] 16 | if 'items' in tray and isinstance(tray['items'], list): 17 | for item in tray['items']: 18 | items.append(Item(item)) 19 | 20 | trays.append(Tray(items, tray['user'], tray['can_reply'], tray['expiring_at'])) 21 | 22 | self.trays = trays 23 | else: 24 | self.setMessage(response['message']) 25 | self.setStatus(response['status']) 26 | 27 | def getTrays(self): 28 | return self.trays 29 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/Response.py: -------------------------------------------------------------------------------- 1 | class Response(object): 2 | STATUS_OK = "ok" 3 | STATUS_FAIL = "fail" 4 | 5 | status = None 6 | message = None 7 | fullResponse = None 8 | 9 | def setStatus(self, status): 10 | self.status = status 11 | 12 | def getStatus(self): 13 | return self.status 14 | 15 | def setMessage(self, message): 16 | self.message = message 17 | 18 | def getMessage(self): 19 | return self.message 20 | 21 | def setFullResponse(self, response): 22 | self.fullResponse = response 23 | 24 | def getFullResponse(self): 25 | return self.fullResponse 26 | 27 | def isOk(self): 28 | return self.getStatus() == Response.STATUS_OK 29 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/SyncResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response import Response 2 | from InstagramAPI.src.http.Response.Objects.Experiment import Experiment 3 | 4 | 5 | class SyncResponse(Response): 6 | def __init__(self, response): 7 | self.experiments = None 8 | 9 | if self.STATUS_OK == response['status']: 10 | experiments = [] 11 | for experiment in response['experiments']: 12 | experiments.append(Experiment(experiment)) 13 | self.experiments = experiments 14 | else: 15 | self.setMessage(response['message']) 16 | self.setStatus(response['status']) 17 | 18 | def getExperiments(self): 19 | return self.experiments 20 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/TagFeedResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.Item import Item 2 | from .Response import Response 3 | 4 | 5 | class TagFeedResponse(Response): 6 | def __init__(self, response): 7 | self.num_results = None 8 | self.ranked_items = None 9 | self.auto_load_more_enabled = None 10 | self.items = None 11 | self.more_available = None 12 | self.next_max_id = None 13 | 14 | if self.STATUS_OK == response['status']: 15 | self.num_results = response['num_results'] 16 | rankedItems = [] 17 | for rankItem in response['ranked_items']: 18 | rankedItems.append(Item(rankItem)) 19 | 20 | self.ranked_items = rankedItems 21 | self.auto_load_more_enabled = response['auto_load_more_enabled'] 22 | items = [] 23 | for item in response['items']: 24 | items.append(Item(item)) 25 | 26 | self.items = items 27 | self.more_available = response['more_available'] 28 | self.next_max_id = response['next_max_id'] 29 | else: 30 | self.setMessage(response['message']) 31 | 32 | self.setStatus(response['status']) 33 | 34 | def getNumResults(self): 35 | return self.num_results 36 | 37 | def getRankedItems(self): 38 | return self.ranked_items 39 | 40 | def getAutoLoadMoreEnabled(self): 41 | return self.auto_load_more_enabled 42 | 43 | def getItems(self): 44 | return self.items 45 | 46 | def moreAvailable(self): 47 | return self.more_available 48 | 49 | def getNextMaxId(self): 50 | return self.next_max_id 51 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/TimelineFeedResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.FeedAysf import FeedAysf 2 | from InstagramAPI.src.http.Response.Objects.Item import Item 3 | from InstagramAPI.src.http.Response.Objects._Message import _Message 4 | from .Response import Response 5 | 6 | 7 | class TimelineFeedResponse(Response): 8 | def __init__(self, response): 9 | 10 | self.num_results = None 11 | self.is_direct_v2_enabled = None 12 | self.auto_load_more_enabled = None 13 | self.more_available = None 14 | self.next_max_id = None 15 | self._messages = None 16 | self.feed_items = None 17 | self.megaphone = None 18 | 19 | if self.STATUS_OK == response['status']: 20 | self.num_results = response['num_results'] 21 | self.is_direct_v2_enabled = response['is_direct_v2_enabled'] 22 | self.auto_load_more_enabled = response['auto_load_more_enabled'] 23 | self.more_available = response['more_available'] 24 | self.next_max_id = response['next_max_id'] 25 | messages = [] 26 | if '_messages' in response and len(response['_messages']): 27 | for message in response['_messages']: 28 | messages.append(_Message(message)) 29 | 30 | self._messages = messages 31 | items = [] 32 | if 'feed_items' in response and len(response['feed_items']): 33 | for item in response['feed_items']: 34 | if 'media_or_ad' in item and item['media_or_ad']: 35 | items.append(Item(item['media_or_ad'])) 36 | 37 | self.feed_items = items 38 | self.megaphone = FeedAysf(response['megaphone']['feed_aysf']) if \ 39 | ('megaphone' in response and 'feed_aysf' in response['megaphone']) else None 40 | 41 | else: 42 | self.setMessage(response['message']) 43 | self.setStatus(response['status']) 44 | 45 | def getNumResults(self): 46 | return self.num_results 47 | 48 | def isDirectV2Enabled(self): 49 | return self.is_direct_v2_enabled 50 | 51 | def autoLoadMoreEnabled(self): 52 | return self.auto_load_more_enabled 53 | 54 | def moreAvailable(self): 55 | return self.more_available 56 | 57 | def getNextMaxId(self): 58 | return self.next_max_id 59 | 60 | def getExternalId(self): 61 | return self.external_id 62 | 63 | def getMessages(self): 64 | return self._messages 65 | 66 | def getFeedItems(self): 67 | return self.feed_items 68 | 69 | def getMegaphone(self): 70 | return self.megaphone 71 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/UploadJobVideoResponse.py: -------------------------------------------------------------------------------- 1 | from .Response import Response 2 | 3 | 4 | class UploadJobVideoResponse(Response): 5 | def __init__(self, response): 6 | self.upload_id = None 7 | self.video_upload_urls = None 8 | 9 | if self.STATUS_OK == response['status']: 10 | self.upload_id = response['upload_id'] 11 | self.video_upload_urls = response['video_upload_urls'] 12 | else: 13 | self.setMessage(response['message']) 14 | 15 | self.setStatus(response['status']) 16 | 17 | def getUploadId(self): 18 | return self.upload_id 19 | 20 | def getVideoUploadUrls(self): 21 | return self.video_upload_urls 22 | 23 | def getVideoUploadUrl(self): 24 | return self.getVideoUploadUrls()[3]['url'] 25 | 26 | def getVideoUploadJob(self): 27 | return self.getVideoUploadUrls()[3]['job'] 28 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/UploadPhotoResponse.py: -------------------------------------------------------------------------------- 1 | from .Response import Response 2 | 3 | 4 | class UploadPhotoResponse(Response): 5 | def __init__(self, response): 6 | 7 | self.upload_id = None 8 | if self.STATUS_OK == response['status']: 9 | self.upload_id = response['upload_id'] 10 | else: 11 | self.setMessage(response['message']) 12 | 13 | self.setStatus(response['status']) 14 | 15 | def getUploadId(self): 16 | return self.upload_id 17 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/UploadVideoResponse.py: -------------------------------------------------------------------------------- 1 | from .Response import Response 2 | 3 | 4 | class UploadVideoResponse(Response): 5 | def __init__(self, response): 6 | self.upload_id = None 7 | 8 | if self.STATUS_OK == response['status']: 9 | self.upload_id = response['upload_id'] 10 | else: 11 | self.setMessage(response['message']) 12 | 13 | self.setStatus(response['status']) 14 | 15 | def getUploadId(self): 16 | return self.upload_id 17 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/UserFeedResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.Item import Item 2 | from .Response import Response 3 | 4 | 5 | class UserFeedResponse(Response): 6 | def __init__(self, response): 7 | self.num_results = None 8 | self.auto_load_more_enabled = None 9 | self.items = None 10 | self.more_available = None 11 | self.next_max_id = null = None 12 | 13 | if self.STATUS_OK == response['status']: 14 | if 'next_max_id' in response: 15 | self.next_max_id = response['next_max_id'] 16 | 17 | self.num_results = response['num_results'] 18 | self.auto_load_more_enabled = response['auto_load_more_enabled'] 19 | items = [] 20 | for item in response['items']: 21 | items.append(Item(item)) 22 | self.items = items 23 | self.more_available = response['more_available'] 24 | else: 25 | self.setMessage(response['message']) 26 | self.setStatus(response['status']) 27 | 28 | def getNumResults(self): 29 | return self.num_results 30 | 31 | def getAutoLoadMoreEnabled(self): 32 | return self.auto_load_more_enabled 33 | 34 | def getItems(self): 35 | return self.items 36 | 37 | def moreAvailable(self): 38 | return self.more_available 39 | 40 | def getNextMaxId(self): 41 | return self.next_max_id 42 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/UsernameInfoResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.HdProfilePicUrlInfo import HdProfilePicUrlInfo 2 | from .Response import Response 3 | 4 | 5 | class UsernameInfoResponse(Response): 6 | def __init__(self, response): 7 | 8 | self.usertags_count = None 9 | self.has_anonymous_profile_picture = None 10 | self.full_name = None 11 | self.following_count = None 12 | self.auto_expand_chaining = None 13 | self.external_lynx_url = '' 14 | self.can_boost_post = False 15 | self.hd_profile_pic_versions = None 16 | self.biography = None 17 | self.has_chaining = None 18 | self.media_count = None 19 | self.follower_count = None 20 | self.pk = None 21 | self.username = None 22 | self.geo_media_count = None 23 | self.profile_pic_url = None 24 | self.can_see_organic_insights = False 25 | self.is_private = None 26 | self.can_convert_to_business = False 27 | self.is_business = None 28 | self.show_insights_terms = False 29 | self.hd_profile_pic_url_info = None 30 | self.usertag_review_enabled = False 31 | self.external_url = None 32 | self.is_favorite = None 33 | self.is_verified = None 34 | 35 | if self.STATUS_OK == response['status']: 36 | self.usertags_count = response['user']['usertags_count'] 37 | self.has_anonymous_profile_picture = response['user']['has_anonymous_profile_picture'] 38 | self.full_name = response['user']['full_name'] 39 | self.following_count = response['user']['following_count'] 40 | self.auto_expand_chaining = response['user']['auto_expand_chaining'] 41 | if 'external_lynx_url' in response['user']: 42 | self.external_lynx_url = response['user']['external_lynx_url'] 43 | 44 | if 'can_boost_post' in response['user']: 45 | self.can_boost_post = response['user']['can_boost_post'] 46 | 47 | if 'hd_profile_pic_versions' in response['user']: 48 | profile_pics_vers = [] 49 | for profile_pic in response['user']['hd_profile_pic_versions']: 50 | profile_pics_vers.append(HdProfilePicUrlInfo(profile_pic)) 51 | 52 | self.hd_profile_pic_versions = profile_pics_vers 53 | 54 | self.biography = response['user']['biography'] 55 | self.has_chaining = response['user']['has_chaining'] 56 | self.media_count = response['user']['media_count'] 57 | self.follower_count = response['user']['follower_count'] 58 | self.pk = response['user']['pk'] 59 | self.username = response['user']['username'] 60 | if 'geo_media_count' in response['user']: 61 | self.geo_media_count = response['user']['geo_media_count'] 62 | self.profile_pic_url = response['user']['profile_pic_url'] 63 | if 'can_see_organic_insights' in response['user']: 64 | self.can_see_organic_insights = response['user']['can_see_organic_insights'] 65 | 66 | self.is_private = response['user']['is_private'] 67 | if 'is_favorite' in response['user']: 68 | self.is_favorite = response['user']['is_favorite'] 69 | if 'is_verified' in response['user']: 70 | self.is_favorite = response['user']['is_verified'] # todo possible typo bug 71 | if 'can_convert_to_business' in response['user']: 72 | self.can_convert_to_business = response['user']['can_convert_to_business'] 73 | 74 | self.is_business = response['user']['is_business'] 75 | if 'show_insights_terms' in response['user']: 76 | self.show_insights_terms = response['user']['show_insights_terms'] 77 | 78 | self.hd_profile_pic_url_info = HdProfilePicUrlInfo(response['user']['hd_profile_pic_url_info']) 79 | if 'usertag_review_enabled' in response['user']: 80 | self.usertag_review_enabled = response['user']['usertag_review_enabled'] 81 | 82 | self.external_url = response['user']['external_url'] 83 | else: 84 | self.setMessage(response['message']) 85 | 86 | self.setStatus(response['status']) 87 | 88 | def getUsertagCount(self): 89 | return self.usertags_count 90 | 91 | def getHasAnonymousProfilePicture(self): 92 | return self.has_anonymous_profile_picture 93 | 94 | def getFullName(self): 95 | return self.full_name 96 | 97 | def getFollowingCount(self): 98 | return self.following_count 99 | 100 | def autoExpandChaining(self): 101 | return self.auto_expand_chaining 102 | 103 | def getExternalLynxUrl(self): 104 | return self.external_lynx_url 105 | 106 | def canBoostPost(self): 107 | return self.can_boost_post 108 | 109 | def getProfilePicVersions(self): 110 | return self.hd_profile_pic_versions 111 | 112 | def getBiography(self): 113 | return self.biography 114 | 115 | def hasChaining(self): 116 | return self.has_chaining 117 | 118 | def getMediaCount(self): 119 | return self.media_count 120 | 121 | def getFollowerCount(self): 122 | return self.follower_count 123 | 124 | def getUsernameId(self): 125 | return self.pk 126 | 127 | def getUsername(self): 128 | return self.username 129 | 130 | def getGeoMediaCount(self): 131 | return self.geo_media_count 132 | 133 | def getProfilePicUrl(self): 134 | return self.profile_pic_url 135 | 136 | def canSeeOrganicInsights(self): 137 | return self.can_see_organic_insights 138 | 139 | def isPrivate(self): 140 | return self.is_private 141 | 142 | def canConvertToBusiness(self): 143 | return self.can_convert_to_business 144 | 145 | def isFavorite(self): 146 | return self.is_favorite 147 | 148 | def isVerified(self): 149 | return self.is_verified 150 | 151 | def isBusiness(self): 152 | return self.is_business 153 | 154 | def showInsightsTerms(self): 155 | return self.show_insights_terms 156 | 157 | def getHdProfilePicUrlInfo(self): 158 | return self.hd_profile_pic_url_info 159 | 160 | def getUsertagReviewEnabled(self): 161 | return self.usertag_review_enabled 162 | 163 | def getExternalUrl(self): 164 | return self.external_url 165 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/UsernameSuggestionsResponse.py: -------------------------------------------------------------------------------- 1 | from .Response import Response 2 | 3 | 4 | class UsernameSuggestionsResponse(Response): 5 | def __init__(self, response): 6 | self.username_suggestions = None 7 | if self.STATUS_OK == response['status']: 8 | if 'username_suggestions' in response: 9 | self.username_suggestions = response['username_suggestions'] 10 | else: 11 | self.setMessage(response['message']) 12 | 13 | self.setStatus(response['status']) 14 | 15 | def getUsernameSuggestions(self): 16 | return self.username_suggestions 17 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/UsertagsResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.Item import Item 2 | from .Response import Response 3 | 4 | 5 | class UsertagsResponse(Response): 6 | def __init__(self, response): 7 | 8 | self.num_results = None 9 | self.auto_load_more_enabled = None 10 | self.items = None 11 | self.more_available = None 12 | self.next_max_id = None 13 | self.total_count = None 14 | self.requires_review = None 15 | self.new_photos = None 16 | 17 | if self.STATUS_OK == response['status']: 18 | self.num_results = response['num_results'] 19 | self.auto_load_more_enabled = response['auto_load_more_enabled'] 20 | items = [] 21 | for item in response['items']: 22 | items.append(Item(item)) 23 | 24 | self.items = items 25 | self.more_available = response['more_available'] 26 | self.next_max_id = response['next_max_id'] 27 | self.total_count = response['total_count'] 28 | self.requires_review = response['requires_review'] 29 | self.new_photos = response['new_photos'] 30 | else: 31 | self.setMessage(response['message']) 32 | 33 | self.setStatus(response['status']) 34 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/V2InboxResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.Inbox import Inbox 2 | from .Response import Response 3 | 4 | 5 | class V2InboxResponse(Response): 6 | def __init__(self, response): 7 | self.pending_requests_total = None 8 | self.seq_id = None 9 | self.pending_requests_users = None 10 | self.inbox = None 11 | self.subscription = None 12 | 13 | if self.STATUS_OK == response['status']: 14 | self.pending_requests_total = response['pending_requests_total'] 15 | self.seq_id = response['seq_id'] 16 | self.pending_requests_users = response['pending_requests_users'] 17 | self.inbox = Inbox(response['inbox']) 18 | self.subscription = response['subscription'] 19 | else: 20 | self.setMessage(response['message']) 21 | 22 | self.setStatus(response['status']) 23 | 24 | def getPendingRequestsTotal(self): 25 | return self.pending_requests_total 26 | 27 | def getSeqId(self): 28 | return self.seq_id 29 | 30 | def getPendingRequestsUsers(self): 31 | return self.pending_requests_users 32 | 33 | def getInbox(self): 34 | return self.inbox 35 | 36 | def getSubscription(self): 37 | return self.subscription 38 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/__init__.py: -------------------------------------------------------------------------------- 1 | from .AccountCreationResponse import AccountCreationResponse 2 | from .ChallengeResponse import ChallengeResponse 3 | from .CheckEmailResponse import CheckEmailResponse 4 | from .CheckUsernameResponse import CheckUsernameResponse 5 | from .CommentResponse import CommentResponse 6 | from .ConfigureResponse import ConfigureResponse 7 | from .ConfigureVideoResponse import ConfigureVideoResponse 8 | from .ExploreResponse import ExploreResponse 9 | from .ExposeResponse import ExposeResponse 10 | from .FollowerResponse import FollowerResponse 11 | from .FollowingResponse import FollowingResponse 12 | from .LocationResponse import LocationResponse 13 | from .LoginResponse import LoginResponse 14 | from .LogoutResponse import LogoutResponse 15 | from .MediaCommentsResponse import MediaCommentsResponse 16 | from .MediaInfoResponse import MediaInfoResponse 17 | from .MediaLikersResponse import MediaLikersResponse 18 | from .MegaphoneLogResponse import MegaphoneLogResponse 19 | from .PendingInboxResponse import PendingInboxResponse 20 | from .ProfileResponse import ProfileResponse 21 | from .RankedRecipientsResponse import RankedRecipientsResponse 22 | from .RecentRecipientsResponse import RecentRecipientsResponse 23 | from .ReelsTrayFeedResponse import ReelsTrayFeedResponse 24 | from .Response import Response 25 | from .SyncResponse import SyncResponse 26 | from .TagFeedResponse import TagFeedResponse 27 | from .TimelineFeedResponse import TimelineFeedResponse 28 | from .UploadJobVideoResponse import UploadJobVideoResponse 29 | from .UploadPhotoResponse import UploadPhotoResponse 30 | from .UploadVideoResponse import UploadVideoResponse 31 | from .UserFeedResponse import UserFeedResponse 32 | from .UsernameInfoResponse import UsernameInfoResponse 33 | from .UsernameSuggestionsResponse import UsernameSuggestionsResponse 34 | from .UsertagsResponse import UsertagsResponse 35 | from .V2InboxResponse import V2InboxResponse 36 | from .autoCompleteUserListResponse import autoCompleteUserListResponse 37 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/Response/autoCompleteUserListResponse.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src.http.Response.Objects.User import User 2 | from .Response import Response 3 | 4 | 5 | class autoCompleteUserListResponse(Response): 6 | 7 | def __init__(self, response): 8 | self.expires = None 9 | self.users = None 10 | 11 | if self.STATUS_OK == response['status']: 12 | self.expires = response['expires'] 13 | users = [] 14 | for user in response['users']: 15 | users.append(User(user)) 16 | self.users = users 17 | else: 18 | self.setMessage(response['message']) 19 | self.setStatus(response['status']) 20 | 21 | def getExpires(self): 22 | return self.expires 23 | 24 | def getUsers(self): 25 | return self.users 26 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/UserAgent.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI.src import Constants 2 | from InstagramAPI.src.Utils import * 3 | 4 | 5 | class UserAgent: 6 | def __init__(self, parent): 7 | self.parent = None 8 | 9 | self.parent = parent 10 | 11 | def getDeviceData(self): 12 | csvfile = os.path.join( 13 | os.path.join(os.path.dirname(os.path.realpath(__file__)), 'devices.csv') 14 | ) 15 | line_of_text = [] 16 | with open(csvfile, 'rb') as file_handle: 17 | for line in file_handle.readlines(): 18 | line_of_text.append(line.strip()) 19 | # todo doesn't look like original 20 | deviceData = (line_of_text[mt_rand(0, 11867)]).decode("utf-8").split(';') 21 | return deviceData 22 | 23 | def buildUserAgent(self): 24 | deviceData = self.getDeviceData() 25 | 26 | self.parent.settings.set('manufacturer', deviceData[0]) 27 | self.parent.settings.set('device', deviceData[1]) 28 | self.parent.settings.set('model', deviceData[2]) 29 | 30 | return 'Instagram %s Android (18/4.3; 320dpi; 720x1280; %s; %s; %s; qcom; en_US)' % ( 31 | Constants.VERSION, deviceData[0], deviceData[1], deviceData[2]) 32 | -------------------------------------------------------------------------------- /InstagramAPI/src/http/__init__.py: -------------------------------------------------------------------------------- 1 | from .HttpInterface import HttpInterface 2 | from .UserAgent import UserAgent 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 mgp25 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.md 3 | include InstagramAPI/src/http/devices.csv 4 | recursive-include docs * -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | *Please go through the [contribution guidelines](https://github.com/danleyb2/Instagram-API/blob/master/.github/CONTRIBUTING.md)*, 2 | *just a translated Python implementation of this PHP [repository](https://github.com/mgp25/Instagram-API)* 3 | 4 | # ![logo](/examples/assets/instagram.png) Instagram Python [![License](https://poser.pugx.org/mgp25/instagram-php/license)](https://packagist.org/packages/mgp25/instagram-php) 5 | 6 | PHP [![Latest Stable Version](https://poser.pugx.org/mgp25/instagram-php/v/stable)](https://packagist.org/packages/mgp25/instagram-php) [![Total Downloads](https://poser.pugx.org/mgp25/instagram-php/downloads)](https://packagist.org/packages/mgp25/instagram-php) 7 | 8 | PYTHON [![Latest Stable Version](http://img.shields.io/pypi/v/instagram-python.svg)](https://pypi.python.org/pypi/instagram-python) [![Total Downloads](http://img.shields.io/pypi/dm/instagram-python.svg)](https://pypi.python.org/pypi/instagram-python) 9 | 10 | 11 | 12 | This is Instagram's private API. It has all the features the Instagram app has, including media upload. 13 | 14 | **Read the [wiki](https://github.com/danleyb2/Instagram-API/wiki)** and previous issues before opening a new one! Maybe your issue is already answered. 15 | **Wiki for the PHP code should be 90% applicable too because the code is just translated, not transformed** 16 | 17 | **Frequently Asked Questions:** [F.A.Q.](https://github.com/danleyb2/Instagram-API/wiki/FAQ) 18 | 19 | **Do you like this project? Support it by donating** 20 | - To the [PHP](https://github.com/mgp25/Instagram-API) repo 21 | 22 | ---------- 23 | ## Installation 24 | 25 | ### PYPI 26 | 27 | ```sh 28 | pip install instagram-python 29 | ``` 30 | 31 | ```py 32 | from InstagramAPI import Instagram 33 | 34 | instagram = Instagram(); 35 | ``` 36 | 37 | If you want to test code that is in the master branch, which hasn't been pushed as a release, you can use Github. 38 | 39 | ```sh 40 | pip install https://github.com/danleyb2/Instagram-API/archive/master.zip 41 | ``` 42 | 43 | ## Examples 44 | 45 | All examples can be found [here](https://github.com/danleyb2/Instagram-API/tree/master/examples) 46 | 47 | ## Why did i do the API? 48 | For me, 49 | *i love writing code*, 50 | for him 51 | *After legal measures, Facebook, WhatsApp and Instagram blocked my accounts. In order to use Instagram 52 | on my phone i needed a new phone, as they banned my UDID, so that is basically why i made this API.* 53 | 54 | ### What is Instagram? 55 | According to [the company](https://instagram.com/about/faq/): 56 | 57 | > "Instagram is a fun and quirky way to share your life with friends through a series of pictures. Snap a photo with your mobile phone, then choose a filter to transform the image into a memory to keep around forever. We're building Instagram to allow you to experience moments in your friends' lives through pictures as they happen. We imagine a world more connected through photos." 58 | 59 | # License 60 | 61 | MIT 62 | 63 | # Terms and conditions 64 | 65 | - You will NOT use this API for marketing purposes (spam, massive sending...). 66 | - We do NOT give support to anyone that wants this API to send massive messages or similar. 67 | - We reserve the right to block any user of this repository that does not meet these conditions. 68 | 69 | ## Legal 70 | 71 | This code is in no way affiliated with, authorized, maintained, sponsored or endorsed by Instagram or any of its affiliates or subsidiaries. This is an independent and unofficial API. Use at your own risk. 72 | 73 | ### Contributing 74 | **If you have any suggestions,contributions or improvements, (unless it should only be applied on this side) please make them to the php [repo](https://github.com/mgp25/Instagram-API) if you can so i can replicate them to this side** 75 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | *Please go through the* 2 | `contribution guidelines `_. *This is 3 | just a translated Python implementation of this PHP* `repository `_. 4 | 5 | |logo| Instagram Python 6 | ####################### 7 | 8 | |license| 9 | 10 | `PHP `_ |latestphp| |downloadsphp| 11 | 12 | `PYTHON `_ |latestpy| |downloadspy| 13 | 14 | This is Instagram's private API. It has all the features the Instagram app has, including media upload. 15 | 16 | **Read the** `wiki `_ **and previous issues before opening a new one!** 17 | Maybe your issue is already answered. 18 | 19 | **Wiki for the PHP code should be 90% applicable too because the code is just translated, not transformed.** 20 | 21 | **Frequently Asked Questions:** `F.A.Q. `_ 22 | 23 | **Do you like this project? Support it by donating to the** `PHP `_ **repo.** 24 | 25 | Installation 26 | ************ 27 | 28 | PyPI 29 | ==== 30 | 31 | .. code-block:: bash 32 | 33 | pip install instagram-python 34 | 35 | 36 | .. code-block:: python 37 | 38 | from InstagramAPI import Instagram 39 | 40 | instagram = Instagram() 41 | 42 | If you want to test code that is in the master branch, which hasn't been pushed as a release, you can use Github. 43 | 44 | .. code-block:: bash 45 | 46 | pip install https://github.com/danleyb2/Instagram-API/archive/master.zip 47 | 48 | Examples 49 | ******** 50 | 51 | All examples can be found `here `_. 52 | 53 | Why did i do the API? 54 | ********************* 55 | 56 | For me: *I love writing code*. 57 | 58 | For him: 59 | 60 | After legal measures, Facebook, WhatsApp and Instagram blocked my accounts. In order to use Instagram 61 | on my phone i needed a new phone, as they banned my UDID, so that is basically why i made this API. 62 | 63 | What is Instagram? 64 | ****************** 65 | 66 | According to `the company `_: 67 | 68 | Instagram is a fun and quirky way to share your life with friends through a series of pictures. Snap a photo with 69 | your mobile phone, then choose a filter to transform the image into a memory to keep around forever. We're building 70 | Instagram to allow you to experience moments in your friends' lives through pictures as they happen. We imagine a 71 | world more connected through photos." 72 | 73 | License 74 | ******* 75 | 76 | MIT 77 | 78 | Terms and conditions 79 | ******************** 80 | 81 | - You will **NOT** use this API for marketing purposes (spam, massive sending...). 82 | - We do **NOT** give support to anyone that wants this API to send massive messages or similar. 83 | - We reserve the right to block any user of this repository that does not meet these conditions. 84 | 85 | Legal 86 | ***** 87 | 88 | This code is in no way affiliated with, authorized, maintained, sponsored or endorsed by Instagram or any of its 89 | affiliates or subsidiaries. This is an independent and unofficial API. Use at your own risk. 90 | 91 | Contributing 92 | ************ 93 | 94 | If you have any suggestions,contributions or improvements, (unless it should only be applied on this side) please 95 | make them to the php `repo `_ if you can so i can replicate them to this 96 | side. 97 | 98 | 99 | .. |latestpy| image:: http://img.shields.io/pypi/v/instagram-python.svg 100 | .. _latestpy: https://pypi.python.org/pypi/instagram-python 101 | 102 | .. |latestphp| image:: https://poser.pugx.org/mgp25/instagram-php/v/stable 103 | .. _latestphp: https://packagist.org/packages/mgp25/instagram-php 104 | 105 | .. |downloadspy| image:: http://img.shields.io/pypi/dm/instagram-python.svg 106 | .. _downloadspy: https://pypi.python.org/pypi/instagram-python 107 | 108 | .. |downloadsphp| image:: https://poser.pugx.org/mgp25/instagram-php/downloads 109 | .. _downloadsphp: https://packagist.org/packages/mgp25/instagram-php 110 | 111 | .. |license| image:: https://poser.pugx.org/mgp25/instagram-php/license 112 | .. _license: https://packagist.org/packages/mgp25/instagram-php 113 | 114 | .. |logo| image:: /examples/assets/instagram.png 115 | -------------------------------------------------------------------------------- /examples/assets/instagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danleyb2/Instagram-API/3435dc6855e1cccf2c85a41839d15ca930563b21/examples/assets/instagram.png -------------------------------------------------------------------------------- /examples/checkpoint.py: -------------------------------------------------------------------------------- 1 | from InstagramAPI import Checkpoint 2 | 3 | debug = True 4 | 5 | print("####################") 6 | print("# #") 7 | print("# CHECKPOINT #") 8 | print("# #") 9 | print("####################") 10 | 11 | username = raw_input("\n\nYour username: ").strip() 12 | 13 | if username == '': 14 | print("\n\nYou have to set your username\n") 15 | exit() 16 | 17 | settingsPath = raw_input("\n\nYour settings path folder ([ENTER] if dedault): ").strip() 18 | print settingsPath 19 | if settingsPath == '': 20 | settingsPath = None 21 | 22 | c = Checkpoint(username, settingsPath, debug) 23 | 24 | token = c.doCheckpoint() 25 | 26 | code = raw_input("\n\nCode you have received via mail: ").strip() 27 | 28 | c.checkpointThird(code, token) 29 | 30 | print("\n\nDone") 31 | -------------------------------------------------------------------------------- /examples/registrationTool.py: -------------------------------------------------------------------------------- 1 | import InstagramAPI 2 | 3 | # // NOTE: THIS IS A CLI TOOL 4 | # /// DEBUG MODE /// 5 | debug = False 6 | 7 | r = InstagramAPI.InstagramRegistration(debug) 8 | 9 | print "###########################" 10 | print "# #" 11 | print "# Instagram Register Tool #" 12 | print "# #" 13 | print "###########################" 14 | 15 | 16 | def do_get_username(): 17 | new_username = raw_input("\n\nUsername: ").strip() 18 | check = r.checkUsername(new_username) 19 | return new_username, check.isAvailable() 20 | 21 | 22 | username, is_available = do_get_username() 23 | while not is_available: 24 | print "Username " + username + " not available, try with another one\n" 25 | username, is_available = do_get_username() 26 | 27 | print "Username " + username + " is available\n\n" 28 | 29 | password = raw_input("\nPassword: ").strip() 30 | 31 | 32 | def do_get_email(): 33 | new_email = raw_input("\n\nEmail: ").strip() 34 | check = r.checkEmail(new_email) 35 | return new_email, check.isAvailable() 36 | 37 | 38 | email, is_available = do_get_email() 39 | while not is_available: 40 | print "Email is not available, try with another one\n" 41 | email, is_available = do_get_email() 42 | 43 | name = raw_input("\nName (Optional): ").strip() 44 | 45 | result = r.createAccount(username, password, email) 46 | 47 | if result.isAccountCreated(): 48 | print 'Your account was successfully created! :)' 49 | else: 50 | print "Error during registration." 51 | -------------------------------------------------------------------------------- /examples/uploadPhoto.py: -------------------------------------------------------------------------------- 1 | import InstagramAPI 2 | 3 | # /////// CONFIG /////// 4 | username = '' 5 | password = '' 6 | debug = False 7 | 8 | photo = '' # path to the photo 9 | caption = '' # caption 10 | # ////////////////////// 11 | 12 | i = InstagramAPI.Instagram(username, password, debug) 13 | 14 | try: 15 | i.login() 16 | except Exception as e: 17 | e.message 18 | exit() 19 | 20 | try: 21 | i.uploadPhoto(photo, caption) 22 | except Exception as e: 23 | print e.message 24 | -------------------------------------------------------------------------------- /examples/uploadVideo.py: -------------------------------------------------------------------------------- 1 | import InstagramAPI 2 | 3 | # /////// CONFIG /////// 4 | username = '' 5 | password = '' 6 | debug = False 7 | 8 | video = '' # path to the video 9 | caption = '' # caption 10 | # ////////////////////// 11 | 12 | i = InstagramAPI.Instagram(username, password, debug) 13 | 14 | try: 15 | i.login() 16 | except Exception as e: 17 | e.message 18 | exit() 19 | 20 | try: 21 | i.uploadVideo(video, caption) 22 | except Exception as e: 23 | print e.message 24 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pycurl==7.43.0 2 | Pillow==3.4.2 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import setuptools 3 | 4 | __version__ = "1.4" 5 | __author__ = "Nyaundi Brian" 6 | 7 | with open(os.path.join(os.path.dirname(__file__), 'README.md')) as readme: 8 | README = readme.read() 9 | 10 | os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) 11 | 12 | setuptools.setup( 13 | name='instagram-api', 14 | version=__version__, 15 | packages=setuptools.find_packages(), 16 | include_package_data=True, 17 | zip_safe=False, 18 | license='MIT', 19 | description='Instagram private API PHP', 20 | long_description=README, 21 | keywords="Instagram Private API Python", 22 | platforms='any', 23 | url='https://github.com/danleyb2/Instagram-API', 24 | author=__author__, 25 | author_email='ndieksman@gmail.com', 26 | install_requires=[ 27 | 'pycurl==7.43.0', 28 | 'Pillow==3.4.2', 29 | ], 30 | classifiers=[ 31 | # 'Development Status :: 1 - Alpha', 32 | 'Environment :: Console', 33 | 'Intended Audience :: Developers', 34 | 'License :: OSI Approved :: MIT License', 35 | 'Operating System :: OS Independent', 36 | 'Programming Language :: Python', 37 | 'Programming Language :: Python :: 2.7', 38 | ], 39 | ) 40 | --------------------------------------------------------------------------------