feat: add trigger-podcast workflow for manual podcast generation (#496)
Allows re-triggering podcast generation for an already-published week without running the full crawl pipeline. Takes week, article_url, and article_path as inputs and calls the handoff script in real mode. Co-authored-by: jmservera <jmservera@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Juan Manuel Servera committed
Jun 15, 2026 at 21:27 UTC
50af9c1d4365108cfa8bbe67068859a2d6d52e11
1 file changed
+115
.github/workflows/trigger-podcast.yml
new
+115
@@ -0,0 +1,115 @@
1
+name: Trigger podcast generation
2
+
3
+on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ week:
7
+ description: 'Week slug, e.g. 2026-W25.'
8
+ required: true
9
+ type: string
10
+ article_url:
11
+ description: 'Published SquadScope article URL.'
12
+ required: true
13
+ type: string
14
+ article_path:
15
+ description: 'Article content path, e.g. content/weekly/2026/W25.md.'
16
+ required: true
17
+ type: string
18
+
19
+permissions:
20
+ contents: read
21
+
22
+jobs:
23
+ trigger-podcast:
24
+ runs-on: ubuntu-latest
25
+ permissions:
26
+ contents: read
27
+
28
+ steps:
29
+ - name: Check out repository
30
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
31
+ with:
32
+ persist-credentials: false
33
+
34
+ - name: Set up Python
35
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
36
+ with:
37
+ python-version: '3.12'
38
+
39
+ - name: Build manifest and trigger podcast generation
40
+ env:
41
+ PODCASTER_ENDPOINT: ${{ vars.PODCASTER_ENDPOINT }}
42
+ PODCASTER_API_KEY: ${{ secrets.PODCASTER_API_KEY }}
43
+ WEEK: ${{ inputs.week }}
44
+ ARTICLE_URL: ${{ inputs.article_url }}
45
+ ARTICLE_PATH: ${{ inputs.article_path }}
46
+ PUBLISH_RUN_ID: ${{ github.run_id }}
47
+ run: |
48
+ set -euo pipefail
49
+ if [ -z "$PODCASTER_ENDPOINT" ] || [ -z "$PODCASTER_API_KEY" ]; then
50
+ echo "::error::Requires PODCASTER_ENDPOINT variable and PODCASTER_API_KEY secret."
51
+ exit 1
52
+ fi
53
+ if [ ! -f "$ARTICLE_PATH" ]; then
54
+ echo "::error::article_path '$ARTICLE_PATH' does not exist in the repository."
55
+ exit 1
56
+ fi
57
+
58
+ # Build a minimal publish manifest for the handoff script
59
+ mkdir -p .podcast-trigger
60
+ python3 - <<'PY' "$WEEK" "$ARTICLE_PATH" .podcast-trigger/publish-manifest.json
61
+ import hashlib
62
+ import json
63
+ import sys
64
+ from pathlib import Path
65
+
66
+ week, article_path, manifest_path = sys.argv[1:]
67
+ article = Path(article_path)
68
+ article_bytes = article.read_bytes()
69
+ article_sha = hashlib.sha256(article_bytes).hexdigest()
70
+ raw_payload = {"week": week, "source": "github", "article_path": article_path}
71
+ raw_bytes = (json.dumps(raw_payload, sort_keys=True) + "\n").encode("utf-8")
72
+ raw_sha = hashlib.sha256(raw_bytes).hexdigest()
73
+
74
+ manifest = {
75
+ "week": week,
76
+ "run_mode": "normal",
77
+ "candidate": {"summary_sha256": article_sha},
78
+ "analysis": {"ai_status": "ai"},
79
+ "promotion": {"eligible": True, "decision": "promote"},
80
+ "source_artifacts": [
81
+ {
82
+ "role": "raw_github",
83
+ "path": f"data/raw/{week}.json",
84
+ "name": f"{week}-raw-github",
85
+ "sha256": raw_sha,
86
+ "generated_at": "2026-01-01T00:00:00Z",
87
+ "source_status": "fresh",
88
+ "exists": True,
89
+ "size_bytes": len(raw_bytes),
90
+ "freshness": {"status": "fresh", "reasons": []},
91
+ "provenance": {"path": f"data/raw/{week}.json", "sha256": raw_sha},
92
+ },
93
+ {
94
+ "role": "published_summary",
95
+ "path": article_path,
96
+ "sha256": article_sha,
97
+ "generated_at": "2026-01-01T00:00:00Z",
98
+ "exists": True,
99
+ "size_bytes": len(article_bytes),
100
+ "provenance": {"path": article_path, "sha256": article_sha},
101
+ },
102
+ ],
103
+ }
104
+ Path(manifest_path).write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
105
+ PY
106
+
107
+ # Trigger real podcast generation (no --podcaster-dry-run)
108
+ python3 scripts/podcaster_handoff.py \
109
+ --week "$WEEK" \
110
+ --article-url "$ARTICLE_URL" \
111
+ --article-path "$ARTICLE_PATH" \
112
+ --publish-run-id "$PUBLISH_RUN_ID" \
113
+ --publish-mode normal \
114
+ --manifest .podcast-trigger/publish-manifest.json \
115
+ --podcast-config config/podcast.json