GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 63e8f6...199bb8 )
by Nyaundi
01:03
created

Instagram   F

Complexity

Total Complexity 148

Size/Duplication

Total Lines 1388
Duplicated Lines 2.67 %

Importance

Changes 27
Bugs 3 Features 2
Metric Value
c 27
b 3
f 2
dl 37
loc 1388
rs 0.6314
wmc 148

81 Methods

Rating   Name   Duplication   Size   Complexity  
B setUser() 0 26 4
B checkSettings() 0 22 6
A syncFeatures() 0 11 1
A timelineFeed() 0 2 1
A megaphoneLog() 0 2 1
A getPendingInbox() 0 14 2
A autoCompleteUserList() 0 2 1
F setProxy() 36 37 11
A __init__() 0 49 3
D login() 0 65 9
A expose() 0 11 1
A explore() 0 14 2
A logout() 0 13 2
A uploadPhoto() 0 12 1
A changePassword() 0 23 1
A getReelsTrayFeed() 0 7 2
A getDirectShare() 0 8 1
B configure() 0 37 1
A direct_message() 0 12 1
A searchUsers() 0 16 2
A changeProfilePicture() 0 7 1
B deleteCommentsBulk() 0 30 3
A getSelfUserFeed() 0 7 1
A getUserTags() 0 14 2
A like() 0 18 1
A getUsernameId() 0 2 1
A getv2Inbox() 0 12 2
A fbUserSearch() 0 17 2
A uploadPhotoReel() 0 3 1
A deleteMedia() 0 17 1
A removeProfilePicture() 0 10 1
A searchUsername() 0 16 2
A comment() 0 19 1
A searchFBLocation() 0 17 2
A syncFromAdressBook() 0 12 1
A getFollowingRecentActivity() 0 12 2
A uploadVideo() 0 12 1
A getSelfUsernameInfo() 0 7 1
A unlike() 0 18 1
A removeSelftag() 0 16 1
A directThread() 0 16 2
B editProfile() 0 32 1
B configureToReel() 0 34 1
A getUserFollowings() 0 12 1
B configureVideo() 0 43 1
A setPublicAccount() 0 14 1
A getUserFollowers() 0 12 1
A getSelfUsersFollowing() 0 8 1
A getSelfGeoMedia() 0 7 1
A setPrivateAccount() 0 15 1
A getLocationFeed() 0 20 3
A getPopularFeed() 0 13 2
A getSelfUserFollowers() 0 8 1
A getTimeline() 0 15 3
A mediaInfo() 0 18 1
A directThreadAction() 0 20 1
B getUserFeed() 0 23 4
A getSelfUserTags() 0 7 1
A getHashtagFeed() 0 18 3
A searchLocation() 0 9 2
A direct_share() 0 2 1
A editMedia() 0 19 1
A getProfileData() 0 15 1
A getGeoMedia() 0 14 2
A deleteComment() 0 20 1
A getRecentActivity() 0 12 2
A searchTags() 0 14 2
A tagFeed() 0 15 2
A setNameAndPhone() 0 21 1
A getMediaComments() 0 9 1
A getUsernameInfo() 0 8 1
A getMediaLikers() 0 14 2
A verifyPeer() 0 2 1
A verifyHost() 0 2 1
A follow() 0 21 1
A unfollow() 0 19 1
A getLikedMedia() 0 9 2
A block() 0 20 1
F backup() 0 37 9
A userFriendship() 0 20 1
A unblock() 0 20 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Instagram often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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):
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
41
        self.uuid = None  # // UUID
42
        self.device_id = None  # // Device ID
43
        self.username_id = None  # // Username ID
44
        self.token = None  # // _csrftoken
45
        self.isLoggedIn = False  # // Session status
46
        self.rank_token = None  # // Rank token
47
        self.IGDataPath = None  # // Data storage path
48
        self.customPath = False
49
        self.http = None
50
        self.settings = None
51
        self.proxy = None  # Full Proxy
52
        self.proxyHost = None  # Proxy Host and Port
53
        self.proxyAuth = None  # Proxy User and Pass
54
55
        self.debug = debug
56
        self.device_id = SignatureUtils.generateDeviceId(hashlib.md5(username + password))
57
58
        if IGDataPath is not None:
59
            self.IGDataPath = IGDataPath
60
            self.customPath = True
61
        else:
62
            self.IGDataPath = os.path.join(
63
                os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data'),
64
                username,
65
                ''
66
            )
67
            if not os.path.isdir(self.IGDataPath):
68
                os.mkdir(self.IGDataPath, 0777)
69
70
        self.checkSettings(username)
71
72
        self.http = HttpInterface(self)
73
74
        self.setUser(username, password)
75
76
    def setUser(self, username, password):
77
        """
78
         Set the user. Manage multiple accounts.
79
80
        :type username: str
81
        :param username: Your Instagram username.
82
        :type password: str
83
        :param password: Your Instagram password.
84
        :
85
        """
86
        self.username = username
87
        self.password = password
88
89
        self.checkSettings(username)
90
91
        self.uuid = SignatureUtils.generateUUID(True)
92
93
        if os.path.isfile(self.IGDataPath + self.username + '-cookies.dat') and \
94
                (self.settings.get('username_id') != None) and \
95
                (self.settings.get('token') != None):
96
            self.isLoggedIn = True
97
            self.username_id = self.settings.get('username_id')
98
            self.rank_token = self.username_id + '_' + self.uuid
99
            self.token = self.settings.get('token')
100
        else:
101
            self.isLoggedIn = False
102
103
    def checkSettings(self, username):
104
        if self.customPath:
105
            self.IGDataPath = os.path.join(
106
                os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data'),
107
                username,
108
                ''
109
            )
110
111
        if not os.path.isdir(self.IGDataPath): os.mkdir(self.IGDataPath, 0777)
112
113
        self.settings = Settings(
114
            os.path.join(self.IGDataPath, 'settings-' + username + '.dat')
115
        )
116
        if self.settings.get('version') is None:
117
            self.settings.set('version', Constants.VERSION)
118
119
        if (self.settings.get('user_agent') is None) or (
120
                    LooseVersion(self.settings.get('version')) < LooseVersion(Constants.VERSION)):
