Как упаковать готовый ролик, сделать субтитры, залить его на YouTube, дотянуть обратно 4K-копию и обложку, разложить на Google Drive и заполнить строку в ContentList. Сквозной процесс «как мы это делаем».
От готового мастера до заполненной строки в таблице — один и тот же путь для любого канала.
Загружаем unlisted (черновик по ссылке), а публикует человек в Studio в 1 клик — гибрид обходит «private-lock» неаудированного API-проекта. Обе видео-версии (мастер + 4K-копия с YouTube) едут в 06_YouTube на Drive, ссылки + обложка + статус — в таблицу.
Заголовок · описание · теги · категория · язык. Пишем под зрителя, а не под «контент-гика».
❤️ Поддержать: https://…/help/ + строка-усилитель.0:00 … (≥3, каждая ≥10с, первая 0:00). Берём из транскрипта финального ката.--default-language по каналу: RU-каналы → ru, EN → en (список — §9). Задаёт defaultLanguage + defaultAudioLanguage.📁 Метаданные кладём в папку проекта 06_YouTube/: <CODE>_upload.json (title/desc/tags/cat/lang) + description.txt + tags.txt (их читает загрузчик через --pack-dir).
К каждому ролику — субтитры на русском и английском. Не сырой автотранскрипт: выверенные и адаптированные под готовое видео.
01_Source — расшифровки/съёмка, 02_Edit — что реально вошло в монтаж). Исправить ошибки распознавания, термины, имена, числа.01_Source/Transcription).# 1) транскрипт финального ката (пословный тайминг) mlx_transcribe_review.py --video "06_YouTube/<CODE>_*.mp4" --language ru # роли, если >1 спикера (pyannote, пословно) wordrole_transcribe.py --media "06_YouTube/<CODE>_*.mp4" --speaker-names "Ведущий,Гость" # 2) выверить по видео + 01_Source/02_Edit → 3) перевести → SRT ru/en → 4) залить captions_insert.py --video <id> --srt <CODE>_ru.srt --lang ru # затем --lang en
Инструменты: mlx_transcribe_review.py (транскрипт), wordrole_transcribe.py (пословно + роли pyannote), captions_insert.py (загрузка сабов в YouTube). Финально — глазами по готовому видео.
Гибрид: API заливает черновиком (unlisted/private), публикуешь сам в Studio. Загрузчик scripts/08_youtube/upload_youtube.py (resumable, retry).
# из папки проекта; токен и канал — свои (см. §9) ~/YTAI/environment/.venv_transcribe/bin/python \ ~/YTAI/scripts/08_youtube/upload_youtube.py \ --video "06_YouTube/<CODE>_vN_*.mp4" \ --title "…" \ --pack-dir "06_YouTube" # description.txt + tags.txt \ --privacy unlisted --default-language ru --category <id> \ --token ~/.config/ytai/token_<channel>_youtube.json \ --expect-channel <UC…>
--privacy unlisted → ролик по ссылке, не публичный. Человек открывает Studio-ссылку из вывода → Publish (1 клик).--expect-channel UC… — упадёт, если авторизован не тот бренд-аккаунт.OAUTHLIB_RELAX_TOKEN_SCOPE=1 (YouTube переставляет scope'ы); при consent выбирать бренд-канал, не личный.scripts/08_youtube/channels.json (токен · channelId · категория).YouTube сам делает перекодированную 4K-версию (легче мастера) и хранит обложку. Дотягиваем оба обратно.
06_YouTube/. --force-ipv4 обязательно (иначе троттлинг).yt-dlp --force-ipv4 \ -f "bv*[height=2160]+ba[ext=m4a]/bv*[height=2160]+ba/best" \ --merge-output-format mp4 \ -o "06_YouTube/<CODE>_vN_YT4K.mp4" "https://youtu.be/<id>"
05_Thumbnail/.thumbnails().set отклонит). Если дизайн-экспорт > 2 МБ — сжать ровно настолько, чтобы влезть под 2 МБ, сохранив качество: lossless 1280×720 PNG (ровно тот размер, что YT показывает) или near-lossless / oxipng в нативном разрешении. Лимит — это максимум, а не цель: не крушить оригинал в мелкий JPG.curl -sL \ "https://i.ytimg.com/vi/<id>/maxresdefault.jpg" \ -o "05_Thumbnail/<CODE>_thumbnail.jpg"
Обе видео-версии (мастер, залитый на YouTube + 4K-копия с YouTube) — в 06_YouTube; обложка — в 05_Thumbnail папки проекта на Shared Drive канала.
Shared Drive «<Канал>» → <Канал> S1 → <CODE>_… →<CODE>_vN_*.mp4 (мастер = Video link) + <CODE>_vN_YT4K.mp4 (Light link) + метаданные (upload.json / description.txt / tags.txt)<CODE>_thumbnail.jpg
0ALdB…VPVA · YTRF 0ALPYd…9PVA · YTFP 0AGxM…_Uk9PVA · YTCH 0AL5m…znzUk9PVA · RYA 0AN4C…pdUk9PVA.У каждого канала свой лист «<Канал> ContentList» (реестр — _data/channels.json), колонки и смысл одинаковые (канон v2, A–O). ⚠️ Адресовать колонки по ЗАГОЛОВКУ, не по букве. Здесь — только что заполняет заливка; полный стандарт листа — на подстранице ниже.
https://youtu.be/<id> — смарт-чипом делает человек в UI (API не умеет).yyyy-mm-dd (только пустые ячейки — ручные даты не перезаписывать).[m]:ss из Drive-метаданных (fallback — yt-dlp с YouTube).01Created…11Archived — строгий дропдаун, ячейка красится CF-правилом (см. стандарт §3).Запись в лист — Sheets API под rscore-токеном (§9). Колонку находим по тексту заголовка в row1, затем пишем в её ячейку.
Кнопку «Chip» (Drive-файл → карточка-превью) ставим через API — вручную кликать не нужно.
python3 ~/YTAI/scripts/999_extra/sheets_chip_links.py \ --sheet <SHEET_ID> --tab "<Канал> Videos" \ --chip "Video-link-cell=<fileId|url>" \ --chip "Light-link-cell=…" --chip "Thumbnail-cell=…"
"@" (плейсхолдер) + chipRuns[].chip.richLinkProperties.uri, fields:"chipRuns,userEnteredValue". Сервер сам резолвит имя+mime.@; перезапись userEnteredValue стирает старые runs (слать вместе); на чтении чип = chipRuns.Что различается между каналами — здесь: язык, токен, categoryId, Drive. Секреты в самих файлах, тут только пути и ID. Запись в Google — под одним rscore-токеном.
Язык канала определяет --default-language при заливке и какой язык субтитров «родной» (выверенный транскрипт), а какой — перевод. Субтитры всё равно делаем на обоих языках (§3).
~/.config/winston-smith/yt-oauth-desktop.json (GCP hubweb-437211) · реестр scripts/08_youtube/channels.json · scopes upload+readonly+force-ssl.~/.config/ytai/token_fond_youtube.jsonUCDisHNgdMxrsPondMwu8pog · cat 26~/.config/ytai/token_pravmir_sluh.jsonUCzd4kOoBsHFOBbDTjA3OA1Q · cat 27~/.config/ytai/token_burodd_youtube.jsonUCiJTns9nQjPixMbxzx0BmPg · cat 22~/.config/ytai/token_technodelo_youtube.jsonUCn5irJMzUZ5aZ5WKnjDlH6A · cat 27/28~/.config/winston-smith/yt-oauth-token-rs.jsonUC202ZZZJCqfv3EkhAFdazdA · READ-ONLY (аналитика)~/.config/rscore/token.json[email protected] · scope drive покрывает и Sheets v4 — consent не нужен. Этим пишем строки, заливаем файлы, ставим чипы.0ALdB53qbkaKMUk9PVA · YTRF 0ALPYdcdYxhOOUk9PVA · YTFP 0AGxMtru0d5W_Uk9PVA · YTCH 0AL5m1S49VznzUk9PVAscripts/08_youtube/upload_youtube.pyscripts/999_extra/sheets_chip_links.pyyt-dlp --force-ipv4 · i.ytimg.com/.../maxresdefault.jpgmlx_transcribe_review.py · wordrole_transcribe.py · captions_insert.py06_YouTube/upload_youtube.py --privacy unlisted своим токеном → получить videoIdyt-dlp --force-ipv4) + обложку (maxresdefault.jpg)06_YouTube, обложку → 05_Thumbnail (anyone-with-link)09Ready — по заголовкам (стандарт таблицы →)sheets_chip_links.py)10Publishedupload_youtube.py, sheets_chip_links.py, yt-dlp, captions_insert.py. · подстраница: 3.2.1 ContentList → · смежное: Project Ops → · обновлено 2026-07-03.