#!/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" 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/__*/_/;s/[^[:blank:][:print:]]//g')" #[ $verbose ] && echo "Исходный текст $source_text" >> "out.txt" ping -c 3 ya.ru &>/dev/null || { echo "Интернет недоступен."; exit; } split_size=1400 [ $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=$(mktemp -t "txt2mp3_audio_file_name_${file_index}_XXXXXXXXXXX.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 -y -f concat -safe 0 -i <(for ((i = 0; i < ${#audio_file_names_array[@]}; i++)) do echo "file '${audio_file_names_array[$i]}'"; done) -acodec copy -vcodec copy ${ffmpeg_opt} "$out_file" [ $verbose ] && echo "ffmpeg $?" 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'!"