Пунктир — шаг, который делается руками. Всё остальное — команды одного инструмента, порядок — в разделе Команды и файлы.
Размеры — в пикселях кадра 1080×1920. Они записаны в профиле канала и одинаковы для всех его шортсов.
123
45
Первый шортс в мобильном YouTube. Плеер кладёт на кадр кнопки справа и подпись снизу.
Отбирает агент Draper по расшифровке с ролями. Задание для него пишется само — с каналом, выпуском и правилами канала. Человек смотрит уже готовые шортсы на контрольном листе.
Почему сильно: контринтуитивный тезис первой же фразой, рабочий приём и смешной финал про футболку и рубашку.
Границы — по репликам, не по секундам: от начала первой реплики до конца последней. К ним добавляется воздух до соседних слов — до 0,25 с в начале и 0,30 с в конце, чтобы фраза не начиналась встык и чужое слово не попадало. Проверка кодом ловит то, что иначе всплывёт после рендера: длину, несуществующие реплики, уточнение к чужой реплике или с обрезанным текстом, запреты канала, имя файла.
Слева — кадр выпуска с рамкой, которую выбрала машина. Справа — то, что попало в шортс.




Под каждым лицом берём пятно на груди и смотрим его средний цвет. Одежда меняется от съёмки к съёмке — правила пишутся в задании выпуска.
| кто | одежда | место |
|---|---|---|
| Татьяна | светлая | слева |
| Семён | тёмная | по центру |
| Ксения | красная | справа |
На этом кадре по одежде узнана только Ксения. Остальным имя дало место за столом: люди слева направо не меняются местами, поэтому неузнанный левее гостя — Татьяна.
Лица соседних замеров одной склейки — одна дорожка, один человек. Имя получает дорожка целиком, а не каждый кадр.
Вопросы задаются по порядку, первый ответ «да» решает. В паузе говорящим считается тот, чья реплика ближе.
было
стало
было
сталоСлева — рука в жесте: детектор принял её за второе крупное лицо, и рамка на полсекунды уехала. Справа — тень на одежде ведущей: на один замер её пятно стало «тёмным», как у гостя, и наезд ушёл на неё. Обе ошибки — один замер из десятков. Дорожка судит по большинству, поэтому одиночный замер больше ничего не решает. Шесть кадров через равные промежутки такие скачки не показывали — теперь контрольный лист берёт кадр из каждого куска.
Вертикаль вырезается из горизонтального кадра. Из мастера 1080p вырезанное приходится растягивать вдвое. Из 4K крупный план даже сжимается, а наезд растянут на 19 % — ниже порога, с которого мягкость видна. Белая черта — родной размер.
Отбор и субтитры привязаны ко времени старого мастера. Машина ищет его звук в новом файле — по 12 секунд в начале, в середине, в конце и в начале каждого шортса.
Старый мастер хранить не нужно. При первом рендере рядом с заданием остаётся эталон его звука — файл на несколько мегабайт. Он едет на Drive вместе с заданием, и по нему сверяется любой новый мастер.
Базовый шортс — речь, кадр и субтитры. Два варианта добавляются по желанию: рендер берёт их сам, если находит файл для этого шортса. Файл сверяется с шортсом: поменяли отбор — чужие выноски и музыка не подхватятся.
13
2
Проверено на шортсе S02 первого прогона: две выноски и подложка. Замер: речь −13,0 LUFS без музыки и с ней, подложка в сведении −33,9 LUFS — на 21 дБ тише. Это демо — на YouTube оно не залито.
# в picks.json у кандидата — поле viz "viz": [{"id": 434, "shift": 2.7, "dur": 3.9, "kind": "number", "value": "> $4 млн", "label": "потрачено на тест на инсульт"}, {"id": 438, "kind": "phrase", "text": "Тест так и не сделали"}] $V $S viz --job $JOB --only S02 --init # проект HyperFrames viz/S02/ — его можно править $V $S viz --job $JOB --only S02 --render # viz/S02.mov, прозрачное видео $V $S render --job $JOB --only S02
id — реплика, к началу которой привязана выноска; shift — секунды от её начала; dur — сколько держится. Рядом с проектом лежит brief.json: реплики во времени шортса и свободные зоны кадра — для того, кто дорисовывает сцену. render --plain собирает шортс без вариантов. Выноске нужно не меньше 1,2 с до конца шортса. Шортс уже залит — вариант добавляется новой версией: render --version 2.
$V $S music --job $JOB --find "light minimal background for a business talk"
$V $S music --job $JOB --track <id> --only S02 # music/S02.wav ровно под длину шортса
$V $S render --job $JOB --only S02
"music": {"below_db": 21} в задании или профиле канала: на сколько децибел музыка тише речи.~/.config/ytai/epidemic_sound.env. В базу знаний, git и переписку его не кладём. Ключ живёт год.epidemic-sound: музыку и звуковые эффекты можно искать разговором.Шортсы сдаются одной страницей на вышедший выпуск: все шортсы серией, вышедшие, залитые по ссылке и те, что ждут выбора. Оформление на согласовании идёт вариантами рядом — Роман выбирает у каждого шортса, ответ собирается одной строкой.
Первый шортс выходит сразу, остальные — с шагом. До выхода каждый открывается по ссылке: его можно показать гостю и ведущим. Ниже — график YTTRBM01, версия 7 (моушн): S02 вышел сразу по слову Романа, новая версия уже вышедшего S01 — последней.
Состояние одной командой. status спрашивает YouTube и показывает по каждому шортсу: вышел, по ссылке или приватный; время выхода; стоит ли он в графике — и что осталось сделать. Путь публикации проверен 02.10.2026 сухим прогоном в тех же условиях, в каких работает задача; первый боевой выход по графику — 03.10.2026.
Пересобранный шортс — новый файл и новый ролик на YouTube. Манифест, график и YouTube меняются не разом: остановиться посередине — значит выпустить старую версию.
| шаг | манифест | график | YouTube |
|---|---|---|---|
| 1 · рендер версии 2 | новое имя файла; прежний ролик записан как заменённый; время выхода осталось | стоит прежний ролик | прежний — по ссылке |
| 2 · заливка | номер нового ролика | стоит прежний ролик | оба по ссылке |
| 3 · график | время выхода подтверждено | новый — на прежнем времени | оба по ссылке |
| 4 · удалить прежний | его id — в deleted | — | Studio или инструментом выпуска |
Рендер версии, которая уже залита, откажется работать: файл разошёлся бы с YouTube и с копией на Drive. Вышедшее не трогаем.
04_Shorts проекта04_Shorts/Instagram04_Shorts/Archive00_Setup/07_ShortsНа YouTube шортс выходит без субтитров в кадре, но с дорожками субтитров — русской и английской: зритель включает их кнопкой «Субтитры». Для Инстаграма — та же версия с субтитрами в кадре, своей папкой (Роман, 03.10.2026).
…_v7_insta_….mp4 — в папке Instagram"captions": {"burn": false} — YouTube без субтитров; render --insta — с ними04_Shorts/ ├─ YTTRBM01_S02_v7_proval-na-4-mln.mp4 # для YouTube, без субтитров — 8 ├─ Instagram/ # с субтитрами в кадре — 8 └─ Archive/ # прежние версии: перенос, не удаление
Контрольный лист — кадр из каждого куска рамки с подписью: время, план, кто в кадре. Там, где стоит плашка, кадр взят с плашкой. Ошибка рамки видна в любом куске — без просмотра ролика.

