Files
last30days-skill/docs/plans/2026-02-15-fix-youtube-display-and-search-quality-plan.md
T
Matt Van Horn 32992834ee Merge PR #48: feat: add Xiaohongshu source + Reddit public fallback
- Xiaohongshu search via local MCP service (opt-in, zero impact if service not running)
- Reddit public JSON fallback (works with zero API keys)
- Reddit priority: ScrapeCreators -> OpenAI -> public fallback
- Updated env.py: Reddit always available via public fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 16:11:35 -08:00

222 lines
8.2 KiB
Markdown

---
title: Fix YouTube Display and Search Quality
type: fix
date: 2026-02-15
---
# Fix YouTube Display and Search Quality
## Overview
YouTube is the v2.1 headline feature but it's broken in two ways: results don't appear in Claude's synthesis (display bug), and search quality is worse than youtube.com (search bug). Both need fixing before launch.
## Problem Statement
**Display bug:** YouTube data exists in the script output but Claude never sees it. Reproduced on 4/5 recent test runs (Kanye, Seedance 2, Peter Steinberger, YouTube thumbnails). The skill worked once — the earlier "YouTube thumbnails" and "OpenClaw" runs showed YouTube stats — but subsequent runs silently dropped it.
**Search quality bug:** User searched "how to get on seedance 2" on youtube.com and got multiple recent results. yt-dlp returned 10 videos for the same query, but they included old irrelevant content because date filtering is broken.
## Root Cause Analysis
### Display Bug — Three compounding causes
1. **`2>&1` in SKILL.md bash command** (line 79) merges stderr progress messages into stdout. When Claude Code receives this mixed output, the YouTube section (which renders LAST after Reddit + X) can get lost in the noise or hit the 30K char Bash output limit.
2. **Background execution** (partially fixed). The old SKILL.md said "DO WEBSEARCH WHILE SCRIPT RUNS" which caused Claude to background the bash command. Backgrounded commands return truncated output via Task Output. *Already fixed in this session — SKILL.md now says FOREGROUND with 5-minute timeout.*
3. **No explicit model instruction to look for YouTube.** The SKILL.md tells Claude to synthesize but doesn't emphasize that YouTube data is in the script output and must be included.
### Search Quality Bug — `--flat-playlist` breaks date filtering
The yt-dlp command in `youtube_yt.py:110-116`:
```bash
yt-dlp ytsearch{count}:{query} --dateafter {YYYYMMDD} --flat-playlist --dump-json
```
**`--flat-playlist` causes three problems:**
1. `--dateafter` is silently ignored (no video-level metadata to filter on)
2. All items have `date: None` (upload_date not in flat-playlist JSON)
3. Old content leaks in (e.g., "the greatest youtube thumbnails of all time" returned for a 30-day query)
**`_extract_core_subject()` over-strips useful YouTube terms:**
- Strips "tips", "tutorial", "review" — but these ARE the content types people search for on YouTube
- "youtube thumbnail tips" → "youtube thumbnail" loses the intent signal
## Proposed Solution
### Phase 1: Fix Display (Critical — blocks launch)
#### 1a. Remove `2>&1` from SKILL.md bash command
**File:** `SKILL.md:79` (both `last30days-skill-private/SKILL.md` and `~/.claude/skills/last30days21/SKILL.md`)
```bash
# Before:
python3 "${SKILL_ROOT}/scripts/last30days.py" "$ARGUMENTS" --emit=compact 2>&1
# After:
python3 "${SKILL_ROOT}/scripts/last30days.py" "$ARGUMENTS" --emit=compact
```
This removes ~1-5KB of progress spam from the model's input and ensures clean stdout-only output.
#### 1b. Add YouTube-specific synthesis instruction to SKILL.md
After the "Read the ENTIRE output" instruction, add:
```markdown
**The script output has THREE sections: Reddit items, X items, and YouTube items (in that order).
If you see YouTube items in the output, you MUST include them in your synthesis and stats block.
YouTube items look like: `**{video_id}** (score:N) {channel} [N views, N likes]`**
```
#### 1c. Verify fix with test run
Run `/last30days21 youtube thumbnail tips` and confirm YouTube appears in stats.
### Phase 2: Fix Search Quality (High — headline feature quality)
#### 2a. Remove `--flat-playlist` flag
**File:** `scripts/lib/youtube_yt.py:110-116`
```python
# Before:
cmd = [
"yt-dlp",
f"ytsearch{count}:{core_topic}",
"--dateafter", date_filter,
"--flat-playlist",
"--dump-json",
]
# After:
cmd = [
"yt-dlp",
f"ytsearch{count}:{core_topic}",
"--dateafter", date_filter,
"--dump-json",
"--no-warnings",
"--no-download",
]
```
**Impact:** Slower (yt-dlp resolves each video page for metadata) but:
- `--dateafter` actually works — filters old content
- `upload_date` populated — items get real dates
- Engagement metrics more accurate
**Risk:** Could increase search time from ~5s to ~30-60s for 20 videos. Mitigate by reducing default count or increasing timeout.
**Alternative if too slow:** Keep `--flat-playlist` but append year to search query:
```python
# Bias toward recent content since --dateafter doesn't work with flat-playlist
search_query = f"{core_topic} {from_date[:4]}" # e.g., "youtube thumbnail 2026"
```
#### 2b. Fix `_extract_core_subject()` for YouTube-relevant terms
**File:** `scripts/lib/youtube_yt.py:67-76`
Don't strip terms that are useful YouTube content type signals:
```python
# YouTube-specific: keep 'tips', 'tutorial', 'review' etc.
# These are stripped for Reddit/X search but are valuable for YouTube
noise = {
'best', 'top', 'good', 'great', 'awesome', 'killer',
'latest', 'new', 'news', 'update', 'updates',
'trending', 'hottest', 'popular', 'viral',
'practices', 'features',
'recommendations', 'advice',
'prompt', 'prompts', 'prompting',
'methods', 'strategies', 'approaches',
}
# NOTE: 'tips', 'tricks', 'tutorial', 'guide', 'review', 'reviews'
# are intentionally KEPT — they're YouTube content types
```
#### 2c. Clean question marks and trailing punctuation
**File:** `scripts/lib/youtube_yt.py:48-80`
```python
# At the end of _extract_core_subject():
result = ' '.join(filtered) if filtered else text
return result.rstrip('?!.') # Clean trailing punctuation
```
### Phase 3: Polish (Medium — nice to have before launch)
#### 3a. Increase subprocess timeout for non-flat-playlist mode
**File:** `scripts/lib/youtube_yt.py:119-121`
```python
# Before:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
# After — resolving video pages takes longer:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
```
#### 3b. Add year hint to search query for recency bias
Even with `--dateafter` working, YouTube's search algorithm ranks by relevance not recency. Adding the year helps:
```python
# After core_topic extraction:
import datetime
current_year = datetime.datetime.now().year
search_query = f"{core_topic} {current_year}"
```
#### 3c. Reduce compact render item count for YouTube
The compact render currently shows up to 15 YouTube items. With transcripts, this is too much output. Reduce to 10:
**File:** `scripts/lib/render.py` — in `render_compact()`, add YouTube-specific limit or reduce the default.
## Acceptance Criteria
- [ ] `/last30days21 youtube thumbnail tips` shows YouTube in stats block
- [ ] YouTube items have real dates (not `None`)
- [ ] Old content (> 30 days) filtered out by `--dateafter`
- [ ] "youtube thumbnail tips" search returns videos about thumbnail tips (not generic old content)
- [ ] "How to access Seedance 2" returns recent Seedance 2 tutorials
- [ ] Script completes within 5 minutes for default depth
- [ ] No `2>&1` in SKILL.md bash command
## Files to Modify
| File | Changes |
|------|---------|
| `SKILL.md` | Remove `2>&1`, add YouTube synthesis instruction |
| `scripts/lib/youtube_yt.py` | Remove `--flat-playlist`, fix noise words, add year hint, increase timeout |
| `scripts/lib/render.py` | Optional: reduce YouTube item limit in compact mode |
## Testing
```bash
# Quick smoke test — should show YouTube items with dates
cd ~/.claude/skills/last30days21
python3 scripts/last30days.py "youtube thumbnail tips" --quick --emit=compact 2>/dev/null | grep -c "youtube.com"
# Date test — should show YYYY-MM-DD dates, not None
python3 -c "
from scripts.lib import youtube_yt
r = youtube_yt.search_youtube('youtube thumbnail tips', '2026-01-16', '2026-02-15', depth='quick')
for v in r['items'][:3]: print(v['date'], v['title'][:50])
"
# Full integration — run the skill in Claude Code and verify YouTube in stats
```
## References
- SKILL.md bash command: `scripts/last30days.py` line 79
- YouTube search: `scripts/lib/youtube_yt.py` lines 83-174
- Core subject extraction: `scripts/lib/youtube_yt.py` lines 48-80
- Compact render: `scripts/lib/render.py` lines 48-238
- Prior YouTube plan: `docs/plans/2026-02-14-feat-youtube-transcript-search-plan.md`