Сборка вставки не начинается заново от каждой правки

Затухание в семьдесят секунд не собиралось никогда: сборка сведённого
куска шла полторы минуты, и любая правка в это время сбрасывала её на
ноль. В журнале это видно как «Расстановка изменилась» и тот же самый
запуск ffmpeg по кругу.

Причина — в вопросе, который задавался. «Нужна ли ещё эта работа»
проверялось по списку недостающего, а недостающее у нас — это то, чего
нет на диске. У куска, который делается прямо сейчас, файл уже есть:
ffmpeg создаёт его в первую же секунду. Кусок в список не попадал, ответ
был «не нужна», работа отменялась.

Теперь уплощение отдельно отдаёт список нужного — независимо от того,
лежит файл на диске или ещё пишется. Заодно закрыта та же дыра со
вставками тишины: проверка их вообще не видела, потому что звуковые
дорожки считаются отдельным проходом.

Проверено обеими сторонами (tests/genrestart.sh, на настоящем материале,
затухание 70 с): пять резов в стороне от затухания — один запуск и ни
одной отмены, было шесть запусков и десять отмен. Удалили всё — работа
прекращается за две секунды, как и прежде.
This commit is contained in:
4aiman 2026-10-01 00:47:28 +03:00
commit d2a49343c3
4 changed files with 229 additions and 7 deletions

130
tests/genrestart.sh Executable file
View file

@ -0,0 +1,130 @@
#!/bin/sh
# Сборка сведённого куска не должна начинаться заново от каждой правки.
#
# Затухание, наплыв, прозрачность — всё это предпросмотр не умеет играть
# как есть: такой кусок заранее сводится в отдельный файл. На затухании в
# семьдесят секунд файл считается около полутора минут, и всё это время
# человек продолжает работать.
#
# Проверяется два обратных случая:
# 1. Режем монтаж в стороне от затухания. Сам кусок от этого не
# меняется — значит сборка обязана продолжаться, а не начинаться
# заново.
# 2. Удаляем всё. Кусок стал не нужен — сборка обязана прекратиться.
#
# Раньше первый случай отменял работу: «нужен ли ещё этот кусок»
# спрашивалось по списку недостающего, а у куска, который делается прямо
# сейчас, файл уже есть — ffmpeg создаёт его сразу. Кусок в список не
# попадал, работа отменялась в разгаре и начиналась с нуля.
#
# Запуск: tests/genrestart.sh [<путь к nlve>]
# Проект берётся из test/поток/длинный-фейд.nlve (см. README, раздел
# проверок): один клип с затуханием в семьдесят секунд.
set -e
cd "$(dirname "$0")/.."
BIN=${1:-$PWD/nlve}
DISP=${NLVE_DISPLAY:-:99}
# Проект для проверки в репозиторий не входит: он ссылается на съёмку,
# которой в нём нет. Годится любой с одним клипом и долгим затуханием —
# путь можно задать переменной.
PROJ=${NLVE_FADE_PROJECT:-$PWD/test/поток/длинный-фейд.nlve}
LOG=$(dirname "$BIN")/nlve.log
[ -f "$PROJ" ] || { echo "нет проекта для проверки: $PROJ"; exit 2; }
start() {
pkill -x nlve 2>/dev/null || true
# Закрытая программа не уносит с собой свой ffmpeg: дочерний процесс
# остаётся и продолжает писать в кэш. Убираем только его — по пути
# этого самого проекта, чтобы не задеть чужую работу.
pkill -f "длинный-фейд.nlve-cache" 2>/dev/null || true
sleep 1
rm -rf "$PWD/test/поток/длинный-фейд.nlve-cache" "$PWD/test/поток/профиль-$1"
rm -f "$PROJ.autosave"
SP=$PWD/test/поток/профиль-$1
mkdir -p "$SP"
: > "$LOG"
XDG_CONFIG_HOME=$SP XDG_CACHE_HOME=$SP XDG_DATA_HOME=$SP DISPLAY=$DISP \
"$BIN" "$PROJ" >/dev/null 2>&1 &
sleep 16
WIN=$(DISPLAY=$DISP xdotool search --name "длинный-фейд" | tail -1)
DISPLAY=$DISP xdotool windowmove "$WIN" 0 0 windowsize "$WIN" 1500 860
sleep 2
}
runs() { grep -c filter_complex "$LOG" || true; }
stops() { grep -c 'Расстановка изменилась' "$LOG" || true; }
BAD=0
echo "1. Правки в стороне от затухания"
start правки
echo " сборка началась: запусков $(runs)"
X=650
I=0
while [ $I -lt 5 ]; do
DISPLAY=$DISP xdotool mousemove $X 640 click 1
sleep 0.6
DISPLAY=$DISP xdotool key s
sleep 3
X=$((X + 40))
I=$((I + 1))
done
sleep 5
N=$(runs)
S=$(stops)
echo " после пяти резов: запусков $N, отмен $S"
case "$(DISPLAY=$DISP xdotool getwindowname "$WIN")" in
*\*) ;;
*) echo " ПЛОХО: монтаж не изменился, правки не дошли — проверка ничего не значит"
BAD=$((BAD + 1)) ;;
esac
if [ "$N" = "1" ] && [ "$S" = "0" ]; then
echo " ok: работа не сбрасывалась"
else
echo " ПЛОХО: сборка начиналась заново"
BAD=$((BAD + 1))
fi
echo
echo "2. Кусок стал не нужен"
start отмена
echo " сборка началась: запусков $(runs)"
DISPLAY=$DISP xdotool mousemove 700 600 click 1
sleep 0.5
DISPLAY=$DISP xdotool key ctrl+a
sleep 0.8
DISPLAY=$DISP xdotool key Delete
# Ждём, пока работа прекратится, а не спим наугад: ffmpeg получает сигнал
# и ещё дописывает то, что у него в руках. Именно -x у pgrep: иначе под
# раздачу попадёт и сама эта оболочка, у которой слово ffmpeg есть в
# командной строке.
ALIVE=1
WAITED=0
while [ "$WAITED" -lt 30 ]; do
sleep 1
WAITED=$((WAITED + 1))
ALIVE=$(pgrep -a -x ffmpeg | grep -c "длинный-фейд.nlve-cache" || true)
[ "$ALIVE" = "0" ] && break
done
S=$(stops)
echo " отмен $S, живых ffmpeg $ALIVE, ждали $WAITED с"
if [ "$S" -ge 1 ] && [ "$ALIVE" = "0" ]; then
echo " ok: ненужная работа прекращена"
else
echo " ПЛОХО: работа продолжается впустую"
BAD=$((BAD + 1))
fi
pkill -x nlve 2>/dev/null || true
pkill -f "длинный-фейд.nlve-cache" 2>/dev/null || true
rm -f "$PROJ.autosave"
echo
if [ "$BAD" = "0" ]; then
echo "ВЕРДИКТ: сборка вставок не сбрасывается зря и не идёт впустую"
else
echo "ВЕРДИКТ: не пройдено случаев: $BAD"
exit 1
fi