Skip to content

Commit 8773e8e

Browse files
committed
Support stickers for story [#18] Added StoryLocation, change location to locations for upload story, fix story_sticker_ids
1 parent bffef42 commit 8773e8e

File tree

7 files changed

+117
-46
lines changed

7 files changed

+117
-46
lines changed

README.md

+16-5
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ The current types are in [types.py](/instagrapi/types.py):
7676
| Comment | Comments to Media |
7777
| Story | Story |
7878
| StoryLink | Link (Swipe up) |
79+
| StoryLocation | Tag Location in Story (as stocker) |
7980
| StoryMention | Mention users in Story (user, coordinates and dimensions) |
8081
| StoryHashtag | Hashtag for story (as sticker) |
8182
| StoryBuild | [StoryBuilder](/instagrapi/story.py) return path to photo/video and mention cordinats |
@@ -356,7 +357,7 @@ Upload medias to your feed. Common arguments:
356357
* `path` - Path to source file
357358
* `caption` - Text for you post
358359
* `usertags` - List[Usertag] of mention users (see `Usertag` in [types.py](/instagrapi/types.py))
359-
* `location` - Location (e.g. `Location(lat=42.0, lng=42.0)`)
360+
* `location` - Location (e.g. `Location(name='Test', lat=42.0, lng=42.0)`)
360361

361362
| Method | Return | Description |
362363
| ------------------------------------------------------------------------------------------------------------------------- | ------- | ---------------------------------- |
@@ -373,28 +374,38 @@ Upload medias to your stories. Common arguments:
373374
* `caption` - Caption for story (now use to fetch mentions)
374375
* `thumbnail` - Thumbnail instead capture from source file
375376
* `mentions` - Tag profiles in story
376-
* `location` - Location (e.g. `Location(lat=42.0, lng=42.0)`)
377+
* `locations` - Add locations to story
377378
* `links` - "Swipe Up" links (now use first)
378379
* `hashtags` - Add hashtags to story
379380

380381
| Method | Return | Description |
381382
| ------------------------------------------------------------------------------------------------ | -------- | ------------- |
382-
| photo_upload_to_story(path: Path, caption: str, upload_id: str, mentions: List[Usertag], location: Location, links: List[StoryLink], hashtags: List[StoryHashtag]) | Media | Upload photo (Support JPG files)
383-
| video_upload_to_story(path: Path, caption: str, thumbnail: Path, mentions: List[Usertag], location: Location, links: List[StoryLink], hashtags: List[StoryHashtag]) | Media | Upload video (Support MP4 files)
383+
| photo_upload_to_story(path: Path, caption: str, upload_id: str, mentions: List[Usertag], locations: List[StoryLocation], links: List[StoryLink], hashtags: List[StoryHashtag]) | Story | Upload photo (Support JPG files)
384+
| video_upload_to_story(path: Path, caption: str, thumbnail: Path, mentions: List[Usertag], locations: List[StoryLocation], links: List[StoryLink], hashtags: List[StoryHashtag]) | Story | Upload video (Support MP4 files)
384385

385386
Examples:
386387

387388
``` python
389+
from instagrapi import Client
390+
from instagrapi.types import Location, StoryMention, StoryLocation, StoryLink, StoryHashtag
391+
392+
cl = Client()
393+
cl.login(USERNAME, PASSWORD)
394+
388395
media_path = cl.video_download(
389396
cl.media_pk_from_url('https://www.instagram.com/p/CGgDsi7JQdS/')
390397
)
391398
adw0rd = cl.user_info_by_username('adw0rd')
399+
loc = cl.location_complete(Location(name='Test', lat=42.0, lng=42.0))
400+
ht = cl.hashtag_info('dhbastards')
392401

393402
cl.video_upload_to_story(
394403
media_path,
395404
"Credits @adw0rd",
396405
mentions=[StoryMention(user=adw0rd, x=0.49892962, y=0.703125, width=0.8333333333333334, height=0.125)],
397-
links=[StoryLink(webUri='https://github.com/adw0rd/instagrapi')]
406+
locations=[StoryLocation(location=loc, x=0.33, y=0.22, width=0.4, height=0.7)],
407+
links=[StoryLink(webUri='https://github.com/adw0rd/instagrapi')],
408+
hashtags=[StoryHashtag(hashtag=ht, x=0.23, y=0.32, width=0.5, height=0.22)],
398409
)
399410
```
400411

instagrapi/extractors.py

+1
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ def extract_story_v1(data):
240240
story["mentions"] = [
241241
StoryMention(**mention) for mention in story.get("reel_mentions", [])
242242
]
243+
story["locations"] = []
243244
story["hashtags"] = []
244245
story["links"] = []
245246
for cta in story.get("story_cta", []):

instagrapi/mixins/photo.py

+31-17
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
PhotoConfigureStoryError, PhotoNotUpload)
1515
from instagrapi.extractors import extract_media_v1
1616
from instagrapi.types import (Location, Media, Story, StoryHashtag, StoryLink,
17-
StoryMention, Usertag)
17+
StoryLocation, StoryMention, Usertag)
1818
from instagrapi.utils import dumps
1919

