Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 49 additions & 8 deletions docs/social-media-scheduling.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ screenshotted with Puppeteer.

### Speaker cards

Speaker cards are generated per-session. Speakers with multiple qualifying
sessions (Talk, Tutorial, or other session types) get one card per session,
named `social-${slug}-${sessionCode}.png`. Single-session speakers get the
standard `social-${slug}.png`.

```bash
node scripts/download_social_speakers.cjs
```
Expand All @@ -59,6 +64,11 @@ Screenshots are saved to the current directory. Move them to the right place:
mv social-*.png public/media/speakers/
```

When regenerating, skip files that already exist to avoid overwriting images for
speakers whose posts are already scheduled. If a speaker previously had one
session and now has a second, delete the old generic `social-${slug}.png` after
the per-session images are committed.

### Sponsor & partner cards

```bash
Expand Down Expand Up @@ -102,8 +112,33 @@ Regenerate it by hitting the API endpoint while the dev server is running:
curl -s http://localhost:4321/api/media/combined_socials_queue > src/pages/api/media/combined_socials_queue.json
```

This overwrites `src/pages/api/media/combined_socials_queue.json` with all 150+
items sorted and interleaved.
This overwrites `src/pages/api/media/combined_socials_queue.json` with all items
sorted and interleaved.

> **Note:** There are two queue files:
>
> - `combined_socials_queue.json` — the freshly generated queue, used as the
> source of truth and read by `buffer-scheduling.py`
> - `combined_socials_queue_2026.json` — the manually curated queue that
> preserves already-scheduled posts at the top; new entries are appended after
> the last scheduled position

When new speakers or sponsors are added, regenerate
`combined_socials_queue.json` and then merge the new entries into
`combined_socials_queue_2026.json` manually — keeping already-posted entries
intact and appending only new/unposted ones.

### Session types and labels

The queue includes all qualifying session types — not just talks and tutorials.
The label used in post text is determined by session type:

- `"Talk"` / `"Talk (long session)"` → `"talk"`
- `"Tutorial"` → `"tutorial"`
- Everything else (Poster, Summit, etc.) → `"session"`

Speakers with multiple qualifying sessions get one queue entry per session, each
with its own per-session card image.

### Tier classification

Expand Down Expand Up @@ -238,9 +273,11 @@ python src/pages/api/media/buffer-scheduling.py
### Channel notes

- **Instagram**: requires `postType: post` — handled automatically
- **Sponsors/partners**: no Instagram channel (only x, linkedin, bsky,
- **TikTok**: supports photo posts with an optional `title` (set to the speaker
name) — handled automatically
- **Sponsors/partners**: no Instagram or TikTok channel (only x, linkedin, bsky,
fosstodon)
- **Speakers**: all 5 channels including Instagram
- **Speakers**: all 6 channels including Instagram and TikTok
- **Bluesky**: Buffer returns this as `"bluesky"` — normalized to `"bsky"`
automatically

Expand All @@ -249,12 +286,16 @@ python src/pages/api/media/buffer-scheduling.py
After each successful run, note the last `QUEUE_END` value. The next run should
set `QUEUE_START = previous QUEUE_END + 1`.

Already scheduled as of initial setup:
The script reads from `combined_socials_queue.json` by default. When switching
to the curated `combined_socials_queue_2026.json`, update `queue_path` in the
script accordingly.

Already scheduled as of June 2026:

- Positions 1–3: Abhik Sarkar, Abhimanyu Singh Shekhawat, Abigail Afi Gbadago
- Positions 1–67 in `combined_socials_queue_2026.json` (up to and including
PyGda partner post)

Next batch (positions 4–8): Adam Gorgoń, Alejandro Cabello Jiménez,
ActiveCampaign, Aleksander, 1Password
Next batch starts at position 68 (Giovanni Barillari).

---

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/media/speakers/social-cheuk-ting-ho.png
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/media/speakers/social-diego-russo.png
Binary file not shown.
Binary file added public/media/speakers/social-gyeongjae-choi.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/media/speakers/social-hood-chatham.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/media/speakers/social-jannis-leidel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
11 changes: 8 additions & 3 deletions scripts/download_social_speakers.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,16 @@ const puppeteer = require("puppeteer");
for (let i = 0; i < elements.length; i++) {
const el = elements[i];

// Get the slug from the element
// Get the slug and optional session code from the element
const slug = await page.evaluate((el) => el.getAttribute("data-slug"), el);
const code = await page.evaluate((el) => el.getAttribute("data-code"), el);

// Fallback if slug is missing
const filename = slug ? `social-${slug}.png` : `social-${i}.png`;
// Use session code suffix when present (multi-session speaker)
const filename = code
? `social-${slug}-${code}.png`
: slug
? `social-${slug}.png`
: `social-${i}.png`;

await el.screenshot({ path: filename });
console.log(`Saved ${filename}`);
Expand Down
7 changes: 5 additions & 2 deletions src/components/SocialMediaCard.astro
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
---
import { getEntries, type CollectionEntry } from "astro:content";

const { entry } = Astro.props;
const { entry, session } = Astro.props;

const sessions: CollectionEntry<"sessions">[]= await getEntries(entry.data.submissions);
// If a specific session is passed use it, otherwise fall back to all (legacy)
const sessions: CollectionEntry<"sessions">[] = session
? [session]
: await getEntries(entry.data.submissions);
---
<svg class="bg" width="900" height="900" class="h-full w-full -z-10">
<image href="/social/speaker_card.png" width="900" height="900" />
Expand Down
5 changes: 3 additions & 2 deletions src/pages/api/media/buffer-scheduling.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,9 @@
"text": text,
"schedulingType": "automatic",
"mode": "addToQueue",
"assets": [{"image": {"url": item["image"], "alt_text": item.get("alt_text", "")}}] if item.get("image") else [],
**({"metadata": {"instagram": {"type": "post", "shouldShareToFeed": True}}} if network == "instagram" else {})
"assets": [{"image": {"url": item["image"], "metadata": {"altText": item.get("alt_text", "")}}}] if item.get("image") else [],
**({"metadata": {"instagram": {"type": "post", "shouldShareToFeed": True}}} if network == "instagram" else {}),
**({"metadata": {"tiktok": {"title": item["name"]}}} if network == "tiktok" else {})
}
}

Expand Down
Loading
Loading