121
            userAgent = UserAgent(self)
122
            ua = userAgent.buildUserAgent()
123
            self.settings.set('version', Constants.VERSION)
124
            self.settings.set('user_agent', ua)
125
126
    def setProxy(self, proxy, port=None, username=None, password=None):
127 View Code Duplication
        """
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
128
        Set the proxy.
129
130
        :type proxy: str
131
        :param proxy: Full proxy string. Ex: user:[email protected]:8080
132
                        Use $proxy = "" to clear proxy
133
        :type port: int
134
        :param port: Port of proxy
135
        :type username: str
136
        :param username: Username for proxy
137
        :type password: str
138
        :param password: Password for proxy
139
140
        :raises: InstagramException
141
        """
142
        self.proxy = proxy
143
144
        if proxy == '':
145
            return
146
147
        proxy = parse_url(proxy)
148
149
        if port and isinstance(port, int):
150
            proxy['port'] = int(port)
151
152
        if username and password:
153
            proxy['user'] = username
154
            proxy['pass'] = password
155
156
        if proxy['host'] and proxy['port'] and isinstance(proxy['port'], int):
157
            self.proxyHost = proxy['host'] + ':' + proxy['port']
158
        else:
159
            raise InstagramException('Proxy host error. Please check ip address and port of proxy.')
160
161
        if proxy['user'] and proxy['pass']:
162
            self.proxyAuth = proxy['user'] + ':' + proxy['pass']
163
164
    def login(self, force=False):
165
        """
166
        Login to Instagram.
167
168
        :type force: bool
169
        :param force: Force login to Instagram, this will create a new session
170
        :return: Login data
171
        :rtype List:
172
        """
173
        if (not self.isLoggedIn) or force:
174
            fetch = self.http.request(
175
                'si/fetch_headers/?challenge_type=signup&guid=' + SignatureUtils.generateUUID(False), None, True)
176
            header = fetch[0]
177
            response = ChallengeResponse(fetch[1])
178
179
            if not header or not response.isOk():
180
                raise InstagramException("Couldn't get challenge, check your connection")
181
                # return response #FIXME unreachable code
182
183
            match = re.search(r'^Set-Cookie: csrftoken=([^;]+)', fetch[0], re.MULTILINE)
184
            if match:
185
                self.token = match.group(1)
186
            else:
187
                raise InstagramException('Missing csfrtoken')
188
189
            data = OrderedDict([
190
                ('username', self.username),
191
                ('guid', self.uuid),
192
                ('device_id', self.device_id),
193
                ('password', self.password),
194
                ('login_attempt_count', 0)
195
            ])
196
197
            login = self.http.request('accounts/login/', SignatureUtils.generateSignature(json.dumps(data)), True)
198
            response = LoginResponse(login[1])
199
200
            if not response.isOk(): raise InstagramException(response.getMessage())
201
202
            self.isLoggedIn = True
203
            self.username_id = response.getUsernameId()
204
            self.settings.set('username_id', self.username_id)
205
            self.rank_token = self.username_id + '_' + self.uuid
206
            match = re.search(r'^Set-Cookie: csrftoken=([^;]+)', login[0], re.MULTILINE)
207
            if match: self.token = match.group(1)
208
            self.settings.set('token', self.token)
209
210
            self.syncFeatures()
211
            self.timelineFeed()
212
            self.getReelsTrayFeed()
213
            self.autoCompleteUserList()
214
            self.getv2Inbox()
215
            self.getRecentActivity()
216
            self.explore()
217
218
            return response
219
220
        check = self.timelineFeed()
221
222
        if check.getMessage() == 'login_required':
223
            self.login(True)
224
225
        # self.getReelsTrayFeed()
226
        # self.autoCompleteUserList()
227
        self.getv2Inbox()
228
        self.getRecentActivity()
229
        # self.explore()
230
231
    def syncFeatures(self):
232
        data = json.dumps(
233
            OrderedDict([
234
                ('_uuid', self.uuid),
235
                ('_uid', self.username_id),
236
                ('id', self.username_id),
237
                ('_csrftoken', self.token),
238
                ('experiments', Constants.EXPERIMENTS)
239
            ])
240
        )
241
        return self.http.request('qe/sync/', SignatureUtils.generateSignature(data))[1]
242
243
    def autoCompleteUserList(self):
244
        return autoCompleteUserListResponse(self.http.request('friendships/autocomplete_user_list/')[1])
245
246
    def timelineFeed(self):
247
        return TimelineFeedResponse(self.http.request('feed/timeline/')[1])
248
249
    def megaphoneLog(self):
250
        return self.http.request('megaphone/log/')[1]
251
252
    def getPendingInbox(self):
253
        """
254
        Pending Inbox
255
256
        :rtype: object
257
        :return: Pending Inbox Data
258
        """
259
        pendingInbox = PendingInboxResponse(self.http.request('direct_v2/pending_inbox/?')[1])
260
261
        if not pendingInbox.isOk():
262
            raise InstagramException(pendingInbox.getMessage() + "\n")
263
            # return FIXME unreachable code
264
265
        return pendingInbox
266
267
    def explore(self):
268
        """
269
        Explore Tab
270
271
        :rtype: object
272
        :return: Explore data
273
        """
274
        explore = ExploreResponse(self.http.request('discover/explore/?')[1])
275
276
        if not explore.isOk():
277
            raise InstagramException(explore.getMessage() + "\n")
278
279
            # return todo unreachable code
280
        return explore
281
282
    def expose(self):
283
        data = json.dumps(
284
            OrderedDict([
285
                ('_uuid', self.uuid),
286
                ('_uid', self.username_id),
287
                ('id', self.username_id),
288
                ('_csrftoken', self.token),
289
                ('experiment', 'ig_android_profile_contextual_feed')
290
            ])
291
        )
292
        return ExposeResponse(self.http.request('qe/expose/', SignatureUtils.generateSignature(data))[1])
293
294
    def logout(self):
295
        """
296
        Logout of Instagram.
297
298
        :rtype: bool
299
        :return: Returns true if logged out correctly
300
        """
301
        logout = LogoutResponse(self.http.request('accounts/logout/')[1])
