Skip to content

Instantly share code, notes, and snippets.

@hwayne
Last active April 11, 2025 18:09
Show Gist options
  • Save hwayne/511506d2426f2aa7623e99ee3393d25f to your computer and use it in GitHub Desktop.
Save hwayne/511506d2426f2aa7623e99ee3393d25f to your computer and use it in GitHub Desktop.
Bsky spinner

Bsky spinner

Spins your avatar like a clock

https://bsky.app/settings/app-passwords

Disclaimer: I set this up locally half a year ago and forgot all the steps, so the steps below may be wrong.

To run locally

  1. Set up a virtualenv and activate it
  2. pip install -r requirements.txt
  3. Get an app password from https://bsky.app/settings/app-passwords
  4. Add BSKY_USERNAME, BSKY_PASSWORD, and AVATAR_URL to your enviromental variables, or ride the lightning and hardcode it in
  5. Uncomment the # run line at the bottom
  6. Call with python spinner.py
  7. Ask an LLM "write a script to call python spinner.py every two minutes", and then never turn your computer off

To run on AWS Lambda

Only do this if you're at least a little bit comfortable with AWS.

  1. Do steps 1-3 of "To run Locally"
  2. zappa init
  3. zappa package dev
  4. Create a lambda and "upload from zip file"
  5. Set the environmental variables in the configuration tab, under environmental variables
  6. In configuration > trigger, click "add trigger", select "eventbridge (cloudwatch events)".
  7. Set the "schedule expression" as rate(2 minutes).

To run on Azure

¯\_(ツ)_/¯

annotated-types==0.7.0
anyio==4.6.2.post1
argcomplete==3.5.1
atproto==0.0.55
boto3==1.35.71
botocore==1.35.71
certifi==2024.8.30
cffi==1.17.1
cfn-flip==1.3.0
charset-normalizer==3.4.0
click==8.1.7
colorama==0.4.6
cryptography==43.0.3
dnspython==2.7.0
durationpy==0.9
exceptiongroup==1.2.2
h11==0.14.0
hjson==3.1.0
httpcore==1.0.7
httpx==0.27.2
idna==3.10
jmespath==1.0.1
kappa==0.6.0
libipld==3.0.0
MarkupSafe==3.0.2
pillow==11.0.0
placebo==0.9.0
pycparser==2.22
pydantic==2.10.2
pydantic_core==2.27.1
python-dateutil==2.9.0.post0
python-slugify==8.0.4
PyYAML==6.0.2
requests==2.32.3
s3transfer==0.10.4
six==1.16.0
sniffio==1.3.1
text-unidecode==1.3
toml==0.10.2
tqdm==4.67.1
troposphere==4.8.3
typing_extensions==4.12.2
urllib3==2.2.3
websockets==13.1
Werkzeug==3.1.3
zappa==0.59.0
from atproto import Client, models
from atproto.exceptions import BadRequestError
from PIL import Image
from requests import get
from datetime import datetime
from os import getenv
import io
def run(*args, **kwargs) -> str:
username = getenv("BSKY_USERNAME")
password = getenv("BSKY_PASSWORD") # https://bsky.app/settings/app-passwords
avatar = getenv("AVATAR_URL")
client = Client()
client.login(username, password)
current_profile_record = client.app.bsky.actor.profile.get(client.me.did, 'self')
current_profile = current_profile_record.value
swap_record_cid = current_profile_record.cid
url_image = get(avatar, stream=True).raw
image = Image.open(url_image).rotate(-(360/60 * datetime.now().minute))
img_as_bytestream = io.BytesIO()
image.save(img_as_bytestream, format="png")
resp = client.upload_blob(img_as_bytestream.getvalue())
client.com.atproto.repo.put_record(
models.ComAtprotoRepoPutRecord.Data(
collection=models.ids.AppBskyActorProfile,
repo=client.me.did,
rkey='self',
swap_record=swap_record_cid,
record=models.AppBskyActorProfile.Record(
avatar=resp.blob,
banner=current_profile.banner,
description=current_profile.description,
display_name=current_profile.display_name
),
)
)
return "success"
# run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment