From 960817fdd54c24b9ee00f724d677bbd4ac9ff96c Mon Sep 17 00:00:00 2001 From: Alexei Bezborodov Date: Sun, 7 Jan 2024 21:21:00 +0300 Subject: [PATCH] =?UTF-8?q?=D0=92=D0=B5=D1=80=D1=81=D0=B8=D1=8F=201.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE | 3 + Logo.png | Bin 0 -> 35993 bytes Logo.svg | 50 ++++++++++++ README.md | 5 ++ parse_arg_lib | 108 +++++++++++++++++++++++++ pdf2video | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ txt2mp3 | 163 +++++++++++++++++++++++++++++++++++++ 7 files changed, 584 insertions(+) create mode 100644 LICENSE create mode 100644 Logo.png create mode 100644 Logo.svg create mode 100644 README.md create mode 100755 parse_arg_lib create mode 100755 pdf2video create mode 100755 txt2mp3 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..237c39d --- /dev/null +++ b/LICENSE @@ -0,0 +1,3 @@ +Этот продукт является ОБЩЕСТВЕННЫМ ДОСТОЯНИЕМ и может быть использован КАК ЕСТЬ, со всеми достоинствами и недостатками, полностью или частично, кем угодно и в каких угодно целях БЕЗ КАКИХ-ЛИБО ОГРАНИЧЕНИЙ. + +This product is PUBLIC DOMAIN and may be used AS IS, with all advantages and faults, in whole or in part, by anyone for any purpose, WITHOUT ANY CONDITIONS. diff --git a/Logo.png b/Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e34d1fb96526bc401a9ec13bb41aae8da6c9efe9 GIT binary patch literal 35993 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Úv@7sY0q1Vg(9_{g#Da)%o&I<8;1_$mdS( zdMi)+ohw3~D$zEyZcBBMPU^mPC$rnuEsA*oqJHxzu;~XfD5dm9OfET`Gj9#|yb0qypv-~VPX5+fHhan9fN><9-@luHFI_E@>Z`&OC z7VVG~<&a^URzTIJ_)*4M>O8(>$`)5FbMe~^q)g62vE7oZlF zsZ6tG8*oki`dACE+-clg>Y;PcTLE4EH?Oe#Lx-4(xR4izSD%xr-P3b*(EjDjo~?_=k@YRztV=I}>7)sYRn5z5xisXxp=&#(;pxuTI5-q@6;rR7 zdOKLG$_uv=eCOAbYr(AJ=~ej zRx^*?I=ypKc4)B+~0gp!+j=v0RL7G}7sPp@~X3h`9wc>brAD@s9$-=eD5svuYz zFJa}i{k{t#1&a#2Y}0D+t4Ck8sd*nWd#M9Rt3VK`LYBF`0yL&!XkMH7E!FgP{n47O zz%L8&b??k5;}_fKwphLv9$WZbM<8{O3QAs+|Nb##3?Ab9xvBk&dUzb-r7^Ilwvkg- z@Kx~G1;=rd6QtJ7!>q=Iq#nDch8X5}mVaSb7TU%N88%b=<-6qb|B>qXkH_F0JyG&l z{`&`|19;V2wHmJU3tY880=F8sYnwFa7%YMEcbQw|K=^D4o|7PjnBG2f-F*jB(lwy> zOXCAvUvb+~Qf64G zExhj@wczzvlb~9- zHxyWHYv-zN{>6#E=dN=d$;m%dH75wRGoKZs{lLm!Gas2pAe-oCZvLvE9&;3WD3#^W z%nebv-2<)pfKzr_B|w81Wt2fyqSC)QlyScHCHYo;lO^2mvt!2;4^k(5V{myHcD?JOLN$kzMVCp0a*Q2gtLbXM#kV?D0_8Z^j zi&H=v%y{h6p-Zgh;lyYRYIGOrrHIWw{w{1-IpkLL=y319i=TcPD25&9J zY)l^iPl2k-$=-;Sz)<7skwC2dB`90uJx`f${+cS{;|E;}Ibn(IMjAIRs#Z1N@1?PM zKcDD}xw4wn{W5(>{tst*70>ipw^xUc)>tE?c#X4C<-bmf>k{DAGj$2y4tlQDa9F&{ zIo_O|@b|lpDod!|SDW;MliNmjsJ+c_w_-k^S!!S7N|>`rC_c4x+^+Cd_yr}tW0lro7V_|SiX+;Ci>aqZfGn$ z-_e^k+q+ugD|>4LD4;7{;aq#0xO>nt{5ZC^u{o~oO+UvrOQw$YXe+e;Fk z8pQ<)YxsfAqLe2LrIM4)Wq16vDyqMn5@C8f1F;ksS|2UBtS@pSp=s{j&8kVMp0009 zZru)#mrBuUQx5J>e9Nln*-h)q6|d_M!UAGu{{8 z3;Le0Q1N@c9{!AK`>kQ^4&|LdxYYDX@$R##>jUIlW0+;Ssdh@7H}P=ETtDb;WTr{S3!ow&2PwY>

Lr>a!y99*OvA!a4D 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 YinfHz_JZ$-ZGfB(xY!r(_r3K00i_cUi2wiq literal 0 HcmV?d00001 diff --git a/Logo.svg b/Logo.svg new file mode 100644 index 0000000..7eac8c9 --- /dev/null +++ b/Logo.svg @@ -0,0 +1,50 @@ + + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..f3606b1 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Программа для преобразования электронных книг в видео + + + +Для помощи используйте ключ '-h' \ No newline at end of file diff --git a/parse_arg_lib b/parse_arg_lib new file mode 100755 index 0000000..744258c --- /dev/null +++ b/parse_arg_lib @@ -0,0 +1,108 @@ +#!/bin/bash +# Общественное достояние, 2024, Алексей Безбородов (Alexei Bezborodov) + +# Обработка входных параметров + +# Формат: +# "Однобуквенная команда|Расширенная команда|Справка|Параметр|Значение по умолчанию|Команда на исполнение" +# Параметр: Пусто - нет параметров, : - есть параметр, :: - параметр не обязателен + +# Пример +#common_params=( +# "i|input|Входной текстовый файл.|:|'1.txt'|" +# ) + +function ProcessParams { + local iparams=$1[@] + local work_func=$2 + local params=("${!iparams}") + local custom_arg1="$3" + local custom_arg2="$4" + + SAVE_IFS=$IFS + IFS="" + + for (( i=0; i< ${#params[*]}; i++)) + do + p="${params[i]}" + readarray -d "|" -t cur_params <<< "$p" + small_cmd="${cur_params[0]}" + large_cmd="${cur_params[1]}" + comment="${cur_params[2]}" + use_param="${cur_params[3]}" + default="${cur_params[4]}" + custom_cmd="${cur_params[5]}" + + $work_func "$small_cmd" "$large_cmd" "$comment" "$use_param" "$default" "$custom_cmd" "$custom_arg1" "$custom_arg2" + done + + IFS=$SAVE_IFS +} + +param_var='local small_cmd="$1";local large_cmd="$2";local comment="$3";local use_param="$4";local default="$5";local custom_cmd="$6";local custom_arg1="$7";local custom_arg2="$8";' + +function Params2InitVar { + eval "$param_var" + + if [ "$use_param" != '' ]; then + eval "${large_cmd}=${default}" + fi +} + +function Params2Help { + eval "$param_var" + + echo "-${small_cmd}, -${large_cmd}, --${large_cmd}" + echo " ${comment/"!DEFAULT!"/"${!large_cmd}"}" +} + +function Params2small_list { + eval "$param_var" + + echo -n "${small_cmd}${use_param}" +} + +function Params2large_list { + eval "$param_var" + + echo -n ",${large_cmd}${use_param}" +} + +function Params2Case { + eval "$param_var" + + if [ "$custom_arg1" = "-${small_cmd}" ] || [ "$custom_arg1" = "-${large_cmd}" ] || [ "$custom_arg1" = "--${large_cmd}" ]; then + clear_custom_cmd="${custom_cmd//[$'\t\r\n ']/}" + if [ "${clear_custom_cmd}" != "" ]; then + eval "${custom_cmd}" + else + eval "${large_cmd}=\"$custom_arg2\"" + fi + fi +} + +# Инициализация переменных +ProcessParams all_params Params2InitVar + +# $@ is all command line parameters passed to the script. +# -o is for short options like -v +# -l is for long options with double dash like --version +# the comma separates different long options +# -a is for long options with single dash like -version +# Example +# 'h' is a no-value option. +# 'v:' implies that option -v has value and is a mandatory option. ':' means has a value. +# 't::' implies that option -t has value but is optional. '::' means optional. +small_params_list=$(ProcessParams all_params Params2small_list) +small_params_list="${small_params_list:1}" + +large_params_list=$(ProcessParams all_params Params2large_list) +large_params_list="${large_params_list:1}" + +options=$(getopt --long "$large_params_list" -o "$small_params_list" -a -- "$@") + +# set --: +# If no arguments follow this option, then the positional parameters are unset. Otherwise, the positional parameters +# are set to the arguments, even if some of them begin with a ‘-’. +eval set -- "$options" + diff --git a/pdf2video b/pdf2video new file mode 100755 index 0000000..eed54ea --- /dev/null +++ b/pdf2video @@ -0,0 +1,255 @@ +#!/bin/bash +# Общественное достояние, 2024, Алексей Безбородов (Alexei Bezborodov) + +# Озвучивание русского текста из файла pdf и сохранение в видео + +version=1.0 + +# Формат: +# "Однобуквенная команда|Расширенная команда|Справка|Параметр|Значение по умолчанию|Команда на исполнение" +# Параметр: Пусто - нет параметров, : - есть параметр, :: - параметр не обязателен + +common_params=( + "h|help|Посмотреть помощь.|||ShowHelp; exit;" + "v|version|Посмотреть версию программы.|||echo \$version; exit;" + "V|verbose|Подробный вывод.|||verbose=true" +# "|||||" + ) + +sound_params=( + "i|input|Входной текстовый файл.|:||" + "e|emotion|Эмоциональный настрой говорящего. Может принимать значения 'neutral', 'good', 'evil'. По умолчанию '!DEFAULT!'.|:|'neutral'|" + "s|speaker|Голос говорящего. Может принимать значения 'oksana','jane','omazh','zahar','ermil','silaerkan','erkanyavas','alyss', 'nick'. По умолчанию '!DEFAULT!'.|:|'erkanyavas'|" + "S|speed|Скорость озвучки. По умолчанию '!DEFAULT!'.|:|'1.0'|" + "O|ffmpeg_opt|Дополнительные параметры ffmpeg.|:|''|" + "f|format|Выходной формат. Может быть либо 'mp3', либо 'wav'. По умолчанию '!DEFAULT!'.|:|'mp3'|" + "q|quality|Качество выходного файла. Может быть либо 'hi', либо 'lo'. По умолчанию '!DEFAULT!'.|:|'hi'|" + "l|lang|Язык озвучки. По умолчанию '!DEFAULT!'.|:|'ru_RU'|" +# "|||:||" + ) + +video_params=( + "o|output|Выходной видео файл.|:|''|" + "k|split|Деление страницы пополам. Может быть либо 'yes', либо 'no'. По умолчанию '!DEFAULT!'.|:|'yes'|" + "W|video_width|Размер видео в пикселях по ширине. По умолчанию '!DEFAULT!'.|:|1920|" + "H|video_height|Размер видео в пикселях по высоте. По умолчанию '!DEFAULT!'.|:|1080|" + "p|ffmpeg_pre_options|Опции ffmpeg в самом начале. По умолчанию '!DEFAULT!'.|:|'-loop 1 -r 2'|" + "P|ffmpeg_options|Опции ffmpeg. По умолчанию '!DEFAULT!'.|:|'-c:v libx264 -tune stillimage -preset ultrafast -crf 20 -shortest -pix_fmt yuv420p'|" + "r|page_range|Указывает страницы из выходного файла для обработки. Пример '{1..32}', '{2..10..2}', '\$(seq 5 3 30)'|:|''|" + "m|minimum_text_on_page|Минимальное количество символов на странице при котором происходит разделение страницы на две. По умолчанию '!DEFAULT!'.|:|1000|" +# "|||:||" + ) + +all_params=("${common_params[@]}" "${sound_params[@]}" "${video_params[@]}") + +# Загружаем библиотеку +function GetExec { + local exec_file_name="$1" + + exec="$exec_file_name" + [ ! -f "$exec" ] && exec="./$exec_file_name" + [ ! -f "$exec" ] && exec="~/$exec_file_name" + + echo "$exec" +} + +eval "source $(GetExec "parse_arg_lib")" + +function ShowHelp() { +cat << EOF +Использование: pdf2video -i [-o ] [-hV] +Озвучивание русского текста из файла pdf и сохранение в видео + +Общие параметры +$(ProcessParams common_params Params2Help) + +Параметры звука +$(ProcessParams sound_params Params2Help) + +Параметры видео +$(ProcessParams video_params Params2Help) +EOF +} + +# ------------------------------------------- + +while true +do +cur_arg="$1" +[ "$cur_arg" = '--' ] && { shift; break; } +ProcessParams all_params Params2Case "$cur_arg" "$2" +shift +done + +input_file="$input" +out_file="$output" + +unuse_param="$*" +if [ "${input_file}" = "" ] || [ "${unuse_param}" != "" ]; then + [ "${unuse_param}" != "" ] && echo "Параметры не расшифрованы \"$unuse_param\"" + ShowHelp + exit +fi + +[ "$out_file" = "" ] && { out_file="${input_file}.mp4"; [ $verbose ] && echo "Выходное имя файла \"$out_file\""; } + +#---------------------------------------------------- + +page_count=$(pdfinfo "${input_file}" | awk '/^Pages:/ {print $2}') + +video_file_names_array=() + +function Text2mp3 { + local text_file=$1 + local mp3_file=$2 + verb="" + [ $verbose ] && verb="-V" + + [ $verbose ] && echo "Найден исполняемый файл для преобразования в звук текста $(GetExec txt2mp3)" + eval "$(GetExec "txt2mp3") -i '${text_file}' -o '${mp3_file}' -e '${emotion}' -s '${speaker}' -S '${speed}' -f '${format}' -q '${quality}' -l '${lang}' '${verb}'" +} + +function MakeVideo { + local page_image_file=$1 + local page_mp3_file=$2 + local page_mp4_file=$3 + + local resized_page_image_file="${page_image_file}_resized.png" + + ffmpeg -y -i "${page_image_file}" -vf "scale=${video_width}:${video_height}:force_original_aspect_ratio=decrease,pad=${video_width}:${video_height}:(ow-iw)/2:(oh-ih)/2" "${resized_page_image_file}" + + local time_play=$(mp3info -p "%S\n" "${page_mp3_file}") + local time_opt="-c:a copy" + if [ ${minimum_time_on_page} -ge ${time_play} ]; then + local add_time=5 # $(( 5 - ${time_play} )) + time_opt="-c:a mp3 -af adelay=${add_time}s:all=true" # + [ $verbose ] && echo "time_opt ${time_opt}" + fi + + ffmpeg ${ffmpeg_pre_options} -i "${resized_page_image_file}" -i "${page_mp3_file}" ${ffmpeg_options} ${time_opt} "${page_mp4_file}" + + SAVE_IFS=$IFS + IFS="" + video_file_names_array+=(${page_mp4_file}) + IFS=$SAVE_IFS + + rm "${resized_page_image_file}" +} + +[ $verbose ] && echo "Всего страниц $page_count" + +for ((page=1;page<=${page_count};page++)); do + + if [ $page_range ]; then + skip="true" + for p in $(eval echo "$page_range"); + do + if [ $p = $page ]; then + skip="false" + break + fi + done + + if [ $skip = "true" ]; then + [ $verbose ] && echo "Пропускаем страницу №$page" + continue + fi + fi + + [ $verbose ] && echo "------------------------------------------------" + [ $verbose ] && echo "Обрабатываем страницу №$page" + + page_text_file="${input_file}_${page}.txt" + page_image_file="${input_file}_${page}" + pdftotext -f $page -l $page "${input_file}" "$page_text_file" + pdftoppm -r 300 -f $page -l $page -png -singlefile "${input_file}" "$page_image_file" + + page_image_file="${page_image_file}.png" + + source_text="$(cat "${page_text_file}")" + + if [ "$split" = "yes" ] && [ ${#source_text} -ge $minimum_text_on_page ]; then + + space_char=" " + split_size=$(( ${#source_text} / 2 + 2)) # Половина с небольшим запасом + file_index=0 + for ((i=1;i<=${#source_text};i++)); do + cur_char=${source_text:$i-1:1} + cur_text="${cur_text}${cur_char}" + if [ "$cur_char" = "$space_char" ] && [ ${#cur_text} -ge $split_size ] || [ $i = ${#source_text} ]; then + let file_index+=1 + + echo "$cur_text" > "${page_text_file}_half${file_index}" + + cur_text="" + fi + done + + file_txt_half1="${page_text_file}_half1" + file_txt_half2="${page_text_file}_half2" + + page_mp3_file_half1="${file_txt_half1}.mp3" + page_mp3_file_half2="${file_txt_half2}.mp3" + + Text2mp3 "$file_txt_half1" "$page_mp3_file_half1" + Text2mp3 "$file_txt_half2" "$page_mp3_file_half2" + + width=$(identify -format "%w" "$page_image_file")> /dev/null + height=$(identify -format "%h" "$page_image_file")> /dev/null + + height_half=$(( $height / 2 + $height / 20 )) + + page_image_file_half1="${page_image_file}_half1.png" + page_image_file_half2="${page_image_file}_half2.png" + + # format (widthxheight+left+top / wxh+l+t) + convert "$page_image_file" -crop ${width}x${height_half}+0+0 "$page_image_file_half1" + convert "$page_image_file" -crop ${width}x${height_half}+0+$(( $height - $height_half )) "$page_image_file_half2" + + page_mp4_file_half1="${input_file}_${page}_half1.mp4" + page_mp4_file_half2="${input_file}_${page}_half2.mp4" + + MakeVideo "$page_image_file_half1" "$page_mp3_file_half1" "$page_mp4_file_half1" + + MakeVideo "$page_image_file_half2" "$page_mp3_file_half2" "$page_mp4_file_half2" + + rm "$page_image_file_half1" + rm "$page_image_file_half2" + + rm "$file_txt_half1" + rm "$file_txt_half2" + rm "$page_mp3_file_half1" + rm "$page_mp3_file_half2" + + else + page_mp3_file="${page_text_file}.mp3" + + Text2mp3 "$page_text_file" "$page_mp3_file" + + page_mp4_file="${input_file}_${page}.mp4" + + MakeVideo "$page_image_file" "$page_mp3_file" "$page_mp4_file" + + rm "$page_mp3_file" + + fi + + rm "$page_image_file" + rm "$page_text_file" + +done + +SAVE_IFS=$IFS +IFS="" +[ $verbose ] && echo "Объединяем файлы ${video_file_names_array[*]} в $out_file" +ffmpeg -f concat -safe 0 -i <(for ((i = 0; i < ${#video_file_names_array[@]}; i++)) do echo "file '$PWD/${video_file_names_array[$i]}'"; done) -acodec copy -vcodec copy "$out_file" + +for ((i = 0; i < ${#video_file_names_array[@]}; i++)) do + f="${video_file_names_array[$i]}" + [ $verbose ] && echo "Удаляем файл '$f'" + rm "$f" +done +IFS=$SAVE_IFS + +[ $verbose ] && echo "Конечный файл создан '$out_file'!" + diff --git a/txt2mp3 b/txt2mp3 new file mode 100755 index 0000000..3ec6ef9 --- /dev/null +++ b/txt2mp3 @@ -0,0 +1,163 @@ +#!/bin/bash +# Общественное достояние, 2024, Алексей Безбородов (Alexei Bezborodov) + +# Озвучивание текста из файла + +version=1.0 + +# Формат: +# "Однобуквенная команда|Расширенная команда|Справка|Параметр|Значение по умолчанию|Команда на исполнение" +# Параметр: Пусто - нет параметров, : - есть параметр, :: - параметр не обязателен + +common_params=( + "h|help|Посмотреть помощь.|||ShowHelp; exit;" + "v|version|Посмотреть версию программы.|||echo \$version; exit;" + "V|verbose|Подробный вывод.|||verbose=true" +# "|||||" + ) + +sound_params=( + "i|input|Входной текстовый файл.|:||" + "o|output|Выходной видео файл.|:|''|" + "e|emotion|Эмоциональный настрой говорящего. Может принимать значения 'neutral', 'good', 'evil'. По умолчанию '!DEFAULT!'.|:|'neutral'|" + "s|speaker|Голос говорящего. Может принимать значения 'oksana','jane','omazh','zahar','ermil','silaerkan','erkanyavas','alyss', 'nick'. По умолчанию '!DEFAULT!'.|:|'erkanyavas'|" + "S|speed|Скорость озвучки. По умолчанию '!DEFAULT!'.|:|'1.0'|" + "O|ffmpeg_opt|Дополнительные параметры ffmpeg.|:|''|" + "f|format|Выходной формат. Может быть либо 'mp3', либо 'wav'. По умолчанию '!DEFAULT!'.|:|'mp3'|" + "q|quality|Качество выходного файла. Может быть либо 'hi', либо 'lo'. По умолчанию '!DEFAULT!'.|:|'hi'|" + "l|lang|Язык озвучки. По умолчанию '!DEFAULT!'.|:|'ru_RU'|" +# "|||:||" + ) + +all_params=("${common_params[@]}" "${sound_params[@]}") + +# Загружаем библиотеку +function GetExec { + local exec_file_name="$1" + + exec="$exec_file_name" + [ ! -f "$exec" ] && exec="./$exec_file_name" + [ ! -f "$exec" ] && exec="~/$exec_file_name" + + echo "$exec" +} + +eval "source $(GetExec "parse_arg_lib")" + +function ShowHelp() { +cat << EOF +Использование: pdf2mp3 -i [-o ] [-hV] +Озвучивание текста из файла + +Общие параметры +$(ProcessParams common_params Params2Help) + +Параметры звука +$(ProcessParams sound_params Params2Help) +EOF +} + +# ------------------------------------------- + +while true +do +cur_arg="$1" +[ "$cur_arg" = '--' ] && { shift; break; } +ProcessParams all_params Params2Case "$cur_arg" "$2" +shift +done + +input_file="$input" +out_file="$output" + +unuse_param="$*" +if [ "${input_file}" = "" ] || [ "$unuse_param" != "" ]; then + [ "$unuse_param" != "" ] && echo "Параметры не расшифрованы \"$unuse_param\"" + ShowHelp + exit +fi + +[ "$out_file" = "" ] && { out_file="$input_file.mp3"; [ $verbose ] && echo "Выходное имя файла \"$out_file\""; } + +source_text=$(cat "${input_file}") + +# Удаляем все пробелы в начале и в конце строк и заменяем два и более пробелов на один, удаляем все непечатаемые символы +source_text="$(echo "${source_text//[$'\t\r\n']/' '}" | sed 's/^ *//;s/[ ^]*$//;s/ */ /;s/[^[:blank:][:print:]]//g')" + +#[ $verbose ] && echo "Исходный текст $source_text" >> "out.txt" + +ping -c 3 ya.ru &>/dev/null || { echo "Интернет недоступен."; exit; } + +split_size=1450 +[ $verbose ] && echo "Длина текста ${#source_text}: Разбиваем на части по $split_size" + +txt_array=() + +space_char=" " +for ((i=1;i<=${#source_text};i++)); do + cur_char=${source_text:$i-1:1} + cur_text="${cur_text}${cur_char}" + if [ "$cur_char" = "$space_char" ] && [ ${#cur_text} -ge $split_size ] || [ $i = ${#source_text} ]; then + + # Максимальная длина SEND_IRI - 1590 символов, длина SEND_IRI без текста = 75 символов + # Максимальная длина текста = 1590 - 75 = 1515 символов + text_count=${#cur_text} + [ $text_count -ge 1515 ] && { echo "Превышено максимальное колличество символов - 1515"; exit; } + + SAVE_IFS=$IFS + IFS="" + txt_array+=($cur_text) + IFS=$SAVE_IFS + + cur_text="" + fi +done + +audio_file_names_array=() + +# Если текст пустой, то всё равно создаём выходной файл +[ ${#txt_array[@]} -le 0 ] && { txt_array+="."; } + +SAVE_IFS=$IFS +IFS="" +file_index=0 +for ((i = 0; i < ${#txt_array[@]}; i++)) do + cur_text="${txt_array[$i]}" + + let file_index+=1 + [ $verbose ] && echo "Часть номер $file_index" + [ $verbose ] && echo "------------------------------" + [ $verbose ] && echo $cur_text + [ $verbose ] && echo "------------------------------" + + #[ $verbose ] && echo $cur_text >> "out.txt" + + audio_file_name="${input_file}_${file_index}.mp3" + + [ $verbose ] && echo -en "\nЗагрузка аудио в файл '$audio_file_name'...\n" + + #touch "$audio_file_name" + wget -q -O "$audio_file_name" "http://tts.voicetech.yandex.net/tts?format=mp3&quality=hi&lang=ru_RU&speed=${speed}&speaker=${speaker}&emotion=${emotion}&text=${cur_text}" || { echo "Ошибка при загрузке аудио."; exit; } + + [ $verbose ] && echo "Файл '$audio_file_name' загружен." + + SAVE_IFS=$IFS + IFS="" + audio_file_names_array+=($audio_file_name) + IFS=$SAVE_IFS +done + +[ $verbose ] && echo "Объединяем файлы ${audio_file_names_array[*]} в $out_file" + +ffmpeg -f concat -safe 0 -i <(for ((i = 0; i < ${#audio_file_names_array[@]}; i++)) do echo "file '$PWD/${audio_file_names_array[$i]}'"; done) -acodec copy -vcodec copy ${ffmpeg_opt} "$out_file" + +for ((i = 0; i < ${#audio_file_names_array[@]}; i++)) do + f="${audio_file_names_array[$i]}" + [ $verbose ] && echo "Удаляем файл '$f'" + rm "$f" +done +IFS=$SAVE_IFS + +[ $verbose ] && echo "Конечный файл создан '$out_file'!" + +