Skip to content

Commit

Permalink
Set a hashtag for a story [#77] Added StoryHashtag and support hashta…
Browse files Browse the repository at this point in the history
…gs to photo_upload_to_story and video_upload_to_story
  • Loading branch information
adw0rd committed Jan 6, 2021
1 parent dd61796 commit 1426971
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 15 deletions.
1 change: 1 addition & 0 deletions instagrapi/extractors.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ def extract_story_v1(data):
story["mentions"] = [
StoryMention(**mention) for mention in story.get("reel_mentions", [])
]
story["hashtags"] = []
story["links"] = []
for cta in story.get("story_cta", []):
for link in cta.get("links", []):
Expand Down
43 changes: 38 additions & 5 deletions instagrapi/mixins/photo.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
from instagrapi.exceptions import (PhotoConfigureError,
PhotoConfigureStoryError, PhotoNotUpload)
from instagrapi.extractors import extract_media_v1
from instagrapi.types import (Location, Media, Story, StoryLink, StoryMention,
Usertag)
from instagrapi.types import (Location, Media, Story, StoryHashtag, StoryLink,
StoryMention, Usertag)
from instagrapi.utils import dumps

try:
Expand Down Expand Up @@ -265,6 +265,7 @@ def photo_upload_to_story(
mentions: List[StoryMention] = [],
location: Location = None,
links: List[StoryLink] = [],
hashtags: List[StoryHashtag] = [],
) -> Story:
"""
Upload photo as a story and configure it
Expand All @@ -283,6 +284,8 @@ def photo_upload_to_story(
Location tag for this upload, default is None
links: List[StoryLink]
URLs for Swipe Up
hashtags: List[StoryHashtag], optional
List of hashtags to be tagged on this upload, default is empty list.
Returns
-------
Expand All @@ -295,13 +298,21 @@ def photo_upload_to_story(
self.logger.debug(f"Attempt #{attempt} to configure Photo: {path}")
time.sleep(3)
if self.photo_configure_to_story(
upload_id, width, height, caption, mentions, location, links
upload_id,
width,
height,
caption,
mentions,
location,
links,
hashtags,
):
media = self.last_json.get("media")
self.expose()
return Story(
links=links,
mentions=mentions,
hashtags=hashtags,
**extract_media_v1(media).dict()
)
raise PhotoConfigureStoryError(
Expand All @@ -317,6 +328,7 @@ def photo_configure_to_story(
mentions: List[StoryMention] = [],
location: Location = None,
links: List[StoryLink] = [],
hashtags: List[StoryHashtag] = [],
) -> Dict:
"""
Post configure photo
Expand All @@ -337,6 +349,8 @@ def photo_configure_to_story(
Location tag for this upload, default is None
links: List[StoryLink]
URLs for Swipe Up
hashtags: List[StoryHashtag], optional
List of hashtags to be tagged on this upload, default is empty list.
Returns
-------
Expand Down Expand Up @@ -382,8 +396,9 @@ def photo_configure_to_story(
if links:
links = [link.dict() for link in links]
data["story_cta"] = dumps([{"links": links}])
tap_models = []
if mentions:
mentions = [
reel_mentions = [
{
"x": 0.5002546,
"y": 0.8583542,
Expand All @@ -398,7 +413,25 @@ def photo_configure_to_story(
}
for mention in mentions
]
data["tap_models"] = data["reel_mentions"] = json.dumps(mentions)
data["reel_mentions"] = json.dumps(reel_mentions)
tap_models.extend(reel_mentions)
if hashtags:
for mention in hashtags:
item = {
"x": mention.x,
"y": mention.y,
"z": 0,
"width": mention.width,
"height": mention.height,
"rotation": 0.0,
"type": "hashtag",
"tag_name": mention.hashtag.name,
"is_sticker": True,
"tap_state": 0,
"tap_state_str_id": "hashtag_sticker_gradient"
}
tap_models.append(item)
data["tap_models"] = dumps(tap_models)
return self.private_request(
"media/configure_to_story/", self.with_default_data(data)
)
26 changes: 25 additions & 1 deletion instagrapi/mixins/video.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
VideoConfigureStoryError, VideoNotDownload,
VideoNotUpload)
from instagrapi.extractors import extract_media_v1
from instagrapi.types import (Location, Media, Story, StoryLink,
from instagrapi.types import (Location, Media, Story, StoryHashtag, StoryLink,
StoryMention, Usertag)
from instagrapi.utils import dumps

Expand Down Expand Up @@ -319,6 +319,7 @@ def video_upload_to_story(
mentions: List[StoryMention] = [],
location: Location = None,
links: List[StoryLink] = [],
hashtags: List[StoryHashtag] = [],
) -> Story:
"""
Upload video as a story and configure it
Expand All @@ -337,6 +338,8 @@ def video_upload_to_story(
Location tag for this upload, default is None
links: List[StoryLink]
URLs for Swipe Up
hashtags: List[StoryHashtag], optional
List of hashtags to be tagged on this upload, default is empty list.
Returns
-------
Expand All @@ -363,6 +366,7 @@ def video_upload_to_story(
mentions,
location,
links,
hashtags,
)
except Exception as e:
if "Transcode not finished yet" in str(e):
Expand All @@ -379,6 +383,7 @@ def video_upload_to_story(
return Story(
links=links,
mentions=mentions,
hashtags=hashtags,
**extract_media_v1(media).dict()
)
raise VideoConfigureStoryError(
Expand All @@ -396,6 +401,7 @@ def video_configure_to_story(
mentions: List[StoryMention] = [],
location: Location = None,
links: List[StoryLink] = [],
hashtags: List[StoryHashtag] = [],
) -> Dict:
"""
Story Configure for Photo
Expand All @@ -420,6 +426,8 @@ def video_configure_to_story(
Location tag for this upload, default is None
links: List[StoryLink]
URLs for Swipe Up
hashtags: List[StoryHashtag], optional
List of hashtags to be tagged on this upload, default is empty list.
Returns
-------
Expand Down Expand Up @@ -512,6 +520,22 @@ def video_configure_to_story(
data["text_metadata"] = dumps(text_metadata)
data["reel_mentions"] = dumps(reel_mentions)
tap_models.extend(reel_mentions)
if hashtags:
for mention in hashtags:
item = {
"x": mention.x,
"y": mention.y,
"z": 0,
"width": mention.width,
"height": mention.height,
"rotation": 0.0,
"type": "hashtag",
"tag_name": mention.hashtag.name,
"is_sticker": True,
"tap_state": 0,
"tap_state_str_id": "hashtag_sticker_gradient"
}
tap_models.append(item)
data["tap_models"] = dumps(tap_models)
return self.private_request(
"media/configure_to_story/?video=1", self.with_default_data(data)
Expand Down
23 changes: 16 additions & 7 deletions instagrapi/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,13 @@ class Comment(BaseModel):
like_count: Optional[int]


class Hashtag(BaseModel):
id: int
name: str
media_count: Optional[int]
profile_pic_url: Optional[HttpUrl]


class StoryMention(BaseModel):
user: UserShort
x: Optional[float]
Expand All @@ -136,6 +143,14 @@ class StoryMention(BaseModel):
height: Optional[float]


class StoryHashtag(BaseModel):
hashtag: Hashtag
x: Optional[float]
y: Optional[float]
width: Optional[float]
height: Optional[float]


class StoryBuild(BaseModel):
mentions: List[StoryMention]
path: FilePath
Expand All @@ -158,6 +173,7 @@ class Story(BaseModel):
video_duration: Optional[float] = 0.0 # for Video and IGTV
mentions: List[StoryMention]
links: List[StoryLink]
hashtags: List[StoryHashtag]


class DirectMessage(BaseModel):
Expand Down Expand Up @@ -218,10 +234,3 @@ def is_seen(self, user_id: int):
if k != user_id
]
return not any(timestamps)


class Hashtag(BaseModel):
id: int
name: str
media_count: Optional[int]
profile_pic_url: Optional[HttpUrl]
11 changes: 9 additions & 2 deletions tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
MediaOembed,
Story,
StoryMention,
StoryHashtag,
StoryLink,
User,
UserShort,
Expand Down Expand Up @@ -1111,15 +1112,18 @@ def test_upload_photo_story(self):
self.assertIsInstance(path, Path)
caption = 'Test photo caption'
adw0rd = self.api.user_info_by_username('adw0rd')
dhbastards = self.api.hashtag_info('dhbastards')
self.assertIsInstance(adw0rd, User)
mentions = [StoryMention(user=adw0rd)]
links = [StoryLink(webUri='https://adw0rd.com/')]
hashtags = [StoryHashtag(hashtag=dhbastards)]
try:
story = self.api.photo_upload_to_story(
path,
caption,
mentions=mentions,
links=links
links=links,
hashtags=hashtags
)
self.assertIsInstance(story, Story)
self.assertTrue(story)
Expand All @@ -1135,9 +1139,11 @@ def test_upload_video_story(self):
self.assertIsInstance(path, Path)
caption = 'Test video caption'
adw0rd = self.api.user_info_by_username('adw0rd')
dhbastards = self.api.hashtag_info('dhbastards')
self.assertIsInstance(adw0rd, User)
mentions = [StoryMention(user=adw0rd)]
links = [StoryLink(webUri='https://adw0rd.com/')]
hashtags = [StoryHashtag(hashtag=dhbastards)]
try:
buildout = StoryBuilder(
path, caption, mentions,
Expand All @@ -1147,7 +1153,8 @@ def test_upload_video_story(self):
buildout.path,
caption,
mentions=buildout.mentions,
links=links
links=links,
hashtags=hashtags
)
self.assertIsInstance(story, Story)
self.assertTrue(story)
Expand Down

0 comments on commit 1426971

Please sign in to comment.