302
303
        if logout.isOk():
304
            return True
305
        else:
306
            return False
307
308
    def uploadPhoto(self, photo, caption=None, upload_id=None, customPreview=None):
309
        """
310
        Upload photo to Instagram.
311
312
        :type photo: str
313
        :param photo: Path to your photo
314
        :type caption: str
315
        :param caption: Caption to be included in your photo.
316
        :rtype: object
317
        :return: Upload data
318
        """
319
        return self.http.uploadPhoto(photo, caption, upload_id, customPreview)
320
321
    def uploadPhotoReel(self, photo, caption=None, upload_id=None, customPreview=None):
322
323
        return self.http.uploadPhoto(photo, caption, upload_id, customPreview, True)
324
325
    def uploadVideo(self, video, caption=None, customPreview=None):
326
        """
327
        Upload video to Instagram.
328
329
        :type video: str
330
        :param photo: Path to your video
331
        :type caption: str
332
        :param caption: Caption to be included in your video.
333
        :rtype: object
334
        :return: Upload data
335
        """
336
        return self.http.uploadVideo(video, caption), customPreview
337
338
    def direct_share(self, media_id, recipients, text=None):
339
        self.http.direct_share(media_id, recipients, text)
340
341
    def direct_message(self, recipients, text):
342
        """
343
        Send direct message to user by inbox
344
345
        :type recipients: list|int
346
        :param recipients: Users id
347
        :type text: str
348
        :param text: Text message
349
350
        :return: void
351
        """
352
        self.http.direct_message(recipients, text)
353
354
    def directThread(self, threadId):
355
        """
356
        Direct Thread Data
357
358
        :type threadId: str
359
        :param threadId: Thread Id
360
        :rtype: object
361
        :return: Direct Thread Data
362
        """
363
        directThread = self.request("direct_v2/threads/" + str(threadId) + "/?")[1]
364
365
        if directThread['status'] != 'ok':
366
            raise InstagramException(directThread['message'] + "\n")
367
            # return Fixme unreachable code
368
369
        return directThread
370
371
    def directThreadAction(self, threadId, threadAction):
372
        """
373
        Direct Thread Action
374
375
        :type threadId: str
376
        :param threadId: Thread Id
377
        :type threadAction: str
378
        :param threadAction: Thread Action 'approve' OR 'decline' OR 'block'
379
        :rtype: object
380
        :return: Direct Thread Action Data
381
        """
382
        data = json.dumps(
383
            OrderedDict([
384
                ('_uuid', self.uuid),
385
                ('_uid', self.username_id),
386
                ('_csrftoken', self.token)
387
            ])
388
        )
389
        return self.request("direct_v2/threads/" + str(threadId) + "/" + str(threadAction) + "/",
390
                            self.generateSignature(data))[1]
391
392
    def configureVideo(self, upload_id, video, caption='', customPreview=None):
393
394
        self.uploadPhoto(video, caption, upload_id, customPreview)
395
        size = Image.open(video).size[0]
396
397
        post = json.dumps(
398
            OrderedDict([
399
                ('upload_id', upload_id),
400
                ('source_type', 3),
401
                ('poster_frame_index', 0),
402
                ('length', 0.00),
403
                ('audio_muted', False),
404
                ('filter_type', '0'),
405
                ('video_result', 'deprecated'),
406
                ('clips', OrderedDict([
407
                    ('length', Utils.getSeconds(video)),
408
                    ('source_type', '3'),
409
                    ('camera_position', 'back')
410
                ])),
411
                ('extra', OrderedDict([
412
                    ('source_width', 960),
413
                    ('source_height', 1280)
414
                ])),
415
416
                ('device', OrderedDict([
417
                    ('manufacturer', self.settings.get('manufacturer')),
418
                    ('model', self.settings.get('model')),
419
                    ('android_version', Constants.ANDROID_VERSION),
420
                    ('android_release', Constants.ANDROID_RELEASE)
421
                ])),
422
                ('_csrftoken', self.token),
423
                ('_uuid', self.uuid),
424
                ('_uid', self.username_id),
425
                ('caption', caption)
426
427
            ])
428
429
        )
430
431
        post = post.replace('"length":0', '"length":0.00')
432
433
        return ConfigureVideoResponse(
434
            self.http.request('media/configure/?video=1', SignatureUtils.generateSignature(post))[1])
435
436
    def configure(self, upload_id, photo, caption=''):
437
438
        size = Image.open(photo).size[0]
439
440
        post = json.dumps(
441
            OrderedDict([
442
                ('upload_id', upload_id),
443
                ('camera_model', self.settings.get('model').replace(" ", "")),
444
                ('source_type', 3),
445
                ('date_time_original', time.strftime('%Y:%m:%d %H:%M:%S')),
446
                ('camera_make', self.settings.get('manufacturer')),
447
                ('edits', OrderedDict([
448
                    ('crop_original_size', [size, size]),
449
                    ('crop_zoom', 1.3333334),
450
                    ('crop_center', [0.0, -0.0])
451
                ])),
452
                ('extra', OrderedDict([
453
                    ('source_width', size),
454
                    ('source_height', size)
455
                ])),
456
457
                ('device', OrderedDict([
458
                    ('manufacturer', self.settings.get('manufacturer')),
459
                    ('model', self.settings.get('model')),
460
                    ('android_version', Constants.ANDROID_VERSION),
461
                    ('android_release', Constants.ANDROID_RELEASE)
462
                ])),
463
                ('_csrftoken', self.token),
464
                ('_uuid', self.uuid),
465
                ('_uid', self.username_id),
466
                ('caption', caption)
467
468
            ])
469
        )
470
        post = post.replace('"crop_center":[0,0]', '"crop_center":[0.0,-0.0]')
471
472
        return ConfigureResponse(self.http.request('media/configure/', SignatureUtils.generateSignature(post))[1])
473
474
    def configureToReel(self, upload_id, photo):
475
476
        size = Image.open(photo).size[0]
