Skip to content

Commit ffb4f75

Browse files
committed
add docs
1 parent 840fd32 commit ffb4f75

1 file changed

Lines changed: 143 additions & 0 deletions

File tree

docs/keynoter-scheduling.md

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# Keynoter Social Media Scheduling
2+
3+
This document describes the process for scheduling keynote speaker
4+
announcement posts to Buffer. In short, you should:
5+
* prepare the images in canva and deploy them to have a live url to the image
6+
* prepare copy for each platform and put it into a json file
7+
* run the script to schedule posts for the keynoters, one at a time, to all the supported social media platform
8+
9+
The script posts to all connected channels in one run per keynoter:
10+
`instagram`, `linkedin`, `fosstodon`, `bsky`, `x`, `tiktok`.
11+
12+
---
13+
14+
## Prerequisites
15+
16+
- Python environment with `requests` and `python-dotenv` installed
17+
- A `.env.local` file in the **repo root** with your Buffer API key:
18+
19+
```
20+
BUFFER_API_KEY=your_buffer_api_key_here
21+
```
22+
23+
24+
### Getting the Buffer API key
25+
26+
1. Log in to [buffer.com](https://buffer.com) with the EuroPython account
27+
2. Go to **Account Settings → Apps & Integrations**
28+
3. Copy the personal access token under **Access Token**
29+
4. Paste it as `BUFFER_API_KEY` in `.env.local`
30+
31+
32+
---
33+
34+
## Step 1 — Prepare and deploy the images
35+
36+
Buffer requires a **publicly accessible image URL** — local file paths, Google
37+
Drive links, and Canva share links do not work. The image must be hosted on the
38+
live site before the script can use it.
39+
40+
### Prepare the images
41+
42+
- Export images as PNG from your design tool (Canva)
43+
- Name them `firstname-lastname.png` (lowercase, hyphenated)
44+
- Place them in `website/public/media/keynoters/`
45+
46+
### Deploy
47+
48+
1. Commit the images and open a PR
49+
2. Wait for the PR to be merged and deployed to production
50+
3. Verify each image is accessible, e.g.:
51+
`https://ep2026.europython.eu/media/keynoters/leah-wasser.png`
52+
53+
> ⚠️ Do not run the scheduling script until the images are live. Buffer fetches
54+
> the URL at scheduling time and will fail with a "Not Found" error if the file
55+
> hasn't been deployed yet.
56+
57+
## Step 2 — Prepare the post copy (`keynoters.json`)
58+
59+
All post text lives in `keynoters.json`
60+
61+
```json
62+
{
63+
"Speaker Name": {
64+
"image": "https://ep<year>.europython.eu/media/keynoters/firstname-lastname.png",
65+
"instagram": "Post text for Instagram...",
66+
"linkedin": "Post text for LinkedIn...",
67+
"fosstodon": "Post text for Fosstodon/Mastodon...",
68+
"bsky": "Post text for Bluesky...",
69+
"x": "Post text for X/Twitter...",
70+
"tiktok": "Post text for TikTok..."
71+
}
72+
}
73+
```
74+
75+
A few things to keep in mind when writing copy:
76+
77+
- Social handles (e.g. `@leahawasser.bsky.social`) go **inline in the post text**,
78+
not as separate fields. Each platform's post should use the handle format native
79+
to that platform.
80+
- X and Bluesky have character limits — keep those posts short.
81+
- Instagram and TikTok don't render clickable URLs, so use the short form
82+
(`europython.eu/tickets/`) rather than the full URL.
83+
- LinkedIn and Fosstodon support full clickable URLs.
84+
85+
Add one entry per keynoter. The key must match exactly what you'll set in the
86+
script in Step 3.
87+
---
88+
89+
## Step 3 — Schedule posts via Buffer
90+
91+
The scheduling script is `buffer-keynoters.py`.
92+
Run it once per keynoter.
93+
94+
### Configure the script
95+
96+
Open `buffer-keynoters.py` and edit the two lines at the top:
97+
98+
```python
99+
KEYNOTER = "Leah Wasser" # must match the key in keynoters.json exactly
100+
SCHEDULED_AT = datetime(2026, 6, 16, 10, 0,
101+
tzinfo=ZoneInfo("Europe/London"))
102+
```
103+
104+
Set `SCHEDULED_AT` to the date and time you want the post to go live. The
105+
timezone is `Europe/London` — adjust the year, month, day, hour, and minute
106+
as needed.
107+
108+
### Preview before posting
109+
110+
```bash
111+
python buffer-keynoters.py --dry-run
112+
```
113+
114+
This prints the first 200 characters of the post for each platform without
115+
sending anything to Buffer. Use it to sanity-check the copy and confirm the
116+
right keynoter is selected.
117+
118+
### Run
119+
120+
```bash
121+
python buffer-keynoters.py
122+
```
123+
124+
The script will:
125+
126+
1. Connect to Buffer and fetch your channel IDs
127+
2. Fetch the image from the live URL in `keynoters.json`
128+
3. Schedule the post to every platform that has text defined
129+
4. Skip any platform not connected in your Buffer account
130+
5. Print a confirmation line with the Buffer post ID for each channel
131+
132+
Repeat for each keynoter, updating `KEYNOTER` and `SCHEDULED_AT` each time.
133+
134+
---
135+
136+
## Troubleshooting
137+
138+
| Error | Cause | Fix |
139+
|---|---|---|
140+
| `BUFFER_API_KEY not set` | Missing `.env.local` | Create `website/.env.local` with the key |
141+
| `Image upload failed (404)` | Image not deployed yet | Merge the images PR and wait for deployment |
142+
| `not connected in Buffer — skipped` | Channel not linked in Buffer | Log in to Buffer and connect the missing channel |
143+
| `not found in keynoters.json` | Typo in `KEYNOTER` | Check the exact key spelling in `keynoters.json` |

0 commit comments

Comments
 (0)