
Automatické sdílení článků na X a Facebook přes GitHub Actions
Jak nastavit GitHub Actions workflow pro automatické publikování nových článků na sociální sítě po deployi.
Publikujete článek a pak ho ručně sdílíte na X, Facebook, LinkedIn? Tenhle proces lze snadno automatisovat pomocí GitHub Actions. Po každém deployi se nový článek automaticky publikuje na sociální sítě.
Předpoklady
Toto řešení předpokládá, že obsah webu spravujete přes Git. Články jsou uložené jako soubory v repozitáři (např. Markdown v content/posts/) a publikování probíhá přes push do main branch. Workflow detekuje nové články pomocí git diff, takže bez Gitu to nefunguje.
Nejpracnější část celého nastavení je získání API klíčů od jednotlivých platforem. X i Facebook mají komplikovaná vývojářská rozhraní, kde se člověk snadno ztratí. Počítejte s tím, že proklikávání formulářů, nastavování oprávnění a generování tokenů zabere víc času než samotné psaní workflow.
Jak to funguje
Workflow se spouští po úspěšném Vercel deployi pomocí deployment_status eventu:
- Vercel dokončí deploy a pošle status do GitHubu
- GitHub Actions workflow detekuje nové články pomocí
git diff - Pro každý nový článek zavolá API sociálních sítí
- Uloží seznam publikovaných článků, aby se předešlo duplicitám
Základní workflow
name: Share New Articles on Social Media
on:
deployment_status:
jobs:
share-articles:
runs-on: ubuntu-latest
if: |
github.event.deployment_status.state == 'success' &&
github.event.deployment.environment == 'Production'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Detect new articles
id: detect
run: |
node scripts/social/get-new-articles.js --json > new-articles.json
ARTICLE_COUNT=$(node -e "console.log(require('./new-articles.json').articles.length)")
echo "article_count=$ARTICLE_COUNT" >> $GITHUB_OUTPUT
echo "has_articles=$([[ $ARTICLE_COUNT -gt 0 ]] && echo true || echo false)" >> $GITHUB_OUTPUT
- name: Post to X (Twitter)
if: steps.detect.outputs.has_articles == 'true'
env:
X_API_KEY: ${{ secrets.X_API_KEY }}
X_API_SECRET: ${{ secrets.X_API_SECRET }}
X_ACCESS_TOKEN: ${{ secrets.X_ACCESS_TOKEN }}
X_ACCESS_TOKEN_SECRET: ${{ secrets.X_ACCESS_TOKEN_SECRET }}
run: node scripts/social/post-to-x.js
- name: Post to Facebook
if: steps.detect.outputs.has_articles == 'true'
env:
FACEBOOK_PAGE_ID: ${{ secrets.FACEBOOK_PAGE_ID }}
FACEBOOK_ACCESS_TOKEN: ${{ secrets.FACEBOOK_ACCESS_TOKEN }}
run: node scripts/social/post-to-facebook.js
Detekce nových článků
Klíčem je správně detekovat pouze nově přidané články, ne upravené. Používáme git diff s filtrem --diff-filter=A (Added):
git diff --name-only --diff-filter=A HEAD~1..HEAD -- 'content/posts/*.md'
Tím získáme seznam souborů, které byly přidány v posledním commitu. Důležité je fetch-depth: 2 v checkout action, jinak nemáme historii pro porovnání.
Nastavení X (Twitter) API
X používá OAuth 1.0a, což vyžaduje 4 klíče:
- Vytvořte aplikaci na X Developer Portal
- V User authentication settings nastavte Read and write oprávnění
- Vygenerujte API Key, API Secret, Access Token a Access Token Secret
Důležité: Access Token musí být vygenerován po nastavení Read and write oprávnění. Pokud změníte oprávnění, musíte token regenerovat.
OAuth 1.0a signature
X API vyžaduje podepsané požadavky. Signature se generuje takto:
function generateOAuthSignature(method, url, params, consumerSecret, tokenSecret) {
const sortedParams = Object.keys(params)
.sort()
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
.join('&');
const signatureBaseString = [
method.toUpperCase(),
encodeURIComponent(url),
encodeURIComponent(sortedParams)
].join('&');
const signingKey = `${encodeURIComponent(consumerSecret)}&${encodeURIComponent(tokenSecret)}`;
return crypto.createHmac('sha1', signingKey)
.update(signatureBaseString)
.digest('base64');
}
Nastavení Facebook API
Facebook je jednodušší - stačí Page Access Token:
- Vytvořte aplikaci na Facebook Developers
- V Graph API Explorer vygenerujte token s oprávněním
pages_manage_posts - Převeďte na dlouhodobý token (viz níže)
Permanentní Page Access Token
Krátkodobý token vyprší za pár hodin. Pro automatisaci potřebujete permanentní:
# 1. Převeďte user token na dlouhodobý (60 dní)
GET /oauth/access_token?
grant_type=fb_exchange_token&
client_id={APP_ID}&
client_secret={APP_SECRET}&
fb_exchange_token={SHORT_TOKEN}
# 2. Získejte permanentní page token
GET /{PAGE_ID}?fields=access_token&access_token={LONG_LIVED_USER_TOKEN}
Výsledný token nevyprší, dokud nezměníte heslo nebo neodeberete oprávnění aplikaci.
Publikování na Facebook
const response = await fetch(
`https://graph.facebook.com/v19.0/${pageId}/feed`,
{
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
message: 'Text příspěvku',
link: 'https://example.com/clanek',
access_token: pageAccessToken
})
}
);
Prevence duplicit
Při re-runu workflow by se článek publikoval znovu. Řešením je tracking soubor:
// .github/shared-articles.json
{
"articles": ["slug-clanku-1", "slug-clanku-2"]
}
Před publikováním zkontrolujeme, zda článek už není v seznamu:
function getSharedArticles() {
const filePath = '.github/shared-articles.json';
if (!fs.existsSync(filePath)) return new Set();
const data = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
return new Set(data.articles || []);
}
// Filtrování nových článků
const sharedArticles = getSharedArticles();
const newArticles = articles.filter(a => !sharedArticles.has(a.slug));
Po úspěšném publikování přidáme slug do souboru a commitneme:
- name: Commit shared articles tracking
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add .github/shared-articles.json
git diff --staged --quiet || git commit -m "chore: mark articles as shared [skip ci]"
git push
Důležitý je [skip ci] v commit message - zabrání spuštění dalšího workflow a Vercel rebuildu.
GitHub Secrets
Všechny API klíče uložte v Settings → Secrets and variables → Actions:
| Secret | Popis |
|---|---|
X_API_KEY | X API Key (Consumer Key) |
X_API_SECRET | X API Secret |
X_ACCESS_TOKEN | X Access Token (s Read+Write) |
X_ACCESS_TOKEN_SECRET | X Access Token Secret |
FACEBOOK_PAGE_ID | ID vaší Facebook stránky |
FACEBOOK_ACCESS_TOKEN | Permanentní Page Access Token |
Debugging
Nejčastější chyby:
- X 401 Unauthorized - Access Token má špatná oprávnění. Zkontrolujte, že je "Read and write" a regenerujte token.
- Facebook (#200) Permissions error - Token nemá oprávnění
pages_manage_posts. - Článek se nepublikuje - Zkontrolujte, že
fetch-depth: 2je nastaveno a článek mástatus: 1.
Pro lokální testování:
# X
export X_API_KEY="..." X_API_SECRET="..." X_ACCESS_TOKEN="..." X_ACCESS_TOKEN_SECRET="..."
node scripts/social/post-to-x.js --article='{"title":"Test","url":"https://example.com","tags":["test"]}'
# Facebook
export FACEBOOK_PAGE_ID="..." FACEBOOK_ACCESS_TOKEN="..."
node scripts/social/post-to-facebook.js --article='{"title":"Test","url":"https://example.com"}'
Rozšíření
Stejný princip lze použít pro LinkedIn, Mastodon nebo jiné platformy. Stačí přidat další krok do workflow a odpovídající skript pro volání API.