477
478
        post = json.dumps(
479
            OrderedDict([
480
                ('upload_id', upload_id),
481
                ('source_type', 3),
482
                ('edits', OrderedDict([
483
                    ('crop_original_size', [size, size]),
484
                    ('crop_zoom', 1.3333334),
485
                    ('crop_center', [0.0, 0.0])
486
                ])),
487
                ('extra', OrderedDict([
488
                    ('source_width', size),
489
                    ('source_height', size)
490
                ])),
491
492
                ('device', OrderedDict([
493
                    ('manufacturer', self.settings.get('manufacturer')),
494
                    ('model', self.settings.get('model')),
495
                    ('android_version', Constants.ANDROID_VERSION),
496
                    ('android_release', Constants.ANDROID_RELEASE)
497
                ])),
498
                ('_csrftoken', self.token),
499
                ('_uuid', self.uuid),
500
                ('_uid', self.username_id)
501
502
            ])
503
        )
504
        post = post.replace('"crop_center":[0,0]', '"crop_center":[0.0,0.0]')
505
506
        return ConfigureResponse(
507
            self.http.request('media/configure_to_reel/', SignatureUtils.generateSignature(post))[1])
508
509
    def editMedia(self, mediaId, captionText=''):
510
        """
511
        Edit media.
512
        :type mediaId: str
513
        :param mediaId: Media id
514
        :type captionText: str
515
        :param captionText: Caption text
516
        :rtype: object
517
        :return: edit media data
518
        """
519
        data = json.dumps(
520
            OrderedDict([
521
                ('_uuid', self.uuid),
522
                ('_uid', self.username_id),
523
                ('_csrftoken', self.token),
524
                ('caption_text', captionText)
525
            ])
526
        )
527
        return self.http.request("media/" + mediaId + "/edit_media/", SignatureUtils.generateSignature(data))[1]
528
529
    def removeSelftag(self, mediaId):
530
        """
531
        Remove yourself from a tagged media.
532
        :type mediaId: str
533
        :param mediaId: Media id
534
        :rtype: object
535
        :return: edit media data
536
        """
537
        data = json.dumps(
538
            OrderedDict([
539
                ('_uuid', self.uuid),
540
                ('_uid', self.username_id),
541
                ('_csrftoken', self.token)
542
            ])
543
        )
544
        return self.http.request("usertags/" + mediaId + "/remove/", SignatureUtils.generateSignature(data))[1]
545
546
    def mediaInfo(self, mediaId):
547
        """
548
        Media info
549
        :type mediaId: str
550
        :param mediaId: Media id
551
        :rtype: object
552
        :return: delete request data
553
        """
554
        data = json.dumps(
555
            OrderedDict([
556
                ('_uuid', self.uuid),
557
                ('_uid', self.username_id),
558
                ('_csrftoken', self.token),
559
                ('media_id', mediaId)
560
            ])
561
        )
562
        return MediaInfoResponse(
563
            self.http.request("media/" + mediaId + "/info/", SignatureUtils.generateSignature(data))[1])
564
565
    def deleteMedia(self, mediaId):
566
        """
567
        Delete photo or video.
568
        :type mediaId: str
569
        :param mediaId: Media id
570
        :rtype: object
571
        :return: delete request data
572
        """
573
        data = json.dumps(
574
            OrderedDict([
575
                ('_uuid', self.uuid),
576
                ('_uid', self.username_id),
577
                ('_csrftoken', self.token),
578
                ('media_id', mediaId)
579
            ])
580
        )
581
        return self.http.request("media/" + mediaId + "/delete/", SignatureUtils.generateSignature(data))[1]
582
583
    def comment(self, mediaId, commentText):
584
        """
585
        Comment media.
586
        :type mediaId: str
587
        :param mediaId: Media id
588
        :type commentText: str
589
        :param commentText: Comment Text
590
        :rtype: object
591
        :return: comment media data
592
        """
593
        data = json.dumps(
594
            OrderedDict([
595
                ('_uuid', self.uuid),
596
                ('_uid', self.username_id),
597
                ('_csrftoken', self.token),
598
                ('comment_text', commentText)
599
            ])
600
        )
601
        return self.http.request("media/" + mediaId + "/comment/", SignatureUtils.generateSignature(data))[1]
602
603
    def deleteComment(self, mediaId, commentId):
604
        """
605
        Delete Comment.
606
        :type mediaId: str
607
        :param mediaId: Media ID
608
        :type commentId: str
609
        :param commentId: Comment ID
610
        :rtype: object
611
        :return: Delete comment data
612
        """
613
        data = json.dumps(
614
            OrderedDict([
615
                ('_uuid', self.uuid),
616
                ('_uid', self.username_id),
617
                ('_csrftoken', self.token)
618
            ])
619
        )
620
        return \
621
            self.http.request("media/" + mediaId + "/comment/" + commentId + "/delete/",
622
                              SignatureUtils.generateSignature(data))[1]
623
624
    def deleteCommentsBulk(self, mediaId, commentIds):
625
        """
626
        Delete Comment Bulk.
627
628
        :type mediaId: str
629
        :param mediaId: Media ID
630
        :type commentIds: list
631
        :param commentIds: List of comments to delete
632
        :rtype: object
633
        :return: Delete Comment Bulk Data
634
        """
635
        if not isinstance(commentIds, list):
636
            commentIds = [commentIds]
637
638
        string = []
639
        for commentId in commentIds:
640
            string.append(str(commentId))
641
642
        comment_ids_to_delete = ','.join(string)
643
644
        data = json.dumps(
645
            OrderedDict([
646
                ('_uuid', self.uuid),
647
                ('_uid', self.username_id),
648
                ('_csrftoken', self.token),
649
                ('comment_ids_to_delete', comment_ids_to_delete)
650
            ])
651
        )
652
        return self.http.request("media/" + mediaId + "/comment/bulk_delete/",
653
                                 SignatureUtils.generateSignature(data))[1]
654
655
    def changeProfilePicture(self, photo):
656
        """
657
        Sets account to public.
658
        :type photo: str
659
        :param photo: Path to photo
660
        """
661
        self.http.changeProfilePicture(photo)
662
663
    def removeProfilePicture(self):
664
        """
665
        Remove profile picture.
666
        :rtype: object
667
        :return: status request data
668
        """
