Skip to content

Commit

Permalink
Add Client.send_video high-level method (#395)
Browse files Browse the repository at this point in the history
Co-authored-by: Ilya (Marshal) <[email protected]>
  • Loading branch information
Meorge and MarshalX authored Sep 13, 2024
1 parent ec10135 commit 9668e5f
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 1 deletion.
16 changes: 16 additions & 0 deletions examples/send_video.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from atproto import Client


def main() -> None:
client = Client()
client.login('my-handle', 'my-password')

# replace the path to your video file
with open('video.mp4', 'rb') as f:
vid_data = f.read()

client.send_video(text='Post with video from Python', video=vid_data, video_alt='Text version of the video (ALT)')


if __name__ == '__main__':
main()
45 changes: 45 additions & 0 deletions packages/atproto_client/client/async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ async def send_post(
'models.AppBskyEmbedExternal.Main',
'models.AppBskyEmbedRecord.Main',
'models.AppBskyEmbedRecordWithMedia.Main',
'models.AppBskyEmbedVideo.Main',
]
] = None,
langs: t.Optional[t.List[str]] = None,
Expand Down Expand Up @@ -287,6 +288,50 @@ async def send_image(
facets=facets,
)

async def send_video(
self,
text: t.Union[str, TextBuilder],
video: bytes,
video_alt: t.Optional[str] = None,
profile_identify: t.Optional[str] = None,
reply_to: t.Optional['models.AppBskyFeedPost.ReplyRef'] = None,
langs: t.Optional[t.List[str]] = None,
facets: t.Optional[t.List['models.AppBskyRichtextFacet.Main']] = None,
) -> 'models.AppBskyFeedPost.CreateRecordResponse':
"""Send post with attached video.
Note:
If `profile_identify` is not provided will be sent to the current profile.
Args:
text: Text of the post.
video: Binary video to attach.
video_alt: Text version of the video.
profile_identify: Handle or DID. Where to send post.
reply_to: Root and parent of the post to reply to.
langs: List of used languages in the post.
facets: List of facets (rich text items).
Returns:
:obj:`models.AppBskyFeedPost.CreateRecordResponse`: Reference to the created record.
Raises:
:class:`atproto.exceptions.AtProtocolError`: Base exception.
"""
if video_alt is None:
video_alt = ''

upload = await self.upload_blob(video)

return await self.send_post(
text,
profile_identify=profile_identify,
reply_to=reply_to,
embed=models.AppBskyEmbedVideo.Main(video=upload.blob, alt=video_alt),
langs=langs,
facets=facets,
)

async def get_post(
self, post_rkey: str, profile_identify: t.Optional[str] = None, cid: t.Optional[str] = None
) -> 'models.AppBskyFeedPost.GetRecordResponse':
Expand Down
45 changes: 45 additions & 0 deletions packages/atproto_client/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ def send_post(
'models.AppBskyEmbedExternal.Main',
'models.AppBskyEmbedRecord.Main',
'models.AppBskyEmbedRecordWithMedia.Main',
'models.AppBskyEmbedVideo.Main',
]
] = None,
langs: t.Optional[t.List[str]] = None,
Expand Down Expand Up @@ -278,6 +279,50 @@ def send_image(
facets=facets,
)

def send_video(
self,
text: t.Union[str, TextBuilder],
video: bytes,
video_alt: t.Optional[str] = None,
profile_identify: t.Optional[str] = None,
reply_to: t.Optional['models.AppBskyFeedPost.ReplyRef'] = None,
langs: t.Optional[t.List[str]] = None,
facets: t.Optional[t.List['models.AppBskyRichtextFacet.Main']] = None,
) -> 'models.AppBskyFeedPost.CreateRecordResponse':
"""Send post with attached video.
Note:
If `profile_identify` is not provided will be sent to the current profile.
Args:
text: Text of the post.
video: Binary video to attach.
video_alt: Text version of the video.
profile_identify: Handle or DID. Where to send post.
reply_to: Root and parent of the post to reply to.
langs: List of used languages in the post.
facets: List of facets (rich text items).
Returns:
:obj:`models.AppBskyFeedPost.CreateRecordResponse`: Reference to the created record.
Raises:
:class:`atproto.exceptions.AtProtocolError`: Base exception.
"""
if video_alt is None:
video_alt = ''

upload = self.upload_blob(video)

return self.send_post(
text,
profile_identify=profile_identify,
reply_to=reply_to,
embed=models.AppBskyEmbedVideo.Main(video=upload.blob, alt=video_alt),
langs=langs,
facets=facets,
)

def get_post(
self, post_rkey: str, profile_identify: t.Optional[str] = None, cid: t.Optional[str] = None
) -> 'models.AppBskyFeedPost.GetRecordResponse':
Expand Down
6 changes: 5 additions & 1 deletion packages/atproto_codegen/clients/generate_async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def gen_client(input_filename: str, output_filename: str) -> None:
'send_post',
'send_image',
'send_images',
'upload_blob',
'_set_session',
'_get_and_set_session',
'_refresh_and_set_session',
Expand All @@ -39,10 +40,13 @@ def gen_client(input_filename: str, output_filename: str) -> None:
code = code.replace('self.app', 'await self.app')

for method in methods:
# TODO(MarshalX): abnormally hacky; rework
code = re.sub(rf'(\[self\.{method}.*\])', r'await asyncio.gather(*\1)', code)

code = code.replace(f'self.{method}(', f'await self.{method}(')
code = code.replace(f'super().{method}(', f'await super().{method}(')

code = re.sub(r'(\[self\.upload_blob.*\])', r'await asyncio.gather(*\1)', code)
code = code.replace('gather(*[await', 'gather(*[') # rollback specific case

code = DISCLAIMER + code

Expand Down

0 comments on commit 9668e5f

Please sign in to comment.