Skip to content

Commit 4a651f7

Browse files
committed
added upload_story() with link stickers
1 parent 7914c80 commit 4a651f7

File tree

5 files changed

+167
-5
lines changed

5 files changed

+167
-5
lines changed

README.md

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -369,8 +369,44 @@ mobile.unblock(123456789) # Use UserID
369369

370370
Any missing feature? Please raise an issue.
371371

372+
### Stories
373+
374+
<details>
375+
376+
<summary>Upload Story (Picture)</summary>
377+
378+
```python
379+
from ensta import Mobile
380+
381+
mobile = Mobile(username, password)
382+
383+
upload_id = mobile.get_upload_id("image.jpg")
384+
385+
mobile.upload_story(upload_id)
386+
```
387+
388+
</details>
389+
390+
<details>
391+
392+
<summary>Upload Story (Picture) + Link Sticker</summary>
393+
394+
```python
395+
from ensta import Mobile
396+
from ensta.structures import StoryLink
397+
398+
mobile = Mobile(username, password)
399+
400+
upload_id = mobile.get_upload_id("image.jpg")
401+
402+
mobile.upload_story(upload_id, entities=[
403+
StoryLink(title="Google", url="https://google.com")
404+
])
405+
```
406+
407+
</details>
408+
372409
### Direct Messaging
373-
Tap on the headings to view code:
374410

375411
<details>
376412

@@ -404,8 +440,6 @@ direct.send_photo(media_id, thread_id)
404440

405441
</details>
406442

407-
We'll implement more features soon.
408-
409443
## Basic Usage
410444

411445
<details>

ensta/Mobile.py

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
from json import JSONDecodeError
66
from pathlib import Path
77
import string
8+
import datetime
89
import json
910
from .parser.ProfileParser import parse_profile
10-
from .structures import Profile
11+
from .structures import Profile, StoryLink
1112
from .Direct import Direct
1213
from ensta.Utils import time_id, fb_uploader
1314