669
        data = json.dumps(
670
            OrderedDict([('_uuid', self.uuid), ('_uid', self.username_id), ('_csrftoken', self.token)])
671
        )
672
        return self.http.request('accounts/remove_profile_picture/', SignatureUtils.generateSignature(data))[1]
673
674
    def setPrivateAccount(self):
675
        """
676
        Sets account to private.
677
678
        :rtype: object
679
        :return: status request data
680
        """
681
        data = json.dumps(
682
            OrderedDict([
683
                ('_uuid', self.uuid),
684
                ('_uid', self.username_id),
685
                ('_csrftoken', self.token)
686
            ])
687
        )
688
        return self.http.request('accounts/set_private/', SignatureUtils.generateSignature(data))[1]
689
690
    def setPublicAccount(self):
691
        """
692
        Sets account to public.
693
        :rtype: object
694
        :return: status request data
695
        """
696
        data = json.dumps(
697
            OrderedDict([
698
                ('_uuid', self.uuid),
699
                ('_uid', self.username_id),
700
                ('_csrftoken', self.token)
701
            ])
702
        )
703
        return self.http.request('accounts/set_public/', SignatureUtils.generateSignature(data))[1]
704
705
    def getProfileData(self):
706
        """
707
        Get personal profile data.
708
        :rtype: object
709
        :return:
710
        """
711
        data = json.dumps(
712
            OrderedDict([
713
                ('_uuid', self.uuid),
714
                ('_uid', self.username_id),
715
                ('_csrftoken', self.token)
716
            ])
717
        )
718
        return ProfileResponse(
719
            self.http.request('accounts/current_user/?edit=true', SignatureUtils.generateSignature(data))[1])
720
721
    def editProfile(self, url, phone, first_name, biography, email, gender):
722
        """
723
        Edit profile.
724
        :type url: str
725
        :param url: Url - website. "" for nothing
726
        :type phone: str
727
        :param phone: Phone number. "" for nothing
728
        :type first_name: str
729
        :param first_name: Name. "" for nothing
730
        :type email: str
731
        :param email: Email. Required.
732
        :type gender: int
733
        :param gender: Gender. male = 1 , female = 0
734
        :rtype: object
735
        :return: edit profile data
736
        """
737
        data = json.dumps(
738
            OrderedDict([
739
                ('_uuid', self.uuid),
740
                ('_uid', self.username_id),
741
                ('_csrftoken', self.token),
742
                ('external_url', url),
743
                ('phone_number', phone),
744
                ('username', self.username),
745
                ('first_name', first_name),
746
                ('biography', biography),
747
                ('email', email),
748
                ('gender', gender)
749
            ])
750
        )
751
752
        return ProfileResponse(self.http.request('accounts/edit_profile/', SignatureUtils.generateSignature(data))[1])
753
754
    def changePassword(self, oldPassword, newPassword):
755
        """
756
        Change Password.
757
758
        :type oldPassword: str
759
        :param oldPassword: Old Password
760
        :type newPassword: str
761
        :param newPassword: New Password
762
        :rtype: object
763
        :return: Change Password Data
764
        """
765
766
        data = json.dumps(
767
            OrderedDict([
768
                ('_uuid', self.uuid),
769
                ('_uid', self.username_id),
770
                ('_csrftoken', self.token),
771
                ('old_password', oldPassword),
772
                ('new_password1', newPassword),
773
                ('new_password2', newPassword)
774
            ])
775
        )
776
        return self.http.request('accounts/change_password/', SignatureUtils.generateSignature(data))[1]
777
778
    def getUsernameInfo(self, usernameId):
779
        """
780
        Get username info.
781
        :param usernameId: Username id
782
        :rtype: object
783
        :return: Username data
784
        """
785
        return self.http.request("users/" + str(usernameId) + "/info/")[1]
786
787
    def getSelfUsernameInfo(self):
788
        """
789
        Get self username info.
790
        :rtype: object
791
        :return: Username data
792
        """
793
        return self.getUsernameInfo(self.username_id)
794
795
    def getRecentActivity(self):
796
        """
797
        Get recent activity.
798
        :rtype: object
799
        :return: Recent activity data
800
        """
801
        activity = self.http.request('news/inbox/')[1]
802
803
        if activity['status'] != 'ok':
804
            raise InstagramException(activity['message'] + "\n")
805
806
        return activity
807
808
    def getFollowingRecentActivity(self):
809
        """
810
        Get recent activity from accounts followed.
811
812
        :rtype: object
813
        :return: Recent activity data of follows
814
        """
815
        activity = self.http.request('news/?')[1]
816
        if activity['status'] != 'ok':
817
            raise InstagramException(activity['message'] + "\n")
818
819
        return activity
820
821
    def getv2Inbox(self):
822
        """
823
        I dont know this yet.
824
        :rtype: object
825
        :return: v2 inbox data
826
        """
827
        inbox = V2InboxResponse(self.http.request('direct_v2/inbox/?')[1])
828
829
        if not inbox.isOk():
830
            raise InstagramException(inbox.getMessage() + "\n")
831
832
        return inbox
833
834
    def getUserTags(self, usernameId):
835
        """
836
        Get user tags.
837
        :type usernameId: str
838
        :param usernameId:
839
        :rtype: object
840
        :return: user tags data
841
        """
842
        tags = UsertagsResponse(self.http.request("usertags/" + str(usernameId) + "/feed/?rank_token=" + self.rank_token
843
                                                  + "&ranked_content=true&")[1])
844
        if not tags.isOk():
845
            raise InstagramException(tags.getMessage() + "\n")
846
847
        return tags
848
849
    def getSelfUserTags(self):
850
        """
851
        Get self user tags.
852
        :rtype: object
853
        :return: self user tags data
854
        """
855
        return self.getUserTags(self.username_id)
856
857
    def tagFeed(self, tag):
858
        """
859
        Get tagged media.
860
        :type tag: str
861
        :param tag:
862
        :rtype: object
863
        :return:
864
        """
865
        userFeed = TagFeedResponse(
866
            self.http.request("feed/tag/" + tag + "/?rank_token=" + self.rank_token + "&ranked_content=true&")[1])
867
868
        if not userFeed.isOk():
