1 ---
2 name: podcast-marketing
3 description: Repurpose podcast episodes into social posts, show notes, clips, and quote cards.
4 ---
5
6 # Podcast Marketing
7
8 Turn podcast episodes into a full suite of marketing content. Supports four input modes, extracts content atoms with viral scoring, and produces platform-ready content pieces that can be published immediately.
9
10 ## Requirements & Setup
11
12 ### Tier 1: Text Content (always needed)
13
14 These are required for transcript extraction and content generation (show notes, blog, social, newsletter, pull quotes):
15
16 | Dependency | Install | Purpose |
17
18 |-----------|---------|---------|
19
20 | Python 3.10+ | `installProgrammingLanguage({ language: "python-3.11" })` | Runtime for all scripts |
21
22 | youtube-transcript-api | `installLanguagePackages({ language: "python", packages: ["youtube-transcript-api"] })` | YouTube caption extraction |
23
24 | yt-dlp | `installLanguagePackages({ language: "python", packages: ["yt-dlp"] })` | YouTube metadata + video/audio download |
25
26 | LLM API | Set up via Anthropic or OpenAI AI integration (Replit proxy — no user API key needed) | Content atom extraction and content generation |
27
28 ### Tier 2: Quote Card Images
29
30 These are required to generate visual quote card PNG files:
31
32 | Dependency | Install | Purpose |
33
34 |-----------|---------|---------|
35
36 | Pillow | `installLanguagePackages({ language: "python", packages: ["Pillow"] })` | Image generation |
37
38 | System fonts | Already available on Nix (DejaVu Sans at `/usr/share/fonts/truetype/dejavu/`) | Typography |
39
40 No API keys needed. Run `scripts/generate_quote_cards.py` directly.
41
42 ### Tier 3: Short-Form Video Clips (basic)
43
44 These produce trimmed, vertical-reformatted video clips without animated captions:
45
46 | Dependency | Install | Purpose |
47
48 |-----------|---------|---------|
49
50 | ffmpeg | `installSystemDependencies({ packages: ["ffmpeg"] })` | Video trimming, reformatting, subtitle burning |
51
52 | yt-dlp | (already in Tier 1) | Download source video from YouTube |
53
54 ### Tier 4: Animated Captions (Opus Clips style)
55
56 These add word-by-word highlighted captions to video clips:
57
58 | Dependency | Install | Purpose |
59
60 |-----------|---------|---------|
61
62 | OpenAI API | Set up OpenAI AI integration OR user provides `OPENAI_API_KEY` | Whisper word-level timestamps |
63
64 | Pillow | (already in Tier 2) | Caption frame generation (alternative to ASS subtitles) |
65
66 The animated caption pipeline re-transcribes each trimmed clip through Whisper with `timestamp_granularities=["word"]` to get per-word timing. Without this, clips still work but use segment-level static captions instead.
67
68 ### Setup Checklist
69
70 Before running the pipeline, verify:
71
72 ```python
73
74 # Tier 1
75
76 import youtube_transcript_api \# YouTube captions
77
78 import yt_dlp \# YouTube metadata/download
79
80 import anthropic \# or openai — for content generation
81
82 # Tier 2 (if generating quote cards)
83
84 from PIL import Image, ImageFont
85
86 ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 48)
87
88 # Tier 3 (if generating video clips)
89
90 import subprocess
91
92 subprocess.run(["ffmpeg", "-version"], capture_output=True, check=True)
93
94 # Tier 4 (if generating animated captions)
95
96 import openai \# OPENAI_API_KEY must be set
97
98 ```
99
100 ## When to Use
101
102 - User wants to repurpose a podcast episode into marketing content
103 - User asks to create social media posts, blog articles, or newsletters from an episode
104
105 - User wants show notes with timestamps and key takeaways
106 - User asks to generate pull quotes, audiogram clips, or short-form video clips
107
108 - User provides an RSS feed and wants to process episodes in batch
109 - User shares a YouTube link to a podcast episode or video interview
110
111 - User says "turn this episode into content", "repurpose this podcast", or "create marketing from my episode"
112 - User wants to create a content calendar from podcast episodes
113
114 ## When NOT to Use
115
116 - Creating a podcast from scratch (use the `podcast-generator` skill instead)
117 - General social media management unrelated to podcast content
118
119 ## Input Modes
120
121 ### Mode 1: RSS Feed
122
123 Auto-download and transcribe the latest episode(s) from a podcast RSS feed.
124
125 1. Parse the RSS feed to extract episode metadata (title, description, publish date, audio URL).
126 2. Download the audio file.
127
128 3. Transcribe using OpenAI Whisper (produces timestamped transcript).
129 4. Proceed to content generation.
130
131 Read `rss-and-batch.md` for RSS parsing details and the Whisper transcription pipeline.
132
133 ### Mode 2: Raw Transcript
134
135 Accept a transcript file directly — plain text, SRT, or VTT format.
136
137 1. Detect format from file extension or content structure.
138 2. Parse into a normalized transcript (list of segments with optional timestamps).
139
140 3. Proceed to content generation.
141
142 SRT/VTT files preserve timestamps, which enables show notes with time markers. Plain text works but won't have timestamp data.
143
144 ### Mode 3: YouTube Link
145
146 Extract transcript and metadata from a YouTube video — works for podcast episodes, interviews, talks, or any video with speech.
147
148 1. Accept a YouTube URL (full or short format).
149 2. Attempt to fetch YouTube's auto-generated or manually uploaded captions first (fast, free, no API key needed).
150
151 3. If no captions are available, download the audio track and transcribe via Whisper.
152 4. Extract video metadata (title, channel, description, publish date, duration).
153
154 5. Proceed to content generation.
155
156 Read `youtube-processing.md` for the full YouTube extraction pipeline.
157
158 ### Mode 4: Batch Mode
159
160 Process the last N episodes from an RSS feed automatically.
161
162 1. Parse the RSS feed.
163 2. Sort episodes by publish date (newest first).
164
165 3. Download and transcribe each episode.
166 4. Run the content generation pipeline for each episode.
167
168 5. Organize output by episode (one directory per episode).
169
170 Read `rss-and-batch.md` for batch processing details.
171
172 ## Content Generation Pipeline
173
174 Once you have a transcript and episode metadata, follow this pipeline. The order matters — each step builds on the previous one.
175
176 ### Step 1: Extract Content Atoms
177
178 This replaces a simple summary. Analyze the full transcript and extract **7 types of content atoms** — these are the raw material for everything downstream.
179
180 | Atom Type | What to Look For | Example |
181
182 |-----------|-----------------|---------|
183
184 | **Narrative Arcs** | Stories with setup, tension, resolution | "When we almost lost the company in 2019..." |
185
186 | **Quotable Moments** | Punchy, memorable one-liners | "Culture eats strategy for breakfast, but execution eats both" |
187
188 | **Controversial Takes** | Opinions that challenge mainstream thinking | "I think remote work is actually worse for junior employees" |
189
190 | **Data Points** | Statistics, numbers, research findings | "We saw a 340% increase after switching to..." |
191
192 | **Frameworks** | Mental models, step-by-step processes | "The 3-bucket prioritization system..." |
193
194 | **Stories** | Personal anecdotes, case studies, examples | "Our first customer was actually..." |
195
196 | **Predictions** | Forward-looking claims about trends | "In 5 years, every company will need to..." |
197
198 For each atom, capture: the verbatim text, timestamps (start/end), speaker, atom type, and a one-line hook that could open a social post.
199
200 **Timestamp requirement:** Every atom MUST include `start_timestamp`and`end_timestamp` in seconds. Match the verbatim text against the transcript segments to find the correct timestamps. Without timestamps, video clip selection is impossible.
201
202 **Long transcript handling:** If the transcript exceeds 50,000 characters, split into overlapping chunks (5,000 char overlap) and extract atoms from each chunk separately. Deduplicate by comparing verbatim_text similarity (>80% overlap = duplicate). Merge and re-rank.
203
204 Read `content-atoms.md` for the full extraction prompt and output format.
205
206 ### Step 2: Score and Assign Content Atoms
207
208 Score each atom on three dimensions to prioritize the strongest content:
209
210 | Dimension | Weight | What It Measures |
211
212 |-----------|--------|-----------------|
213
214 | **Novelty** | 40% | Is this new, surprising, or counter-intuitive? |
215
216 | **Controversy** | 30% | Will people disagree, debate, or have strong reactions? |
217
218 | **Utility** | 30% | Can someone apply this immediately? |
219
220 #### Score thresholds
221
222 - **80-100**: Priority publish — lead with these
223 - **60-79**: Strong fill — solid content for the calendar
224
225 - **40-59**: Gap filler — use when scheduling needs variety
226 - **Below 40**: Cut — not worth publishing
227
228 **Atom-to-platform assignment (anti-repetition rule):** After scoring, assign each atom to AT MOST 2 content pieces. No single quote should appear verbatim in more than 2 outputs. Use this mapping to assign the highest-scoring atoms first:
229
230 | Platform | Best Atom Types | Lead Atom |
231
232 |----------|----------------|-----------|
233
234 | Twitter thread | Controversial takes, data points | Assign atom \#1 by score |
235
236 | LinkedIn post | Frameworks, data points | Assign a DIFFERENT atom than Twitter |
237
238 | Blog post | Narrative arcs, stories | Assign a DIFFERENT atom than Twitter/LinkedIn |
239
240 | Newsletter | Top 2-3 by score, any type | Can reuse 1 atom from blog |
241
242 | Quote cards | Quotable moments | Use atoms NOT already assigned to other platforms |
243
244 | Video clips | Controversial takes, stories, data points | Based on timestamp availability |
245
246 This ensures each platform leads with a unique angle rather than repeating the same quote everywhere.
247
248 ### Step 3: Show Notes
249
250 Generate structured show notes with:
251
252 - Episode title and one-paragraph description
253 - Timestamped topic outline (if timestamps available)
254
255 - Key takeaways as bullet points (5-7)
256 - **ALL links mentioned** in the episode — parse from YouTube description, transcript mentions of URLs, and episode metadata. Include every reference link, not just a subset
257
258 - Guest bio (if interview format — pull from transcript intro or episode metadata)
259
260 ### Step 4: Blog Post
261
262 Write an 800-1200 word article that:
263
264 - Opens with the atom assigned to the blog (from Step 2) as the hook (not "In this episode...")
265 - Expands on 2-3 top atoms with context and examples from the conversation
266
267 - Includes 1-2 pull quotes from the transcript
268 - Ends with a CTA to listen to the full episode
269
270 - Uses subheadings for scannability
271
272 **Hard limit: 1,200 words maximum.** Count words before saving. If over, cut the weakest section.
273
274 ### Step 5: Social Media Posts
275
276 Generate platform-specific posts. Each platform MUST lead with a DIFFERENT atom (from Step 2 assignment):
277
278 #### Twitter/X Thread (5-8 tweets)
279
280 - Tweet 1: Hook — the atom assigned to Twitter (controversial take or novel insight)
281 - Tweets 2-6: One atom per tweet, using the speakers' own words when possible
282
283 - Final tweet: CTA with episode link
284 - **HARD LIMIT: Every tweet MUST be under 280 characters including spaces and URLs.** Count characters before saving. Split long quotes across two tweets if needed.
285
286 ##### LinkedIn Post (1 long-form)
287
288 - Open with the atom assigned to LinkedIn (framework or data point — NOT the same as Twitter hook)
289 - Share 2-3 insights with brief context
290
291 - Professional tone, first-person perspective
292 - End with a question to drive engagement + episode link
293
294 - 1,200-1,500 characters
295
296 ###### Instagram Caption
297
298 - Conversational, accessible tone
299 - Lead with the "why should I care" angle
300
301 - Include 3-5 relevant hashtags
302 - End with CTA to listen (link in bio)
303
304 - 300-500 characters
305
306 **Multi-topic episodes:** If the episode covers 3+ distinct topics, also generate 1 standalone tweet per topic (not threads — single tweets) for drip-posting throughout the week. Include these in the calendar.
307
308 Read `content-templates.md` for detailed templates and examples for each platform.
309
310 ### Step 6: Email Newsletter
311
312 Write newsletter copy that:
313
314 - Subject line: curiosity-driven, under 50 characters
315 - Preview text: complements the subject line, under 90 characters
316
317 - Body: 200-300 words built around the top 2-3 atoms
318 - Include 1 pull quote (can reuse 1 from blog)
319
320 - Clear CTA button text (e.g., "Listen Now", "Hear the Full Conversation")
321
322 ### Step 7: Pull Quotes
323
324 Select 5-8 standalone quotes that:
325
326 - Make sense without context
327 - Are surprising, insightful, or emotionally resonant
328
329 - Are under 150 characters each (for shareable graphics)
330 - Include speaker attribution
331
332 - Have timestamps (for linking to the exact moment)
333
334 ### Step 8: Quote Cards
335
336 Generate visual quote card images for the top 3-5 pull quotes.
337
338 **Requires Tier 2 dependencies** (Pillow + system fonts). Run `scripts/generate_quote_cards.py`:
339
340 ```python
341
342 from generate_quote_cards import batch_generate
343
344 quotes = [
345
346 {"text": "Quote text here", "speaker_name": "Speaker", "speaker_title": "Title"},
347
348 ...
349
350 ]
351
352 paths = batch_generate(quotes, output_dir="quote-cards/", podcast_name="Podcast Name")
353
354 ```
355
356 Each quote produces 3 files:
357
358 - `quote-N-instagram-1080x1080.png` (feed posts, carousels)
359 - `quote-N-twitter-1200x675.png` (tweets, LinkedIn)
360
361 - `quote-N-stories-1080x1920.png` (Instagram Stories, TikTok)
362
363 Read `quote-cards.md` for design specs, color customization, and AI background generation.
364
365 ### Step 9: Short-Form Video Clips (Opus Clips Style)
366
367 Automatically identify and extract the best 30-90 second moments from the episode for YouTube Shorts, TikTok, and Instagram Reels.
368
369 **Requires Tier 3 dependencies** (ffmpeg + yt-dlp). For animated captions, also requires Tier 4 (OpenAI Whisper).
370
371 The pipeline:
372
373 1. Use content atoms (especially controversial takes, stories, and data points) to identify clip-worthy moments. **Atoms MUST have start/end timestamps** — atoms without timestamps are skipped.
374 2. Download the source video if from YouTube (`scripts/generate_video_clips.download_youtube_video`).
375
376 3. Trim clips at the identified timestamps with fade in/out.
377 4. Reformat to 9:16 vertical (center-crop or letterbox).
378
379 5. **If Tier 4 available:** Add animated word-by-word captions (Opus Clips style) via Whisper re-transcription of each clip.
380 6. **If Tier 4 unavailable:** Add static segment-level captions using transcript data (still readable, just not word-highlighted).
381
382 7. Burn in a progress bar and speaker name lower third.
383
384 Target: 3-5 clips per episode, each scored by viral potential. Generate a hook title for each clip.
385
386 ```python
387
388 from generate_video_clips import extract_clips
389
390 results = extract_clips(
391
392 video_path="episode.mp4",
393
394 atoms=scored_atoms, \# must have start_timestamp/end_timestamp
395
396 output_dir="clips/",
397
398 speaker_name="Speaker Name",
399
400 max_clips=5,
401
402 )
403
404 ```
405
406 Read `video-clips.md` for the full video clip extraction and captioning pipeline.
407
408 ### Step 10: Content Calendar
409
410 Auto-schedule all generated content across platforms using best-practice timing:
411
412 | Platform | Best Times | Frequency | Content Types |
413
414 |----------|-----------|-----------|--------------|
415
416 | Twitter/X | 9-11am, 1-3pm weekdays | 1-2 posts/day | Threads, quote cards, clip links, topic tweets |
417
418 | LinkedIn | Tue-Thu 8-10am | 2-3 posts/week | Articles, quote cards, insights |
419
420 | Instagram | Mon/Wed/Fri 11am-1pm | 3-5 posts/week | Quote cards, carousels, Reels |
421
422 | TikTok | Tue/Thu/Sat 7-9pm | 3-5 posts/week | Short-form clips |
423
424 | YouTube | Sat/Sun 9am-12pm | 1-2 Shorts/week | Short-form clips |
425
426 | Newsletter | Tue/Thu morning | 1/week | Newsletter copy |
427
428 | Blog | Any weekday | 1/episode | Blog post |
429
430 Read `content-calendar.md` for scheduling logic, content mix optimization, and calendar output format.
431
432 ## Quality Checklist
433
434 Run this checklist before delivering content to the user:
435
436 - [ ] **No quote recycling**: No verbatim quote appears in more than 2 content pieces
437 - [ ] **Platform leads are unique**: Twitter, LinkedIn, and blog each open with a different atom/angle
438
439 - [ ] **Twitter character limits**: Every tweet is under 280 characters (count them)
440 - [ ] **Blog word count**: Blog post is 800-1,200 words (count them)
441
442 - [ ] **LinkedIn character count**: Post is 1,200-1,500 characters
443 - [ ] **Instagram length**: Caption is 300-500 characters before hashtags
444
445 - [ ] **Newsletter subject line**: Under 50 characters
446 - [ ] **All links captured**: Show notes include every link from the YouTube description/episode metadata
447
448 - [ ] **Timestamps on atoms**: Every atom has start*timestamp and end*timestamp
449 - [ ] **Pull quotes are short**: Each under 150 characters
450
451 - [ ] **Content pieces generated individually**: Each piece was generated in its own LLM call (not batched with ---SEPARATOR--- patterns that cause content to bleed between files)
452
453 ## Generation Best Practices
454
455 **Generate each content piece in a separate LLM call.** Do NOT batch multiple outputs (e.g., "generate blog + social + newsletter separated by ---SEPARATOR---"). This causes:
456
457 - Content bleeding between files (e.g., Twitter thread ends up in LinkedIn file)
458 - Quality degradation on later pieces as the model runs out of attention
459
460 - Inconsistent formatting
461
462 Instead: generate atoms first, then generate each content piece independently with the atoms + relevant assignment as context. This produces better quality and avoids file-splitting bugs.
463
464 **For long transcripts (>50K chars):** Split into 2-3 chunks with 5K char overlap. Extract atoms from each chunk. Merge and deduplicate before scoring.
465
466 ## Output Structure
467
468 ```text
469
470 podcast-content/
471
472 ├── episode-title/
473
474 │ ├── atoms.json \# Extracted + scored content atoms with timestamps
475
476 │ ├── show-notes.md
477
478 │ ├── blog-post.md
479
480 │ ├── social/
481
482 │ │ ├── twitter-thread.md
483
484 │ │ ├── linkedin-post.md
485
486 │ │ ├── instagram-caption.md
487
488 │ │ └── topic-tweets.md \# (multi-topic episodes only)
489
490 │ ├── newsletter.md
491
492 │ ├── pull-quotes.md
493
494 │ ├── quote-cards/ \# (Tier 2)
495
496 │ │ ├── quote-1-instagram-1080x1080.png
497
498 │ │ ├── quote-1-twitter-1200x675.png
499
500 │ │ ├── quote-1-stories-1080x1920.png
501
502 │ │ └── ...
503
504 │ ├── clips/ \# (Tier 3+)
505
506 │ │ ├── clip-1-vertical.mp4
507
508 │ │ ├── clip-2-vertical.mp4
509
510 │ │ └── clips-metadata.json
511
512 │ ├── audiograms/ \# (audio-only or requested)
513
514 │ │ ├── clip-1.mp4
515
516 │ │ └── ...
517
518 │ └── calendar.json \# Scheduled content calendar
519
520 ```
521
522 ## Tone & Voice Calibration
523
524 Before generating content, ask the user (or infer from their existing content):
525
526 - **Brand voice** — formal, conversational, edgy, academic, playful?
527 - **Target audience** — who reads/follows their content?
528
529 - **Platform priorities** — which platforms matter most?
530 - **Minimum viral score** — threshold for content to make the cut (default: 40)
531
532 If not specified, default to conversational and professional. Mirror the energy of the podcast itself — if the hosts are casual and funny, the marketing content should reflect that.
533
534 ## Composability
535
536 This skill works alongside the `podcast-generator` skill. A typical workflow might be:
537
538 1. Use `podcast-generator` to create an episode from research
539 2. Use `podcast-marketing` to repurpose that episode into content
540
541 ## References
542
543 - `content-atoms.md` — Content atom extraction prompt, the 7 atom types, output format, and scoring rubric. Read first — atoms are the foundation for all content.
544 - `content-templates.md` — Detailed templates and examples for each content type (social posts, blog, newsletter, show notes, pull quotes). Read when generating specific content types.
545 - `quote-cards.md` — Quote card design specifications, image generation, and multi-format output. Read when generating quote cards.
546 - `video-clips.md` — Opus Clips-style video clip extraction, vertical reformatting, animated captions, and progress bar overlay. Read when generating short-form video clips.
547 - `content-calendar.md` — Platform-specific scheduling rules, content mix optimization, and calendar JSON output format. Read when generating a content calendar.
548 - `audio-processing.md` — Whisper transcription setup, audiogram generation pipeline, and audio clip extraction. Read when handling audio input or generating audiograms.
549 - `rss-and-batch.md` — RSS feed parsing, episode downloading, and batch processing logic. Read when the input is an RSS feed or batch mode is requested.
550 - `youtube-processing.md` — YouTube URL handling, caption extraction, audio download, and metadata retrieval. Read when the input is a YouTube link.