@@ -411,3 +412,107 @@ def unblock(self, user_id: str) -> bool:
411412
"Unable to unblock. Is the user_id correct? Username should not be used. Try using another account, switch "
412413
"to a different network, or use reputed proxies."
413414
)
415+
416+
def upload_story(
417+
self,
418+
upload_id: str,
419+
resolution: tuple[int, int] = (1080, 1920),
420+
entities: list[StoryLink] = None
421+
) -> bool:
422+
"""
423+
Uploads media to story
424+
:param upload_id: Returned by get_upload_id(media_path)
425+
:param resolution: Resolution (Width, Height) of device canvas
426+
:param entities: Entities like stickers, links etc.
427+
:return: Boolean (Uploaded or not)
428+
"""
429+
430+
date = datetime.datetime.now()
431+
432+
data: dict = {
433+
"supported_capabilities_new": "[{\"name\":\"SUPPORTED_SDK_VERSIONS\",\"value\":\"131.0,132.0,133.0,134.0,135.0,136.0,137.0,138.0,139.0,140.0,141.0,142.0,143.0,144.0,145.0,146.0,147.0,148.0,149.0,150.0,151.0,152.0,153.0,154.0,155.0,156.0,157.0,158.0,159.0\"},{\"name\":\"FACE_TRACKER_VERSION\",\"value\":\"14\"},{\"name\":\"COMPRESSION\",\"value\":\"ETC2_COMPRESSION\"},{\"name\":\"gyroscope\",\"value\":\"gyroscope_enabled\"}]",
434+
"has_original_sound": "1",
435+
"camera_entry_point": "12",
436+
"original_media_type": "1",
437+
"camera_session_id": str(uuid4()),
438+
"date_time_digitalized": f"{date.year}:{date.month:02}:{date.day:02} {date.hour:02}:{date.minute:02}:{date.second:02}",
439+
"camera_model": "sdk_gphone64_x86_64",
440+
"scene_capture_type": "",
441+
"timezone_offset": (datetime.datetime.fromtimestamp(date.timestamp() * 1e-3) - datetime.datetime.utcfromtimestamp(date.timestamp() * 1e-3)).seconds,
442+
"client_shared_at": int(date.timestamp()),
443+
"story_sticker_ids": "link_sticker_default",
444+
"configure_mode": "1",
445+
"source_type": "3",
446+
"camera_position": "front",
447+
"_uid": self.user_id,
448+
"device_id": self.device_id,
449+
"composition_id": str(uuid4()),
450+
"_uuid": self.phone_id,
451+
"creation_surface": "camera",
452+
"can_play_spotify_audio": "1",
453+
"date_time_original": f"{date.year}:{date.month:02}:{date.day:02} {date.hour:02}:{date.minute:02}:{date.second:02}",
454+
"capture_type": "normal",
455+
"upload_id": upload_id,
456+
"client_timestamp": int(date.timestamp()),
457+
"private_mention_sharing_enabled": "1",
458+
"media_transformation_info": f"{{\"width\":\"{resolution[0]}\",\"height\":\"{resolution[1]}\",\"x_transform\":\"0\",\"y_transform\":\"0\",\"zoom\":\"1.0\",\"rotation\":\"0.0\",\"background_coverage\":\"0.0\"}}",
459+
"camera_make": "Google",
460+
"device": {
461+
"manufacturer": "Google",
462+
"model": "sdk_gphone64_x86_64",
463+
"android_version": 31,
464+
"android_release": "12"
465+
},
466+
"edits": {
467+
"filter_type": 0,
468+
"filter_strength": 1.0,
469+
"crop_original_size": [
470+
float(resolution[0]),
471+
float(resolution[1])
472+
]
473+
},
474+
"extra": {
475+
"source_width": resolution[0],
476+
"source_height": resolution[1]
477+
}
478+
}
479+
480+
tap_models: list[dict] = []
481+
482+
if entities is not None:
483+
for entity in entities:
484+
485+
# A Story Link?
486+
if isinstance(entity, StoryLink):
487+
tap_models.append(
488+
{
489+
"x": entity.x,
490+
"y": entity.y,
491+
"z": entity.z,
492+
"width": entity.width,
493+
"height": entity.height,
494+
"rotation": entity.rotation,
495+
"type": entity.type,
496+
"link_type": entity.link_type,
497+
"custom_cta": entity.title if entity.title != "" else entity.url,
498+
"url": entity.url,
499+
"is_sticker": entity.is_sticker,
500+
"tap_state": entity.tap_state,
501+
"tap_state_str_id": entity.tap_state_str_id,
502+
}
503+
)
504+
505+
if len(tap_models) > 0: data["tap_models"] = tap_models
506+
507+
response: Response = self.session.post(
508+
url="https://i.instagram.com/api/v1/media/configure_to_story/",
509+
data={"signed_body": "SIGNATURE." + json.dumps(data)}
510+
)
511+
512+
try: return response.json().get("status", "") == "ok"
513+
514+
except JSONDecodeError:
515+
raise NetworkError(
516+
"Failed to publish story. Is your media correct? Are all entities correct? "
517+
"Maybe you're being rate limited, try using a different account."
518+
)

ensta/structures/StoryLink.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from dataclasses import dataclass
2+
3+
4+
@dataclass
5+
class StoryLink:
6+
7+
url: str
8+
title: str = ""
9+
10+
tap_state_str_id: str = "link_sticker_default"
11+
type: str = "story_link"
12+
is_sticker: bool = True
13+
link_type: str = "web"
14+
tap_state: int = 0
15+
16+
x: float = 0.5
17+
y: float = 0.49980468
18+
z: float = 0
19+
20+
width: float = 0.45520985
21+
height: float = 0.06875
22+
rotation: float = 0.0

ensta/structures/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
from .Profile import Profile
22
from .BiographyLink import BiographyLink
3+
from .StoryLink import StoryLink

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from distutils.core import setup
22
from pathlib import Path
33

4-
version = "5.1.8"
4+
version = "5.1.9"
55
long_description = (Path(__file__).parent / "README.md").read_text(encoding="utf-8")
66

77
setup(

0 commit comments

Comments
 (0)