869
            raise InstagramException(userFeed.getMessage() + "\n")
870
871
        return userFeed
872
873
    def getMediaLikers(self, mediaId):
874
        """
875
        Get media likers.
876
        :type mediaId: str
877
        :param mediaId:
878
        :rtype: object
879
        :return:
880
        """
881
        likers = MediaLikersResponse(self.http.request("media/" + mediaId + "/likers/")[1])
882
        if not likers.isOk():
883
            raise InstagramException(likers.getMessage() + "\n")
884
            # return #fixme unreachable code
885
886
        return likers
887
888
    def getGeoMedia(self, usernameId):
889
        """
890
        Get user locations media.
891
        :type usernameId: str
892
        :param usernameId: Username id
893
        :rtype: object
894
        :return: Geo Media data
895
        """
896
        locations = self.http.request("maps/user/" + str(usernameId) + "/")[1]
897
898
        if locations['status'] != 'ok':
899
            raise InstagramException(locations['message'] + "\n")
900
901
        return locations
902
903
    def getSelfGeoMedia(self):
904
        """
905
        Get self user locations media.
906
        :rtype: object
907
        :return: Geo Media data
908
        """
909
        return self.getGeoMedia(self.username_id)
910
911
    def searchLocation(self, latitude, longitude):
912
        locations = LocationResponse(self.http.request(
913
            "location_search/?rank_token=" + self.rank_token + "&latitude=" + latitude + "&longitude=" + longitude)[1])
914
915
        if not locations.isOk():
916
            raise InstagramException(locations.getMessage() + "\n")
917
            # return fixme unreachable code
918
919
        return locations
920
921
    def fbUserSearch(self, query):
922
        """
923
        facebook user search.
924
        :type query: str
925
        :param query:
926
        :rtype: object
927
        :return: query data
928
        """
929
        query = urllib.quote(query)
930
        query = \
931
            self.http.request("fbsearch/topsearch/?context=blended&query=" + query + "&rank_token=" + self.rank_token)[
932
                1]
933
934
        if query['status'] != 'ok':
935
            raise InstagramException(query['message'] + "\n")
936
937
        return query
938
939
    def searchUsers(self, query):
940
        """
941
        Search users.
942
        :type query: str
943
        :param query:
944
        :rtype: object
945
        :return: query data
946
        """
947
        query = self.http.request(
948
            'users/search/?ig_sig_key_version=' + Constants.SIG_KEY_VERSION \
949
            + "&is_typeahead=true&query=" + query + "&rank_token=" + self.rank_token)[1]
950
951
        if query['status'] != 'ok':
952
            raise InstagramException(query['message'] + "\n")
953
954
        return query
955
956
    def searchUsername(self, usernameName):
957
        """
958
        Search exact username
959
960
        :type usernameName: str
961
        :param usernameName: username as STRING not an id
962
963
        :rtype: object
964
        :return: query data
965
        """
966
        query = UsernameInfoResponse(self.http.request("users/" + usernameName + "/usernameinfo/")[1])
967
968
        if not query.isOk():
969
            raise InstagramException(query.getMessage() + "\n")
970
971
        return query
972
973
    def getUsernameId(self, username):
974
        return self.searchUsername(username).getUsernameId()
975
976
    def syncFromAdressBook(self, contacts):
977
        """
978
        Search users using addres book.
979
        :type contacts: list
980
        :param contacts:
981
        :rtype: object
982
        :return:
983
        """
984
        data = OrderedDict([(
985
            ('contacts=', json.dumps(contacts))
986
        )])
987
        return self.http.request('address_book/link/?include=extra_display_name,thumbnails', data)[1]
988
989
    def searchTags(self, query):
990
        """
991
        Search tags.
992
        :type query: str
993
        :param query:
994
        :rtype: object
995
        :return: query data
996
        """
997
        query = self.http.request("tags/search/?is_typeahead=true&q=" + query + "&rank_token=" + self.rank_token)[1]
998
999
        if query['status'] != 'ok':
1000
            raise InstagramException(query['message'] + "\n")
1001
1002
        return query
1003
1004
    def getTimeline(self, maxid=None):
1005
        """
1006
        Get timeline data.
1007
        :rtype: object
1008
        :return: timeline data
1009
        """
1010
        timeline = self.http.request(
1011
            "feed/timeline/?rank_token=" + self.rank_token + "&ranked_content=true" +
1012
            (("&max_id=" + str(maxid)) if maxid is not None else '')
1013
        )[1]
1014
1015
        if timeline['status'] != 'ok':
1016
            raise InstagramException(timeline['message'] + "\n")
1017
1018
        return timeline
1019
1020
    def getReelsTrayFeed(self):
1021
        feed = ReelsTrayFeedResponse(self.http.request('feed/reels_tray/')[1])
1022
        if not feed.isOk():
1023
            raise InstagramException(feed.getMessage() + "\n")
1024
            # return todo Unreachable code
1025
1026
        return feed
1027
1028
    def getUserFeed(self, usernameId, maxid=None, minTimestamp=None):
1029
        """
1030
        Get user feed.
1031
        :type usernameId: str
1032
        :param usernameId: Username id
1033
        :type maxid: str
1034
        :param maxid: Max Id
1035
        :type minTimestamp: str
1036
        :param minTimestamp: Min timestamp
1037
        :rtype: object
1038
        :return: User feed data
1039
        :raises: InstagramException
1040
        """
1041
        userFeed = UserFeedResponse(self.http.request("feed/user/" + str(usernameId) + "/?rank_token=" + self.rank_token
1042
                                                      + (("&max_id=" + str(maxid)) if maxid is not None else '') \
1043
                                                      + (("&minTimestamp=" + str(minTimestamp)) if minTimestamp is not None else '') \
1044
                                                      + "&ranked_content=true"
1045
                                                      )[1])
1046
1047
        if not userFeed.isOk():
1048
            raise InstagramException(userFeed.getMessage() + "\n")
1049
1050
        return userFeed
1051
1052
    def getHashtagFeed(self, hashtagString, maxid=''):
1053
        """
1054
        Get hashtag feed.
1055
        :type hashtagString: str
1056
        :param hashtagString: Hashtag string, not including the #
1057
        :rtype: object
1058
        :return: Hashtag feed data
1059
        """
