Skip to content

Instantly share code, notes, and snippets.

@zzstoatzz
Last active December 6, 2024 06:11
Show Gist options
  • Save zzstoatzz/7a145b728455f8d8a3fecb9bad55a71b to your computer and use it in GitHub Desktop.
Save zzstoatzz/7a145b728455f8d8a3fecb9bad55a71b to your computer and use it in GitHub Desktop.
its like quite bespoke spelling, but ive been digging in this SDK for a while :)
import httpx
from atproto import Client, models
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
"""set the following in your .env file
BSKY_USERNAME=your_username
BSKY_PASSWORD=your_password
"""
model_config = SettingsConfigDict(env_file='.env')
bsky_username: str
bsky_password: str
settings = Settings() # type: ignore[call-arg]
DEFAULT_IMAGE_URL = 'https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:xbtmt2zjwlrfegqvch7fboei/bafkreiae4rcokecag5qlpvg6l3otzulqn3hllnazmz2ezyqfl6xzpy5noe@jpeg'
def main(
user_to_quote: str,
post_to_quote: str,
message: str = 'Check this out!',
image_url: str = DEFAULT_IMAGE_URL,
image_path: str | None = None,
image_alt: str = '',
image_aspect_ratio: tuple[int, int] = (1, 1), # width, height
) -> None:
"""Post an image while quoting another post."""
if bool(image_url) == bool(image_path):
raise ValueError('Exactly one of image_url or image_path must be provided')
client = Client()
client.login(settings.bsky_username, settings.bsky_password)
if image_path:
with open(image_path, 'rb') as f:
img_data = f.read()
else:
assert image_url is not None, 'image_url must be provided' # noqa: S101
img_data = httpx.get(image_url).content
if len(img_data) > 1_000_000:
raise ValueError(f'Image must be under 1MB. Got {len(img_data) / 1_000_000:.1f}MB')
uploaded_blob = client.upload_blob(img_data).blob
handle_response = client.resolve_handle(user_to_quote)
quote_post_uri = f'at://{handle_response.did}/app.bsky.feed.post/{post_to_quote}'
quoted_post = client.get_post(post_rkey=post_to_quote, profile_identify=handle_response.did)
assert quoted_post.cid is not None, 'Quoted post CID is required' # noqa: S101
client.send_post(
text=message,
embed=models.AppBskyEmbedRecordWithMedia.Main(
record=models.AppBskyEmbedRecord.Main(
record=models.ComAtprotoRepoStrongRef.Main(
uri=quote_post_uri,
cid=quoted_post.cid,
)
),
media=models.AppBskyEmbedImages.Main(
images=[
models.AppBskyEmbedImages.Image(
image=uploaded_blob,
alt=image_alt,
aspect_ratio=models.AppBskyEmbedDefs.AspectRatio(
width=image_aspect_ratio[0], height=image_aspect_ratio[1]
),
)
]
),
),
)
if __name__ == '__main__':
# Example usage
main(
user_to_quote='alternatebuild.dev',
post_to_quote='3lbydu5wsdk2h',
message='I scorn you! (from the atproto python client)',
image_alt='cat with a condescending glare',
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment