CAM-*, звук и транскрипты рядом. Решается это не в терминале, а глазами:
каждая итерация — HTML-страница, где видно кадры, звук, время и из чего собирается сцена. Раскладка
собирается только после «принято» — и собирается симлинками: карта и оригиналы не двигаются.ingest.json и таймлайны. Ingest сюда
не тянем: это отдельный этап, и делать его одновременно с раскладкой — верный способ
не доделать ни то, ни другое.Одна сцена — один смысловой кусок дня, а не одна кассета. Внутри сцены —
папка на каждую камеру, звук и расшифровки. Канон, который ждут make_ingest.py, UXP-билдер,
витрина лутов и прокси: без обёрток Video//Audio/, одна папка сцены = один таймлайн.
Всё в раскладке — симлинки на исходники: ни один байт не копируется, ни один файл на карте не
переименовывается. Ниже — выездной день YTEVO03 (0120_day_ingest/s10_layout.py).
*M01.XML рядом с каждым — без него Sony теряет гаммуCAM-*.LRF — собственная запись DJI о дубле{stem}.words.json — пословная расшифровка каждого файла, в сцене, а не в общей папке00_* витрина цвета не берёт01_bright_scene.cube · 02_normal_scene.cube · 03_dark_scene.cube) + README.md + _build/ — 3.3 LUTsСтудийный день курса (YTUVIE01, 0121_studio_day/layout.py) раскладывается
деревом курса, а не дня: блок = сцена, внутри тема и урок, и уже в уроке — всё по нему.
*M01.XMLlavcut.py)CAM-* и Screencast без доказанного урока.LRFСтруктура решается по содержанию, а содержание известно только после анализа. Предлагать слияния по названиям папок — прямой путь к ошибке: из трёх «очевидных» склеек по именам две оказались неверными. Поэтому цикл всегда один и тот же, и он повторяется, пока не будет «принято».
Хвосты пофайлово, локальный анализ картинки и текста, хронология по creation_time,
дыры в звуке. Ничего не двигается.
Предлагаемая структура собирается с диска в одну страницу: кадры, звук, время,
из чего собирается каждая сцена. На выездном дне это страница приёмки {CODE}_review.html
(s14), на студийном — страница дня и спорных дублей.
«Эти две — одна сцена», «это назвать иначе», «этот клип — в другую сцену». Правки идут
в decisions.json, а не в файловую систему.
Без «да» ни один файл не двигается. Пока не принято — возврат на шаг 2, карта пересобирается заново.
Одним прогоном, симлинками на карту: s13_apply_decisions.py → s10_layout.py
на выездном дне, layout.py --apply на студийном. Без --apply — только рассказ.
Карта пересобирается по факту с диска — она же становится документом проекта. Дальше — этап 4, ingest.
| Гейт | Что показывается до действия |
|---|---|
| Хвосты | список уникального — до того, как что-либо уедет в архив |
| Анализ | что из готовых JSON выбрасываем как непроверенное |
| Структура | карта сцен целиком — без «да» ни один файл не двигается |
| Раскладка | сводка «было → стало» с инвариантом по файлам и байтам |
Карта — это единственный способ принять решение осмысленно: по именам папок структуру не проверишь. Каждая сцена — карточка, где рядом стоят картинка, звук, время и происхождение.
01_Drive_To_Abramovo_Anya_Story ·
02_Lost_On_The_Way_To_Abramovo · 03_Village_Recognition_And_Meeting_Yulia| Блок карточки | Зачем он там |
|---|---|
| Кадры из клипов | видно содержимое, а не название папки. Кадры тянутся из самих клипов, по нескольку на сцену |
| Имя папки на диске | ровно то, что покажет Finder — моноширинным, кликом копируется |
| Человеческое название + описание | о чём сцена: кто говорит, что происходит, где начинается и где кончается разговор |
Время tc_in–tc_out | по нему видно стыки: разрыв в две минуты между сценами — почти всегда один кусок дня |
| Счётчики: клипы · минуты · петлички · вес | сцена без петлички или с одной вместо шести — сразу заметна |
| «Собирается из N старых папок» | провенанс: видно, что именно склеивается, и легко возразить |
| Группировка по дням | у многодневной смены хронология дня важнее сквозной нумерации |
| KPI сверху | «38 → 12 папок, 151 клип, 7.3 ч, 75 петличек, 492 ГБ» — масштаб изменения одной строкой |
Готовая карта остаётся в проекте как 00_Setup/05_Review/{CODE}_structure_map.html,
а обоснования слияний — рядом, в {CODE}_restructure_proposal.html.
| LUT | Под какой кадр | Побочный эффект |
|---|---|---|
normal.cube | ровный свет — рабочая середина, выигрывает почти везде | — |
bright.cube | пересвет: окно, улица, солнце в кадре | на ровном материале топит тени |
dark.cube | недосвет: комната без окон, вечер, тень | вымывает цвет |
Правило выбора: самый сочный из тех, что не завалил тени. Луты названы по тому, каким снят кадр, а не по результату — иначе на выборе постоянно путаешься.
Звук раскладывается вместе с картинкой и в тот же момент. Если отложить — петличка окажется не в той сцене, а найдётся это уже на монтаже.
TX01, TX02).__S{NN} показывает,
из какой нумерации пришла копия. Байт-идентичные копии потом схлопываются дедупом.creation_time только для порядка. Точный синхрон дорожек — отдельная задача
следующего этапа, по речи: 4.1 Multicam Word-Sync.
На спринте YTCH часы FX3 врали на 57 минут, и по-разному в каждый день.На YTCH12 в такой оболочке нашлись три петлички, которых не было больше нигде. На YTCH10 — тоже три, и одна закрывала реальную дыру в звуке: петличка обрывалась на 14:13 и продолжалась с 14:21, а в оболочке лежал ровно этот кусок — полторы минуты живого звука дороги, где камера не писала. Плюс 15 транскриптов второй камеры, единственная копия которых была в наследии оффлоада.
Сверка: имя без сценового суффикса __S{NN} + размер, при совпадении —
SHA-256. Уникальное разносим по сценам по времени записи, дубли — в архив
99_Pipeline/_dupes_scene_merge_YYYYMMDD/, не в корзину.
project.json
блок «лучшие цитаты» оказался вымышленным целиком: 7 из 7, ни одной строки нет
в транскрипте. Самый длинный дословный кусок — 17–40 % цитаты.
Поэтому каждая цитата ищется дословно в Claude4_assembly.json
после нормализации (регистр, ё, пунктуация). Метрика близости — длина самого длинного
непрерывного совпадения, а не сумма совпавших кусков: на стоге в 50 тысяч слов сумма даёт
≈1.0 для любого набора русских слов и ничего не различает.
| Файл | Что проверять | Что находится на практике |
|---|---|---|
project.json | каждую строку best_quotes |
выдуманы целиком — блок удалять |
quotes.json | anchored:true против реального текста |
~4 % помечены привязанными, но не подтверждаются |
scenes.json | привязку «цитата → клип» по тексту этого клипа | сцена верна почти всегда, клип врёт в ~10 %; иногда в поле клипа лежит имя сцены |
Что не подтвердилось — выбрасываем, а не «правим по смыслу». Исходное
значение стоит сохранить рядом (clip_claimed, best_quotes_removed):
это провенанс, по нему видно, чему нельзя доверять в следующий раз.
Ключ слияния — непрерывный кусок дня. Практический критерий: построить
хронологию сцен по creation_time и посмотреть разрывы между соседними клипами.
Разрыв 0–2 минуты — почти всегда один кусок; 10–20 минут — надо смотреть содержание;
час и больше — разные блоки.
11_Photos_Handover_And_Son_Story — по имени «про сына и фотографии», по факту
финал интервью: «спасибо большое, очень хорошо рассказали». Идёт встык к предыдущей папке.35_Drive_Scrolling_Chats — по имени перегон, по факту тот же стол,
что и фотоальбом, телефон в руках, разрыв 2 минуты.03_Village_Recognition_And_Meeting_Yulia — выглядит как отдельная сцена приезда,
а по часам это хвост той же дороги, разрыв ноль минут.Дыры внутри таймлайна допустимы: в сцене «вечерний итог» и до слияния было 53 минуты пустоты. Но склейка, дающая полтора часа дырки, — повод спросить, а не решать молча.
# выездной день — после приёмки на странице s14 python3 s13_apply_decisions.py --dry-run && python3 s13_apply_decisions.py # s13 сам гонит s10_layout → s9 → s12 → s15 → s14 # студийный день python3 layout.py # сухой прогон: дерево, счётчики, что куда python3 layout.py --apply # ссылками python3 layout.py --apply --move # день уже разложен файлами: переносим внутри 01_Source
| Правило | Почему |
|---|---|
| Сцены меняются именами папок, а не переездом файлов | s13 раскладывает блоки
по сценам человека и пересоздаёт симлинки; привязка — по составу _akeys сегмента, а не по
времени. Идемпотентно: decisions.json можно править и применять сколько угодно раз |
| Сайдкар неразлучен с клипом | *M01.XML несёт гамму Sony и тайминг, .LRF —
запись DJI о дубле. Разлучишь — цвет откажет на всём дне |
| Имена файлов не менять | переименование рвёт ссылки в транскриптах, ингесте и wordsync. Ориентир — папка, а не имя файла |
| Прежние ссылки снимаются перед новой раскладкой | раскладка добавляет, а не перекладывает:
дубль, сменивший урок, оказался бы в двух уроках сразу — витрина цвета падает на
DuplicateClip, монтажёр не заметил бы. Снимаются только симлинки и только в сценах
^\d\d_, кроме 00_LUT |
| Весь план проверяется до первого касания | если источник мёртв, а на месте ссылки лежит
реальный файл — день переехал, и замена ссылкой стёрла бы единственную копию. Отказ целиком,
а не на середине; перепись чинит reindex.py |
--move — только внутри 01_Source | день, разложенный переносом, ссылками уже не перестроить. Карту и зеркало не трогаем ни при каких условиях — оттуда только ссылка |
| Петлички студийного дня — реальной копией | они дневные и должны пережить извлечение карты;
_edit.wav в 01_Source не попадает вовсе |
Симлинки указывают на карту и при её отключении «побьются» — это осознанно. После выгрузки
на Drive их перенацеливает relink_symlinks.py, не трогая структуру; сколько ссылок битых и
куда они ведут, считает project_check.py — 3.1 · 5.
Этап закрыт, когда сходятся четыре вещи: дерево на диске, карта,
транскрипты и инвариант. Всё, что связано с ingest.json и таймлайнами, —
уже следующий этап: 4.5 Ingest.
NN_Scene_Name/{CAM-*,Sound,Transcription} (на студийном дне — блок/тема/урок) симлинками{CODE}_structure_map.html, пересобранная с диска, а не из планаscene_t0 и wall_offset — пересчитать заново, а не перенести:
у слитой сцены новый ноль0113_frame_align.py — timeline-рендеры петличек
{TX}_{сцена}_timeline.wav пересобрать под новые сцены (у слитой сцены новый ноль,
старые рендеры невалидны): ingest (tx_strips) и секвенции ссылаются
только на них, не на оригиналыscenes, vision_catalog, quotes,
broll_index, Claude4_assemblyvalidate_ingest.py до exit 0 — и только потом Build IngestCAM-*, где бы она ни стояла. cam_of() в цвете ищет префикс
CAM- в любом месте пути: на студийном дне между сценой и файлом ещё тема и урок, и «папка сразу
под сценой» вернула бы имя темы. Имя папки сцены принадлежит таймлайну, а не камере. Перед каждым
Build Ingest — validate_ingest.py до exit 0.
Зеркало проекта на Google Drive — тоже отдельная работа, по диффу и server-side:
3.8 Project Drive Sync. Коротко: двигать rclone moveto
внутри одного remote, папки назначения создавать заранее и последовательно (Drive допускает
одноимённые папки и параллельные moveto их плодят), в конце — rclone dedupe
и сверка множеств путей.
⚠️ YTCH / проекты с frame-align: звук на Drive живёт не как на SSD.
Оригиналы рекордера (*_orig_*.wav) в 01_Source на Drive не заливаются —
server-side уезжают в архив 99_Pipeline/DJI_Audio/{сцена}/; в 01_Source
на Drive и в прокси-комплекте монтажёра — только {TX}_{сцена}_timeline.wav
(+ видео, транскрипты, LUT). Понадобились оригиналы — не тащить их обратно руками:
вернуть в 01_Source локально и перегнать 0113_frame_align.py
(пересборка — единственный путь). Локально на SSD оригиналы остаются в сценах, ничего не переносится.
| Грабля | Как проявляется | Лечение |
|---|---|---|
| Раскладка «молча», без карты | перекладывать приходится дважды, второй раз — поверх сдвинутых артефактов | страница → приёмка → и только потом --apply |
| Дедуп по полному имени | 26 байт-идентичных копий петличек (8.2 ГБ) переживают раскладку | второй проход по имени без __S{NN} |
| Кадры без LUT в карте | S-Log серый, по превью ничего не понять — структуру принимают «на веру» | шоу-LUT под каждый кадр + подпись на картинке |
| Камера из «папки сразу под сценой» | на дереве блок/тема/урок камерой становится тема,
профиль канала молча ветвится на «камеры» вида 1.1_Karta_tseha | камера = папка CAM-* в любом месте пути |
| Раскладка после переезда дня | index.json держит пути карты, на их месте реальные
файлы — замена ссылкой стёрла бы 52 клипа за секунды | проверка всего плана до касания, reindex.py, --move |
| Переименование сцен в транскрипте | 38 заголовков вместо 12 | слить разделы, а не заменить строки |
| Фоновая транскрибация во время раскладки | инвариант не сходится на несколько файлов | дождаться конца фоновых задач перед --apply |
| Метрика «похожести» цитат | сумма совпавших кусков даёт ≈1.0 на любом тексте | длина самого длинного непрерывного совпадения |
| Часы камеры | расходятся на ~57 минут, по-разному в каждый день | синхрон только по речи, см. 4.1 |
| exFAT | плодит ._*, они уезжают на Drive мусором |
--exclude "._*" |
Артефакты, по которым потом видно, что и почему сделано:
| Файл | Что в нём |
|---|---|
{work}/decisions.json | решения человека по сценам и голосам — единственный
файл, который он правит; s13 применяет его идемпотентно |
{work}/layout.json | итог раскладки: сцены, ссылок, сайдкаров, расшифровок
({work} — рабочая папка дня вне проекта, у YTEVO03 ~/YTAI/_work/YTEVO03_day) |
00_Setup/05_Review/{CODE}_structure_map.html | карта сцен с кадрами под шоу-LUT, звуком и временем — собранная с диска по факту |
00_Setup/05_Review/{CODE}_restructure_proposal.html | обоснования слияний и что не сошлось в анализе |
00_Setup/logs/restructure_YYYYMMDD.jsonl | журнал каждого перемещения |
00_Setup/01_Ingest/_pre_merge_backup_YYYYMMDD/ | все артефакты до слияния |
99_Pipeline/_dupes_scene_merge_YYYYMMDD/ | дубли и хвосты — целиком, не в корзине |
Дальше по конвейеру: 4.7 Audio Enhance · 3.10 Pre-Edit Word Precision · 3.7 Source Enrichment → и этап 4 · Ingest.