1060
        if maxid == '':
1061
            endpoint = "feed/tag/" + hashtagString + "/?rank_token=" + self.rank_token + "&ranked_content=true&"
1062
        else:
1063
            endpoint = "feed/tag/" + hashtagString + "/?max_id=" \
1064
                       + maxid + "&rank_token=" + self.rank_token + "&ranked_content=true&"
1065
        hashtagFeed = self.http.request(endpoint)[1]
1066
        if hashtagFeed['status'] != 'ok':
1067
            raise InstagramException(hashtagFeed['message'] + "\n")
1068
1069
        return hashtagFeed
1070
1071
    def searchFBLocation(self, query):
1072
        """
1073
        Get locations.
1074
        :type query: str
1075
        :param query: search query
1076
        :rtype: object
1077
        :return: Location location data
1078
        """
1079
        query = urllib.quote(query)
1080
        endpoint = "fbsearch/places/?rank_token=" + self.rank_token + "&query=" + query
1081
1082
        locationFeed = self.http.request(endpoint)[1]
1083
1084
        if locationFeed['status'] != 'ok':
1085
            raise InstagramException(locationFeed['message'] + "\n")
1086
1087
        return locationFeed
1088
1089
    def getLocationFeed(self, locationId, maxid=''):
1090
        """
1091
        Get location feed.
1092
        :type locationId: str
1093
        :param locationId: location id
1094
        :rtype: object
1095
        :return: Location feed data
1096
        """
1097
        if maxid is '':
1098
            endpoint = "feed/location/" + locationId + "/?rank_token=" + self.rank_token + "&ranked_content=true&"
1099
        else:
1100
            endpoint = "feed/location/" + locationId + "/?max_id=" \
1101
                       + maxid + "&rank_token=" + self.rank_token + "&ranked_content=true&"
1102
1103
        locationFeed = self.http.request(endpoint)[1]
1104
1105
        if locationFeed['status'] != 'ok':
1106
            raise InstagramException(locationFeed['message'] + "\n")
1107
1108
        return locationFeed
1109
1110
    def getSelfUserFeed(self, max_id=None):
1111
        """
1112
        Get self user feed.
1113
        :rtype: object
1114
        :return: User feed data
1115
        """
1116
        return self.getUserFeed(self.username_id, max_id)
1117
1118
    def getPopularFeed(self):
1119
        """
1120
        Get popular feed.
1121
        :rtype: object
1122
        :return: popular feed data
1123
        """
1124
        popularFeed = self.http.request("feed/popular/?people_teaser_supported=1&rank_token=" \
1125
                                        + self.rank_token + "&ranked_content=true&")[1]
1126
1127
        if popularFeed['status'] != 'ok':
1128
            raise InstagramException(popularFeed['message'] + "\n")
1129
1130
        return popularFeed
1131
1132
    def getUserFollowings(self, usernameId, maxid=''):
1133
        """
1134
        Get user followings.
1135
        :type usernameId: str
1136
        :param usernameId: Username id
1137
1138
        :rtype: object
1139
        :return: followers data
1140
        """
1141
        return FollowingResponse(self.http.request(
1142
            "friendships/" + usernameId + "/following/?max_id=" + maxid + "&ig_sig_key_version=" \
1143
            + Constants.SIG_KEY_VERSION + "&rank_token=" + self.rank_token)[1])
1144
1145
    def getUserFollowers(self, usernameId, maxid=''):
1146
        """
1147
        Get user followers.
1148
        :type usernameId: str
1149
        :param usernameId: Username id
1150
1151
        :rtype: object
1152
        :return: followers data
1153
        """
1154
        return FollowerResponse(self.http.request(
1155
            "friendships/" + usernameId + "/followers/?max_id=" + maxid \
1156
            + "&ig_sig_key_version=" + Constants.SIG_KEY_VERSION + "&rank_token=" + self.rank_token)[1])
1157
1158
    def getSelfUserFollowers(self):
1159
        """
1160
        Get self user followers.
1161
1162
        :rtype: object
1163
        :return: followers data
1164
        """
1165
        return self.getUserFollowers(self.username_id)
1166
1167
    def getSelfUsersFollowing(self):
1168
        """
1169
        Get self users we are following.
1170
1171
        :rtype: object
1172
        :return: users we are following data
1173
        """
1174
        return self.getUserFollowings(self.username_id)
1175
1176
    def like(self, mediaId):
1177
        """
1178
        Like photo or video.
1179
1180
        :type mediaId: str
1181
        :param mediaId: Media id
1182
        :rtype: object
1183
        :return: status request
1184
        """
1185
        data = json.dumps(
1186
            OrderedDict([
1187
                ('_uuid', self.uuid),
1188
                ('_uid', self.username_id),
1189
                ('_csrftoken', self.token),
1190
                ('media_id', mediaId)
1191
            ])
1192
        )
1193
        return self.http.request("media/" + mediaId + "/like/", SignatureUtils.generateSignature(data))[1]
1194
1195
    def unlike(self, mediaId):
1196
        """
1197
        Unlike photo or video.
1198
1199
        :type mediaId: str
1200
        :param mediaId: Media id
1201
        :rtype: object
1202
        :return: status request
1203
        """
1204
        data = json.dumps(
1205
            OrderedDict([
1206
                ('_uuid', self.uuid),
1207
                ('_uid', self.username_id),
1208
                ('_csrftoken', self.token),
1209
                ('media_id', mediaId)
1210
            ])
1211
        )
1212
        return self.http.request("media/" + mediaId + "/unlike/", SignatureUtils.generateSignature(data))[1]
1213
1214
    def getMediaComments(self, mediaId):
1215
        """
1216
        Get media comments.
1217
        :type mediaId: str
1218
        :param mediaId: Media id
1219
        :rtype: object
1220
        :return: Media comments data
1221
        """
1222
        return self.http.request("media/" + mediaId + "/comments/?")[1]
1223
1224
    def setNameAndPhone(self, name='', phone=''):
