diff --git a/core_actions.sh b/core_actions.sh index 5fb47dd..ac28e9a 100644 --- a/core_actions.sh +++ b/core_actions.sh @@ -35,7 +35,31 @@ run_processing() { return fi - local confirmation_text="Вы уверены, что хотите выполнить '${CURRENT_ACTION}' для ${#FILE_TRIPLETS[@]} файлов?\n\n" + local skip_count=0 + local pending_count=0 + local triplet video audio output + # Снимок на момент старта. Файл, появившийся уже в этом запуске, + # нельзя считать «и так был» — иначе отчёт завысит число обработанных. + local -A ALREADY_PRESENT=() + for triplet in "${FILE_TRIPLETS[@]}"; do + IFS=$'\t' read -r video audio output <<< "$triplet" + if output_file_exists "$output"; then + ALREADY_PRESENT["$output"]=1 + skip_count=$((skip_count + 1)) + else + pending_count=$((pending_count + 1)) + fi + done + + if [ "$pending_count" -eq 0 ]; then + ui_show_message "Запуск" "Все файлы уже есть в каталоге вывода ($skip_count шт.). Обработка не требуется." + return + fi + + local confirmation_text="Вы уверены, что хотите выполнить '${CURRENT_ACTION}' для ${pending_count} файлов?\n\n" + if [ "$skip_count" -gt 0 ]; then + confirmation_text+="Будет пропущено (уже есть): $skip_count\n\n" + fi confirmation_text+="Результаты будут сохранены в:\n$OUTPUT_BASE_DIR" if ! ui_confirm "Финальное подтверждение" "$confirmation_text"; then ui_show_message "Отмена" "Операция отменена пользователем." @@ -52,6 +76,8 @@ run_processing() { fi # Шаг 2: Выполнение с прогресс-баром (без изменений) + local conflict_file + conflict_file=$(mktemp) { local total_files=${#FILE_TRIPLETS[@]} local current_file_num=0 @@ -61,6 +87,19 @@ run_processing() { local progress_before=$(( ((current_file_num - 1) * 100) / total_files )) echo "$progress_before" + + if [[ -n ${ALREADY_PRESENT["$output"]+x} ]]; then + echo -e "XXX\n($current_file_num/$total_files) Пропуск (уже есть):\n$(basename "$output")\nXXX" + continue + fi + + if output_file_exists "$output"; then + printf '%s' "$output" > "$conflict_file" + echo -e "XXX\nОшибка: имя занято во время обработки:\n$(basename "$output")\nXXX" + sleep 1 + exit 0 + fi + echo -e "XXX\n($current_file_num/$total_files) Обработка:\n$(basename "$video")\nXXX" case "$CURRENT_ACTION" in @@ -78,10 +117,18 @@ run_processing() { } | dialog "${DIALOG_OPTS[@]}" --title "Выполнение..." --gauge "Подготовка..." 10 70 0 + if [[ -s "$conflict_file" ]]; then + local conflict_path + conflict_path=$(cat "$conflict_file") + rm -f "$conflict_file" + ui_show_message "Ошибка" "Файл появился во время обработки и не входил в список уже существующих:\n$conflict_path\n\nОбработка остановлена." + return 1 + fi + rm -f "$conflict_file" + # --- НОВЫЙ БЛОК: ФИНАЛЬНЫЙ ОТЧЕТ --- # Шаг 3: Показываем отчет о проделанной работе local action_text - local total_processed=${#FILE_TRIPLETS[@]} case "$CURRENT_ACTION" in "MERGE") @@ -93,7 +140,10 @@ run_processing() { esac local report_message="Статус: $action_text\n\n" - report_message+="Обработано файлов: $total_processed\n" + report_message+="Обработано файлов: $pending_count\n" + if [ "$skip_count" -gt 0 ]; then + report_message+="Пропущено (уже есть): $skip_count\n" + fi report_message+="Результаты сохранены в:\n$OUTPUT_BASE_DIR" ui_show_message "Отчёт о выполнении" "$report_message" diff --git a/core_logic.sh b/core_logic.sh index 1eeb264..d24b857 100644 --- a/core_logic.sh +++ b/core_logic.sh @@ -71,6 +71,58 @@ logic_prepare_file_lists() { done fi + logic_check_output_paths || return 1 + return 0 +} + +# Уже готовый результат: обычный файл или симлинк (в том числе битый). +# Каталог сюда не входит: это не серия, а ошибка пути. +output_file_exists() { + local path="$1" + [[ -f "$path" || -L "$path" ]] +} + +# Одинаковые имена и путь-каталог ломают пропуск: вторая серия увидела бы +# файл, созданный первой, и отчёт засчитал бы её как уже готовую. +logic_check_output_paths() { + local -A seen=() + local triplet video audio output + local -a dir_errors=() + local -a dup_errors=() + + for triplet in "${FILE_TRIPLETS[@]}"; do + IFS=$'\t' read -r video audio output <<< "$triplet" + if [[ -d "$output" && ! -L "$output" ]]; then + dir_errors+=("$(basename "$video") → $output") + continue + fi + if [[ -n ${seen["$output"]+x} ]]; then + dup_errors+=("$(basename "${seen[$output]}") и $(basename "$video") → $(basename "$output")") + else + seen["$output"]="$video" + fi + done + + if [ ${#dir_errors[@]} -gt 0 ]; then + local text="Путь вывода указывает на каталог, а не на файл:\n\n" + local line + for line in "${dir_errors[@]}"; do + text+="$line\n" + done + ui_show_message "Ошибка" "$text" + return 1 + fi + + if [ ${#dup_errors[@]} -gt 0 ]; then + local text="Несколько серий получают одно и то же имя:\n\n" + local line + for line in "${dup_errors[@]}"; do + text+="$line\n" + done + ui_show_message "Ошибка" "$text" + return 1 + fi + return 0 } @@ -105,22 +157,40 @@ logic_show_preview() { return fi - local preview_text="РЕЖИМ: $CURRENT_ACTION\nБудут обработаны следующие файлы (${#FILE_TRIPLETS[@]} шт.):\n\n" + local body="" local count=1 + local skip_count=0 for triplet in "${FILE_TRIPLETS[@]}"; do IFS=$'\t' read -r video audio output <<< "$triplet" - preview_text+="$(printf "%02d" $count). \n" + body+="$(printf "%02d" $count). \n" + + local exists=false + if output_file_exists "$output"; then + exists=true + skip_count=$((skip_count + 1)) + fi if [ "$CURRENT_ACTION" == "MERGE" ]; then - preview_text+=" \ZbВИДЕО:\Zn $(basename "$video")\n" - preview_text+=" \ZbАУДИО:\Zn $(basename "$audio")\n" - preview_text+=" \Zb-> ВЫВОД:\Zn $(basename "$output")\n\n" + body+=" \ZbВИДЕО:\Zn $(basename "$video")\n" + body+=" \ZbАУДИО:\Zn $(basename "$audio")\n" + body+=" \Zb-> ВЫВОД:\Zn $(basename "$output")\n" else # SYMLINK - preview_text+=" \ZbИСТОЧНИК:\Zn $(basename "$video")\n" - preview_text+=" \Zb-> ССЫЛКА:\Zn $(basename "$output")\n\n" + body+=" \ZbИСТОЧНИК:\Zn $(basename "$video")\n" + body+=" \Zb-> ССЫЛКА:\Zn $(basename "$output")\n" fi - ((count++)) + + if $exists; then + body+=" \Z3ПРОПУСК:\Zn операция пропущена — файл уже есть\n\n" + else + body+="\n" + fi + count=$((count + 1)) done + local pending=$((${#FILE_TRIPLETS[@]} - skip_count)) + local preview_text="РЕЖИМ: $CURRENT_ACTION\n" + preview_text+="К обработке: $pending, пропуск (уже есть): $skip_count\n\n" + preview_text+="$body" + ui_show_message "Предпросмотр" "$preview_text" }