···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+**_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._**
4455## Overview
6677-This repository contains a Python script that automatically updates your Bluesky avatar (and, optionally, your banner) based on the current hour. The script utilises environment variables for configuration and reads a JSON file mapping blob CIDs to specific hours. In addition to updating your avatar, the script performs several supportive functions including a health check of the API endpoint, comprehensive logging (both to console and to a rotating file system that deletes logs older than 30 days), and the automatic setup of a cron job to ensure regular updates. 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).
77+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.
8899-Developed primarily on macOS and intended for Linux deployment, this tool is designed to run within a virtual environment to isolate dependencies and ensure smooth operation.
99+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.
10101111-## Prerequisites
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).
12121313-Before running the script, please ensure you have the following:
1313+> 🧶 Also available on [Tangled](https://tangled.org/ewancroft.uk/bluesky-avatar-updater)
14141515-- Python 3.6 or later installed. For Ubuntu, run:
1515+## Requirements
1616+1717+- 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`
16221717- ```bash
1818- sudo apt update && sudo apt install -y python3 python3-pip python3-dev
1919- ```
2323+Install the Python dependencies with:
20242121-- The following Python packages (automatically installed if missing):
2222- - `python-dotenv`
2323- - `atproto`
2424- - `requests`
2525- - `python-magic`
2626- - `python-crontab`
2727-- A valid Bluesky account with the necessary API credentials.
2828-- The script must be executed within a virtual environment.
2525+```bash
2626+pip install -r requirements.txt
2727+```
29283030-## Installation
2929+## Setup
31303232-1. **Clone the Repository:**
3131+1. Clone the repository:
33323433 ```bash
3534 git clone https://github.com/ewanc26/bluesky-avatar-updater.git
3635 cd bluesky-avatar-updater
3736 ```
38373939-2. **Ensure Virtual Environment Support:**
4040- On Debian/Ubuntu systems, ensure that the `python3-venv` package is installed:
4141-4242- ```bash
4343- sudo apt install python3-venv # Adjust the version if necessary (e.g., python3.10-venv)
4444- ```
4545-4646-3. **Create and Activate a Virtual Environment:**
3838+2. Create and activate a virtual environment:
47394840 ```bash
4941 python3 -m venv .venv
5050- source .venv/bin/activate # On Windows use: .venv\Scripts\activate
4242+ source .venv/bin/activate
5143 ```
52445353-4. **Install Dependencies:**
5454- With the virtual environment activated, install the required packages:
4545+3. Create `assets/.env` with:
55465656- ```bash
5757- pip install -r requirements.txt
4747+ ```env
4848+ ENDPOINT=your_endpoint
4949+ HANDLE=your_handle
5050+ PASSWORD=your_app_password
5151+ DID=your_did
5252+ UPDATE_BANNER=false
5853 ```
59546060-5. **Configure Environment Variables:**
6161- - Place your `.env` file in the `assets` directory.
6262- - The `.env` file should contain the following entries:
6363-6464- ```env
6565- ENDPOINT=your_endpoint
6666- HANDLE=your_handle
6767- PASSWORD=your_password # App passwords are recommended
6868- DID=your_did
6969- UPDATE_BANNER=true # Set to 'true' to update the banner, or 'false' otherwise
7070- ```
7171-7272-6. **Prepare the JSON File:**
7373- Ensure that a `cids.json` file is located in the `assets` directory. This file should map each hour (in two-digit format) to the corresponding blob CIDs for the avatar (and optionally, the banner). For example:
5555+4. Create `assets/cids.json` with hourly blob mappings:
74567557 ```json
7658 {
7777- "00": { "avatar": "cid_for_midnight", "banner": "banner_cid_for_midnight" },
5959+ "00": {
6060+ "avatar": "cid_for_midnight",
6161+ "banner": "banner_cid_for_midnight"
6262+ },
7863 "01": { "avatar": "cid_for_1am", "banner": "banner_cid_for_1am" }
7964 }
8065 ```
81668267## Usage
83688484-To run the script, execute:
6969+Run the updater from the repository root while the virtual environment is active:
85708671```bash
8772python -u ./src/main.py
8873```
89749090-Upon execution, the script will:
7575+On start-up, the script will:
91769292-- Verify that it is running within a virtual environment.
9393-- Load environment variables from the `.env` file located in the `assets` directory.
9494-- Read the blob CIDs from the `cids.json` file.
9595-- Determine the current hour and select the appropriate blob CIDs.
9696-- Perform a health check on the provided API endpoint.
9797-- Authenticate using the AT Protocol and update your Bluesky profile with the new avatar (and banner, if enabled).
9898-- Automatically set up a cron job to run the script every hour.
9999-- Log activity to both the console and a rotating log file in the `logs` directory. The log file rotates every 14 days (with up to 5 backups) and automatically deletes files older than 30 days.
7777+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
10084101101-## Automating with Cron (Linux)
8585+## Notes
10286103103-The script is designed to automatically configure a cron job to run at the top of every hour. To verify the cron job, use:
104104-105105-```bash
106106-crontab -l
107107-```
108108-109109-If you prefer to manually set up or modify the cron job, follow these steps:
110110-111111-1. Open the crontab editor:
112112-113113- ```bash
114114- crontab -e
115115- ```
116116-117117-2. Add the following line (adjusting paths as necessary):
118118-119119- ```bash
120120- 0 * * * * /path/to/your/.venv/bin/python3 /path/to/bluesky-avatar-updater/src/main.py
121121- ```
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`.
1229012391## Troubleshooting
12492125125-- **Virtual Environment Issues:** The script will exit if it is not run within a virtual environment. Ensure you activate your virtual environment before running the script.
126126-- **Environment Variables Not Loading:** Verify that the `.env` file is correctly placed in the `assets` directory and contains all required entries.
127127-- **Missing Dependencies:** If the script encounters missing packages, run:
128128-129129- ```bash
130130- pip install -r requirements.txt
131131- ```
132132-133133- within your virtual environment.
134134-- **Endpoint Issues:** Ensure that the provided API endpoint is correct and accessible. The script performs a health check and will log an error if the endpoint is unresponsive.
135135-- **Cron Job Not Running:** If the cron job is not automatically set up, check with `crontab -l` or set it up manually using `crontab -e`.
136136-- **Log File Management:** The script manages log rotation and deletion automatically. If logs are not being deleted as expected, verify the file permissions in the `logs` directory.
9393+- 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.
1379713898## License
13999