Compare commits

...

2 commits

2 changed files with 8 additions and 17 deletions

View file

@ -7,21 +7,12 @@ die() {
exit 1
}
usage() {
cat <<'EOF'
Usage:
replace_audio.sh <manifest_file> <video_file> <output_video_file>
Пример:
replace_audio.sh voice/segments/segments.txt rendered_video.mp4 final_output.mp4
EOF
}
require_command() {
command -v "$1" >/dev/null 2>&1 || die "missing required command: $1"
}
[ $# -eq 3 ] || { usage; exit 1; }
[ $# -eq 3 ] || { echo "Usage: $0 <manifest_file> <video_file> <output_file>"; exit 1; }
MANIFEST="$1"
VIDEO_IN="$2"
VIDEO_OUT="$3"
@ -33,13 +24,13 @@ require_command ffprobe
TEMP_LIST="$(mktemp)"
trap 'rm -f "$TEMP_LIST"' EXIT
# 2. Читаем манифест, сортируем по времени и создаем list.txt для ffmpeg
# ffmpeg concat требует файлы без указания таймкодов, просто последовательно.
# Мы также проверяем, что аудиофайлы существуют.
# 2. Читаем манифест, извлекаем только пути к аудиофайлам
echo "Сборка временного списка аудиофайлов из манифеста..."
while IFS= read -r line; do
[[ -z "$line" ]] && continue
# Извлекаем второй столбец (путь к аудиофайлу)
audio_file=$(echo "$line" | awk '{print $2}')
if [ -f "$audio_file" ]; then
# Экранируем спецсимволы в пути для ffmpeg concat
printf "file '%s'\n" "$(echo "$audio_file" | sed "s/'/'\\\\''/g")" >> "$TEMP_LIST"
@ -62,9 +53,7 @@ ffmpeg -y -f concat -safe 0 -i "$TEMP_LIST" -c copy "$TEMP_AUDIO" || die "Оши
AUDIO_DURATION=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$TEMP_AUDIO")
echo "Длительность озвучки: $AUDIO_DURATION секунд"
# 5. Накладываем аудио на видео (обрезаем или дополняем тишиной до длины видео)
# -shortest обрежет по самому короткому потоку (в нашем случае это, скорее всего, аудио)
# Чтобы видео не обрезалось, используем фильтр apad, который добавит тишины, если аудио короче.
# 5. Накладываем аудио на видео
echo "Наложение аудио на видео..."
ffmpeg -y -i "$VIDEO_IN" -i "$TEMP_AUDIO" \
-filter_complex "[1:a]apad[aud]" \

View file

@ -1,3 +1,5 @@
#pip install edge-tts
#python voice/tts_generate.py assets/scenario.json
import argparse
import asyncio
import json