#!/bin/sh # Файл из списка встаёт на курсор, а не в конец дорожки. # # Раньше клип падал в самый конец, стоило месту под ним оказаться # занятым, — а оно занято почти всегда: клип длиной в целый файл упирается # хвостом в то, что правее, даже когда начало легло в свободное место. # Потом человек тащил его на нужное время и получал наезд, то есть заказ # на сборку перехода. # # Проверяется так: курсор ставится посреди первого клипа, файл из списка # добавляется на ту же дорожку. Клип обязан встать на курсор, монтаж — # раздвинуться ровно на его длину, наездов и дыр появиться не должно. # Всё читается из сохранённого проекта, а не с картинки. # # Запуск (экран :99 поднят): # tests/insertat.sh [<путь к nlve>] set -e cd "$(dirname "$0")/.." BIN=${1:-$PWD/nlve} DISP=${NLVE_DISPLAY:-:99} SRC=$PWD/test/поток/пара.nlve PROJ=$PWD/test/поток/вставка.nlve [ -f "$SRC" ] || { echo "нет монтажа $SRC"; exit 2; } # Невидимый экран поднят через xvfb-run, у него свой файл доступа, а в # окружении обычно лежит файл рабочего экрана. С чужим файлом xdotool не # видит ни одного окна, и проверка «проходит» вслепую, ничего не проверив. export DISPLAY=$DISP reachable() { timeout 5 xdotool getdisplaygeometry >/dev/null 2>&1; } if ! reachable; then for p in $(pgrep -x Xvfb); do A=$(tr '\0' '\n' < /proc/$p/cmdline | grep -A1 -x -- -auth | tail -1) [ -f "$A" ] || continue XAUTHORITY=$A; export XAUTHORITY reachable && break done fi reachable || { echo "нет доступа к экрану $DISP: подними его (xvfb-run) и повтори"; exit 2; } cp "$SRC" "$PROJ" for p in $(pgrep -x nlve); do tr '\0' '\n' < /proc/$p/environ 2>/dev/null | grep -qx "DISPLAY=$DISP" && kill $p done sleep 1 SP=$PWD/test/поток/профиль-вставка rm -rf "$SP"; mkdir -p "$SP" rm -f "$PROJ.autosave" XDG_CONFIG_HOME=$SP XDG_CACHE_HOME=$SP XDG_DATA_HOME=$SP \ setsid "$BIN" "$PROJ" >/dev/null 2>&1 < /dev/null & sleep 14 X="timeout 8 xdotool" # Окно ищем по имени монтажа и проверяем, что оно на экране: по одному # «nlve» находятся и обломки прошлых запусков, нажатия в них уходят в # никуда, и проверка молча показывает «ничего не произошло». WID= for w in $($X search --name "вставка.nlve" 2>/dev/null); do xwininfo -id "$w" 2>/dev/null | grep -q IsViewable && { WID=$w; break; } done [ -n "$WID" ] || { echo "живое окно редактора не найдено"; exit 2; } $X windowmove "$WID" 0 0 windowsize "$WID" 1270 990 sleep 2 $X mousemove 700 466 click 1 # курсор воспроизведения — посреди первого клипа sleep 1 $X mousemove 200 512 click 1 # выбрать файл в списке проекта sleep 1 # Меню списка: «Добавить на дорожку» — первый пункт, в подменю первой # стоит V1, она же и нужна. $X click 3 sleep 1.5 $X key Down; sleep 0.5 $X key Right; sleep 0.5 $X key Return; sleep 2 $X key ctrl+s sleep 2 for p in $(pgrep -x nlve); do tr '\0' '\n' < /proc/$p/environ 2>/dev/null | grep -qx "DISPLAY=$DISP" && kill $p done rm -f "$PROJ.autosave" python3 - "$SRC" "$PROJ" <<'PY' import json, sys def clips(path, track): d = json.load(open(path)) for t in d['tracks']: if t['name'] == track: return sorted(t['clips'], key=lambda c: c['tl_start']) return [] было = clips(sys.argv[1], 'V1') стало = clips(sys.argv[2], 'V1') звук = clips(sys.argv[2], 'A1') плохо = 0 медиа = {c['media'] for c in было} новые = [c for c in стало if c['media'] not in медиа] if len(новые) != 1: print(' ПЛОХО: вставленный клип не найден (новых клипов %d)' % len(новые)) raise SystemExit(1) новый = новые[0] конец_было = max(c['tl_start'] + c['duration'] for c in было) print(' вставленный клип: старт %.3f с, длина %.3f с' % (новый['tl_start'], новый['duration'])) if новый['tl_start'] > конец_было - 0.001: print(' ПЛОХО: клип упал в конец дорожки (%.3f с), а не на курсор' % новый['tl_start']) плохо = 1 elif новый['tl_start'] < 0.5: print(' ПЛОХО: клип встал в начало, курсор был посреди первого клипа') плохо = 1 else: print(' ok: клип встал на курсор, внутри материала') # Соседи отъехали ровно на длину вставки: монтаж раздвинулся, а не # затёрся и не разъехался. сдвиг = новый['duration'] последний_было = было[-1] последний_стало = стало[-1] ожидалось = последний_было['tl_start'] + сдвиг if abs(последний_стало['tl_start'] - ожидалось) > 0.001: print(' ПЛОХО: последний клип на %.3f с, ожидалось %.3f с' % (последний_стало['tl_start'], ожидалось)) плохо = 1 else: print(' ok: монтаж раздвинут ровно на длину вставки (%.3f с)' % сдвиг) # Наезд на одной дорожке — это заказ на переход. Его тут быть не должно. for имя, список in (('V1', стало), ('A1', звук)): for a, b in zip(список, список[1:]): зазор = b['tl_start'] - (a['tl_start'] + a['duration']) if зазор < -0.001: print(' ПЛОХО: наезд на %s в %.3f с (%.3f с)' % (имя, b['tl_start'], -зазор)) плохо = 1 elif зазор > 0.001: print(' ПЛОХО: дыра на %s в %.3f с (%.3f с)' % (имя, a['tl_start'] + a['duration'], зазор)) плохо = 1 if not плохо: print(' ok: ни наездов, ни дыр') # Звук обязан уехать вместе с картинкой, иначе синхрон рассыплется. if [round(c['tl_start'], 3) for c in звук] != [round(c['tl_start'], 3) for c in стало]: print(' ПЛОХО: звук разошёлся с картинкой') print(' картинка: %s' % ['%.3f' % c['tl_start'] for c in стало]) print(' звук: %s' % ['%.3f' % c['tl_start'] for c in звук]) плохо = 1 else: print(' ok: звук уехал вместе с картинкой') raise SystemExit(плохо) PY