def login(self,force = False):

        if not self.isLoggedIn or force:
            fetch = self.http.request('si/fetch_headers/?challenge_type=signup&guid='+SignatureUtils.generateUUID(False), None, True)#

            if  not fetch[0] or fetch[1]['status'] == 'fail':
                Exception("Couldn't get challenge, check your connection")#

                return

            import re
            token = re.search('#Set-Cookie: csrftoken=({^#]+)#', fetch[0],re.IGNORECASE)#
            if not token:
                print 'no token'
            data = {
                'phone_id': SignatureUtils.generateUUID(True),
                '_csrftoken': token.group(0),
                'username': self.username,
                'guid': self.uuid,
                'device_id': self.device_id,
                'password': self.password,
                'login_attempt_count': '0',
            }

            login = self.http.request('accounts/login/', SignatureUtils.generateSignature(json.dumps(data)), True)#
            response = LoginResponse(login[1])#

            if not response.isOk() :
                Exception(response.getMessage())#

                return response#


            self.isLoggedIn = True#
            self.username_id = response.getUsernameId()#
            self.settings.set('username_id', self.username_id)#
            self.rank_token = self.username_id+'_'+self.uuid#
            match = re.search('#Set-Cookie: csrftoken=({^#]+)#', login[0], re.IGNORECASE)#
            self.token = match.group(0)#
            self.settings.set('token', self.token)#

            self.syncFeatures()#
            self.autoCompleteUserList()#
            self.timelineFeed()#
            self.getv2Inbox()#
            self.getRecentActivity()#

            return response#


        check = self.timelineFeed()#
        if check['message'] and check['message'] == 'login_required':
            self.login(True)#

        self.getv2Inbox()#
        self.getRecentActivity()#
    def setUser(self, username, password):
        """
         Set the user. Manage multiple accounts.

        :type username: str
        :param username: Your Instagram username.
        :type password: str
        :param password: Your Instagram password.
        :
        """
        self.username = username
        self.password = password

        self.checkSettings(username)

        self.uuid = SignatureUtils.generateUUID(True)

        if os.path.isfile(self.IGDataPath + self.username + '-cookies.dat') and \
                (self.settings.get('username_id') != None) and \
                (self.settings.get('token') != None):
            self.isLoggedIn = True
            self.username_id = self.settings.get('username_id')
            self.rank_token = self.username_id + '_' + self.uuid
            self.token = self.settings.get('token')
        else:
            self.isLoggedIn = False
    def deleteCommentsBulk(self, mediaId, commentIds):
        """
        Delete Comment Bulk.

        :type mediaId: str
        :param mediaId: Media ID
        :type commentIds: list
        :param commentIds: List of comments to delete
        :rtype: object
        :return: Delete Comment Bulk Data
        """
        if not isinstance(commentIds, list):
            commentIds = [commentIds]

        string = []
        for commentId in commentIds:
            string.append(str(commentId))

        comment_ids_to_delete = ','.join(string)

        data = json.dumps(
            OrderedDict([
                ('_uuid', self.uuid),
                ('_uid', self.username_id),
                ('_csrftoken', self.token),
                ('comment_ids_to_delete', comment_ids_to_delete)
            ])
        )
        return self.http.request("media/" + mediaId + "/comment/bulk_delete/",
                                 SignatureUtils.generateSignature(data))[1]
    def configure(self,upload_id, photo, caption = ''):

        size = getimagesize(photo)[0]#

        post = json.dumps({
            'upload_id': upload_id,
            'camera_model': self.settings.get('model').replace(' ', '', ),
            'source_type': 3,
            'date_time_original': datetime.date('Y:m:d H:i:s'),
            'camera_make': self.settings.get('manufacturer'),
            'edits': {
                'crop_original_size': [size, size],
                                    'crop_zoom': 1.3333334,
                                        'crop_center': [0.0, -0.0],
                    },
            'extra': {
            'source_width': size,
                            'source_height': size,
                        },
                'device': {
                            'manufacturer': self.settings.get('manufacturer'),
                            'model': self.settings.get('model'),
                            'android_version': Constants.ANDROID_VERSION,
                            'android_release': Constants.ANDROID_RELEASE,
                        },
                '_csrftoken': self.token,
                '_uuid': self.uuid,
                '_uid': self.username_id,
                'caption': caption,
                })  #

        post = post.replace('"crop_center":[0,0]', '"crop_center":[0.0,-0.0]')  #

        return ConfigureResponse(self.http.request('media/configure/', SignatureUtils.generateSignature(post))[1])#
    def editProfile(self, url, phone, first_name, biography, email, gender):
        """
        Edit profile.
        :type url: str
        :param url: Url - website. "" for nothing
        :type phone: str
        :param phone: Phone number. "" for nothing
        :type first_name: str
        :param first_name: Name. "" for nothing
        :type email: str
        :param email: Email. Required.
        :type gender: int
        :param gender: Gender. male = 1 , female = 0
        :rtype: object
        :return: edit profile data
        """
        data = json.dumps(
            OrderedDict([
                ('_uuid', self.uuid),
                ('_uid', self.username_id),
                ('_csrftoken', self.token),
                ('external_url', url),
                ('phone_number', phone),
                ('username', self.username),
                ('first_name', first_name),
                ('biography', biography),
                ('email', email),
                ('gender', gender)
            ])
        )

        return self.http.request('accounts/edit_profile/', SignatureUtils.generateSignature(data))[1]
    def removeSelftag(self,mediaId):
        data = json.dumps({
            '_uuid': self.uuid,
            '_uid': self.username_id,
            '_csrftoken': self.token,
        })  #

        return self.http.request("usertags/"+mediaId+"/remove/", SignatureUtils.generateSignature(data))[1]#
 def deleteMedia(self,mediaId):
     data = json.dumps({
         '_uuid': self.uuid,
         '_uid': self.username_id,
         '_csrftoken': self.token,
         'media_id': mediaId,
     })  #
     return self.http.request("media/"+mediaId+"/delete/", SignatureUtils.generateSignature(data))[1]#
 def comment(self,mediaId, commentText):
     data = json.dumps({
         '_uuid': self.uuid,
         '_uid': self.username_id,
         '_csrftoken': self.token,
         'comment_text': commentText,
     })  #
     return self.http.request("media/"+mediaId+"/comment/", SignatureUtils.generateSignature(data))[1]#
    def editMedia(self,mediaId, captionText = ''):
        data = json.dumps({
            '_uuid': self.uuid,
            '_uid': self.username_id,
            '_csrftoken': self.token,
            'caption_text': captionText,
        })

        return self.http.request("media/"+mediaId+"/edit_media/", SignatureUtils.generateSignature(data))[1]#
    def getProfileData(self):

        data = json.dumps({
            '_uuid': self.uuid,
            '_uid': self.username_id,
            '_csrftoken': self.token,
        })  #

        return self.http.request('accounts/current_user/?edit=true', SignatureUtils.generateSignature(data))[1]#
    def setAccount(self):

        data = json.dumps({
            '_uuid': self.uuid,
            '_uid': self.username_id,
            '_csrftoken': self.token,
        })  #

        return self.http.request('accounts/set_/', SignatureUtils.generateSignature(data))[1]#
    def deleteComment(self,mediaId, captionText, commentId):
        data = json.dumps({
            '_uuid': self.uuid,
            '_uid': self.username_id,
            '_csrftoken': self.token,
            'caption_text': captionText,
        })  #

        return self.http.request("media/"+mediaId+"/comment/"+commentId+"/delete/", SignatureUtils.generateSignature(data))[1]#
    def removeProfilePicture(self):

        data = json.dumps({
            '_uuid': self.uuid,
            '_uid': self.username_id,
            '_csrftoken': self.token,
        })  #

        return self.http.request('accounts/remove_profile_picture/', SignatureUtils.generateSignature(data))[1]#
    def expose(self):
        data = json.dumps({
            '_uuid': self.uuid,
            '_uid': self.username_id,
            'id': self.username_id,
            '_csrftoken': self.token,
            'experiment': 'ig_android_profile_contextual_feed',
        })  #

        return self.http.request('qe/expose/', SignatureUtils.generateSignature(data))[1]  #
    def userFriendship(self,userId):

        data = json.dumps({
            '_uuid'      : self.uuid,
            '_uid'       : self.username_id,
            'user_id'    : userId,
            '_csrftoken' : self.token,
        })#

        return self.http.request("friendships/show/"+userId+"/", SignatureUtils.generateSignature(data))[1]#
    def setNameAndPhone(self,name = '', phone = ''):

        data = json.dumps({
            '_uuid'         : self.uuid,
            '_uid'          : self.username_id,
            'first_name'    : name,
            'phone_number'  : phone,
            '_csrftoken'    : self.token})

        return self.http.request('accounts/set_phone_and_name/', SignatureUtils.generateSignature(data))[1]#
    def mediaInfo(self,mediaId):

        data = json.dumps({
            '_uuid': self.uuid,
            '_uid': self.username_id,
            '_csrftoken': self.token,
            'media_id': mediaId,
        })  #

        return  MediaInfoResponse(self.http.request("media/"+mediaId+"/info/", SignatureUtils.generateSignature(data))[1])#
 def removeProfilePicture(self):
     """
     Remove profile picture.
     :rtype: object
     :return: status request data
     """
     data = json.dumps(
         OrderedDict([('_uuid', self.uuid), ('_uid', self.username_id), ('_csrftoken', self.token)])
     )
     return self.http.request('accounts/remove_profile_picture/', SignatureUtils.generateSignature(data))[1]
    def syncFeatures(self):

        data = json.dumps({
            '_uuid': self.uuid,
            '_uid': self.username_id,
            'id': self.username_id,
            '_csrftoken': self.token,
            'experiments': Constants.EXPERIMENTS,
        })  #

        return self.http.request('qe/sync/', SignatureUtils.generateSignature(data))[1]#
 def expose(self):
     data = json.dumps(
         OrderedDict([
             ('_uuid', self.uuid),
             ('_uid', self.username_id),
             ('id', self.username_id),
             ('_csrftoken', self.token),
             ('experiment', 'ig_android_profile_contextual_feed')
         ])
     )
     return self.http.request('qe/expose/', SignatureUtils.generateSignature(data))[1]
 def syncFeatures(self):
     data = json.dumps(
         OrderedDict([
             ('_uuid', self.uuid),
             ('_uid', self.username_id),
             ('id', self.username_id),
             ('_csrftoken', self.token),
             ('experiments', Constants.EXPERIMENTS)
         ])
     )
     return self.http.request('qe/sync/', SignatureUtils.generateSignature(data))[1]
    def changePassword(self,oldPassword, newPassword):

        data = json.dumps({
            '_uuid': self.uuid,
            '_uid': self.username_id,
            '_csrftoken': self.token,
            'old_password': oldPassword,
            'new_password1': newPassword,
            'new_password2': newPassword,
        })  #

        return self.http.request('accounts/change_password/', SignatureUtils.generateSignature(data))[1]#
 def setPublicAccount(self):
     """
     Sets account to public.
     :rtype: object
     :return: status request data
     """
     data = json.dumps(
         OrderedDict([
             ('_uuid', self.uuid),
             ('_uid', self.username_id),
             ('_csrftoken', self.token)
         ])
     )
     return self.http.request('accounts/set_public/', SignatureUtils.generateSignature(data))[1]
 def getProfileData(self):
     """
     Get personal profile data.
     :rtype: object
     :return:
     """
     data = json.dumps(
         OrderedDict([
             ('_uuid', self.uuid),
             ('_uid', self.username_id),
             ('_csrftoken', self.token)
         ])
     )
     return self.http.request('accounts/current_user/?edit=true', SignatureUtils.generateSignature(data))[1]
    def __init__(self, username, password, debug=False, IGDataPath=None):

        """
        Default class constructor.
        :type username: str
        :param username: Your Instagram username.
        :type password: str
        :param password: Your Instagram password.
        :param debug: Debug on or off, False by default.
        :param IGDataPath: Default folder to store data, you can change it.
        """
        self.username = None  # // Instagram username
        self.password = None  # // Instagram password
        self.debug = None  # // Debug

        self.uuid = None  # // UUID
        self.device_id = None  # // Device ID
        self.username_id = None  # // Username ID
        self.token = None  # // _csrftoken
        self.isLoggedIn = False  # // Session status
        self.rank_token = None  # // Rank token
        self.IGDataPath = None  # // Data storage path
        self.customPath = False
        self.http = None
        self.settings = None
        self.proxy = None  # Full Proxy
        self.proxyHost = None  # Proxy Host and Port
        self.proxyAuth = None  # Proxy User and Pass

        self.debug = debug
        self.device_id = SignatureUtils.generateDeviceId(hashlib.md5(username + password))

        if IGDataPath is not None:
            self.IGDataPath = IGDataPath
            self.customPath = True
        else:
            self.IGDataPath = os.path.join(
                os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data'),
                username,
                ''
            )
            if not os.path.isdir(self.IGDataPath):
                os.mkdir(self.IGDataPath, 0777)

        self.checkSettings(username)

        self.http = HttpInterface(self)

        self.setUser(username, password)
    def editProfile(self,url, phone, first_name, biography, email, gender):

        data = json.dumps({
            '_uuid': self.uuid,
            '_uid': self.username_id,
            '_csrftoken': self.token,
            'external_url': url,
            'phone_number': phone,
            'username': self.username,
            'full_name': first_name,
            'biography': biography,
            'email': email,
            'gender': gender,
        })  #

        return self.http.request('accounts/edit_profile/', SignatureUtils.generateSignature(data))[1]#
 def removeSelftag(self, mediaId):
     """
     Remove yourself from a tagged media.
     :type mediaId: str
     :param mediaId: Media id
     :rtype: object
     :return: edit media data
     """
     data = json.dumps(
         OrderedDict([
             ('_uuid', self.uuid),
             ('_uid', self.username_id),
             ('_csrftoken', self.token)
         ])
     )
     return self.http.request("usertags/" + mediaId + "/remove/", SignatureUtils.generateSignature(data))[1]
    def setUser(self,username, password):

        self.username = username#
        self.password = password#

        self.checkSettings(username)#

        self.uuid = SignatureUtils.generateUUID(True)#

        if ((os.path.exists(self.IGDataPath+self.username+"-cookies.dat")) and (self.settings.get('username_id') != None)
        and (self.settings.get('token') != None)):
            self.isLoggedIn = True#
            self.username_id = self.settings.get('username_id')#
            self.rank_token = self.username_id+'_'+self.uuid#
            self.token = self.settings.get('token')#
        else :
            self.isLoggedIn = False#
 def deleteMedia(self, mediaId):
     """
     Delete photo or video.
     :type mediaId: str
     :param mediaId: Media id
     :rtype: object
     :return: delete request data
     """
     data = json.dumps(
         OrderedDict([
             ('_uuid', self.uuid),
             ('_uid', self.username_id),
             ('_csrftoken', self.token),
             ('media_id', mediaId)
         ])
     )
     return self.http.request("media/" + mediaId + "/delete/", SignatureUtils.generateSignature(data))[1]
 def mediaInfo(self, mediaId):
     """
     Media info
     :type mediaId: str
     :param mediaId: Media id
     :rtype: object
     :return: delete request data
     """
     data = json.dumps(
         OrderedDict([
             ('_uuid', self.uuid),
             ('_uid', self.username_id),
             ('_csrftoken', self.token),
             ('media_id', mediaId)
         ])
     )
     return MediaInfoResponse(
         self.http.request("media/" + mediaId + "/info/", SignatureUtils.generateSignature(data))[1])