Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Client.send_video high-level method #395

Merged
merged 6 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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),
MarshalX marked this conversation as resolved.
Show resolved Hide resolved
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
Loading