Reels-автопайплайн: идея → публикация без меня
6 шагов, в которых я участвую только на съёмке одним дублем. Остальное — Claude Code: сценарий приходит ночью, монтаж занимает 7 минут, лендинг под ролик с кодовым словом, постинг на IG и YT по расписанию, вечерний отчёт в Telegram.
Что внутри гайда
- Pre-research-агент 07:00 — просыпаешься с готовым сценарием: полный prompt-template, Virlo MCP-вызов с фильтрами, пример готового текста «на камеру» (200–400 символов)
- Съёмка за 15 минут — чек-лист из 10 пунктов: свет, фон, одежда, ракурс, длина, микрофон — всё уже решено до прихода на площадку
- Автомонтаж за ~7 минут: 5 проходов без тебя — faster-whisper word-level, Playwright → alpha PNG, ffmpeg filter_complex с реальными флагами, ducking -18 dB, cover branch
- Лендинг + бот-воронка — 8 шагов от коммента до лида: ManyChat keyword detection, IG Graph webhook, TG Bot deep-link, Mini App анкета, Postgres CRM
- Постинг IG Reels + YT Shorts — Meta Graph API v21.0 payload + YT Data API v3 videos.insert payload, расписание, лицензия музыки
- Daily report 22:00 — что собирается, формат TG-таблицы, пороги алертов, бенчмарки для DeFi/AI-ниши
- Бюджет $125–135/мес — строка за строкой — VPS / CC / Virlo / музыка / альтернативы на каждую статью
- 7-шаговый чек-лист «с нуля до первой публикации» — от установки стека до кнопки Submit
Темы и сценарии — пока ты спишь
В 07:00 в личку падает файл. Внутри — два-три сценария: тема, хук первые 4 секунды, структура пяти сегментов, финальный CTA с кодовым словом. Ты не выбираешь тему — ты выбираешь снимать первый или второй. Это не «идеи» — это готовый текст, который читаешь прямо с телефона.
Агент запускается в 06:30 МСК через cron. Алгоритм трёхшаговый: сигналы → паттерны → сценарий. Ни одной лишней операции — всё что нужно для следующего шага (съёмки) уже внутри.
prompt_template
Это полный системный промпт агента-исследователя. Вставляется в Claude как system, дополняется переменными из profile.yaml.
SYSTEM PROMPT — Reels Research Agent v2.1
=========================================
Ты — агент генерации сценариев для личного бренда в нише {niche}.
Запускаешься в {cron_time} МСК ежедневно.
ВХОДНЫЕ ДАННЫЕ (читаешь из profile.yaml и DB):
- niche: {niche} # например: "DeFi / AI-автоматизация"
- brand_voice: {brand_voice} # "короткие предложения, без канцелярита, ты, реальные цифры"
- past_topics: [{slug_1}, {slug_2}, ...] # список slug'ов последних 14 дней — не повторять
- banned_patterns: [{pattern_1}, ...] # паттерны с retention < 45% — пропустить
- target_duration_sec: {duration} # обычно 45–55 сек
- language: ru
- cta_keyword: {cta_keyword} # текущее кодовое слово, например ПАЙПЛАЙН
ШАГ 1 — VIRLO MCP ПОИСК:
Вызови virlo.search_keywords с параметрами:
keywords: топ-5 терминов ниши
time_period: "this_week"
min_views: 50000
platforms: ["instagram", "youtube"]
Из результата возьми топ-20 роликов по (saves + completion_rate), отбрось по просмотрам.
ШАГ 2 — АНАЛИЗ ПАТТЕРНОВ:
Для каждого из топ-20 роликов выдели:
- тип хука: цифра_в_первых_3_словах / вопрос / провокация / контрнарратив
- структуру: listicle / before-after / personal-story / tutorial
- позицию разворота нарратива (если есть): секунда
- CTA-тип: кодовое_слово / ссылка_в_bio / комментарий
Найди 2–3 паттерна, которые встречаются ≥3 раз в топ-10.
ШАГ 3 — ГЕНЕРАЦИЯ СЦЕНАРИЕВ:
Под каждый найденный паттерн напиши один сценарий.
Формат каждого сценария:
---
ТЕМА: [одна строка]
ПАТТЕРН: [тип]
ХУК (0–4 сек): [точный текст, ≤18 слов]
СЕГМЕНТ 1 (5–14 сек): [текст, ~90–110 символов]
СЕГМЕНТ 2 (15–24 сек): [текст]
СЕГМЕНТ 3 (25–34 сек): [текст]
СЕГМЕНТ 4 (35–44 сек): [текст]
CTA (45–52 сек): [текст с кодовым словом {cta_keyword}]
SLUG: [latin-kebab-case-до-5-слов]
BROLL_HINTS: [5 коротких описаний визуальных вставок по сегментам]
THUMBNAIL_HOOK: [одна строка — для обложки, ≤6 слов, цифра обязательна]
---
ПРАВИЛА:
- Обращение «ты» везде
- Конкретные цифры из реального опыта нарратора (из profile.yaml)
- Без «данный», «осуществляется», «является»
- Каждое предложение ≤15 слов
- Кодовое слово — в последней реплике, органично
ВЫХОД: JSON с полем "scenarios": [...] + поле "top_patterns": [...]
Отправь через TG Bot API на {telegram_chat_id}.
Virlo MCP — два инструмента
Virlo MCP — сервис агрегации вирального контента. В пайплайне используются два инструмента: search_keywords и search_hashtags.
search_keywords — поиск роликов по ключевым словам:
keywords: список из 3–5 терминов ниши (например,["DeFi", "Claude Code", "автоматизация"])time_period:"this_week"(неtoday— слишком мало данных по утрам)min_views: 50 000 — отсечь мусорplatforms:["instagram", "youtube"](TikTok опционально)data_intelligence_enabled:falseдля базового вызова ($0.50),trueесли нужны 40+ полей включая hook-тип и retention ($1.50)
Стоимость базового вызова: $0.50 ($1.50 с data intelligence). При ежедневном запуске и без data_intelligence = ~$15/мес.
search_hashtags — поиск трендовых хэштегов за период:
start_date/end_date: последние 7 днейorder_by:"views"(не count — нужна аудитория, не частота)platform:"instagram"
Возвращает: hashtag, video_count, total_views. Используется для выбора 7–10 хэштегов в caption на шаге 5.
Что НЕ возвращает Virlo напрямую: completion rate и save rate по отдельным роликам — только views. Для retention-фильтрации агент вызывает дополнительно analyze_video на топ-5 роликов ($0.50 × 5 = $2.50). Это опционально — запускать раз в неделю, не ежедневно.
Пример готового сценария
Пример готового сценария (Сегмент 1–CTA) на выходе агента:
ТЕМА: Монтажный агент за $0/мес
ПАТТЕРН: listicle + цифра в хуке
ХУК: Этот ролик смонтирован без человека. Покажу как.
СЕГМЕНТ 1: Шаг один. Агент утром. Сканит виральные ролики в нише.
Присылает текст — читаю с телефона.
СЕГМЕНТ 2: Шаг два. Я снимаю. Один дубль. Монтажный агент берёт файл.
СЕГМЕНТ 3: faster-whisper режет паузы. Playwright вставляет B-roll.
ffmpeg собирает всё в один MOV — 7 минут.
СЕГМЕНТ 4: Лендинг уже готов. ManyChat ловит слово в комментах.
Бот отправляет ссылку. Без меня.
CTA: Пиши слово ПАЙПЛАЙН в комменты — пришлю архитектуру стека.
SLUG: montage-agent-zero-cost
BROLL_HINTS: [terminal с JSON, ffmpeg process bar, telegram chat screenshot,
Playwright browser render, ManyChat flow diagram]
THUMBNAIL_HOOK: 7 минут — полный монтаж
profile.yaml — конфиг агента
Это единственный файл, который нужно поддерживать руками. Агент читает его на каждом запуске.
# profile.yaml — конфиг pre-research агента
niche: "DeFi / AI-автоматизация"
brand_voice: |
Короткие предложения. Без канцелярита. «Ты», не «вы».
Реальные цифры из опыта (а не «много», «быстро»).
Каждая 3-я фраза — конкретика: число / название инструмента / срок.
target_duration_sec: 50
cta_keyword: "ПАЙПЛАЙН"
telegram_chat_id: 123456789
# Темы, которые уже отработаны за 14 дней — не повторять
past_topics:
- news-agent-5-systems
- montage-zero-cost
- reels-autopipeline
# Паттерны с retention < 45% — выкинуть из ротации
banned_patterns:
- "question_hook_without_number" # ХУК-вопрос без цифры — у меня плохо работает
- "personal_story_over_30sec" # длинные сторителлинги — < 50% retention
# Сезонные/нишевые сигналы — добавляются вручную раз в неделю
context:
- "Май 2026: рост интереса к Claude Code в РФ-комьюнити"
- "AI-агенты на TG/IG — пик трендов"
- "Audit Funnel запущен — нужны лиды через коммент-DM"
cron + watchdog
Запуск агента — обычный cron-job. Никаких облачных функций, никаких очередей. Один файл, один процесс, одна задача.
# crontab -e (на VPS, время в UTC — +3 для МСК)
# Pre-research агент: 06:30 МСК = 03:30 UTC
30 3 * * * cd /home/reels && python3 research_agent.py >> logs/research.log 2>&1
# Watchdog для дроп-папки (через systemd unit)
# /etc/systemd/system/reels-watchdog.service
[Unit]
Description=Reels incoming watchdog
After=network.target
[Service]
ExecStart=/usr/bin/python3 /home/reels/watchdog.py
Restart=always
User=reels
WorkingDirectory=/home/reels
[Install]
WantedBy=multi-user.target
queue.json, выбирается следующий по расписанию. Retention rate как фильтр: паттерны с completion < 45% в banned_patterns profile.yaml — агент их не повторяет. Ниши, где пайплайн особенно эффективен: AI-инструменты, DeFi/крипто, автоматизация бизнеса, личные финансы — лидеры по save-rate в Virlo-данных.Один дубль ≤90 секунд
Ты открываешь телефон. Читаешь сценарий, который агент прислал три часа назад. Нажимаешь запись. Говоришь. Нажимаешь стоп. Отправляешь файл в папку. Всё — твоё участие закончено на следующие 7 минут.
Сценарий уже в нужном формате: 45–55 секунд чистой речи, listicle, первые 4 секунды — хук. Никакого импровизированного монтажа в голове — агент написал текст так, чтобы он читался с первого дубля. Паузы ≥0.4 сек автоматически вырежутся на шаге 3.
Чек-лист съёмки — 10 пунктов
- Свет — источник перед лицом. Окно или LED-панель спереди, не сбоку и не сзади. Тень позади — окей. Тень на лице — нет. Время суток: утро или пасмурный день = идеально, прямой полуденный солнечный свет = жёсткие тени → шторы.
- Фон — однотонный или минимальный. Белая стена, тёмная стена, книжная полка в расфокусе. Без мигающих экранов позади, без людей в кадре. Размытие через Blur Background приложение — только если другого варианта нет (артефакты на краях).
- Одежда — контраст с фоном. Тёмный фон → светлая одежда, светлый фон → тёмная. Без мелкого узора (полосы, мелкая клетка) — артефакт кодека на движении. Без логотипов, которые Meta может пометить.
- Ракурс — камера на уровне глаз или чуть выше. Штатив или стабилизатор обязательно. Телефон вертикально. Лицо занимает верхние 2/3 кадра — нижняя треть уйдёт под субтитры.
- Расстояние — 60–80 см от камеры. Ближе — слишком крупный план, дальше — субтитры перекроют лицо. Face cam listicle = средний план по грудь.
- Длина записи — не дольше 90 сек исходника. Финальный ролик 45–55 сек, speed-up 1.2× на монтаже. Если затянул → агент обрежет по VAD, но лучше не давать лишнего материала.
- Формат файла — нативная съёмка 1080p/60fps, MOV или MP4. Не включай встроенную стабилизацию с warp (размыливает края) — физический штатив лучше.
- Пространство — тишина. Закрой окна, выключи кондиционер. Проверь через наушники 15 сек тишины перед стартом — слышен ли фон. Если слышен — устрани или перенеси съёмку.
- Дубль — один. Читаешь сценарий, пауза 2 сек, нажимаешь запись, смотришь в объектив. Если забыл слово — пауза 1 сек + продолжаешь. faster-whisper вырежет паузу, B-roll её закроет. Второго дубля нет — это правило, не рекомендация.
- Отправка — дроп-папка в облако. После съёмки файл улетает в
~/Reels/incoming/(iCloud Drive или Google Drive). Watchdog на сервере видит новый файл → автоматически запускает монтажный pipeline.
Аудио — 80% восприятия
Плохое видео прощается, плохое аудио — нет.
- Микрофон: встроенный микрофон iPhone 14+ — окей при тишине в комнате. Лучше: петличный Rode Wireless GO II или DJI Mic 2 ($200–300 одноразово). Петличка улучшает разборчивость на 40% и снижает шум обработки на шаге 3.
- Мониторинг: запиши 10-секундный тест, послушай в наушниках — не через динамик. Если слышно гудение или реверберация — проблема в комнате, не в микрофоне.
- Уровень: говори так, чтобы волна не клипала (пик < -6 dB в стандартном рекордере). Шаг 3 нормализует до -14 LUFS, но клиппинг не восстановить.
- Паузы: паузы между сегментами — 1 сек, агент специально ставит их в сценарии. Не заполняй их «эм» и «ну» — faster-whisper с
vad_filter=Trueвырезает, но лучше пустая пауза.
Тайминг по платформам
- Оптимальная длина исходника: 60–80 сек чистой речи
- После speed-up 1.2× → 50–67 сек → IG Reels принимает до 90 сек, Shorts < 60 сек
- Для YouTube Shorts: нужно ≤60 сек готового ролика. Если вышло 63 сек — обрезать последний сегмент
- Один дубль → монтаж автоматически → финал через 7 минут
- Смотришь в экран, не в объектив — аудитория чувствует «он не смотрит на меня»
- Начинаешь говорить сразу при записи — дать 1–2 сек паузы в начале для ingest
- Свет сзади → лицо в силуэте, Playwright color grading не спасёт
- Фоновый шум после обработки звучит как «металлический» — это артефакт агрессивного шумоподавления faster-whisper. Лучше тишина изначально
- Слишком длинный ролик (>90 сек) — монтаж добавит speed-up 1.2×, речь станет неразборчивой
faster-whisper → Playwright broll → ffmpeg
Ты отправил файл. Watchdog подхватил. Дальше — конвейер. 5 мегапроходов, 18 под-стадий, ~7 минут, на выходе готовый MOV с субтитрами, B-roll, цветокором, cover-кадром и сведённым аудио. Без тебя. Ниже — каждый шаг с реальной командой.
Pipeline основан на build_reel.py (master script) + render_scenes_v4.py (Playwright multiprocessing). Все стадии обязательны — пропуск любой запрещён. Стадии 3.5 (Cover) и 14.5 (QA) особенно важны: первая даёт thumbnail, вторая не даёт выпустить брак.
Проход 1 — Ingest + Crop + Audio Extract (Stage 0–2)
Что делает: копирует исходник в рабочую директорию, кропит до 9:16 1080×1920, добавляет blur-pad фон, нормализует аудио, удаляет паузы ≥0.4 сек через silencedetect.
# Stage 0 — Ingest (копия, без изменений)
cp ~/Reels/incoming/source.mov ~/brain/reels-production/$(date +%Y-%m-%d)_${SLUG}/source.mov
cd ~/brain/reels-production/$(date +%Y-%m-%d)_${SLUG}/
# Stage 2 — Crop 9:16 с blur-pad фоном
ffmpeg -i source.mov \
-filter_complex \
"[0:v]scale=-2:1920,crop=1080:1920,gblur=sigma=28,eq=brightness=-0.12[bg]; \
[0:v]crop=868:1080:(in_w-868)/2:0,scale=1080:1344[main]; \
[bg][main]overlay=0:288" \
-c:v libx264 -crf 18 -pix_fmt yuv420p -an \
renders/base_crop.raw.mp4
# Вытащить аудио отдельно для Whisper
ffmpeg -i source.mov -vn -ar 16000 -ac 1 -c:a pcm_s16le audio_raw.wav
# Silence detection — найти паузы для последующей нарезки
ffmpeg -i audio_raw.wav \
-af silencedetect=noise=-30dB:duration=0.4 \
-f null - 2>&1 | grep "silence_" > silence_markers.txt
Что получается: renders/base_crop.raw.mp4 — базовый кроп без цветокора, audio_raw.wav — 16kHz моно для Whisper, silence_markers.txt — временные метки пауз.
Проход 2 — faster-whisper word-level STT (Stage 1)
Что делает: транскрибирует речь с точностью до слова (±10 мс при использовании WhisperX с wav2vec2 alignment), выдаёт JSON с таймингами. Этот JSON — основа для субтитров и B-roll синхронизации.
# CLI — faster-whisper 1.2.1 (последняя версия на май 2026)
# Локально на CPU M-серии: ~10 сек на минуту аудио
python3 -m faster_whisper \
audio_raw.wav \
--model large-v3-turbo \
--language ru \
--word_timestamps True \
--vad_filter True \
--vad_parameters '{"min_silence_duration_ms": 400}' \
--output_format json \
--output_dir . \
--beam_size 5
# Переименовать в стандартный путь
mv audio_raw.json transcript.json
Python wrapper для интеграции в build pipeline:
from faster_whisper import WhisperModel
def transcribe(audio_path: str, model_size: str = "large-v3-turbo") -> dict:
"""
Возвращает dict с ключами:
- segments: список сегментов с start/end/text
- words: плоский список {word, start, end, probability}
"""
model = WhisperModel(model_size, device="cpu", compute_type="int8")
segments, info = model.transcribe(
audio_path,
language="ru",
word_timestamps=True,
vad_filter=True,
vad_parameters={"min_silence_duration_ms": 400},
beam_size=5
)
words = []
seg_list = []
for seg in segments:
seg_list.append({"start": seg.start, "end": seg.end, "text": seg.text})
if seg.words:
for w in seg.words:
words.append({
"word": w.word.strip(),
"start": round(w.start, 3),
"end": round(w.end, 3),
"probability": round(w.probability, 3)
})
return {"segments": seg_list, "words": words}
Формат word-level JSON на выходе:
{
"segments": [
{"start": 0.0, "end": 3.8, "text": "Этот ролик смонтирован без человека."}
],
"words": [
{"word": "Этот", "start": 0.42, "end": 0.78, "probability": 0.99},
{"word": "ролик", "start": 0.82, "end": 1.10, "probability": 0.98},
{"word": "смонтирован", "start": 1.14, "end": 1.82, "probability": 0.97},
{"word": "без", "start": 1.86, "end": 2.04, "probability": 0.99},
{"word": "человека", "start": 2.08, "end": 2.64, "probability": 0.98}
]
}
Этот JSON читают 4 downstream-стадии: субтитры, B-roll синхронизация, music brief, cover.
Проход 3 — Субтитрные overlays через Playwright → PNG sequence (Stage 4, 6C, 8)
Что делает: генерирует HTML-субтитры по word-level JSON, рендерит через Playwright в PNG-последовательность с прозрачным фоном, накладывает на base_crop через ffmpeg.
Два формата субтитров — выбор зависит от типа контента:
- Format A (Glass plate) — для listicle/tutorial/фичи. Стеклянная плашка внизу, Inter Bold 58px, backdrop-blur, safe zone
bottom: 450px, ширина 880px. Один активный сегмент на экране. - Format D (Kinetic stack) — для эмоциональных монологов, личных историй, pivot-моментов. Кинетическая стека слов с разными размерами, одно hero-слово за головой спикера (text-behind). Требует rembg-маску лица (~180 кадров на 6-секундную сцену).
Выбор формата определяется из транскрипта автоматически: listicle/tutorial → Format A, личная история/эмоции → Format D.
# Генерация HTML из word JSON (Format A — glass)
def gen_subtitle_html_glass(words: list, out_path: str):
"""Собирает overlay_glass.html по word-level данным"""
# Группируем слова в строки по 4-5 слов
# Каждая группа = один frame-range для субтитра
lines = group_words_into_lines(words, max_words=5)
# Генерируем GSAP timeline с точными start/end из JSON
html = render_template("subtitle_glass_template.html", lines=lines)
Path(out_path).write_text(html)
# Playwright render PNG sequence (render_scenes_v4.py — multiprocessing)
python3 render_scenes_v4.py \
--scenes overlay_glass.html:$(ffprobe -v error -show_entries format=duration \
-of csv=p=0 renders/base_crop.raw.mp4) \
--fps 30 \
--out out_v4/overlay/
# Output: out_v4/overlay/frame_%05d.png (alpha PNG, 1080×1920)
# render_scenes_v4.py — дефолтный рендерер, 5× быстрее baseline
# Копируй из эталона, адаптируй список BROLLS
cp ~/brain/reels-production/_etalon/render_scenes_v4.py render_v4.py
# Отредактируй BROLLS = [("overlay_glass.html", <duration_frames>), ...]
python3 render_v4.py
# Output: out_v4/overlay/frame_%05d.png
Наложение субтитров через ffmpeg:
# Format A — один слой overlay
ffmpeg -i renders/base_crop.mp4 \
-i out_v4/overlay/frame_%05d.png \
-filter_complex \
"[1:v]format=rgba[sub]; \
[0:v][sub]overlay=0:0:format=auto" \
-map 0:a \
-c:v libx264 -preset fast -crf 18 -pix_fmt yuv420p \
renders/composite_subs.mp4
Проход 4 — B-roll HTML render (Stage 5–6, 12 типов)
Что делает: для каждой из 5 B-roll вставок генерирует HTML-сцену, рендерит в PNG-sequence через Playwright, вставляет в timeline по таймингу из word-level JSON.
12 типов B-roll сцен (Format D HTML-типы): chart-card, terminal, listicle-ticker, meme-reference, named-entity-card, progress-bar, split-compare, counter-animate, flow-diagram, pictogram-multi, podcast-hook, narrative-canvas.
Логика выбора типа (из transcript):
- Упомянуто имя собственное (компания, личность) →
named-entity-card(Format E — реальный скриншот через Playwright) - Упомянута цифра/статистика →
counter-animateилиchart-card - Шаги процесса →
flow-diagramилиprogress-bar - Listicle без брендов →
listicle-ticker - Иконка-метафора →
pictogram-multi
# Пример ffmpeg-вставки B-roll поверх face cam
# B-roll занимает секунды [start_t, end_t] в итоговом таймлайне
ffmpeg -i renders/composite_subs.mp4 \
-i out_v4/b01/frame_%05d.png \
-filter_complex \
"[1:v]format=rgba[broll]; \
[0:v][broll]overlay=0:0:enable='between(t,${BROLL_START},${BROLL_END})':format=auto" \
-map 0:a \
-c:v libx264 -preset fast -crf 18 -pix_fmt yuv420p \
renders/composite_broll.mp4
Важно перед concat: нормализация fps + timescale (иначе duration сломается в 20–30×):
for f in segments/*.mp4; do
ffmpeg -y -i "$f" \
-r 30 -fps_mode cfr -vf "fps=30" \
-video_track_timescale 15360 \
-c:v libx264 -crf 18 -preset fast \
-c:a aac -b:a 192k \
"${f}.norm.mp4"
mv "${f}.norm.mp4" "$f"
done
# Concat без re-encoding (~200× быстрее)
ffmpeg -f concat -safe 0 -i segments/concat.txt -c copy out/concat.mp4
# Проверка длительности
ffprobe -v error -show_entries format=duration -of csv=p=0 out/concat.mp4
Cover Branch (Stage 3.5 — параллельно с основным flow)
Запускается параллельно со Stage 3, не блокирует основной pipeline. Даёт cover.png для Stage 14.7.
# Stage 3.5.b — выбор лучшего hero-кадра через mediapipe FaceMesh
# Скорит по: face_size × open_eyes × (1 − rotation) + hands_bonus
python3 cover_hero_select.py \
--video renders/base_crop.raw.mp4 \
--samples 5 \
--out cover/hero.jpg
# Stage 3.5.d — composite через Playwright (шаблон split_v3.html)
# text_above: THUMBNAIL_HOOK из сценария агента
# hero_image: cover/hero.jpg
python3 cover_builder.py \
--template split_v3.html \
--hook "${THUMBNAIL_HOOK}" \
--hero cover/hero.jpg \
--out cover/cover.png
# Stage 14.7 — embed cover как frame 0 (hold 0.3с — IG берёт первый кадр)
ffmpeg -y \
-loop 1 -t 0.3 -framerate 30 -i cover/cover.png \
-i FINAL.mp4 \
-f lavfi -t 0.3 -i anullsrc=r=44100:cl=stereo \
-filter_complex "
[0:v]scale=1080:1920,setsar=1,fps=30,format=yuv420p[c];
[1:v]scale=1080:1920,setsar=1,fps=30,format=yuv420p[m];
[c][m]concat=n=2:v=1:a=0[outv];
[2:a][1:a]concat=n=2:v=0:a=1[outa]" \
-map "[outv]" -map "[outa]" \
-c:v libx264 -preset medium -crf 18 \
-c:a aac -b:a 192k -pix_fmt yuv420p -movflags +faststart \
FINAL_with_cover.mp4
Проход 5 — Speed-up + Audio mux + Ducking (Stage 9–14)
Что делает: ускоряет на 1.2×, прикрепляет оригинальный голос, обнаруживает сцены, генерирует музыку, делает финальный микс с sidechain-ducking. Это самый длинный проход по времени (~3–4 мин).
# Stage 9 — Speed-up 1.2× (ДО генерации музыки)
ffmpeg -i composite_broll.mp4 \
-filter_complex "[0:v]setpts=PTS/1.2[v]" \
-map "[v]" -c:v libx264 -preset fast -crf 18 -pix_fmt yuv420p \
composite_silent_120.mp4
# Stage 10 — Mux оригинального голоса (тоже atempo 1.2)
ffmpeg -i composite_silent_120.mp4 -i source.mov \
-filter_complex "[1:a]atempo=1.2[a]" \
-map 0:v -map "[a]" -c:v copy -c:a aac \
composite_voice.mp4
# Stage 11 — Scene detection (для music brief)
ffmpeg -i composite_voice.mp4 \
-filter:v "select='gt(scene,0.25)',showinfo" -f null - 2>&1 \
| grep showinfo > scene_cuts.txt
# Stage 14 — Final mux + sidechain ducking
# Voice: loudnorm -14 LUFS; Music: -20 dB; Sidechain: ratio=12 attack=15ms release=400ms
ffmpeg -i composite_voice.mp4 -i music.mp3 \
-filter_complex "
[0:a]loudnorm=I=-14:LRA=11:TP=-1.5,asplit=2[voice_main][voice_trig];
[1:a]atrim=0:${DURATION},volume=0.20,aformat=channel_layouts=stereo[music];
[music][voice_trig]sidechaincompress=threshold=0.05:ratio=12:attack=15:release=400:makeup=1[music_ducked];
[voice_main][music_ducked]amix=inputs=2:duration=first:normalize=0[aout]
" \
-map 0:v -map "[aout]" \
-c:v copy -c:a aac -b:a 192k \
-t ${DURATION} \
FINAL.mp4
# Финальная проверка аудио (должно быть 48000 Hz)
ffprobe -v error -select_streams a:0 \
-show_entries stream=sample_rate,codec_name,channels \
-of csv=p=0 FINAL.mp4
QA Engine (Stage 14.5)
Обязателен перед выпуском. Без исключений. Минимальный порог: aggregate ≥ 7.0. Три движка проверки:
Engine A — детерминированные чеки:
- Длительность финального ролика: 45–90 сек для IG, ≤60 сек для YT Shorts
- Аудио sample_rate = 48000 Hz
- Имя файла — только ASCII, slug-формат
- pix_fmt = yuv420p
- Cover frame 0 присутствует (ffprobe первый кадр != black)
- CTA overlay присутствует в последних 4 сек
- 5 B-roll вставок (не 4, не 6)
- Субтитры покрывают все 5-секундные окна
Engine B — визуальный ревью (Playwright):
- Текст субтитров не выходит за safe zone (
x ∈ [65, 1015],y ∈ [269, 1248]) - B-roll качество ≥ V6 threshold (нет пустых кадров, нет GSAP-артефактов с opacity:0)
- Cover hook ≤6 слов, нет текста на лице
Engine C — общий просмотр: смотришь финальный ролик полностью, аудио разборчиво, нет артефактов resize/crop на гранях. Если ≥1 critical rubric «нет» — не публиковать, исправить, перебилдить проход.
- Кириллица в имени файла → Meta 400.
video_urlс кирилличным именем файла = ошибка при создании контейнера. Имя всегда ASCII + slug:reels-autopipeline-2026-05-21.mov. Автоматически форсировать черезos.path.basename(slugify(filename)). - Аудио >48kHz → Meta отклоняет ролик. Meta принимает AAC максимум 48 kHz. Если исходник 44.1 kHz или 96 kHz — ffmpeg явно ресемплит:
-ar 48000. Проверять черезffprobeдо отправки. - Playwright
--disable-gpuобязателен в headless. Без флага backdrop-blur в CSS рендерится с артефактами (серые прямоугольники вместо blur). Обязательный аргумент при launch:chromium.launch(args=["--disable-gpu", "--no-sandbox"]). На Mac локально — не нужен, на Linux VPS — обязателен. - GSAP
opacity:0в paused timeline = пустой PNG. Не использоватьgsap.set('#el', {opacity:0})или CSSopacity:0без последующегоto({opacity:1}). Результат — полностью прозрачный alpha-PNG на всех кадрах. Фикс:opacity:1в CSS, fade через ffmpeg-vf fade=t=in. - B-roll пропуск или меньше 5 вставок. Pipeline проверяет через Engine A, но если скипнуть QA — Meta может опубликовать, но ролик без B-roll теряет save-rate × 2.4 (данные батча май 2026). Всегда 5 вставок. Всегда.
Коммент → DM → Mini App → лид
Каждый ролик — это не просто ролик. Это воронка. Под каждый slug — своя страница, своё кодовое слово, свой лид-магнит. Ты читаешь эту страницу потому что написал слово ПАЙПЛАЙН в комментах или пришёл по ссылке из личного сообщения. Вот как это собрано технически.
Воронка автономна — ни одного ручного шага после публикации ролика. Параллельно с монтажом агент генерирует лендинг, деплоит его, настраивает ManyChat keyword, регистрирует webhook. К моменту публикации ролика всё готово.
8 шагов от комментария до лида
- Пользователь пишет кодовое слово в комментарии к ролику IG. ManyChat слушает comments webhook на посте. Keyword detection: точное совпадение (case-insensitive) с полем
cta_keywordиз конфига (например,ПАЙПЛАЙН). - ManyChat отправляет автоматический DM через Instagram Messaging API. Задержка ≤60 сек от комментария. Тело DM: «Держи ссылку: defi-cap.com/audit/{slug}/» + кнопка «Открыть».
- Параллельно ManyChat отправляет публичный ответ на комментарий (опционально — повышает engagement для алгоритма): «Отправил ссылку в личку!»
- Пользователь открывает лендинг
defi-cap.com/audit/{slug}/. UTM-параметры автоматически:?utm_source=ig_reels&utm_medium=comment&utm_content={slug}. Лендинг уже задеплоен Build-агентом до публикации ролика. - На лендинге — CTA «Получить полный гайд». Кнопка ведёт на
https://t.me/defi_cap_bot?start=audit_{slug}. Deep-link формат:audit_{slug}(underscore, не дефис — ограничение Telegram start-параметра). - TG Bot принимает
/start audit_{slug}. Проверяет подписку на канал@defi_cap_blog. Если нет — предлагает подписаться (soft gate, не hard block). Отправляет анкету из 3 вопросов через inline keyboard. - Анкета (3 вопроса): «Твоя ниша?» (DeFi / AI-автоматизация / Другое), «Главная задача?» (Монетизировать контент / Автоматизировать работу / Разобраться в DeFi), «Опыт с агентами?» (Нет / Немного / Активно использую).
- Ответы → Postgres, лид создан. Поля:
user_id,source_slug,utm_content,niche,goal,experience,created_at. После анкеты бот открывает материал в Mini App и отправляет «Держи гайд + ffmpeg-скрипты».
ManyChat setup — keyword flow через API
Настройка в ManyChat для каждого нового ролика (автоматически через ManyChat API):
import requests
MANYCHAT_API = "https://api.manychat.com"
TOKEN = "Bearer {MANYCHAT_TOKEN}"
def setup_keyword_flow(keyword: str, dm_text: str, page_id: str):
"""Регистрирует keyword trigger + DM flow для нового ролика"""
# Создать Flow с DM-ответом
flow_payload = {
"name": f"KW_{keyword}",
"type": "automation",
"trigger": {
"type": "ig_comment_keyword",
"keywords": [keyword],
"match_type": "exact" # или "contains"
},
"messages": [
{
"type": "ig_dm",
"text": dm_text,
"buttons": [{"type": "url", "caption": "Открыть", "url": "{LANDING_URL}"}]
}
]
}
r = requests.post(f"{MANYCHAT_API}/fb/sending/sendFlow",
headers={"Authorization": TOKEN},
json=flow_payload)
return r.json()
ManyChat Pro план ($15–65/мес) обязателен для comment-to-DM automation. Free plan позволяет только reply в thread, не DM. Ограничения 2026:
- До 1000 DM в сутки с одного IG Business аккаунта через API (Meta messaging limit)
- 24-часовое messaging window: ответить в DM можно только в течение 24ч после комментария пользователя
- Keyword matching в комментариях — только для публичных постов (не Stories)
IG Graph webhook payload
ManyChat слушает comments нативно. Если нужен прямой webhook (для кастомной логики):
# FastAPI endpoint для IG Webhooks
from fastapi import FastAPI, Request
import hmac, hashlib
app = FastAPI()
IG_APP_SECRET = "{YOUR_APP_SECRET}"
@app.post("/webhook/ig-comments")
async def ig_comment_webhook(request: Request):
# Signature verification
body = await request.body()
sig = request.headers.get("x-hub-signature-256", "")
expected = "sha256=" + hmac.new(
IG_APP_SECRET.encode(), body, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(sig, expected):
return {"status": "invalid_signature"}
data = await request.json()
for entry in data.get("entry", []):
for change in entry.get("changes", []):
if change["field"] == "comments":
comment_text = change["value"].get("text", "").upper()
if comment_text == "ПАЙПЛАЙН": # или из config
await handle_keyword_comment(change["value"])
return {"status": "ok"}
Подписка на webhook при регистрации приложения: Field = comments, Object = instagram, Callback URL = https://defiserv.org/webhook/ig-comments, Verify token — произвольная строка из .env.
TG Bot deep-link формат
Формат deep-link для TG Mini App:
https://t.me/defi_cap_bot?start=audit_{slug}
Где {slug} — latin kebab-case, но в start-параметре Telegram только латиница, цифры и подчёркивания. Дефисы не поддерживаются в start. Поэтому audit_reels-pipeline → audit_reels_pipeline.
# TG Bot handler для deep-link
from aiogram import Router
from aiogram.filters import CommandStart
from aiogram.types import Message
router = Router()
@router.message(CommandStart(deep_link=True))
async def handle_start_deeplink(message: Message, command):
payload = command.args # например: "audit_reels_pipeline"
if payload.startswith("audit_"):
slug = payload[6:].replace("_", "-") # обратно в kebab
await send_survey(message.from_user.id, source_slug=slug)
else:
await message.answer("Привет! Напиши ПАЙПЛАЙН под последним роликом.")
Mini App survey → Postgres CRM
Postgres-схема для хранения лидов из воронки:
CREATE TABLE reel_leads (
id SERIAL PRIMARY KEY,
tg_user_id BIGINT NOT NULL,
source_slug VARCHAR(100) NOT NULL, -- slug ролика-источника
utm_source VARCHAR(50),
utm_medium VARCHAR(50),
niche VARCHAR(50), -- DeFi / AI-automation / Other
goal VARCHAR(100),
experience VARCHAR(50), -- none / some / active
subscribed BOOLEAN DEFAULT FALSE, -- подписан на канал
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(tg_user_id, source_slug) -- дедупликация
);
CREATE INDEX idx_reel_leads_slug ON reel_leads(source_slug);
CREATE INDEX idx_reel_leads_created ON reel_leads(created_at DESC);
- 1 ролик → в среднем 4–12 комментариев с кодовым словом
- Комментарий → DM открытие: ~70% (ManyChat delivery rate)
- DM открытие → клик на лендинг: ~45%
- Лендинг → TG Bot: ~35%
- TG Bot → анкета заполнена: ~65%
- Итого: 1 ролик → 1–4 квалифицированных лида через воронку коммент→DM→бот
- Кейс май 2026: 4 ролика → 17 лидов (avg 4.25/ролик) без платной рекламы
Одновременно, по расписанию
MOV готов, лендинг задеплоен, ManyChat keyword настроен. Агент публикует сам. Instagram Reels и YouTube Shorts одновременно — по расписанию, через официальные API. Ручного действия ноль.
Два независимых публикатора запускаются одним cron-job. Meta Graph API и YT Data API v3 — никаких сторонних сервисов, никаких буферов. Прямой вызов, полный контроль метаданных.
Meta Graph API v21.0 — три шага публикации
Шаг 1 — загрузка видео на CDN + создание контейнера:
# Сначала выгрузить файл на публично доступный CDN (S3, Cloudflare R2, или свой VPS)
# Имя файла — только ASCII! Кириллица = ошибка 400
VIDEO_URL="https://cdn.defiserv.org/reels/reels-autopipeline-2026-05-21.mp4"
IG_USER_ID="17841400000000000" # из приложения Meta
ACCESS_TOKEN="EAAGm..." # long-lived token, обновляется каждые 60 дней
curl -X POST \
"https://graph.facebook.com/v21.0/${IG_USER_ID}/media" \
-H "Content-Type: application/json" \
-d '{
"media_type": "REELS",
"video_url": "'"${VIDEO_URL}"'",
"caption": "Этот ролик снят, смонтирован и опубликован — без меня.\n\nПиши ПАЙПЛАЙН в комменты — пришлю архитектуру стека.\n\n#ClaudeCode #AIавтоматизация #DeFi #ffmpeg #Reels",
"share_to_feed": true,
"thumb_offset": 0
}'
# Возвращает: {"id": "<CONTAINER_ID>"}
Обязательные permissions для App: instagram_business_basic, instagram_business_content_publish (старые instagram_basic + instagram_content_publish deprecated с 27 января 2025).
Шаг 2 — polling статуса (не публиковать до FINISHED):
import time
import requests
def wait_for_container(container_id: str, token: str, max_wait: int = 300) -> bool:
"""Ждёт FINISHED статуса, возвращает True если успешно"""
url = f"https://graph.facebook.com/v21.0/{container_id}"
for attempt in range(max_wait // 10):
resp = requests.get(url, params={
"fields": "status_code,status",
"access_token": token
}).json()
status = resp.get("status_code")
if status == "FINISHED":
return True
if status == "ERROR":
print(f"Container error: {resp.get('status')}")
return False
time.sleep(10)
return False # timeout
Шаг 3 — публикация:
def publish_reel(ig_user_id: str, container_id: str, token: str) -> str:
resp = requests.post(
f"https://graph.facebook.com/v21.0/{ig_user_id}/media_publish",
json={"creation_id": container_id, "access_token": token}
)
data = resp.json()
if "id" in data:
return data["id"] # media_id опубликованного поста
raise Exception(f"Publish error: {data}")
Технические требования к файлу (актуально 2026):
- Контейнер: MP4 или MOV (moov atom в начале —
-movflags +faststart) - Видео-кодек: H.264, progressive scan, closed GOP, 4:2:0 chroma
- Аудио-кодек: AAC, 48 kHz максимум, моно или стерео
- Frame rate: 23–60 FPS
- Aspect ratio: 9:16 (обязательно для Reels tab eligibility)
- Длительность: 5–90 сек для Reels tab
- Max file size: 100 MB (для resumable upload — без ограничения)
- Rate limit: 100 API-published posts / 24ч rolling window
YT Data API v3 — videos.insert
YouTube Data API v3, videos.insert. Shorts — обычное видео с тегом #Shorts.
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
def upload_short(
video_path: str,
title: str,
description: str,
tags: list[str],
credentials: Credentials
) -> str:
"""Возвращает video_id опубликованного Shorts"""
youtube = build("youtube", "v3", credentials=credentials)
body = {
"snippet": {
"title": title, # ≤100 символов
"description": description, # ≤5000 символов
"tags": tags, # список строк, 500 chars total
"categoryId": "28", # Science & Technology
"defaultLanguage": "ru"
},
"status": {
"privacyStatus": "public", # public / unlisted / private
"selfDeclaredMadeForKids": False,
"madeForKids": False
}
}
# Resumable upload — обязателен для файлов >5 MB
media = MediaFileUpload(
video_path,
mimetype="video/mp4",
resumable=True,
chunksize=256 * 1024 # 256 KB chunks
)
request = youtube.videos().insert(
part="snippet,status",
body=body,
media_body=media
)
response = None
while response is None:
status, response = request.next_chunk()
if status:
print(f"Upload {int(status.progress() * 100)}%")
return response["id"]
Квота YT Data API: 10 000 units/день (free). videos.insert = 1 600 units. Итого: 6 Shorts/день в рамках квоты.
OAuth2 Setup (одноразово): Google Cloud Console → API & Services → Credentials → OAuth 2.0 Client ID (Desktop app) → скачать client_secrets.json → запустить flow авторизации через google-auth-oauthlib → получить token.json. Хранить в .env или Secret Manager — не в репо.
Метаданные — caption / description / теги
Стандартный шаблон caption/description для каждого ролика:
# IG Caption (до 2200 символов)
{HOOK_FIRST_LINE}
{BODY_2_3_LINES}
Пиши {CTA_KEYWORD} в комменты — пришлю {LEAD_MAGNET}.
{HASHTAGS_7_10}
# YT Description (до 5000 символов)
{HOOK_FIRST_LINE}
{FULL_BODY_3_5_LINES}
Полный гайд: https://defi-cap.com/audit/{SLUG}/
Пиши {CTA_KEYWORD} в комментарии — пришлю ссылку.
Теги: {TAGS_COMMA_SEPARATED}
#Shorts
- Хэштеги (7–10 для IG): выбираются из
search_hashtagsVirlo за последние 7 дней,order_by: views - Миксуй нишевые (~50K–500K постов) и высокочастотные (~1M+)
- Пример для DeFi/AI:
#ClaudeCode #AIавтоматизация #DeFi #Reels #автоматизация #Python #ffmpeg - YT теги: 500 символов total, через запятую, без хештегов
- Title (YT): ≤100 символов, цифра + hook первой строки
Расписание и музыка
Оптимальное время публикации для DeFi/AI-ниши (данные батча + Instagram Insights):
- Вторник / Четверг: 10:00 МСК (аудитория активна до работы) или 19:00–20:00 МСК (вечерний пик engagement)
- Пятница: 18:00–19:00 МСК (перед выходными — пик saves)
- YT публикуется одновременно с IG (алгоритмы независимы, конкуренции нет)
schedule.yamlв директории агента — расписание на неделю вперёд- Лицензия музыки: Epidemic Sound ($15/мес) или Artlist ($16.60/мес) — обе покрывают IG, YT и другие платформы
- Meta: если
media_publishвызван до FINISHED → 400. Всегда polling. Если container зависает в ERROR — создать новый контейнер, не retry старый - YT: видео ≤60 сек + 9:16 → автоматически Shorts. Не нужен отдельный endpoint — просто добавь
#Shortsв описание - IG: нельзя добавить трек из библиотеки Instagram через API. Только аудио, встроенное в файл до загрузки
- YT квота: 1600 units за upload. При 6 роликах/день = 9600 units из 10000 квоты. Остаток уходит на Analytics API — считай заранее
- Meta: access_token живёт 60 дней. Настрой авто-обновление через
/oauth/access_token?grant_type=fb_exchange_tokenраз в 45 дней
Метрики каждого ролика — вечером в Telegram
В 22:00 в личку приходит отчёт. По каждому активному ролику (последние 14 дней) — одна строка: просмотры, retention, комменты, клики, лиды. Открываешь — сразу видишь что сработало сегодня.
Агент дёргает три источника, сводит в таблицу, сравнивает с порогами — и если что-то выходит за рамки (хорошо или плохо), добавляет флаг. Один раз смотришь, одно решение принимаешь.
Метрики — что собирается
- Views —
video_view_count(IG Insights) +views(YT Analytics) - Reach —
reach(IG Insights, уникальные аккаунты) - Retention% —
video_view_rateIG (доля досмотревших до конца) +averageViewPercentageYT - Saves —
saved(IG Insights, signal для алгоритма) - Comments с кодовым словом — из Postgres (webhook лог)
- DM отправлено — ManyChat API
GET /subscribers/countпо flow - Клики на лендинг — UTM-трекинг в Postgres (
utm_content = {slug}) - Открытий Mini App — из Postgres (
tg_eventsWHEREevent_type = 'miniapp_open') - Анкет заполнено — из Postgres (
reel_leads WHERE source_slug = {slug}) - Лидов — итого строк в
reel_leads WHERE source_slug = {slug}
IG Insights доступны через ~6 часов после публикации, YT Analytics — через ~24 часа. Daily report в 22:00 МСК охватывает данные за предыдущие 48 часов (по IG) и 72 часа (по YT).
Формат TG-сообщения
TG-сообщение репорта (JetBrains Mono блок):
📊 Daily Report · 21.05.2026 · 22:00
Ролик │ Views │ Ret% │ Saves │ DMs │ Лиды │ Паттерн
reels-autopipeline │ 1240 │ 68% │ 87 │ 34 │ 4 │ listicle/цифра
news-agent-5sys │ 3579 │ 71% │ 214 │ 120 │ 12 │ counter-narrative
montage-zero-cost │ 890 │ 54% │ 41 │ 18 │ 2 │ tutorial
---
⬆️ Топ: news-agent-5sys · Ret% 71% · Лидов 12
⚠️ Ниже avg: montage-zero-cost · Ret% 54% (< 60% threshold)
Источники: IG Insights + YT Analytics + Postgres CRM
Следующий постинг: 22.05 10:00 МСК → reels-budget-breakdown
Алертинг — когда добавляется флаг
⬆️ OUTLIER— Ret% > 75% или Saves > 200 в первые 48ч → контент попал в рекомендации. Сигнал: повторить паттерн в следующем сценарии⚠️ НИЖЕ НОРМЫ— Ret% < 60% за первые 48ч → паттерн добавляется вbanned_patternsprofile.yaml на следующей итерации агента🚨 ESCALATE— Views < 200 за 48ч → проблема с публикацией (не попало в рекомендации, возможно Meta review delay). Проверить статус поста вручную💰 ЛИДЫ×3— Лидов > 3× average для этого ролика → высокая конверсия воронки. Создать follow-up ролик по той же теме
Бенчмарки DeFi/AI-ниши
Бенчмарки для DeFi/AI-ниши (50–500K подписчиков, данные батча май 2026):
- Views / 48ч: < 500 ниже среднего, 500–2K среднее, 2–10K хорошо, > 10K отлично
- Retention%: < 55% ниже среднего, 55–65% среднее, 65–75% хорошо, > 75% отлично
- Saves / 1K Views: < 5 ниже, 5–15 среднее, 15–30 хорошо, > 30 отлично
- DMs / 1K Views: < 2 ниже, 2–10 среднее, 10–30 хорошо, > 30 отлично
- Лидов / ролик: 0–1 ниже, 2–5 среднее, 5–15 хорошо, > 15 отлично
$125–135/мес — куда именно
Никакой магии. Каждый доллар виден. Разбивка по статьям с альтернативами для каждой.
Breakdown по строкам
- VPS (Hostman) — $20/мес. 2 vCPU / 4 GB RAM — монтажный агент, watchdog, Postgres, TG-бот
- Claude Code — $120/сезон (~$30–40/мес на контент). Pro подписка $20 + API за агентов ~$10–20/мес при умеренном объёме
- Virlo MCP — ~$15/мес. $0.50 × 30 запросов
search_keywords(ежедневно) - faster-whisper — $0. Локально CPU, модель large-v3-turbo — бесплатно
- Playwright — $0. Open-source
- ffmpeg — $0. Open-source
- Meta Graph API — $0. Бесплатно в рамках 100 posts/day квоты
- YT Data API — $0. Бесплатно до 10K units/day (6 uploads)
- Музыка (Epidemic Sound) — $15/мес. Лицензия IG + YT + TikTok
- ManyChat Pro — $15–65/мес. По числу контактов; 500 контактов = $15/мес
- Итого базовый — ~$95–115/мес (без CC, если уже есть)
- Итого с CC — ~$125–155/мес (зависит от активности сессий)
Альтернативы — как сократить бюджет
- Whisper: OpenAI API вместо локального.
whisper-1модель ~$0.006/мин аудио. При 4 роликах/нед × 1 мин = ~$0.10/нед = <$1/мес. Но нет word-level timestamps → SubtitlesXtend или WhisperX alignment (~$0 локально). Локальный faster-whisper на M-серии всё равно быстрее и дешевле. - Музыка: Free tier. YouTube Audio Library (CC0), FreeMusicArchive, Pixabay Music — бесплатно, но выбор ограничен и треки реже в тренде. Artlist One: $16.60/мес (включает синхронизацию).
- ManyChat: self-hosted альтернатива. Собственный IG Webhooks + FastAPI + aiogram. $0, но ~8 часов на setup. При объёме <200 DM/день — окупается за 1 месяц.
- VPS: дешевле. Hetzner CX22 = €4.51/мес (2 vCPU, 4 GB) vs $20 Hostman. Разница в скорости отклика и локации (EU vs RU).
- Virlo: только weekly. Вместо ежедневного запуска — 1 раз в неделю. Экономия: $15 → $2/мес. Агент строит очередь из 7 сценариев на неделю.
От нуля до первой публикации — 7 шагов
Весь стек звучит громоздко. На деле первый ролик можно выпустить за 2–3 дня. Вот конкретный чек-лист.
7 шагов с временными рамками
- День 1 (3 часа): Стек и окружение.
- Арендовать VPS (Hetzner или Hostman, Ubuntu 22.04, 4 GB RAM)
- Установить: Python 3.11, ffmpeg 6+, Node.js 20+, Playwright (
pip install playwright && playwright install chromium) - Установить faster-whisper:
pip install faster-whisper==1.2.1 - Склонировать
build_reel.pyиз эталона, прогнать на тестовом MOV - Результат: конвейер работает локально на тестовом видео
- День 1 (1 час): profile.yaml.
- Создать
profile.yaml: ниша, бренд-войс, target_duration, cta_keyword,banned_patterns: [] - Создать
queue.json: [] - Проверить: агент читает профиль без ошибок
- Создать
- День 2 (2 часа): Meta App + YT OAuth.
- Meta for Developers → создать App → добавить Instagram Basic Display + Content Publishing permissions
- Получить
ig_user_id+ long-lived access token - Google Cloud Console → YouTube Data API v3 → OAuth Client → скачать
client_secrets.json→ авторизоваться - Проверить: тестовая публикация в черновик (
privacyStatus: "private") на YT + тест container creation на Meta
- День 2 (1 час): ManyChat flow.
- Подключить IG Business аккаунт к ManyChat
- Создать первый keyword flow: слово = твоё кодовое, DM = текст с ссылкой на лендинг
- Протестировать: написать слово с другого аккаунта → получить DM
- День 3 (2 часа): Pre-research агент.
- Настроить Virlo MCP (API key)
- Залить
research_agent.pyс prompt_template из section 1 - Запустить вручную: убедиться что агент возвращает 2–3 сценария в нужном формате
- Настроить cron:
30 3 * * * python3 /home/reels/research_agent.py(06:30 МСК = 03:30 UTC)
- День 3 (1 час): Первая съёмка.
- Взять первый сценарий из агента
- Снять по чек-листу section 2 (10 пунктов)
- Отправить в дроп-папку — проверить что watchdog подхватил и запустил
build_reel.py - Дождаться
FINAL_with_cover.mp4(~7 минут)
- День 3 (30 минут): Первая публикация.
- Запустить
publisher.py: Meta + YT одновременно - Проверить в IG и YT через 5 минут — ролик опубликован
- Настроить daily_report cron:
0 19 * * * python3 /home/reels/daily_report.py(22:00 МСК = 19:00 UTC) - Готово. Смотришь вечерний отчёт и видишь первые метрики.
- Запустить
Один час в неделю на запись, всё остальное — машина
- 15 минут на съёмку: штатив, один дубль, дроп-папка — твоё участие закончено
- ~7 минут автомонтажа: 5 проходов, 18 стадий, faster-whisper + Playwright + ffmpeg без тебя
- Лендинг под каждый ролик: деплоится до публикации, уникальный slug, кодовое слово
- Воронка работает сама: ManyChat ловит слово, DM уходит за 60 сек, TG-бот ведёт в анкету
- IG Reels + YT Shorts одновременно, по расписанию, через официальные API
- Вечерний отчёт в 22:00: просмотры, retention, лиды — одна таблица в Telegram
- Паттерны, которые не сработали, автоматически уходят в
banned_patterns - 4 ролика в неделю = 16–48 лидов в месяц без платной рекламы
Честный итог: сборка занимает 6 месяцев, не 3 дня. build_reel.py работает — но он написан под мой стек, мой бренд-войс, мою нишу. Под твой нужно адаптировать profile.yaml, переписать prompt_template, откалибровать silence detection под темп твоей речи. Это не plug-and-play.
Второй честный момент: HUMAN-in-the-loop здесь реальный. Агент не знает когда ты облажался на съёмке и не заметил. Агент не чувствует что тема устарела за ночь (быстрые новостные хуки). Агент не заменяет твой личный опыт в сценарии — он структурирует, ты наполняешь. QA Engine на Stage 14.5 ловит технический брак, но смысловой брак — на тебе.
Третий: бюджет $125–135/мес — это дополнительно к Claude Code ($120 уже есть если используешь). Реальная новая статья: VPS ($20) + музыка ($15) + ManyChat ($15) + Virlo ($15) = ~$65/мес. Остальное уже оплачено или бесплатно.
~/brain/reels-production/_etalon/— эталоны pipeline~/brain/reels-production/_pipeline/build_reel.py— master scriptcontent/reels/01-pipeline.md— 18 stages подробноcontent/reels/07-broll-format-D-html.md— 12 типов B-roll HTML
Забери архитектуру всего пайплайна + ffmpeg-скрипты + Playwright-шаблоны
Внутри: scenario-agent prompt-template с profile.yaml, ffmpeg-команды всех 5 проходов, broll-html шаблоны (12 типов), ManyChat flow JSON, Meta Graph API + YT Data API setup с реальными payload'ами, конфиг daily-report агента. Всё открывается в Mini App после короткой анкеты (3 вопроса, 2 минуты).
Открыть в Telegram →