Что это: Скилл для Claude Code, который берёт YouTube-видео и превращает его в русскоязычный подкаст-диалог двух ведущих (мужчина + женщина). Результат – MP3 файл, отправленный в Telegram.
Пайплайн: YouTube URL → субтитры + research → сценарий диалога → Edge TTS → MP3 → Telegram
- Claude Code (CLI) – установлен и работает
- Python 3.11+
- ffmpeg (для склейки аудио)
- Telegram аккаунт с API credentials (для отправки)
# ffmpeg (macOS)
brew install ffmpeg
# ffmpeg (Ubuntu/Debian)
sudo apt install ffmpeg
# Python-пакеты
pip3 install edge-tts pydub telethon youtube-transcript-api- Зайди на https://my.telegram.org → API Development Tools
- Создай приложение, получи
API_IDиAPI_HASH - Создай сессию Telethon (StringSession):
from telethon.sync import TelegramClient
from telethon.sessions import StringSession
with TelegramClient(StringSession(), API_ID, 'API_HASH') as client:
print(client.session.save()) # Это твоя SESSION_STRING- Создай файл
~/.craft-podcast-telegram.env:
TELEGRAM_API_ID=12345678
TELEGRAM_API_HASH=abcdef1234567890
TELEGRAM_SESSION_STRING=1BVtsOH...длинная строка...
- Создай группу/канал в Telegram для подкастов, узнай его ID (можно через
@userinfobotили форвард сообщения боту@getidsbot)
# Папка скилла
mkdir -p ~/.claude/skills/craft-podcast/references
# Папки для данных (пути можно менять)
mkdir -p ~/craft-podcasts/audio
mkdir -p ~/craft-podcasts/transcripts---
name: craft-podcast
description: >
YouTube video → Russian podcast summary → TTS audio → Telegram.
Triggers: craft podcast, создать подкаст, подкаст из видео, youtube podcast,
craft-podcast, podcast summary, саммари видео.
---
# Craft Podcast Generator
YouTube URL → исследование → русский подкаст-диалог → Edge TTS → Telegram
## Quick Start
Пользователь даёт YouTube URL. Скилл выдаёт: MP3 подкаст в Telegram + сохранённый транскрипт.
**ВАЖНО: Полностью автоматический режим. Никаких вопросов, подтверждений или пауз.
Получил URL → Extract → Research → Script → TTS → Telegram. Без остановок.**
## Process
### Phase 1: Extract
**Step 1: Получить video ID**
Парсим из URL (поддержка форматов):
- `youtube.com/watch?v=VIDEO_ID`
- `youtu.be/VIDEO_ID`
- `youtube.com/embed/VIDEO_ID`
**Step 2: Достать субтитры**
\```python
from youtube_transcript_api import YouTubeTranscriptApi
try:
transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=['ru', 'en'])
text = ' '.join([t['text'] for t in transcript])
except:
try:
tl = YouTubeTranscriptApi.list_transcripts(video_id)
for t in tl:
transcript = t.fetch()
text = ' '.join([t['text'] for t in transcript])
break
except:
text = None # Нет субтитров - используем research
\```
**Step 3: Метаданные видео**
WebFetch на `https://noembed.com/embed?url=https://www.youtube.com/watch?v={video_id}` → title, author_name.
### Phase 2: Research
Параллельные WebSearch запросы:
- Каждый спикер/гость: `"[Name] background career"`
- Тема видео: `"[Topic] key insights summary"`
- Podcast notes: `"[Video title] podcast notes summary"`
### Phase 3: Script
Написать русский диалог на основе транскрипта + исследования:
**Формат:**
\```
<Person1>Текст ведущего</Person1>
<Person2>Текст эксперта</Person2>
\```
**Правила сценария:**
- Person1: мужской ведущий (энергичный, любопытный)
- Person2: женский эксперт (аналитичный, глубокий)
- 35-45 реплик
- Язык: русский
- Структура: Приветствие → Кто герои → Ключевые инсайты → Обсуждение → Заключение
- Конкретика: цифры, факты, протоколы из видео
**Сохранить транскрипт:**
`~/craft-podcasts/transcripts/transcript_[slug].txt`
### Phase 4: Generate & Send
**Step 1: Генерация аудио**
\```bash
python3 ~/.claude/skills/craft-podcast/references/tts-generator.py \
~/craft-podcasts/transcripts/transcript_[slug].txt \
~/craft-podcasts/audio/podcast_[slug].mp3
\```
**Step 2: Отправка в Telegram**
Подготовить caption:
\```
🎙 [Название видео]
[2-3 предложения с ключевыми инсайтами]
[YouTube URL]
\```
Отправить:
\```bash
python3 ~/.claude/skills/craft-podcast/references/telegram-sender.py \
~/craft-podcasts/audio/podcast_[slug].mp3 \
YOUR_GROUP_ID \
"caption text"
\```
## Error Handling
| Ошибка | Решение |
|--------|---------|
| Нет субтитров | Fallback на описание + WebSearch research |
| Edge TTS пустой сегмент | Пропустить (size < 100 bytes) |
| Длинный текст в сегменте | Разбить по предложениям |
## Dependencies
\```bash
pip3 install edge-tts pydub telethon youtube-transcript-api
\```
Также нужен `ffmpeg` (для pydub).
## Rules
- Весь пайплайн автоматический от URL до Telegram
- Русский для контента, английский для имён файлов
- Валидация regex: `r'<(Person[12])>(.*?)</\1>'` - должен найти 30+ совпадений#!/usr/bin/env python3
"""Edge TTS podcast generator - two Russian voices at 2x speed."""
import asyncio
import edge_tts
import re
import os
import sys
import tempfile
import shutil
from pydub import AudioSegment
VOICES = {
'Person1': 'ru-RU-DmitryNeural',
'Person2': 'ru-RU-SvetlanaNeural',
}
RATE = '+100%'
SILENCE_MS = 200
BITRATE = '192k'
async def generate_segment(text, voice, output_file):
communicate = edge_tts.Communicate(text, voice, rate=RATE)
await communicate.save(output_file)
async def generate_podcast(script_file, output_mp3):
with open(script_file, 'r', encoding='utf-8') as f:
script = f.read()
pattern = r'<(Person[12])>(.*?)</\1>'
segments = [(m.group(1), m.group(2).strip())
for m in re.finditer(pattern, script, re.DOTALL)
if m.group(2).strip()]
if not segments:
print('ERROR: No valid segments found')
sys.exit(1)
print(f'Found {len(segments)} segments')
tmpdir = tempfile.mkdtemp()
combined = AudioSegment.empty()
silence = AudioSegment.silent(duration=SILENCE_MS)
for idx, (person, text) in enumerate(segments):
tmp = os.path.join(tmpdir, f'{idx:03d}.mp3')
voice = VOICES[person]
try:
await generate_segment(text, voice, tmp)
if os.path.getsize(tmp) > 100:
combined += AudioSegment.from_mp3(tmp) + silence
print(f' [{idx+1}/{len(segments)}] OK')
else:
print(f' [{idx+1}/{len(segments)}] SKIP (empty)')
except Exception as e:
print(f' [{idx+1}/{len(segments)}] ERROR: {e}')
combined.export(output_mp3, format='mp3', bitrate=BITRATE)
duration = len(combined) / 1000
size = os.path.getsize(output_mp3)
print(f'\nDone! {output_mp3}')
print(f'{size / 1024 / 1024:.1f} MB, {duration / 60:.1f} min')
shutil.rmtree(tmpdir)
if __name__ == '__main__':
if len(sys.argv) != 3:
print('Usage: tts-generator.py <script.txt> <output.mp3>')
sys.exit(1)
asyncio.run(generate_podcast(sys.argv[1], sys.argv[2]))#!/usr/bin/env python3
"""Send audio file to Telegram group via Telethon."""
import asyncio
import os
import sys
from telethon import TelegramClient
from telethon.sessions import StringSession
# ПОМЕНЯЙ на путь к своему .env файлу
ENV_FILE = os.path.expanduser('~/.craft-podcast-telegram.env')
DEFAULT_GROUP = -1234567890 # ПОМЕНЯЙ на ID своей группы
def load_env(path):
env = {}
with open(path) as f:
for line in f:
line = line.strip()
if '=' in line and not line.startswith('#'):
k, v = line.split('=', 1)
env[k.strip()] = v.strip().strip('"').strip("'")
return env
async def send_audio(audio_file, group_id, caption):
env = load_env(ENV_FILE)
client = TelegramClient(
StringSession(env['TELEGRAM_SESSION_STRING']),
int(env['TELEGRAM_API_ID']),
env['TELEGRAM_API_HASH'],
)
await client.connect()
if not await client.is_user_authorized():
print('ERROR: Not authorized')
sys.exit(1)
print('Connected. Sending...')
result = await client.send_file(
group_id,
audio_file,
caption=caption,
voice=False,
)
print(f'Sent! Message ID: {result.id}')
await client.disconnect()
if __name__ == '__main__':
if len(sys.argv) < 3:
print('Usage: telegram-sender.py <audio.mp3> <group_id> [caption]')
sys.exit(1)
audio = sys.argv[1]
group = int(sys.argv[2]) if len(sys.argv) > 2 else DEFAULT_GROUP
caption = sys.argv[3] if len(sys.argv) > 3 else ''
asyncio.run(send_audio(audio, group, caption))| Что | Где | Зачем |
|---|---|---|
ENV_FILE |
telegram-sender.py строка 10 |
Путь к .env с Telegram credentials |
DEFAULT_GROUP |
telegram-sender.py строка 11 |
ID группы/канала в Telegram |
Пути ~/craft-podcasts/ |
SKILL.md (Phase 3 и 4) |
Где хранить аудио и транскрипты |
| Голоса | tts-generator.py строка 13-14 |
Другие Edge TTS голоса (список: edge-tts --list-voices) |
RATE |
tts-generator.py строка 16 |
Скорость речи (+50%, +100%, +0%) |
В Claude Code просто пишешь:
craft podcast https://www.youtube.com/watch?v=VIDEO_ID
или
подкаст из видео https://youtu.be/VIDEO_ID
Claude сам достанет субтитры, изучит тему, напишет сценарий на русском, сгенерирует аудио и отправит в Telegram.