···11# Bluesky Avatar Updater
2233-**_This repository is available on [GitHub](https://github.com/ewanc26/bluesky-avatar-updater) and [Tangled](https://tangled.sh/did:plc:ofrbh253gwicbkc5nktqepol/bluesky-avatar-updater). GitHub is the primary version, and the Tangled version is a mirror._**
33+[](http://unmaintained.tech/)
4455-## Overview
55+A Rust tool to automatically rotate your Bluesky profile avatar and banner every hour.
6677-This repository contains a Python script that updates a Bluesky profile avatar, and optionally a banner, based on the current hour. It looks up blob CIDs in `assets/cids.json`, fetches the blobs from the configured endpoint, and updates the profile record through the AT Protocol.
77+## Features
8899-The script also performs a health check against the endpoint, writes logs to `logs/update.log`, rotates logs every 14 days with up to 5 backups, removes old logs older than 30 days at startup, and installs an hourly cron job so the update runs automatically.
1010-1111-This project was inspired by [@dame.is](https://bsky.app/profile/dame.is)'s blog post ['How I made an automated dynamic avatar for my Bluesky profile'](https://dame.is/blog/how-i-made-an-automated-dynamic-avatar-for-my-bluesky-profile).
1212-1313-> 🧶 Also available on [Tangled](https://tangled.org/ewancroft.uk/bluesky-avatar-updater)
99+- **Automated Rotation**: Automatically updates your profile assets every hour.
1010+- **Environment Support**: Loads configuration from `.env` files.
1111+- **Logging**: Robust file logging with 14-day rotation.
1212+- **Cron Integration**: Self-installs as an hourly cron job for persistent updates.
1313+- **Asset Mapping**: Supports detailed hourly CID mapping for both avatar and banner.
14141515## Requirements
16161717-- Python 3.6 or later
1818-- A virtual environment
1919-- Python packages from `requirements.txt`
2020-- A valid Bluesky account with app password access
2121-- A working AT Protocol endpoint that serves the blobs referenced in `cids.json`
1717+To run this project, you will need the following:
22182323-Install the Python dependencies with:
2424-2525-```bash
2626-pip install -r requirements.txt
2727-```
1919+- Rust 1.85+ (Cargo)
28202929-## Setup
2121+## Installation
302231231. Clone the repository:
3224···3527 cd bluesky-avatar-updater
3628 ```
37293838-2. Create and activate a virtual environment:
3030+2. Build the project:
39314032 ```bash
4141- python3 -m venv .venv
4242- source .venv/bin/activate
3333+ cargo build --release
4334 ```
44354545-3. Create `assets/.env` with:
3636+3. Create a `.env` file in the `assets/` directory (or the root) and add your environment variables:
46374747- ```env
4848- ENDPOINT=your_endpoint
4949- HANDLE=your_handle
3838+ ```plaintext
3939+ ENDPOINT=https://bsky.social
4040+ HANDLE=your_handle.bsky.social
5041 PASSWORD=your_app_password
5151- DID=your_did
4242+ DID=did:plc:your_did
5243 UPDATE_BANNER=false
5344 ```
5445···66576758## Usage
68596969-Run the updater from the repository root while the virtual environment is active:
6060+Run the updater from the repository root:
70617162```bash
7272-python -u ./src/main.py
6363+cargo run --release
7364```
74657566On start-up, the script will:
76677777-1. Verify that it is running inside a virtual environment
7878-2. Load `assets/.env`
7979-3. Confirm the endpoint is healthy
8080-4. Read the CID mapping from `assets/cids.json`
8181-5. Select the avatar CID for the current hour
8282-6. Log in to Bluesky and update the profile record
8383-7. Ensure an hourly cron job exists for future runs
8484-8585-## Notes
8686-8787-- `UPDATE_BANNER=true` enables banner updates when a banner CID is present for the current hour.
8888-- The endpoint value is normalised to HTTPS if necessary.
8989-- The script expects the endpoint to support `/_health` and `com.atproto.sync.getBlob`.
6868+1. Load configuration and environment variables.
6969+2. Confirm the endpoint is healthy.
7070+3. Read the CID mapping from `assets/cids.json`.
7171+4. Select the avatar/banner CID for the current hour.
7272+5. Log in to Bluesky and update the profile record.
7373+6. Ensure an hourly cron job exists for future runs.
90749191-## Troubleshooting
7575+## File Structure
92769393-- If the script exits immediately, double-check that the virtual environment is active.
9494-- If authentication fails, confirm the handle and app password are correct.
9595-- If blob fetching fails, make sure the endpoint can access the DID/CID pair in `cids.json`.
9696-- If cron does not install, verify that `python-crontab` is available in the virtual environment.
7777+- `src/main.rs`: Main orchestration.
7878+- `src/bsky.rs`: Bluesky API and blob handling.
7979+- `src/cron.rs`: Cron job management.
8080+- `src/utils.rs`: Utility functions and environment validation.
8181+- `assets/cids.json`: Mapping of hours to avatar and banner CIDs.
97829883## License
9984100100-This project is released under the MIT License. Please refer to the [LICENSE](./LICENSE) file for full details.
8585+This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
1018610287## ☕ Support
10388