Skip to content

Commit b19d659

Browse files
Zapier conversion (#130)
1 parent 44f294b commit b19d659

File tree

15 files changed

+7383
-7387
lines changed

15 files changed

+7383
-7387
lines changed

.github/INSTALL_DEPENDENCIES.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Install Additional Dependencies for Syndication
2+
3+
To set up the syndication workflow, you'll need to install these additional npm packages:
4+
5+
```bash
6+
npm install axios cheerio html-to-text dotenv
7+
```
8+
9+
These dependencies provide:
10+
- `axios` - HTTP client for API requests
11+
- `cheerio` - Server-side jQuery for HTML parsing
12+
- `html-to-text` - Convert HTML to plain text
13+
- `dotenv` - Environment variable management (for local testing)
14+
15+
## Testing Locally
16+
17+
Create a `.env` file in your project root for testing (DO NOT commit this file):
18+
19+
```bash
20+
# .env file for local testing
21+
SITE_URL=https://www.aaron-gustafson.com
22+
POSTS_FEED_URL=https://www.aaron-gustafson.com/feeds/latest-posts.json
23+
LINKS_FEED_URL=https://www.aaron-gustafson.com/feeds/latest-links.json
24+
25+
# API Keys (use your actual keys for testing)
26+
LINKEDIN_ACCESS_TOKEN=your_test_token
27+
MASTODON_ACCESS_TOKEN=your_test_token
28+
MASTODON_SERVER_URL=https://front-end.social
29+
BUFFER_ACCESS_TOKEN=your_test_token
30+
BUFFER_TWITTER_PROFILE_ID=your_profile_id
31+
BUFFER_BLUESKY_PROFILE_ID=your_profile_id
32+
PINTEREST_ACCESS_TOKEN=your_test_token
33+
PINTEREST_BOARD_ID=your_board_id
34+
SCREENSHOT_API_KEY=your_api_key
35+
IFTTT_WEBHOOK_KEY=your_webhook_key
36+
```
37+
38+
Then test locally:
39+
```bash
40+
# Load environment variables and test
41+
node -r dotenv/config .github/scripts/syndicate-posts.js
42+
node -r dotenv/config .github/scripts/syndicate-links.js
43+
```

.github/SYNDICATION_SETUP.md

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
# Social Media Syndication Setup Guide
2+
3+
This guide explains how to set up the GitHub Actions workflow to replace your Zapier automation for syndicating blog posts and links to social media platforms.
4+
5+
## GitHub Repository Secrets
6+
7+
Add these secrets to your GitHub repository settings (Settings → Secrets and variables → Actions):
8+
9+
### Required Secrets
10+
11+
#### IFTTT (Required for LinkedIn & Pinterest)
12+
```
13+
IFTTT_KEY=your_ifttt_webhook_key
14+
```
15+
16+
**Note**: LinkedIn and Pinterest use IFTTT webhooks due to API limitations.
17+
18+
#### Mastodon API
19+
```
20+
MASTODON_ACCESS_TOKEN=your_mastodon_access_token
21+
MASTODON_SERVER_URL=https://front-end.social # Your Mastodon instance
22+
```
23+
24+
#### Buffer API (for Twitter & Bluesky)
25+
```
26+
BUFFER_ACCESS_TOKEN=your_buffer_access_token
27+
BUFFER_TWITTER_PROFILE_ID=your_twitter_profile_id
28+
BUFFER_BLUESKY_PROFILE_ID=your_bluesky_profile_id
29+
```
30+
31+
### Optional Secrets
32+
33+
#### Screenshot Service
34+
```
35+
SCREENSHOT_API_KEY=your_screenshotmachine_api_key
36+
```
37+
38+
## Syndication Platform Summary
39+
40+
The workflow syndicates content to the following platforms:
41+
42+
**Blog Posts:**
43+
- ✅ LinkedIn (via IFTTT)
44+
- ✅ Mastodon (via Mastodon API)
45+
- ✅ Twitter (via Buffer API)
46+
- ✅ Bluesky (via Buffer API)
47+
48+
**Link Shares:**
49+
- ✅ LinkedIn (via IFTTT)
50+
- ✅ Pinterest (via IFTTT)
51+
- ✅ Mastodon (via Mastodon API)
52+
- ✅ Twitter (via Buffer API)
53+
- ✅ Bluesky (via Buffer API)
54+
55+
**Important**: The workflow only syndicates items published today to prevent re-posting old content.
56+
57+
## API Setup Instructions
58+
59+
### 1. Mastodon API Setup
60+
61+
1. Go to your Mastodon instance settings (e.g., https://front-end.social/settings/applications)
62+
2. Create new application with these scopes:
63+
- `read` - Read account data
64+
- `write:statuses` - Post statuses
65+
- `write:media` - Upload media
66+
3. Copy the access token
67+
68+
### 2. Buffer API Setup
69+
70+
1. Go to [Buffer Developers](https://buffer.com/developers/api)
71+
2. Create an application and get access token
72+
3. Get your profile IDs:
73+
```bash
74+
curl -X GET "https://api.bufferapp.com/1/profiles.json?access_token=YOUR_TOKEN"
75+
```
76+
4. Find the IDs for your Twitter and Bluesky profiles
77+
78+
### 3. Screenshot Service (Optional)
79+
80+
1. Sign up at [Screenshot Machine](https://www.screenshotmachine.com/)
81+
2. Get your API key from the dashboard
82+
3. Or use alternative services like:
83+
- [URLBox](https://urlbox.io/)
84+
- [Bannerbear](https://www.bannerbear.com/)
85+
- [Htmlcsstoimage](https://htmlcsstoimage.com/)
86+
87+
### 4. IFTTT Setup (Required for LinkedIn & Pinterest)
88+
89+
1. Create IFTTT account and go to [Webhooks service](https://ifttt.com/maker_webhooks)
90+
2. Get your webhook key
91+
3. Create applets for each social platform:
92+
- **`linkedin_post`** → LinkedIn post (blog articles)
93+
- **`linkedin_link`** → LinkedIn link post (shared links)
94+
- **`pinterest_pin`** → Pinterest pin (link shares)
95+
- `twitter_post` → Twitter/X post (optional fallback for posts)
96+
- `twitter_link` → Twitter/X link post (optional fallback for links)
97+
98+
**Note**: Bluesky and Mastodon do not have IFTTT integrations, so they rely entirely on their respective APIs.
99+
100+
**LinkedIn IFTTT Webhook Payload Example:**
101+
```json
102+
{
103+
"value1": "Article Title",
104+
"value2": "https://www.aaron-gustafson.com/notebook/article-slug/",
105+
"value3": "Brief excerpt or tags"
106+
}
107+
```
108+
109+
In the IFTTT LinkedIn action (Share a link):
110+
- **Link URL**: `{{Value2}}`
111+
- **Comment**: `{{Value1}}\n\n{{Value3}}`
112+
113+
**Pinterest IFTTT Webhook Payload Example:**
114+
```json
115+
{
116+
"value1": "Link Title",
117+
"value2": "https://external-url.com/article",
118+
"value3": "Your commentary or description"
119+
}
120+
```
121+
122+
In the IFTTT Pinterest action (Create a pin):
123+
- **Image URL**: `https://api.screenshotmachine.com?key=YOUR_KEY&dimension=1000x1500&url={{Value2}}`
124+
- **Link**: `{{Value2}}`
125+
- **Description**: `{{Value1}}\n\n{{Value3}}`
126+
- **Board**: Select your Reading List board
127+
128+
## Netlify Webhook Setup
129+
130+
Configure Netlify to trigger the GitHub workflow after successful deployments:
131+
132+
### Option 1: Netlify Build Hook (Recommended)
133+
134+
1. In your Netlify site settings, go to Build & Deploy → Build hooks
135+
2. Create a new build hook with URL pointing to GitHub:
136+
```
137+
https://api.github.com/repos/aarongustafson/aaron-gustafson.com/dispatches
138+
```
139+
3. Add this to your `netlify.toml`:
140+
```toml
141+
[[plugins]]
142+
package = "netlify-plugin-github-dispatch"
143+
[plugins.inputs]
144+
repo = "aarongustafson/aaron-gustafson.com"
145+
token = "${GITHUB_ACCESS_TOKEN}"
146+
event = "netlify-deploy-succeeded"
147+
```
148+
149+
**Note**: The Netlify environment variable should be named `GITHUB_ACCESS_TOKEN`.
150+
151+
### Option 2: Custom Function
152+
153+
Create `.netlify/functions/github-dispatch.js`:
154+
```javascript
155+
exports.handler = async (event, context) => {
156+
if (event.httpMethod !== 'POST') {
157+
return { statusCode: 405, body: 'Method Not Allowed' };
158+
}
159+
160+
const { default: fetch } = await import('node-fetch');
161+
162+
try {
163+
const response = await fetch(
164+
'https://api.github.com/repos/aarongustafson/aaron-gustafson.com/dispatches',
165+
{
166+
method: 'POST',
167+
headers: {
168+
'Authorization': `token ${process.env.GITHUB_ACCESS_TOKEN}`,
169+
'Content-Type': 'application/json',
170+
'User-Agent': 'Netlify-Function'
171+
},
172+
body: JSON.stringify({
173+
event_type: 'netlify-deploy-succeeded',
174+
client_payload: {
175+
site_id: event.headers['x-netlify-site-id'],
176+
deploy_id: event.headers['x-netlify-deploy-id']
177+
}
178+
})
179+
}
180+
);
181+
182+
return {
183+
statusCode: response.ok ? 200 : 500,
184+
body: JSON.stringify({
185+
success: response.ok,
186+
status: response.status
187+
})
188+
};
189+
} catch (error) {
190+
return {
191+
statusCode: 500,
192+
body: JSON.stringify({ error: error.message })
193+
};
194+
}
195+
};
196+
```
197+
198+
### Option 3: Webhook to GitHub Repository Dispatch
199+
200+
1. Go to your repository settings → Webhooks
201+
2. Add webhook with:
202+
- Payload URL: `https://your-site.netlify.app/.netlify/functions/github-dispatch`
203+
- Content type: `application/json`
204+
- Events: `deployment_status`
205+
206+
## Testing
207+
208+
### Manual Testing
209+
```bash
210+
# Test from repository root
211+
node .github/scripts/syndicate-posts.js
212+
node .github/scripts/syndicate-links.js
213+
```
214+
215+
### GitHub Actions Manual Trigger
216+
1. Go to Actions tab in your repository
217+
2. Select "Syndicate Content to Social Media" workflow
218+
3. Click "Run workflow"
219+
4. Choose content type (posts/links/both)
220+
221+
## Monitoring
222+
223+
The workflow will:
224+
- ✅ Log detailed progress and results
225+
- ❌ Report errors to GitHub Actions logs
226+
- 🔄 Use IFTTT as fallback for failed API calls
227+
- 💾 Cache processed items to prevent duplicates
228+
- ⏰ Run backup checks every 30 minutes
229+
- 📅 Only syndicate items published today (prevents re-posting old content)
230+
231+
## Migration from Zapier
232+
233+
1. ✅ Set up all API credentials as GitHub secrets
234+
2. ✅ Configure Netlify webhook to GitHub
235+
3. ✅ Test the workflow manually
236+
4. ✅ Monitor first few automated runs
237+
5. ✅ Disable Zapier workflows once confident
238+
239+
## Troubleshooting
240+
241+
### Common Issues
242+
243+
1. **Rate Limiting**: APIs have rate limits. The workflow spaces out requests.
244+
2. **Token Expiry**: Some tokens expire. Monitor and refresh as needed.
245+
3. **Content Formatting**: Test with various post types to ensure formatting works.
246+
247+
### Logs and Debugging
248+
249+
- Check GitHub Actions logs for detailed error messages
250+
- Each platform logs success/failure separately
251+
- IFTTT fallbacks are logged when triggered
252+
253+
### Platform-Specific Notes
254+
255+
- **LinkedIn**: Requires IFTTT (API limitations for most developers)
256+
- **Pinterest**: Requires IFTTT (simpler integration with screenshot generation)
257+
- **Mastodon**: Direct API only (no IFTTT integration available)
258+
- **Bluesky**: Via Buffer API only (no IFTTT integration available)
259+
- **Twitter/X**: Via Buffer API with IFTTT fallback option
260+
- **Buffer**: Profile IDs change if you reconnect accounts

0 commit comments

Comments
 (0)