2020
try:
@@ -263,7 +263,7 @@ def photo_upload_to_story(
263263
caption: str,
264264
upload_id: str = "",
265265
mentions: List[StoryMention] = [],
266-
location: Location = None,
266+
locations: List[StoryLocation] = [],
267267
links: List[StoryLink] = [],
268268
hashtags: List[StoryHashtag] = [],
269269
) -> Story:
@@ -280,8 +280,8 @@ def photo_upload_to_story(
280280
Unique upload_id (String). When None, then generate automatically. Example from video.video_configure
281281
mentions: List[StoryMention], optional
282282
List of mentions to be tagged on this upload, default is empty list.
283-
location: Location, optional
284-
Location tag for this upload, default is None
283+
locations: List[StoryLocation], optional
284+
List of locations to be tagged on this upload, default is empty list.
285285
links: List[StoryLink]
286286
URLs for Swipe Up
287287
hashtags: List[StoryHashtag], optional
@@ -303,7 +303,7 @@ def photo_upload_to_story(
303303
height,
304304
caption,
305305
mentions,
306-
location,
306+
locations,
307307
links,
308308
hashtags,
309309
):
@@ -313,6 +313,7 @@ def photo_upload_to_story(
313313
links=links,
314314
mentions=mentions,
315315
hashtags=hashtags,
316+
locations=locations,
316317
**extract_media_v1(media).dict()
317318
)
318319
raise PhotoConfigureStoryError(
@@ -326,7 +327,7 @@ def photo_configure_to_story(
326327
height: int,
327328
caption: str,
328329
mentions: List[StoryMention] = [],
329-
location: Location = None,
330+
locations: List[StoryLocation] = [],
330331
links: List[StoryLink] = [],
331332
hashtags: List[StoryHashtag] = [],
332333
) -> Dict:
@@ -345,8 +346,8 @@ def photo_configure_to_story(
345346
Media caption
346347
mentions: List[StoryMention], optional
347348
List of mentions to be tagged on this upload, default is empty list.
348-
location: Location, optional
349-
Location tag for this upload, default is None
349+
locations: List[StoryLocation], optional
350+
List of locations to be tagged on this upload, default is empty list.
350351
links: List[StoryLink]
351352
URLs for Swipe Up
352353
hashtags: List[StoryHashtag], optional
@@ -358,6 +359,7 @@ def photo_configure_to_story(
358359
A dictionary of response from the call
359360
"""
360361
timestamp = int(time.time())
362+
story_sticker_ids = []
361363
data = {
362364
"text_metadata": '[{"font_size":40.0,"scale":1.0,"width":611.0,"height":169.0,"x":0.51414347,"y":0.8487708,"rotation":0.0}]',
363365
"supported_capabilities_new": json.dumps(config.SUPPORTED_CAPABILITIES),
@@ -366,7 +368,7 @@ def photo_configure_to_story(
366368
"scene_capture_type": "",
367369
"timezone_offset": "10800",
368370
"client_shared_at": str(timestamp - 5), # 5 seconds ago
369-
"story_sticker_ids": "time_sticker_digital",
371+
"story_sticker_ids": "",
370372
"media_folder": "Camera",
371373
"configure_mode": "1",
372374
"source_type": "4",
@@ -378,21 +380,13 @@ def photo_configure_to_story(
378380
"upload_id": upload_id,
379381
"client_timestamp": str(timestamp),
380382
"device": self.device,
381-
"implicit_location": {},
382383
"edits": {
383384
"crop_original_size": [width * 1.0, height * 1.0],
384385
"crop_center": [0.0, 0.0],
385386
"crop_zoom": 1.0,
386387
},
387388
"extra": {"source_width": width, "source_height": height},
388389
}
389-
if location:
390-
assert isinstance(location, Location), \
391-
f'location must been Location (not {type(location)})'
392-
loc = self.location_build(location)
393-
data["implicit_location"] = {
394-
"media_location": {"lat": loc.lat, "lng": loc.lng}
395-
}
396390
if links:
397391
links = [link.dict() for link in links]
398392
data["story_cta"] = dumps([{"links": links}])
@@ -416,6 +410,7 @@ def photo_configure_to_story(
416410
data["reel_mentions"] = json.dumps(reel_mentions)
417411
tap_models.extend(reel_mentions)
418412
if hashtags:
413+
story_sticker_ids.append("hashtag_sticker")
419414
for mention in hashtags:
420415
item = {
421416
"x": mention.x,
@@ -431,7 +426,26 @@ def photo_configure_to_story(
431426
"tap_state_str_id": "hashtag_sticker_gradient"
432427
}
433428
tap_models.append(item)
429+
if locations:
430+
story_sticker_ids.append("location_sticker")
431+
for mention in locations:
432+
mention.location = self.location_complete(mention.location)
433+
item = {
434+
"x": mention.x,
435+
"y": mention.y,
436+
"z": 0,
437+
"width": mention.width,
438+
"height": mention.height,
439+
"rotation": 0.0,
440+
"type": "location",
441+
"location_id": str(mention.location.pk),
442+
"is_sticker": True,
443+
"tap_state": 0,
444+
"tap_state_str_id": "location_sticker_vibrant"
445+
}
446+
tap_models.append(item)
434447
data["tap_models"] = dumps(tap_models)
448+
data["story_sticker_ids"] = dumps(story_sticker_ids)
435449
return self.private_request(
436450
"media/configure_to_story/", self.with_default_data(data)
437451
)

instagrapi/mixins/video.py

+31-16
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
VideoNotUpload)
1414
from instagrapi.extractors import extract_media_v1
1515
from instagrapi.types import (Location, Media, Story, StoryHashtag, StoryLink,
16-
StoryMention, Usertag)
16+
StoryLocation, StoryMention, Usertag)
1717
from instagrapi.utils import dumps
1818

1919

@@ -317,7 +317,7 @@ def video_upload_to_story(
317317
caption: str,
318318
thumbnail: Path = None,
319319
mentions: List[StoryMention] = [],
320-
location: Location = None,
320+
locations: List[StoryLocation] = [],
321321
links: List[StoryLink] = [],
322322
hashtags: List[StoryHashtag] = [],
323323
) -> Story:
@@ -334,8 +334,8 @@ def video_upload_to_story(
334334
Path to thumbnail for video. When None, then thumbnail is generate automatically
335335
mentions: List[StoryMention], optional
336336
List of mentions to be tagged on this upload, default is empty list.
337-
location: Location, optional
338-
Location tag for this upload, default is None
337+
locations: List[StoryLocation], optional
338+
List of locations to be tagged on this upload, default is empty list.
339339
links: List[StoryLink]
340340
URLs for Swipe Up
341341
hashtags: List[StoryHashtag], optional
@@ -364,7 +364,7 @@ def video_upload_to_story(
364364
thumbnail,
365365
caption,
366366
mentions,
367-
location,
367+
locations,
368368
links,
369369
hashtags,
370370
)
@@ -384,6 +384,7 @@ def video_upload_to_story(
384384
links=links,
385385
mentions=mentions,
386386
hashtags=hashtags,
387+
locations=locations,
387388
**extract_media_v1(media).dict()
388389
)
389390
raise VideoConfigureStoryError(
@@ -399,7 +400,7 @@ def video_configure_to_story(
399400
thumbnail: Path,
400401
caption: str,
401402
mentions: List[StoryMention] = [],
402-
location: Location = None,
403+
locations: List[StoryLocation] = [],
403404
links: List[StoryLink] = [],
404405
hashtags: List[StoryHashtag] = [],
405406
) -> Dict:
@@ -422,8 +423,8 @@ def video_configure_to_story(
422423
Media caption
423424
mentions: List[StoryMention], optional
424425
List of mentions to be tagged on this upload, default is empty list.
425-
location: Location, optional
426-
Location tag for this upload, default is None
426+
locations: List[StoryLocation], optional
427+
List of locations to be tagged on this upload, default is empty list.
427428
links: List[StoryLink]
428429
URLs for Swipe Up
429430
hashtags: List[StoryHashtag], optional
@@ -435,6 +436,7 @@ def video_configure_to_story(
435436
A dictionary of response from the call
436437
"""
437438
timestamp = int(time.time())
439+
story_sticker_ids = []
438440
data = {
439441
"supported_capabilities_new": dumps(config.SUPPORTED_CAPABILITIES),
440442
"has_original_sound": "1",
@@ -453,6 +455,7 @@ def video_configure_to_story(
453455
"client_shared_at": str(timestamp - 7), # 7 seconds ago
454456
"imported_taken_at": str(timestamp - 5 * 24 * 3600), # 5 days ago
455457
"date_time_original": time.strftime("%Y%m%dT%H%M%S.000Z", time.localtime()),
458+
"story_sticker_ids": "",
456459
"media_folder": "Camera",
457460
"configure_mode": "1",
458461
"source_type": "4",
@@ -471,19 +474,11 @@ def video_configure_to_story(
471474
# "attempt_id": str(uuid4()),
472475
"device": self.device,
473476
"length": duration,
474-
"implicit_location": {},
475477
"clips": [{"length": duration, "source_type": "4"}],
476478
"extra": {"source_width": width, "source_height": height},
477479
"audio_muted": False,
478480
"poster_frame_index": 0,
479481
}
480-
if location:
481-
assert isinstance(location, Location), \
482-
f'location must been Location (not {type(location)})'
483-
loc = self.location_build(location)
484-
data["implicit_location"] = {
485-
"media_location": {"lat": loc.lat, "lng": loc.lng}
486-
}
487482
if links:
488483
links = [link.dict() for link in links]
489484
data["story_cta"] = dumps([{"links": links}])
@@ -521,6 +516,7 @@ def video_configure_to_story(
521516
data["reel_mentions"] = dumps(reel_mentions)
522517
tap_models.extend(reel_mentions)
523518
if hashtags:
519+
story_sticker_ids.append("hashtag_sticker")
524520
for mention in hashtags:
525521
item = {
526522
"x": mention.x,
@@ -536,7 +532,26 @@ def video_configure_to_story(
536532
"tap_state_str_id": "hashtag_sticker_gradient"
537533
}
538534
tap_models.append(item)
535+
if locations:
536+
story_sticker_ids.append("location_sticker")
537+
for mention in locations:
538+
mention.location = self.location_complete(mention.location)
539+
item = {
540+
"x": mention.x,
541+
"y": mention.y,
542+
"z": 0,
543+
"width": mention.width,
544+
"height": mention.height,
545+
"rotation": 0.0,
546+
"type": "location",
547+
"location_id": str(mention.location.pk),
548+
"is_sticker": True,
549+
"tap_state": 0,
550+
"tap_state_str_id": "location_sticker_vibrant"
551+
}
552+
tap_models.append(item)
539553
data["tap_models"] = dumps(tap_models)
554+
data["story_sticker_ids"] = dumps(story_sticker_ids)
540555
return self.private_request(
541556
"media/configure_to_story/?video=1", self.with_default_data(data)
542557
)

instagrapi/types.py

+9
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,14 @@ class StoryHashtag(BaseModel):
151151
height: Optional[float]
152152

153153

154+
class StoryLocation(BaseModel):
155+
location: Location
156+
x: Optional[float]
157+
y: Optional[float]
158+
width: Optional[float]
159+
height: Optional[float]
160+
161+
154162
class StoryBuild(BaseModel):
155163
mentions: List[StoryMention]
156164
path: FilePath
@@ -174,6 +182,7 @@ class Story(BaseModel):
174182
mentions: List[StoryMention]
175183
links: List[StoryLink]
176184
hashtags: List[StoryHashtag]
185+
locations: List[StoryLocation]
177186

178187

179188
class DirectMessage(BaseModel):

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
setup(
3131
name='instagrapi',
32-
version='1.4.2',
32+
version='1.4.3',
3333
author='Mikhail Andreev',
3434
author_email='[email protected]',
3535
license='MIT',

0 commit comments

Comments
 (0)