Skip to content
Back to skills

Youtube Publish

ASecurity

Публикует готовый контент на личный YouTube-канал Антона [аккаунт]: вычерпывает новое из NotebookLM и очереди, рендерит аудио в видео, пишет описание с фрагментом расшифровки для SEO и авторским блоком Антона, грузит и читает статус обратно. Триггеры: /youtube-publish, /yt, выложи на ютуб, залей на youtube, что ждёт выгрузки. НЕ /teach-podcast и не /notebooklm — те ПРОИЗВОДЯТ, этот ПУБЛИКУЕТ.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 25, 2026
ai-agentspythonbashrailsgcpgitapi

Works with

  • claude code
  • api
  • mcp

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 3, 2026

npx -y skills add tonydzi/second-brain-starter-kit --skill youtube-publish --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Youtube Publish?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Youtube Publish
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tonydzi-youtube-publish/badge)](https://www.skillsdirectory.com/skills/tonydzi-youtube-publish)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: youtube-publish
description: "Публикует готовый контент на личный YouTube-канал Антона [аккаунт]: вычерпывает новое из NotebookLM и очереди, рендерит аудио в видео, пишет описание с фрагментом расшифровки для SEO и авторским блоком Антона, грузит и читает статус обратно. Триггеры: /youtube-publish, /yt, выложи на ютуб, залей на youtube, что ждёт выгрузки. НЕ /teach-podcast и не /notebooklm — те ПРОИЗВОДЯТ, этот ПУБЛИКУЕТ."
version: 1.0.0
consumer: "Антон (/yt, «выложи на ютуб») · /teach-podcast Шаг 6.3 (кладёт строку в очередь) · /notebooklm (артефакт → очередь) · рутина youtube-publish-drip (ночная, после зелёной канарейки)"
---

# /youtube-publish — контент на личный канал Антона

> 🧒 Доклад Антону кончается блоком «Простыми словами» ([[eli5-always]]). Описания видео — без ELI5, у них свой голос.

**Родился 21.09.2026** из голосовой Антона (tg:-[id], 08:34 UTC). Дословно:
«Публиковать разный контент на личный YouTube-канал. Один из основных источников контента
сейчас — NotebookLM... Как только появляется новый материал из NotebookLM, его нужно выкладывать
на YouTube... Делать качественное описание к видео: что это за видео, о чём оно, зачем создано.
Добавлять небольшой транскрипт или фрагмент транскрипта для лучшего SEO/GEO. Сделать так,
чтобы видео легко находилось через поиск. Обязательно добавлять авторский контекст от Антона.»

**Цель контента (его слова):** обучение Антона · подготовка к трудоустройству в LLM-компанию ·
публичный YouTube-след вокруг LLM/AI-тем.

**Склейка с другими скиллами (он прямо просил «будет склеиваться»):** контракт односторонний.
Производители (`/teach-podcast`, `/notebooklm`, `/episode`, любая будущая труба) **кладут строку
в очередь** `$OBSIDIAN_VAULT/05-Resources/NotebookLM/_youtube-queue.md`. Этот скилл **вычерпывает**
её и больше ничего от них не требует. Производитель забыл строку — не беда: движок делает и
свободный скан папок артефактов, файл на диске потерять нельзя (замер 21.09: очередь знала 14
файлов, на диске лежало 35).

## Канал — доказан, не угадан
`[аккаунт]` · `UCa_lk_0LTagC9tI6f9NRF_w` · «Tony» · 305 подписчиков · 75 видео · с 18.03.2011.
Три независимые улики (21.09.2026):
1. YouTube Data API v3 по id из истории браузера вернул title/customUrl/статистику.
2. `browser_history.db`: Антон сам открывал Студию этого канала 30.08 и 02.09 из Firefox-профиля
   `m26xxxkf.anton-clean` — значит и канал его, и живой логин лежит именно там.
3. На канале уже висят его ролики «моя работа с Claude Code» (30–31.08.2026) — та же тематика.

⚠️ Другого личного канала не искали шире истории браузера. Появится второй — уточнить у Антона,
а не выбирать самому.

## ⛔ Законы

1. **Описание несёт ЧЕТЫРЕ обязательных куска** (прямой список Антона): (а) о чём видео;
   (б) зачем создано; (в) фрагмент расшифровки для поиска; (г) авторский контекст от него.
   Нет любого из четырёх — описание бракованное, публиковать нельзя.
2. **Авторский блок пишется от ПЕРВОГО лица Антона и называет Mycroft.** Его формулировка:
   «Это видео от Антона, оно сгенерировано моим кофаундером Mycroft». Раскрытие ИИ живёт
   внутри этого блока — плашки «AI-generated» отдельно не ставим (§3.3, DR-701: планка =
   review control + названное ответственное лицо, а лицо здесь Антон).
3. **Публичность по умолчанию, приватное не едет.** Гейт `privacy_scan` перед каждой загрузкой:
   почта, имена рекрутёров, вилки денег из переписки, секреты. Сработал — видео пропускается,
   строка в леджер `blocked-privacy`, чиним руками. Наш собственный calendly/WhatsApp/github —
   не утечка, это подпись (§1.1).
4. **Подпись обязательна.** Футер = блоки C+E из `$IMPORTS_ROOT/content-factory/_STYLE-footer.md`
   плюс Linktree и `github.com/tonydzi`. YouTube = публичная поверхность, карве-аутов нет.
   EN-описание НЕ упоминает RU-каналы (правило [коллега] 07.07).
5. **Язык описания = язык дорожки.** Суффикс `-ru` / `-en` в имени файла — истина. RU-эпизод
   с английским описанием = брак: YouTube так и проиндексирует.
6. **Находимость строится тремя рычагами, не тегами одними:** (1) субтитры из расшифровки
   (`captions.insert`) — YouTube индексирует их текст целиком и это сильнее любых тегов для
   аудио-контента; (2) `defaultLanguage`/`defaultAudioLanguage` проставлены; (3) первые три
   тега продублированы хэштегами — они показываются над заголовком.
7. **Готово = прочитано обратно.** После загрузки движок сам делает `videos.list` и печатает
   реальный `privacyStatus`. Код ответа 200 доказательством публикации не является (§4.3-бис).
8. **Выдумывать нельзя.** Описание собирается из очереди, пакета урока и расшифровки. Нет
   данных — пишем короче, а не сочиняем содержание, которого в видео нет.
9. **Суточный потолок 5 видео** — не вкус, а арифметика квоты: 1600 (videos.insert) + 400
   (captions.insert) + 1 (videos.list) ≈ 2001 единица, суточная квота проекта 10 000.
   Потолок зашит в `DAILY_CAP` и проверяется регрессом.
10. **Публикуем только вычитанное.** `run` по умолчанию берёт ТОЛЬКО строки очереди — у них
    человеческий заголовок. Файлы свободного скана видны в `scan`, но наружу без флага
    `--include-unqueued` не идут: заголовок «Hedge 01 inside», собранный из имени файла, на
    публичном канале Антона выглядит браком. Нужен нормальный заголовок — строку пишет
    производитель (`/teach-podcast`), а не этот скилл на глаз.
11. **Серия выходит по номерам, а не по дате файла.** «(урок 3)» в заголовке — ключ сортировки.
    Урок 15 сделан позже урока 1, но и выйти должен позже.

## Рельсы: две, и выбор между ними ЗАМЕРЯЕТСЯ

### Рельса A — API (основная, безлюдная)
`videos.insert` resumable + `captions.insert`. Всё ставится одним вызовом: заголовок, описание,
теги, категория 27 (Education), язык, видимость. Только эта рельса умеет работать ночью без человека.

⚠️ **РИСК, КОТОРЫЙ ОБЯЗАН БЫТЬ ЗАМЕРЕН, А НЕ ПРЕДПОЛОЖЕН.** У GCP-проектов, не прошедших
аудит YouTube API, загруженные через API видео могут запираться в `private` без возможности
открыть их руками. Это заявленное поведение платформы, и оно ломает всю цель («публичный след»).
Поэтому `run` **по умолчанию идёт канарейкой `--limit 1`** и сразу читает статус обратно:
* `privacyStatus == public` → рельса A рабочая, дальше можно пачкой;
* иначе → движок **сам останавливается** с кодом 2 и печатает вердикт; переходим на рельсу B.

⛔ До канарейки запрещено говорить «рельса A работает» — это claim (§5.4).

### Рельса B — браузер (фолбэк и первый боевой заход)
Firefox, профиль `m26xxxkf.anton-clean` (там живой логин канала), `studio.youtube.com`.
Команда `manifest` печатает и кладёт готовый пакет: путь к mp4 + заголовок + описание + теги
+ видимость. Дальше Create → Upload videos → перетащить mp4 → вставить поля из манифеста.
Ban-риска нет: это собственный канал Антона, а не чужая площадка.

## Шаг 0. RECALL и состояние
```bash
python ~/.claude/scripts/youtube_publish.py scan      # что ждёт, сколько уже ушло сегодня
python ~/.claude/scripts/youtube_publish.py ledger    # что уже на канале
python ~/.claude/scripts/youtube_publish.py auth check # жива ли рельса A
```
Леджер `~/.claude/state/youtube_ledger.jsonl` — **единственный** источник «что уже выложено».
Статус в очереди волта — подсказка человеку: очередь под Syncthing, её правят три узла, у неё
уже есть sync-conflict-копии. Сторож не живёт в том, что сторожит ([[watchdog-must-verify-the-item]]).

## Шаг 1. Посмотреть описание ГЛАЗАМИ до публикации
```bash
python ~/.claude/scripts/youtube_publish.py meta <имя файла>
```
Печатает ровно то, что увидит зритель, плюс счётчики лимитов (заголовок/100, описание/5000,
теги/500) и вердикт гейта приватности. **Первый эпизод серии смотрим глазами всегда** — дальше
шаблон уже проверен и можно пачкой.

Сомнение по вкусу текста → `/taste-check <файл описания>`.

## Шаг 2. Рендер (аудио → видео)
YouTube не принимает голый `.m4a`, нужен видеоконтейнер.
```bash
python ~/.claude/scripts/youtube_publish.py render <имя файла>
```
Делает обложку 1920×1080 (тёмная карточка: строка серии, заголовок в 5 строк, `[аккаунт]`,
Palo Alto AI Research Lab · NotebookLM) и склеивает с дорожкой: h264, 2 к/с, aac 192k,
`+faststart`. Замер 21.09: эпизод 18 минут → 26,5 МБ за 2 минуты на хабе.

## Шаг 3. Заливка
```bash
python ~/.claude/scripts/youtube_publish.py run --limit 1    # КАНАРЕЙКА, первый раз всегда так
python ~/.claude/scripts/youtube_publish.py run --limit 5    # рабочий заход после зелёной канарейки
python ~/.claude/scripts/youtube_publish.py run --dry-run    # посмотреть план без действий
python ~/.claude/scripts/youtube_publish.py run --include-unqueued   # редко: и файлы без строки
```
Порядок внутри: гейт приватности → рендер → субтитры (faster-whisper локально, 0 токенов) →
загрузка → чтение статуса обратно → строка в леджер → отметка в очереди (best-effort).
Падение на любом шаге пишет причину в леджер и **не** помечает файл сделанным: упавший эпизод
остаётся в очереди, иначе он теряется молча.

Рельса A мертва или заперла видео → рельса B:
```bash
python ~/.claude/scripts/youtube_publish.py manifest --limit 5
```

## Шаг 4. Проверка (§4.3-бис, второй заход другим методом)
1. `verify <videoId>` — `privacyStatus`, `uploadStatus`, причина отказа, если есть.
2. Открыть `https://youtu.be/<id>` и **посмотреть глазами**: звук идёт, обложка та, описание
   не обрезано на середине блока.
3. Через сутки: видео находится поиском по своему заголовку? Нет — значит находимость не
   построена, и это отдельная починка, а не «ну бывает».
4. Итог пишется парой: «проверено: … · НЕ проверено: … (почему)».

## Шаг 5. Учёт и связи (тем же заходом)
1. Леджер пишется движком сам.
2. Строка в очереди → «выложено <дата> <ссылка>» (движок делает best-effort).
3. `_teach-curriculum.md`: статус урока → «на YouTube» + ссылка.
4. **Ссылка уходит обратно в учебный контур:** в шпаргалку `/interview-prep` того звонка,
   к которому урок, — строка «Подкаст: <ссылка>».
5. **Контент-майнер** ([[content-miner-reflex]]): вышел эпизод — черновик тизера в воронку.
   Один эпизод = один тизер, не веер (§1.5 «спам ≠ громкость»).
6. Вердикт о скилле одной строкой: 🔧 обновляю / 📝 обновлю не сейчас / ✅ не надо, с причиной
   (§9.3-бис). Рутина судит ещё и собственную инструкцию (§9.3-бис поправка 13.09).

## Рутина
`youtube-publish-drip` — ночное окно 23:00–06:00 Лиссабон (§4.6), **раз в сутки**, `--limit 5`.
Почему ежедневно, а не «раз в 2–3 дня», как допускал Антон: суточная квота всё равно режет
до 5 видео, а ежедневный мелкий заход ровнее ложится на производство (`/teach-podcast` делает
1–5 эпизодов в день). Накопилось больше — само растянется на несколько ночей.
⛔ Рутина НЕ поднимается из сессии, порождённой scheduled-task (§9.2): сид кладётся в
`spawn_queue.py`, живая сессия его поднимает.
Темп режем по §4.5-тер, если хаб начнёт тормозить.

## Грабли, оплаченные при рождении (21.09.2026)
1. **Порядок чисток в описании.** Черновики очереди кончаются фразой «Контакты и CTA — из
   `_STYLE-footer.md`». Снимать надо СНАЧАЛА бэктики, ПОТОМ фразу: иначе точка внутри
   `_STYLE-footer.md` обрывает замену и в публичное описание уезжает хвост «md`.».
   Поймано регрессом `test_internal_vault_paths_never_leak`, который на этом краснел.
2. **Тайм-коды в расшифровке.** Дорожки NotebookLM идут с `[00:03]` на каждой фразе. В описании
   это мусор: YouTube индексирует слова, а не скобки. Движок их снимает.
3. **Расшифровка машинная и с опечатками** («менажмент», «искусном интеллекте»). Правим не
   текст, а честность: фрагмент помечен «машинная, с опечатками». Вычитывать чужую ASR-дорожку
   ради описания — работа не по цене.
4. **Очередь знает не всё.** 14 строк в очереди против 35 файлов на диске. Поэтому скан
   свободный, а не только по очереди.
5. **Голый `.m4a` YouTube не берёт** — всегда рендер в mp4.

## Потребители
* **Антон** — `/yt`, «выложи на ютуб», «что ждёт выгрузки».
* **`/teach-podcast` Шаг 6.3** — кладёт строку в `_youtube-queue.md`; этот скилл её вычерпывает.
* **`/notebooklm`** — любой артефакт, который не стыдно показать миру, идёт той же дорогой.
* **рутина `youtube-publish-drip`** — ночной вычерп.

## Двери и файлы
* Движок: `~/.claude/scripts/youtube_publish.py` (док внутри файла, §5.8).
* Регресс: `~/.claude/scripts/_test_youtube_publish.py` — 28 проверок, kill-list в шапке.
* Леджер: `~/.claude/state/youtube_ledger.jsonl`.
* Рендер и манифест: `~/.claude/state/youtube_render/`.
* Очередь: `$OBSIDIAN_VAULT/05-Resources/NotebookLM/_youtube-queue.md`.
* Токен рельсы A: `<secrets>/youtube_token_tonydzz.json` (в волт и в always-loaded не кладём, §3.4).

Канон: CLAUDE.md §9.13 (учим Антона подкастом), §1.1 (подпись в каждом касании), §3.3 (голос
и раскрытие), §3.2 (публичные каналы), §5.7 (shadow-first), §4.3-бис (готово = второй заход).
Память: [[teach-anton-by-podcast-default]], [[youtube-publish-channel-and-rails]],
[[everything-becomes-content]], [[outbound-signature]].


<!--kit-footer-->

---

**Like this skill?** It is one of 100 in [second-brain-starter-kit](https://github.com/tonydzi/second-brain-starter-kit): the second brain we built for ourselves and run every day at Palo Alto AI Research Lab. Install the whole set with `npx skills add tonydzi/second-brain-starter-kit`. Everything is open source and free, so take what you need.

Flagships worth a look on their own: [secondop-panel](https://github.com/tonydzi/secondop-panel) (a second opinion from a panel of external models), [claude-memory-tidy](https://github.com/tonydzi/claude-memory-tidy) (stop your agent's memory from rotting), [telegram-mcp-kit](https://github.com/tonydzi/telegram-mcp-kit) (your own Telegram over MCP in about 15 minutes).

Author: **Anton Dziatkovskii**, Palo Alto AI Research Lab. Telegram [@tonydzi](https://t.me/tonydzi) - WhatsApp [+1 341 222 9178](https://wa.me/13412229178) - X [@Tony_Stef_](https://x.com/Tony_Stef_)

**Engineers: want to test-drive this setup?** Message me. I hand out free starter seeds to engineers who test and report back, and custom skill requests are welcome.

Files in this skill

  • SKILL.md19.6 KB
  • routine-seed.md4.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…