1225
        """
1226
        Set name and phone (Optional).
1227
        :type name: str
1228
        :param name:
1229
        :type phone: str
1230
        :param phone:
1231
        :rtype: object
1232
        :return: Set status data
1233
        """
1234
        data = json.dumps(
1235
            OrderedDict([
1236
                ('_uuid', self.uuid),
1237
                ('_uid', self.username_id),
1238
                ('first_name', name),
1239
                ('phone_number', phone),
1240
                ('_csrftoken', self.token)
1241
            ])
1242
        )
1243
1244
        return self.http.request("accounts/set_phone_and_name/", SignatureUtils.generateSignature(data))[1]
1245
1246
    def getDirectShare(self):
1247
        """
1248
        Get direct share.
1249
1250
        :rtype: object
1251
        :return: Direct share data
1252
        """
1253
        return self.http.request('direct_share/inbox/?')[1]
1254
1255
    def backup(self):
1256
        """
1257
        Backups all your uploaded photos :).
1258
        """
1259
        go = False
1260
        while True:
1261
            if not go:
1262
                myUploads = self.getSelfUserFeed()
1263
            else:
1264
                myUploads = self.getSelfUserFeed(myUploads.getNextMaxId() if myUploads.getNextMaxId() else None)
1265
1266
            if not os.path.isdir(self.IGDataPath + 'backup/'):
1267
                os.mkdir(self.IGDataPath + 'backup/')
1268
1269
            for item in myUploads.getItems():
1270
                dir_name = self.IGDataPath + 'backup/' + self.username + "-" + time.strftime('%Y-%m-%d')
1271
                if not os.path.isdir(dir_name):
1272
                    os.mkdir(dir_name)
1273
1274
                if item.getVideoVersions():
1275
                    file_put_contents(
1276
                        os.path.join(dir_name, item.getMediaId() + '.mp4'),
1277
                        urllib.urlopen(item.getVideoVersions()[0].getUrl()).read()
1278
                    )  # todo test and remove below
1279
                else:
1280
                    file_put_contents(
1281
                        os.path.join(dir_name, item.getMediaId() + '.jpg'),
1282
                        urllib.urlopen(item.getImageVersions()[0].getUrl()).read()
1283
                    )  # todo test and remove below
1284
1285
                    # urllib.urlretrieve(
1286
                    #    item['image_versions2']['candidates'][0]['url'],
1287
                    #    self.IGDataPath + 'backup/' + self.username + "-" + time.strftime('%Y-%m-%d') + '/' + item['id'] + '.jpg'
1288
                    # )
1289
            go = True
1290
1291
            if not myUploads.getNextMaxId(): break
1292
1293
    def follow(self, userId):
1294
        """
1295
        Follow.
1296
1297
        :param userId:
1298
        :type userId: str
1299
        :rtype: object
1300
        :return: Friendship status data
1301
        """
1302
1303
        data = json.dumps(
1304
            OrderedDict([
1305
                ('_uuid', self.uuid),
1306
                ('_uid', self.username_id),
1307
                ('user_id', userId),
1308
                ('_csrftoken', self.token)
1309
1310
            ])
1311
        )
1312
1313
        return self.http.request("friendships/create/" + userId + "/", SignatureUtils.generateSignature(data))[1]
1314
1315
    def unfollow(self, userId):
1316
        """
1317
        Unfollow.
1318
1319
        :param userId:
1320
        :type userId: str
1321
        :rtype: object
1322
        :return: Friendship status data
1323
        """
1324
        data = json.dumps(
1325
            OrderedDict([
1326
                ('_uuid', self.uuid),
1327
                ('_uid', self.username_id),
1328
                ('user_id', userId),
1329
                ('_csrftoken', self.token)
1330
            ])
1331
        )
1332
1333
        return self.http.request("friendships/destroy/" + userId + "/", SignatureUtils.generateSignature(data))[1]
1334
1335
    def block(self, userId):
1336
        """
1337
        Block.
1338
1339
        :param userId:
1340
        :type userId: str
1341
        :rtype: object
1342
        :return: Friendship status data
1343
        """
1344
1345
        data = json.dumps(
1346
            OrderedDict([
1347
                ('_uuid', self.uuid),
1348
                ('_uid', self.username_id),
1349
                ('user_id', userId),
1350
                ('_csrftoken', self.token)
1351
            ])
1352
        )
1353
1354
        return self.http.request("friendships/block/" + userId + "/", SignatureUtils.generateSignature(data))[1]
1355
1356
    def unblock(self, userId):
1357
        """
1358
        Unblock.
1359
1360
        :param userId:
1361
        :type userId: str
1362
        :rtype: object
1363
        :return: Friendship status data
1364
        """
1365
1366
        data = json.dumps(
1367
            OrderedDict([
1368
                ('_uuid', self.uuid),
1369
                ('_uid', self.username_id),
1370
                ('user_id', userId),
1371
                ('_csrftoken', self.token)
1372
            ])
1373
        )
1374
1375
        return self.http.request("friendships/unblock/" + userId + "/", SignatureUtils.generateSignature(data))[1]
1376
1377
    def userFriendship(self, userId):
1378
        """
1379
        Show User Friendship.
1380
1381
        :type userId: str
1382
        :param userId:
1383
        :rtype: object
1384
        :return: Friendship relationship data
1385
        """
1386
1387
        data = json.dumps(
1388
            OrderedDict([
1389
                ('_uuid', self.uuid),
1390
                ('_uid', self.username_id),
1391
                ('user_id', userId),
1392
                ('_csrftoken', self.token)
1393
            ])
1394
        )
1395
1396
        return self.http.request("friendships/show/" + userId + "/", SignatureUtils.generateSignature(data))[1]
1397
1398
    def getLikedMedia(self, maxid=None):
1399
        """
1400
        Get liked media.
1401
1402
        :rtype: object
1403
        :return: Liked media data
1404
        """
1405
        endpoint = 'feed/liked/?' + (('max_id=' + str(maxid) + '&') if maxid is not None else '')
1406
        return self.http.request(endpoint)[1]
1407
1408
    def verifyPeer(self, enable):
1409
        self.http.verifyPeer(enable)
1410
1411
    def verifyHost(self, enable):
1412
        self.http.verifyHost(enable)
1413