Канал настраивается один раз. Дальше на каждый выпуск нужны три вещи: расшифровка с ролями, задание и отбор.
status: ролик должен быть «по ссылке», не приватнымОбразец — канал «Тараборим»: ~/YTAI/YTs/YTTRBM/. Имя в дереве копируется по клику.
V=~/YTAI/environment/.venv_transcribe/bin/python
S=~/YTAI/scripts/07_shorts/0701_finished/shorts.py
JOB=<папка 00_Setup/07_Shorts>/{CODE}_shorts_job.json
# расшифровка по словам с ролями — если вычитанных субтитров с ролями ещё нет
# имена — те же, что у людей в профиле канала и в задании
$V ~/YTAI/scripts/999_extra/wordrole_transcribe.py --media <мастер> --language ru --plain \
--num-speakers 3 --speaker-names "Семён,Татьяна,Ксения" --out-dir <папка задания>
# → {base}.words.json, его и вписать в cues. Имена перепутаны — поменять порядок и повторить с --rebuild-only
$V $S transcript --job $JOB # расшифровка одним текстом + задание отборщику picks_prompt.md
# агент Draper по заданию пишет picks.json
$V $S picks --job $JOB # проверка отбора: длина, id реплик, уточнения, запреты, имена
$V $S probe --job $JOB --t 4:45 8:25 # кадры с лицами и цветом одежды
$V $S gfx --job $JOB # знак и плашки → gfx/*.png; без них рендер не начнётся
# по желанию: viz и music — см. «Варианты»
$V $S render --job $JOB # шортсы → out/ + manifest.json + эталон звука master_ref.m4a
$V $S render --job $JOB --version N --insta # Инстаграм: те же шортсы с субтитрами → 04_Shorts/Instagram
$V $S sheet --job $JOB # контрольный лист out/sheet.jpg — кадр из каждого куска рамки
$V $S page --job $JOB --open # страница выпуска: варианты 1·2·3 рядом, выбор Романа строкой
$V $S upload --job $JOB # YouTube по ссылке; не залилось — код выхода 1
$V <выпуск>/00_Setup/07_Shorts/_session_tools/yt_subs.py build # дорожки ru + en → upload → list (пока инструмент выпуска)
$V $S schedule --job $JOB --start now --every 6 # первый выходит сейчас, остальные через 6, 12, 18 часов
$V $S status --job $JOB # что на YouTube: видимость, время выхода, стоит ли в графике
$V $S telegram --job $JOB # файлы в «Избранное»
$V $S archive --job $JOB # прежние версии → 04_Shorts/Archive; в корне — только актуальные
$V $S drive --job $JOB # 04_Shorts, Instagram, Archive и 00_Setup/07_Shorts на Drive
$V $S ledger --job $JOB # таблица канала и карточка Trello — после drive
schedule --start 2026-10-03T06:00:00+03:00 — первый невышедший в это время, дальше с шагом. --start now — первый выходит сейчас. Без --start — каждому его прежнее время из манифеста.--only S02,S04 — работать с частью. Лишний флаг у команды, которая его не умеет, — ошибка, а не тихий пропуск.render --version 2 — новая версия файла. Прежняя заливка остаётся в графике, пока не пройдут upload и schedule — см. «Новая версия до выхода».$V $S find4k --job $JOB # есть ли 4K-версия выпуска на общем диске проекта # в задании: "master" — путь к 4K-экспорту того же монтажа $V $S check --job $JOB # тот же монтаж? есть сдвиг начала? # ⚠ сдвиг → вписать в задание "master_offset": 0.48 и повторить check $V $S render --job $JOB --only S02,S03,S04,S05 --version 2 $V $S sheet --job $JOB --only S02,S03,S04,S05 $V $S upload --job $JOB --only S02,S03,S04,S05 $V $S schedule --job $JOB --only S02,S03,S04,S05 # без --start: время выхода прежнее $V $S status --job $JOB $V $S drive --job $JOB $V $S ledger --job $JOB
Номера — те шортсы, что ещё не вышли. schedule сам снимает прежние ролики с графика; удалить их — в Studio или инструментом выпуска (yt_cleanup.py, удаляет только ролик по ссылке не длиннее трёх минут). Мастер версии 1 в 04_Shorts остаётся: мастера на Drive не перезаписываются, рабочие файлы задания — обновляются.
{
"project": "YTTRBM01",
"channel": "YTTRBM",
"master": "/путь/к/финальному_мастеру_4K.mp4",
"cues": "YTTRBM01_roles.json",
"picks": "picks.json",
"version": 1,
"people": {
"Семён": {"plate": ["СЕМЁН", "ПОКАЦКИЙ"], "role": "сооснователь Rapid Bio",
"seat": "center", "wear": "dark", "big_face": 200},
"Татьяна": {"wear": "light_warm"},
"Ксения": {"wear": "red"}
},
"wear_order": ["Ксения", "Семён", "Татьяна"],
"tags": ["Семён Покацкий", "Rapid Bio"],
"drive": "gdrive_rscore,team_drive=<id общего диска>:YTTRBM S1/YTTRBM01_Semyon_Pokatskii"
}
drive — rclone-путь проекта на общем диске, именно в таком виде: по нему работают выгрузка, поиск 4K и учёт. cues — расшифровка с ролями: .words.json (по словам), .srt с именем в начале реплики или JSON. Ведущие, их плашки и места берутся из профиля канала. Одежда: red, dark, light_warm, blue, green, white или точный цвет с кадра пробы — {"rgb": [137, 30, 46], "tol": 50}. big_face — очень крупное лицо без опознанной одежды считается этим человеком. seat — место за столом, как его видит камера: left, center, right.
{"candidates": [
{"rank": 2, "take": true,
"pieces": [{"from_id": 430, "to_id": 438}],
"scores": {"hook": 5, "flow": 4, "value": 4, "emotion": 5},
"why": "Цифра и провал первой же фразой…",
"title": "Больше $4 млн на тест на инсульт, который так и не сделали",
"description": "… #shorts #Тараборим",
"slug": "proval-na-4-mln",
"clarifications": [{"id": 433, "text": "Чтобы вы понимали, в ДРД [прежнее название компании] совокупно, вместе с грантами Бортника, инвесторскими"}]}
]}
from_id и to_id — номера реплик из расшифровки. take — берём в работу. clarifications — реплика из этого же шортса, целиком, со скобками после поясняемого слова: её текст заменяет реплику на экране. Обрезанный текст с многоточиями обрежет и субтитр — проверка отбора это ловит.
Шаблон лежит рядом с кодом — PICKS_PROMPT.md. Команда transcript подставляет в фигурные скобки канал, выпуск, говорящих, хэштеги и правила из профиля и кладёт готовое задание в папку выпуска.
Дон, выбери лучшие моменты для YouTube Shorts из выпуска {PROJECT} канала «{TITLE}» ({CHANNEL}). Работай сам, без вопросов.
## Источник
Расшифровка финальной версии с ролями и таймкодами по репликам:
{TRANSCRIPT}
Формат строки: `[id] м:сс.сс–м:сс.сс Говорящий: текст`. Говорящие: {SPEAKERS}.
{CONTEXT}
## Что нужно
1. 8–10 кандидатов, из них **пять к выпуску** (`"take": true`), по приоритету: rank 1 — самый сильный, он выйдет первым.
- 25–59 с (строго < 60 с), законченная мысль: не начинается и не обрывается на полуслове;
- первые 2–3 с — крючок (вопрос, сильное утверждение, цифра, конфликт); конец — панчлайн или вывод;
- понятен без выпуска; если нужен контекст «кто / о чём» — уточнение в квадратных скобках прямо в реплике: «он [CEO компании]»;
- один непрерывный кусок (предпочтительно) или два, если вырезанная середина пустая.
2. Для каждого: куски по id реплик (первая и последняя включительно), оценки Hook / Flow / Value / Emotion (1–5) и одна строка «почему».
3. Для пяти к выпуску — упаковка:
- `title` ≤ 70 знаков, крючок в первых ~40, честное обещание (PROMISE CHECK из памяти: feedback_draper_promise_honesty.md);
- `description` — 1–2 строки и хэштеги в конце: {HASHTAGS} (+1 по теме);
- `slug` — латиница kebab-case, 2–5 слов, транслит крючка: он станет именем файла;
- `clarifications` — реплики с уточнениями: `[{"id": …, "text": "реплика целиком, с [уточнением] в скобках"}]`.
`text` заменяет реплику на экране полностью: бери её текст из расшифровки слово в слово и вставляй скобки сразу
после слова, которое они поясняют; сокращать многоточиями нельзя. Этим же полем правится ошибка расшифровки
внутри реплики. `id` — реплика из кусков этого же шортса;
- `viz` (по желанию, не больше двух на шортс) — выноска на экране, когда в куске звучит сильная цифра или тезис:
`{"id": реплика, "shift": секунд от её начала, "dur": 3–4, "kind": "number", "value": "> $4 млн", "label": "…"}`
или `{"id": …, "kind": "phrase", "text": "…"}`. Только то, что действительно сказано в кадре.
4. ⚠️ Правила канала: {RULES}
## Выход
JSON в {PICKS}:
```json
{"candidates": [{"rank": 1, "take": true, "pieces": [{"from_id": 0, "to_id": 0}],
"scores": {"hook": 0, "flow": 0, "value": 0, "emotion": 0}, "why": "…",
"title": "…", "description": "…", "slug": "…", "clarifications": [], "viz": []}]}
```
Проверь кодом: `{CHECK}` — длительности (код пропускает 20–60 с, целимся в 25–59), id реплик существуют и лежат
внутри кусков своего шортса, уточнения не переписывают реплику, в названиях и описаниях нет запретов канала.
В ответе — таблица пяти (ранг, время, длительность, title) и коротко, почему именно они.
| что | зачем |
|---|---|
~/YTAI/environment/.venv_transcribe | интерпретатор всех команд |
ffmpeg, ffprobe | кадры, звук, кодирование |
environment/models/face/yunet.onnx | поиск лиц; в git не лежит |
~/Library/Fonts/Montserrat-Bold.ttf | шрифт субтитров |
| Google Chrome и сеть | знак канала и плашки; шрифт страницы грузится из сети |
Node 22+, npx и сеть | только выноски HyperFrames |
токен канала и запись в 08_youtube/channels.json | заливка по ссылке и публикация через API: права youtube.upload и youtube.force-ssl |
задача launchd com.romansergeev.ytai-publish-schedule | выход по графику; одна на мак, на все каналы |
задача launchd com.romansergeev.ytai-shorts-pending | очередь доливки — если заливка упёрлась в дневной лимит канала |
~/.config/rscore/token.json, rclone-remote gdrive_rscore | Drive, поиск 4K, таблица |
~/.config/rya/trello.env | карточка Trello |
python3 из Homebrew с Telethon и сеанс Telegram | файлы в «Избранное»; команда сама находит нужный интерпретатор |
~/.config/ytai/epidemic_sound.env | только музыка |
~/.cache/huggingface/token, очередь локальных моделей | только расшифровка по словам с ролями |
# задачи графика и очереди доливки ставятся один раз
cp ~/YTAI/scripts/08_youtube/com.romansergeev.ytai-publish-schedule.plist ~/Library/LaunchAgents/
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.romansergeev.ytai-publish-schedule.plist
cp ~/YTAI/scripts/07_shorts/0701_finished/com.romansergeev.ytai-shorts-pending.plist ~/Library/LaunchAgents/
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.romansergeev.ytai-shorts-pending.plist
Команда schedule сама скажет, если задача не загружена. Проверки для каждой строки — в README рядом с кодом.
schedule пишет время выхода в ~/.config/ytai/publish_schedule.json.com.romansergeev.ytai-publish-schedule раз в 5 минут запускает scheduled_publish.py.~/Library/Logs/ytai_publish_schedule.log.scheduled_publish.py --dry-run --schedule <копия.json> — в ответ строка DRY would publish.~/.config/ytai/shorts_pending.json, задача launchd com.romansergeev.ytai-shorts-pending раз в два часа запускает pending.py run. Очередь пуста — ни одного запроса. Журнал: ~/Library/Logs/ytai_shorts_pending.log.| что случилось | что делать |
|---|---|
| рендер упал посередине | манифест уже хранит собранные шортсы. Запустить render --only на остальных |
| рендер: «нет графики» | сначала gfx |
upload вернул код 1 | причины в выводе: сеть, запрет канала, нет файла. Повторный upload зальёт только незалитые |
upload: лимит заливок канала | окно лимита — сутки. Поставить в очередь: pending.py add --job … --only S04,S05 — дольёт, поставит в график и напишет в Telegram. До тех пор в графике прежние версии |
| шортс не вышел в срок | в Telegram придёт ⛔ с причиной. Мак спал — выйдет при пробуждении. Вручную: scheduled_publish.py |
status: приватный | доступ сменили в Studio — вернуть «Доступ по ссылке». На выход не влияет: публикатор переводит в публичный из любого состояния. Если YouTube сам запирает ролики канала приватными — выпускать руками в Studio |
status: не в графике | после новой версии забыли upload и schedule |
check: другой монтаж | сдвиг начала команда нашла бы сама — значит, монтаж правда другой: новая расшифровка и отбор |
find4k: видео без размера | Drive считает размер свежей заливки до нескольких часов — повторить позже |
ledger: нет папки 04_Shorts | сначала drive. В таблице нужны заголовки «Video Project», «Shorts», «Shorts folder» и одна строка проекта; на доске — одна карточка с кодом проекта |
status показывает, что осталось--sni-bypass, команда upload ставит его самаviz делает это самаrender --version команда upload льёт заново сама~/YTAI/scripts/07_shorts/0701_finished/