diff --git a/instagrapi/mixins/photo.py b/instagrapi/mixins/photo.py index 03b2f3e0..060def8b 100644 --- a/instagrapi/mixins/photo.py +++ b/instagrapi/mixins/photo.py @@ -442,11 +442,11 @@ def photo_configure_to_story( "media_transformation_info": dumps({ "width": str(width), "height": str(height), - "x_transform":"0", - "y_transform":"0", - "zoom":"1.0", - "rotation":"0.0", - "background_coverage":"0.0" + "x_transform": "0", + "y_transform": "0", + "zoom": "1.0", + "rotation": "0.0", + "background_coverage": "0.0" }), "original_media_type": "photo", "camera_entry_point": str(random.randint(25, 164)), # e.g. 25 @@ -586,7 +586,8 @@ def photo_configure_to_story( } tap_models.append(item) data["reshared_media_id"] = str(feed_media.media_pk) - data["tap_models"] = dumps(tap_models) + if tap_models: + data["tap_models"] = dumps(tap_models) if static_models: data["static_models"] = dumps(static_models) if story_sticker_ids: diff --git a/instagrapi/mixins/video.py b/instagrapi/mixins/video.py index fc21af3f..ac132862 100644 --- a/instagrapi/mixins/video.py +++ b/instagrapi/mixins/video.py @@ -519,34 +519,35 @@ def video_configure_to_story( # "is_segmented_video": "1", # SEGMENT MODE # --------------------------------- # COMMON properties: + "_uid": str(self.user_id), "supported_capabilities_new": dumps(config.SUPPORTED_CAPABILITIES), - # "has_original_sound": "1", - # "filter_type": "0", + "has_original_sound": "1", + "filter_type": "0", "camera_session_id": self.client_session_id, - "camera_entry_point": str(random.randint(35, 45)), - # "date_time_digitalized":"2021:03:12+00:59:35", - # "composition_id":"ce3b1324-3761-4e8a-9212-fbac6c5e7d7d" - "camera_make": self.device_settings.get("manufacturer", "Xiaomi"), - "camera_model": self.device_settings.get("model", "MI+5s"), + "camera_entry_point": str(random.randint(35, 164)), + "composition_id": self.generate_uuid(), + # "camera_make": self.device_settings.get("manufacturer", "Xiaomi"), + # "camera_model": self.device_settings.get("model", "MI+5s"), "timezone_offset": str(self.timezone_offset), "client_timestamp": str(timestamp), "client_shared_at": str(timestamp - 7), # 7 seconds ago # "imported_taken_at": str(timestamp - 5 * 24 * 3600), # 5 days ago "date_time_original": date_time_original(time.localtime()), + # "date_time_digitalized": date_time_original(time.localtime()), # "story_sticker_ids": "", # "media_folder": "Camera", "configure_mode": "1", # "configure_mode": "2", <- when direct - "source_type": "4", # "3" - # "video_result": "", + "source_type": "3", # "3" + "video_result": "", "creation_surface": "camera", - "software": config.SOFTWARE.format(**self.device_settings), - "caption": caption, + # "software": config.SOFTWARE.format(**self.device_settings), + # "caption": caption, "capture_type": "normal", - "rich_text_format_types": '["classic_v2"]', # default, typewriter + # "rich_text_format_types": '["classic_v2"]', # default, typewriter "upload_id": upload_id, - "scene_capture_type": "standard", - "scene_type": "", + # "scene_capture_type": "standard", + # "scene_type": "", "original_media_type": "video", "camera_position": "back", # Facebook Sharing Part: @@ -557,27 +558,30 @@ def video_configure_to_story( # "fb_access_token":"EAABwzLixnjYBACVgqBfLyDuPWs6RN2sTZC........cnNkjHCH2", # "attempt_id": str(uuid4()), "device": self.device, - # "length": duration, - # "clips": [{"length": duration, "source_type": "4"}], + "length": duration, + "clips": [{"length": duration, "source_type": "3", "camera_position": "back"}], # "edits": { - # "crop_original_size": [ - # 960, - # 960 - # ], - # "crop_center": [ - # 0, - # 0 - # ], - # "crop_zoom": 1 + # "filter_type": 0, + # "filter_strength": 1.0, + # "crop_original_size": [width, height], + # # "crop_center": [0, 0], + # # "crop_zoom": 1 # }, + "media_transformation_info": dumps({ + "width": str(width), + "height": str(height), + "x_transform": "0", + "y_transform": "0", + "zoom": "1.0", + "rotation": "0.0", + "background_coverage": "0.0" + }), "extra": {"source_width": width, "source_height": height}, - # "audio_muted": False, - # "poster_frame_index": 0, + "audio_muted": False, + "poster_frame_index": 0, + # "app_attribution_android_namespace": "", } data.update(extra_data) - if links: - links = [link.dict() for link in links] - data["story_cta"] = dumps([{"links": links}]) tap_models = [] static_models = [] if mentions: @@ -649,42 +653,72 @@ def video_configure_to_story( "tap_state_str_id": "location_sticker_vibrant" } tap_models.append(item) + if links: + # instagram allow one link now + link = links[0] + self.private_request("media/validate_reel_url/", { + "url": link.webUri, + "_uid": str(self.user_id), + "_uuid": str(self.uuid), + }) + stickers.append( + StorySticker( + type="story_link", + x=link.x, + y=link.y, + z=link.z, + width=link.width, + height=link.height, + rotation=link.rotation, + extra=dict( + link_type="web", + url=link.webUri, + tap_state_str_id="link_sticker_default" + ) + ) + ) + story_sticker_ids.append("link_sticker_default") if stickers: for sticker in stickers: - str_id = sticker.id # "gif_Igjf05J559JWuef4N5" - static_models.append({ - "x": sticker.x, - "y": sticker.y, + sticker_extra = sticker.extra or {} + if sticker.id: + sticker_extra["str_id"] = sticker.id + story_sticker_ids.append(sticker.id) + tap_models.append({ + "x": round(sticker.x, 7), + "y": round(sticker.y, 7), "z": sticker.z, - "width": sticker.width, - "height": sticker.height, + "width": round(sticker.width, 7), + "height": round(sticker.height, 7), "rotation": sticker.rotation, - "str_id": str_id, - "sticker_type": sticker.type, + "type": sticker.type, + "is_sticker": True, + "selected_index": 0, + "tap_state": 0, + **sticker_extra }) - story_sticker_ids.append(str_id) if sticker.type == "gif": data["has_animated_sticker"] = "1" if medias: for feed_media in medias: - assert feed_media.media_pk, 'Required StoryMedia.media_pk' + assert feed_media.media_pk, "Required StoryMedia.media_pk" # if not feed_media.user_id: # user = self.media_user(feed_media.media_pk) # feed_media.user_id = user.pk item = { - 'x': feed_media.x, - 'y': feed_media.y, - 'z': feed_media.z, - 'width': feed_media.width, - 'height': feed_media.height, - 'rotation': feed_media.rotation, - 'type': 'feed_media', - 'media_id': str(feed_media.media_pk), - 'media_owner_id': str(feed_media.user_id or ""), - 'product_type': 'feed', - 'is_sticker': True, - 'tap_state': 0, - 'tap_state_str_id': 'feed_post_sticker_square' + "x": feed_media.x, + "y": feed_media.y, + "z": feed_media.z, + "width": feed_media.width, + "height": feed_media.height, + "rotation": feed_media.rotation, + "type": "feed_media", + "media_id": str(feed_media.media_pk), + "media_owner_id": str(feed_media.user_id or ""), + "product_type": "feed", + "is_sticker": True, + "tap_state": 0, + "tap_state_str_id": "feed_post_sticker_square" } tap_models.append(item) data["reshared_media_id"] = str(feed_media.media_pk) @@ -708,8 +742,8 @@ def video_configure_to_story( if static_models: data["static_models"] = dumps(static_models) if story_sticker_ids: - data["story_sticker_ids"] = dumps(story_sticker_ids) - return self.private_request("media/configure_to_story/", self.with_default_data(data)) + data["story_sticker_ids"] = story_sticker_ids[0] + return self.private_request("media/configure_to_story/?video=1", self.with_default_data(data)) def video_upload_to_direct( self, @@ -776,7 +810,7 @@ def video_upload_to_direct( continue raise e if configured and thread_ids: - return extract_direct_message(configured.get('message_metadata', [])[0]) + return extract_direct_message(configured.get("message_metadata", [])[0]) raise VideoConfigureStoryError( response=self.last_response, **self.last_json ) diff --git a/instagrapi/story.py b/instagrapi/story.py index 69222000..ec236e1b 100644 --- a/instagrapi/story.py +++ b/instagrapi/story.py @@ -1,8 +1,9 @@ import tempfile +from urllib.parse import urlparse from pathlib import Path from typing import List -from .types import StoryBuild, StoryMention +from .types import StoryBuild, StoryMention, StorySticker try: from moviepy.editor import CompositeVideoClip, ImageClip, TextClip, VideoFileClip @@ -53,7 +54,7 @@ def __init__( self.mentions = mentions self.bgpath = Path(bgpath) if bgpath else None - def build_main(self, clip, max_duration: int = 0, font: str = 'Arial', fontsize: int = 100, color: str = 'white') -> StoryBuild: + def build_main(self, clip, max_duration: int = 0, font: str = 'Arial', fontsize: int = 100, color: str = 'white', link: str = "") -> StoryBuild: """ Build clip @@ -76,6 +77,7 @@ def build_main(self, clip, max_duration: int = 0, font: str = 'Arial', fontsize: An object of StoryBuild """ clips = [] + stickers = [] # Background if self.bgpath: assert self.bgpath.exists(), f"Wrong path to background {self.bgpath}" @@ -115,6 +117,42 @@ def build_main(self, clip, max_duration: int = 0, font: str = 'Arial', fontsize: .fadein(3) ) clips.append(text_clip) + if link: + url = urlparse(link) + link_clip = TextClip( + url.netloc, + color="blue", + bg_color="white", + font=font, + kerning=-1, + fontsize=32, + method="label", + ) + link_clip_left = (self.width - 400) / 2 + link_clip_top = clip.size[1] / 2 + link_clip = ( + link_clip.resize(width=400) + .set_position((link_clip_left, link_clip_top)) + .fadein(3) + ) + link_sticker = StorySticker( + # x=160.0, y=641.0, z=0, width=400.0, height=88.0, + x=link_clip_left / self.width, # e.g. 0.49953705 + y=link_clip_top / self.height, # e.g. 0.5 + z=0, + width=link_clip.size[0] / self.width, # e.g. 0.50912 + height=link_clip.size[1] / self.height, # e.g. 0.06875 + rotation=0.0, + # id="link_sticker_default", + type="story_link", + extra=dict( + link_type="web", + url=link, # e.g. "https//github.com/" + tap_state_str_id="link_sticker_default", + ) + ) + stickers.append(link_sticker) + clips.append(link_clip) # Mentions mentions = [] if mention: @@ -142,9 +180,9 @@ def build_main(self, clip, max_duration: int = 0, font: str = 'Arial', fontsize: sub = cvc.subclip(start, end) sub.write_videofile(path, codec="libx264", audio=True, audio_codec="aac") paths.append(path) - return StoryBuild(mentions=mentions, path=destination, paths=paths) + return StoryBuild(mentions=mentions, path=destination, paths=paths, stickers=stickers) - def video(self, max_duration: int = 0, font: str = 'Arial', fontsize: int = 100, color: str = 'white'): + def video(self, max_duration: int = 0, font: str = 'Arial', fontsize: int = 100, color: str = 'white', link: str = ''): """ Build CompositeVideoClip from source video @@ -165,9 +203,9 @@ def video(self, max_duration: int = 0, font: str = 'Arial', fontsize: int = 100, An object of StoryBuild """ clip = VideoFileClip(str(self.path), has_mask=True) - return self.build_main(clip, max_duration, font, fontsize, color) + return self.build_main(clip, max_duration, font, fontsize, color, link) - def photo(self, max_duration: int = 0, font: str = 'Arial', fontsize: int = 100, color: str = 'white'): + def photo(self, max_duration: int = 0, font: str = 'Arial', fontsize: int = 100, color: str = 'white', link: str = ''): """ Build CompositeVideoClip from source video @@ -195,4 +233,4 @@ def photo(self, max_duration: int = 0, font: str = 'Arial', fontsize: int = 100, height_in_ratio = int((float(image_height) * float(width_reduction_percent))) clip = ImageClip(str(self.path)).resize(width=self.width, height=height_in_ratio) - return self.build_main(clip, max_duration or 15, font, fontsize, color) + return self.build_main(clip, max_duration or 15, font, fontsize, color, link) diff --git a/setup.py b/setup.py index fdf26f9a..6cc0b4f6 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ setup( name='instagrapi', - version='1.16.5', + version='1.16.6', author='Mikhail Andreev', author_email='x11org@gmail.com', license='MIT',