master
Sergey Marinkevich 7 months ago
commit 074630a351

Binary file not shown.

@ -0,0 +1,18 @@
ROOTPATH="/var/www/nextcloud/data/grayhook/files/"
INDIR="Torrents"
OUTDIR="Archive/Anime"
ORIGNAME="Dandadan [WEB-DL CR 1080p AVC DDP]"
NAME="Dan Da Dan"
OUTPUTPATH="${ROOTPATH}/${OUTDIR}/${NAME}"
INPUTPATH="${ROOTPATH}/${INDIR}/${ORIGNAME}"
mkdir -p "${ROOTPATH}/${OUTDIR}/${NAME}" || exit -1;
paste -d '\n' \
<(find "$INPUTPATH" -maxdepth 1 -name '*.mkv' | sort) \
<(find "$INPUTPATH" -name '*AniLibria*.mka' | sort) \
<(find "$INPUTPATH" -maxdepth 1 -name '*.mkv' | sort | \
sed -e "s/.* \([0-9]\{2\}\) .*/${OUTPUTPATH//\//\\\/}\/${NAME} s01e\1.mkv/g") | \
xargs -d '\n' printf '"%s" "%s" "%s"\n' | \
xargs -n 3 \
ffmpeg_add_audio_into_video \
;

@ -0,0 +1,30 @@
ROOTPATH="/var/www/nextcloud/data/grayhook/files/"
INDIR="Torrents"
OUTDIR="Archive/Anime"
ORIGNAME="Kimetsu.no.Yaiba.Hashira.Geiko.hen.WEB-DL.1080p"
NAME="Kimetsu no Yaiba Hashira Training"
OUTPUTPATH="${ROOTPATH}/${OUTDIR}/${NAME}"
INPUTPATH="${ROOTPATH}/${INDIR}/${ORIGNAME}"
[ -e "${ROOTPATH}/${OUTDIR}/${NAME}" ] || exit -1;
paste -d '\n' \
<(find "$INPUTPATH" -maxdepth 1 -name '*.mkv' | sort) \
<(find "$INPUTPATH/RUS Sound/StudioBand" -name '*.mka' | sort) \
<(find "$INPUTPATH" -maxdepth 1 -name '*.mkv' | sort | \
sed -e "s/.* \([0-9]\{2\}\) .*/${OUTPUTPATH//\//\\\/}\/${NAME} s05e\1.mkv/g") | \
xargs -d '\n' printf '"%s" "%s" "%s"\n' | \
xargs -n 3 \
ffmpeg_add_audio_into_video -d \
;
read || exit 1;
paste -d '\n' \
<(find "$INPUTPATH" -maxdepth 1 -name '*.mkv' | sort) \
<(find "$INPUTPATH/RUS Sound/StudioBand" -name '*.mka' | sort) \
<(find "$INPUTPATH" -maxdepth 1 -name '*.mkv' | sort | \
sed -e "s/.* \([0-9]\{2\}\) .*/${OUTPUTPATH//\//\\\/}\/${NAME} s05e\1.mkv/g") | \
xargs -d '\n' printf '"%s" "%s" "%s"\n' | \
xargs -n 3 \
ffmpeg_add_audio_into_video \
;

@ -0,0 +1,8 @@
DIRPATH="/var/www/nextcloud/data/grayhook/files/Torrents/Kimetsu.no.Yaiba.Katanakaji.no.Sato.hen.WEB-DL.1080p"
PRENAME="[SubsPlease] Kimetsu no Yaiba - Katanakaji no Sato-hen - "
POSTNAME=" [1080p]"
SOUNDDIR="RUS Sound/StudioBand"
for x in {0..11}; do
ffmpeg_add_audio_into_video "$DIRPATH/$PRENAME`printf "%02d" $x`$POSTNAME.mkv" \
"$DIRPATH/$SOUNDDIR/$PRENAME`printf "%02d" $x`$POSTNAME.mka";
done

@ -0,0 +1,19 @@
ROOTPATH="/var/www/nextcloud/data/grayhook/files/"
INDIR="Torrents"
OUTDIR="Archive/Anime"
ORIGNAME="Hunter x Hunter [6][BD 720] TV2"
NAME="Hunter x Hunter"
SED_NUMBER='s/-_\([0-9]\{3\}\)_/ \1 /g'
OUTPUTPATH="${ROOTPATH}/${OUTDIR}/${NAME}"
INPUTPATH="${ROOTPATH}/${INDIR}/${ORIGNAME}"
mkdir -p "${ROOTPATH}/${OUTDIR}/${NAME}" || exit -1;
paste -d '\n' \
<(find "$INPUTPATH" -name '*.mkv' | sort) \
<(find "$INPUTPATH/Rus Audio/JAM" -name '*.ac3' | sort) \
<(find "$INPUTPATH" -name '*.mkv' | sort | \
sed -e "s/.*-_\([0-9]\{3\}\)_.*/${OUTPUTPATH//\//\\\/}\/${NAME} s01e\1.mkv/g") | \
xargs -d '\n' printf '"%s" "%s" "%s"\n' | \
xargs -n 3 \
ffmpeg_add_audio_into_video \
;

@ -0,0 +1,19 @@
ROOTPATH="/var/www/nextcloud/data/grayhook/files/"
INDIR="Torrents"
OUTDIR="Archive/Anime"
ORIGNAME="MASHLE Season 2 [2024][WEB-DL][1080p]"
NAME="MASHLE: MAGIC AND MUSCLES"
SED_NUMBER='s/ \([0-9]\{2\}\) / 0\1 /g'
OUTPUTPATH="${ROOTPATH}/${OUTDIR}/${NAME}"
INPUTPATH="${ROOTPATH}/${INDIR}/${ORIGNAME}"
mkdir -p "${ROOTPATH}/${OUTDIR}/${NAME}" || exit -1;
paste -d '\n' \
<(find "$INPUTPATH" -name '*.mkv' | sort) \
<(find "$INPUTPATH" -name '*Anilibria*.mka' | sort) \
<(find "$INPUTPATH" -name '*.mkv' | sort | \
sed -e "s/.* \([0-9]\{2\}\) .*/${OUTPUTPATH//\//\\\/}\/${NAME} s02e\1.mkv/g") | \
xargs -d '\n' printf '"%s" "%s" "%s"\n' | \
xargs -n 3 \
ffmpeg_add_audio_into_video \
;

@ -0,0 +1,18 @@
ROOTPATH="/var/www/nextcloud/data/grayhook/files/"
INDIR="Torrents"
OUTDIR="Archive/Anime"
ORIGNAME="[Kawaiika-Raws] (2020) Ishuzoku Reviewers [BDRip 1920x1080 HEVC FLAC]"
NAME="Interspecies Reviewers"
OUTPUTPATH="${ROOTPATH}/${OUTDIR}/${NAME}"
INPUTPATH="${ROOTPATH}/${INDIR}/${ORIGNAME}"
mkdir -p "${ROOTPATH}/${OUTDIR}/${NAME}" || exit -1;
paste -d '\n' \
<(find "$INPUTPATH" -maxdepth 1 -name '*.mkv' | sort) \
<(find "$INPUTPATH" -name '*Wakanim*.mka' | sort) \
<(find "$INPUTPATH" -maxdepth 1 -name '*.mkv' | sort | \
sed -e "s/.* \([0-9]\{2\}\) .*/${OUTPUTPATH//\//\\\/}\/${NAME} s01e\1.mkv/g") | \
xargs -d '\n' printf '"%s" "%s" "%s"\n' | \
xargs -n 3 \
ffmpeg_add_audio_into_video \
;

@ -0,0 +1,19 @@
ROOTPATH="/var/www/nextcloud/data/grayhook/files/"
INDIR="Torrents"
OUTDIR="Archive/Anime"
#ORIGNAME="[Beatrice-Raws] Re.Zero - 2nd Season [BDRip 1080p HEVC TrueHD]"
ORIGNAME="[Beatrice-Raws] Re.Zero - 2nd Season - Part 2 [BDRip 1080p x265 Dolby TrueHD]"
NAME="Re ZERO Starting Life in Another World"
OUTPUTPATH="${ROOTPATH}/${OUTDIR}/${NAME}"
INPUTPATH="${ROOTPATH}/${INDIR}/${ORIGNAME}"
[ -e "${ROOTPATH}/${OUTDIR}/${NAME}" ] || exit -1;
paste -d '\n' \
<(find "$INPUTPATH" -maxdepth 1 -name '*.mkv' | sort) \
<(find "$INPUTPATH/Sounds/Crunchyroll" -name '*.mka' | sort) \
<(find "$INPUTPATH" -maxdepth 1 -name '*.mkv' | sort | \
sed -e "s/.* \([0-9]\{2\}\) .*/${OUTPUTPATH//\//\\\/}\/${NAME} s02e\1.mkv/g") | \
xargs -d '\n' printf '"%s" "%s" "%s"\n' | \
xargs -n 3 \
ffmpeg_add_audio_into_video \
;

@ -0,0 +1,18 @@
ROOTPATH="/var/www/nextcloud/data/grayhook/files/"
INDIR="Torrents"
OUTDIR="Archive/Series"
ORIGNAME="Young Sheldon (Season 4) WEB-DL 1080p"
NAME="Young Sheldon S4"
OUTPUTPATH="${ROOTPATH}/${OUTDIR}/${NAME}"
INPUTPATH="${ROOTPATH}/${INDIR}/${ORIGNAME}"
[ -e "${OUTPUTPATH}" ] || { echo "$OUTPUTPATH does not exist"; exit -1; }
paste -d '\n' \
<(find "$INPUTPATH" -maxdepth 1 -name '*.mkv' | sort) \
<(find "${ROOTPATH}/${INDIR}/Young.Sheldon.2021.S04.1080p.(Kurazh-Bambej)" -name '*.mkv' | sort) \
<(find "$INPUTPATH" -maxdepth 1 -name '*.mkv' | sort | \
sed -e "s/.*S04E\([0-9]\{2\}\).*/${OUTPUTPATH//\//\\\/}\/${NAME} s04e\1.mkv/g") | \
xargs -d '\n' printf '"%s" "%s" "%s"\n' | \
xargs -n 3 \
ffmpeg_add_audio_into_video \
;

@ -0,0 +1,19 @@
ROOTPATH="/var/www/nextcloud/data/grayhook/files/"
INDIR="Torrents"
OUTDIR="Archive/Anime"
#ORIGNAME="[Kawaiika-Raws] (2016) KonoSuba S1 [BDRip 1920x1080 HEVC FLAC]"
ORIGNAME="[Kawaiika-Raws] (2017) KonoSuba S2 [BDRip 1920x1080 HEVC FLAC]"
NAME="KonoSuba"
OUTPUTPATH="${ROOTPATH}/${OUTDIR}/${NAME}"
INPUTPATH="${ROOTPATH}/${INDIR}/${ORIGNAME}"
[ -e "${ROOTPATH}/${OUTDIR}/${NAME}" ] || exit -1;
paste -d '\n' \
<(find "$INPUTPATH" -maxdepth 1 -name '*.mkv' | sort) \
<(find "$INPUTPATH/RUS Sound" -name '*crunchyroll*.mka' | sort) \
<(find "$INPUTPATH" -maxdepth 1 -name '*.mkv' | sort | \
sed -e "s/.*S2E\([0-9]\{2\}\) .*/${OUTPUTPATH//\//\\\/}\/${NAME} s02e\1.mkv/g") | \
xargs -d '\n' printf '"%s" "%s" "%s"\n' | \
xargs -n 3 \
ffmpeg_add_audio_into_video \
;

@ -0,0 +1,12 @@
DIRPATH="/var/www/nextcloud/data/grayhook/files/Torrents/"
VIDEODIR="Tokyo Ghoul/Tokyo Ghoul "
AUDIODIR="Tokyo Ghoul [BD] [720p]/"
OUTPUTPATH="/var/www/nextcloud/data/grayhook/files/Archive/Anime/Tokyo Ghoul TV-1 2014/Tokyo Ghoul S1E"
PRENAME="[Winter] Tokyo Ghoul "
POSTNAME=" [BDrip 1280x720 x264 Vorbis]"
SOUNDDIR="$AUDIODIR/RUS Sound/[JAM & Oriko]"
for x in {2..12}; do
ffmpeg_add_audio_into_video "$DIRPATH/$VIDEODIR`printf "%d" $x`.mkv" \
"$DIRPATH/$SOUNDDIR/$PRENAME`printf "%02d" $x`$POSTNAME.mka" \
"$OUTPUTPATH`printf "%02d" $x`.mkv";
done

@ -0,0 +1,12 @@
DIRPATH="/var/www/nextcloud/data/grayhook/files/Torrents/"
VIDEODIR="Tokyo Ghoul Re"
AUDIODIR="Tokyo Ghoul Re"
OUTPUTPATH="/var/www/nextcloud/data/grayhook/files/Archive/Anime/Tokyo Ghoul TV-3 2018/Tokyo Ghoul S3E"
PRENAME="[anti-raws]Tokyo Ghoul Re ep."
POSTNAME="[BDRemux]"
SOUNDDIR="$AUDIODIR/RUS Sound/[JAM Club]"
for x in {1..12}; do
ffmpeg_add_audio_into_video "$DIRPATH/$VIDEODIR/$PRENAME`printf "%02d" $x`$POSTNAME.mkv" \
"$DIRPATH/$SOUNDDIR/$PRENAME`printf "%02d" $x`$POSTNAME.JAM Club.mka" \
"$OUTPUTPATH`printf "%02d" $x`.mkv";
done

@ -0,0 +1,12 @@
DIRPATH="/var/www/nextcloud/data/grayhook/files/Torrents/"
VIDEODIR="Tokyo Ghoul Re S2"
AUDIODIR="Tokyo Ghoul Re S2"
OUTPUTPATH="/var/www/nextcloud/data/grayhook/files/Archive/Anime/Tokyo Ghoul TV-4 2018/Tokyo Ghoul S4E"
PRENAME="[anti-raws]Tokyo Ghoul Re S2 ep."
POSTNAME="[BDRemux]"
SOUNDDIR="$AUDIODIR/RUS Sound/[JAM Club]"
for x in {1..12}; do
ffmpeg_add_audio_into_video "$DIRPATH/$VIDEODIR/$PRENAME`printf "%02d" $x`$POSTNAME.mkv" \
"$DIRPATH/$SOUNDDIR/$PRENAME`printf "%02d" $x`$POSTNAME.JAM Club.mka" \
"$OUTPUTPATH`printf "%02d" $x`.mkv";
done

@ -0,0 +1,12 @@
DIRPATH="/var/www/nextcloud/data/grayhook/files/Torrents/"
VIDEODIR="Tokyo Ghoul Root A"
AUDIODIR="Tokyo Ghoul Root A"
OUTPUTPATH="/var/www/nextcloud/data/grayhook/files/Archive/Anime/Tokyo Ghoul TV-2 2015/Tokyo Ghoul S2E"
PRENAME="[anti-raws]Tokyo Ghoul Root A ep."
POSTNAME="[BDRemux]"
SOUNDDIR="$AUDIODIR/RUS Sound/[JAM & Nika Lenina]"
for x in {11..12}; do
ffmpeg_add_audio_into_video "$DIRPATH/$VIDEODIR/$PRENAME`printf "%02d" $x`$POSTNAME.mkv" \
"$DIRPATH/$SOUNDDIR/$PRENAME`printf "%02d" $x`$POSTNAME.JAM & Nika Lenina.mka" \
"$OUTPUTPATH`printf "%02d" $x`.mkv";
done

@ -0,0 +1,139 @@
#!/bin/bash
#==============================================================================
# Модуль действий: выполнение mkvmerge, создание симлинков и т.д.
#==============================================================================
# Функция для склейки видео и аудио
# $1: Исходный видеофайл
# $2: Исходный аудиофайл
# $3: Выходной файл
action_merge_mkv() {
local video_file="$1"
local audio_file="$2"
local output_file="$3"
echo "---"
echo "ИСХОДНОЕ ВИДЕО : $video_file"
echo "ИСХОДНОЕ АУДИО : $audio_file"
echo "РЕЗУЛЬТАТ : $output_file"
# Это основная команда. Вы можете настроить ее под себя.
# --language 0:und - язык первой дорожки (видео) - неопределенный
# --language 1:rus - язык второй дорожки (аудио) - русский
# Вы можете добавить больше опций, например, --track-name, --default-track-flag
mkvmerge \
-o "$output_file" \
--language 0:und "$video_file" \
--language 1:rus "$audio_file"
if [ $? -eq 0 ]; then
echo "УСПЕХ: Файл создан."
else
echo "ОШИБКА: mkvmerge завершился с ошибкой."
fi
echo
}
# Функция для создания символической ссылки
# $1: Исходный видеофайл
# $2: Имя ссылки (выходной файл)
action_create_symlink() {
local video_file="$1"
local output_file="$2"
echo "---"
echo "ИСТОЧНИК: $video_file"
echo "ССЫЛКА : $output_file"
# Создаем символическую ссылку
ln -s "$video_file" "$output_file"
if [ $? -eq 0 ]; then
echo "УСПЕХ: Ссылка создана."
else
echo "ОШИБКА: Не удалось создать ссылку."
fi
echo
}
# Главная функция запуска обработки
run_processing() {
# 1. Готовим списки файлов
if ! logic_prepare_file_lists; then
return 1
fi
if [ ${#FILE_TRIPLETS[@]} -eq 0 ]; then
ui_show_message "Запуск" "Нет файлов для обработки."
return
fi
# 2. Спрашиваем, что делать
local action_to_perform
action_to_perform=$(ui_select_action)
if [[ -z "$action_to_perform" ]]; then
ui_show_message "Отмена" "Операция отменена пользователем."
return
fi
# 3. Финальное подтверждение
local confirmation_text="Вы уверены, что хотите выполнить '${action_to_perform}' для ${#FILE_TRIPLETS[@]} файлов?\n\n"
confirmation_text+="Результаты будут сохранены в:\n$OUTPUT_BASE_DIR"
if ! ui_confirm "Финальное подтверждение" "$confirmation_text"; then
ui_show_message "Отмена" "Операция отменена пользователем."
return
fi
# 4. Создаем выходной каталог, если его нет
if [ ! -d "$OUTPUT_BASE_DIR" ]; then
if ui_confirm "Создание каталога" "Каталог '$OUTPUT_BASE_DIR' не существует. Создать его?"; then
mkdir -p "$OUTPUT_BASE_DIR"
if [ $? -ne 0 ]; then
ui_show_message "Ошибка" "Не удалось создать каталог '$OUTPUT_BASE_DIR'."
return
fi
else
ui_show_message "Отмена" "Операция отменена, так как выходной каталог не существует."
return
fi
fi
# 5. Выполнение операции с прогресс-баром
local total_files=${#FILE_TRIPLETS[@]}
local current_file=0
(
for triplet in "${FILE_TRIPLETS[@]}"; do
# Рассчитываем прогресс
local progress=$(( 100 * current_file / total_files ))
echo "$progress"
# Обновляем текст в прогресс-баре
echo -e "XXX\n$((current_file + 1)) / $total_files\nОбработка: $(basename "$triplet" | cut -f1 -d$'\t')\nXXX"
# Разбираем триплет
IFS=$'\t' read -r video audio output <<< "$triplet"
# Выполняем выбранное действие
case "$action_to_perform" in
"MERGE")
action_merge_mkv "$video" "$audio" "$output"
;;
"SYMLINK")
action_create_symlink "$video" "$output"
;;
esac
((current_file++))
done
# Для завершения прогресс-бара
echo "100"
echo -e "XXX\nГотово!\nНажмите Enter для выхода\nXXX"
sleep 2
) | dialog $DIALOG_OPTS --title "Выполнение..." --gauge "Подготовка..." 10 70 0
clear
}

@ -0,0 +1,109 @@
#!/bin/bash
#==============================================================================
# Модуль основной логики: поиск файлов, сопоставление, генерация имён
#==============================================================================
# Глобальная переменная для хранения подготовленных данных
# Формат: "видеоайл\tаудиоайл\tвыходной_файл" для каждой строки
declare -a FILE_TRIPLETS
# Основная функция, которая находит и сопоставляет файлы
# Возвращает 0 в случае успеха, 1 в случае ошибки
logic_prepare_file_lists() {
# Очищаем предыдущие результаты
FILE_TRIPLETS=()
# Проверка, заданы ли все необходимые пути
if [[ -z "$VIDEO_SRC_DIR" || -z "$AUDIO_SRC_DIR" || -z "$OUTPUT_BASE_DIR" || -z "$OUTPUT_SERIES_NAME" ]]; then
ui_show_message "Ошибка" "Не все обязательные параметры заданы (каталоги видео, аудио, вывода и имя сериала)."
return 1
fi
# 1. Найти видеофайлы
# Использование `find ... -print0` и `mapfile` для безопасной обработки имён с пробелами
local video_list_raw
mapfile -d '' video_list_raw < <(find "$VIDEO_SRC_DIR" -maxdepth 1 -name "$VIDEO_FILE_PATTERN" -print0 | sort -z)
if [ ${#video_list_raw[@]} -eq 0 ]; then
ui_show_message "Ошибка" "Видеофайлы по шаблону '$VIDEO_FILE_PATTERN' в каталоге '$VIDEO_SRC_DIR' не найдены."
return 1
fi
# 2. Найти аудиофайлы
# maxdepth не используется, чтобы искать в подкаталогах, как в примерах
local audio_list_raw
mapfile -d '' audio_list_raw < <(find "$AUDIO_SRC_DIR" -name "$AUDIO_FILE_PATTERN" -print0 | sort -z)
if [ ${#audio_list_raw[@]} -eq 0 ]; then
ui_show_message "Ошибка" "Аудиофайлы по шаблону '$AUDIO_FILE_PATTERN' в каталоге '$AUDIO_SRC_DIR' не найдены."
return 1
fi
# 3. Проверить совпадение количества файлов
if [ ${#video_list_raw[@]} -ne ${#audio_list_raw[@]} ]; then
local msg="Количество найденных файлов не совпадает!\n\n"
msg+="Видео: ${#video_list_raw[@]}\n"
msg+="Аудио: ${#audio_list_raw[@]}\n\n"
msg+="Проверьте каталоги и шаблоны поиска."
ui_show_message "Ошибка сопоставления" "$msg"
return 1
fi
# 4. Сгенерировать выходные имена и собрать триплеты
local i
for i in "${!video_list_raw[@]}"; do
local video_file="${video_list_raw[$i]}"
local audio_file="${audio_list_raw[$i]}"
local video_basename
video_basename=$(basename "$video_file")
# Извлекаем номер эпизода с помощью regex
if [[ "$video_basename" =~ $EPISODE_NUMBER_REGEX ]]; then
local episode_num="${BASH_REMATCH[1]}"
# Приводим к формату с ведущим нулём, если нужно (например, 1 -> 01)
episode_num=$(printf "%02d" "$((10#$episode_num))")
else
ui_show_message "Ошибка Regex" "Не удалось извлечь номер эпизода из файла:\n$video_basename\n\nС помощью регулярного выражения:\n$EPISODE_NUMBER_REGEX"
return 1
fi
# Собираем имя выходного файла из шаблона
local output_name="$OUTPUT_FILENAME_TEMPLATE"
output_name="${output_name/\{SERIES_NAME\}/$OUTPUT_SERIES_NAME}"
output_name="${output_name/\{SEASON\}/$SEASON_NUMBER}"
output_name="${output_name/\{EPISODE\}/$episode_num}"
local output_path="${OUTPUT_BASE_DIR}/${output_name}"
# Сохраняем триплет в массив
FILE_TRIPLETS+=("$video_file"$'\t'"$audio_file"$'\t'"$output_path")
done
return 0
}
# Функция для отображения предпросмотра
logic_show_preview() {
if ! logic_prepare_file_lists; then
# Сообщение об ошибке уже было показано внутри logic_prepare_file_lists
return 1
fi
if [ ${#FILE_TRIPLETS[@]} -eq 0 ]; then
ui_show_message "Предпросмотр" "Нет файлов для обработки."
return
fi
local preview_text="Будут обработаны следующие файлы (${#FILE_TRIPLETS[@]} шт.):\n\n"
local count=1
for triplet in "${FILE_TRIPLETS[@]}"; do
IFS=$'\t' read -r video audio output <<< "$triplet"
preview_text+="$(printf "%02d" $count). \n"
preview_text+=" \ZbВИДЕО:\Zn $(basename "$video")\n"
preview_text+=" \ZbАУДИО:\Zn $(basename "$audio")\n"
preview_text+=" \Zb-> ВЫВОД:\Zn $(basename "$output")\n\n"
((count++))
done
ui_show_message "Предпросмотр" "$preview_text"
}

@ -0,0 +1,69 @@
#!/bin/bash
#==============================================================================
# Модуль интерфейса (TUI) на основе 'dialog'
#==============================================================================
DIALOG_OPTS="--colors --backtitle 'Универсальный обработчик медиа'"
# Показать главное меню
# Принимает массив пунктов меню
ui_main_menu() {
dialog $DIALOG_OPTS --title "Главное меню" \
--menu "Выберите опцию для редактирования или действия:" 20 85 15 "${@}" 2>&1 >/dev/tty
}
# Получить путь к каталогу
# $1: Заголовок окна
# $2: Текущее значение (для старта)
# $3: Путь по умолчанию (если текущее значение пусто)
ui_get_directory() {
local title="$1"
local current_path="$2"
local default_path="$3"
local start_path="${current_path:-$default_path}"
# Убедимся, что путь заканчивается на / для dselect
[[ "$start_path" != */ ]] && start_path="$start_path/"
dialog $DIALOG_OPTS --title "$title" \
--dselect "$start_path" 10 70 2>&1 >/dev/tty
}
# Получить текстовый ввод от пользователя
# $1: Заголовок окна
# $2: Текущее значение
ui_get_input() {
local title="$1"
local current_value="$2"
dialog $DIALOG_OPTS --title "$title" \
--inputbox "Введите новое значение:" 10 70 "$current_value" 2>&1 >/dev/tty
}
# Показать информационное сообщение
# $1: Заголовок
# $2: Текст сообщения
ui_show_message() {
local title="$1"
local text="$2"
dialog $DIALOG_OPTS --title "$title" --msgbox "$text" 20 70
}
# Показать окно с выбором Да/Нет
# $1: Заголовок
# $2: Текст вопроса
ui_confirm() {
local title="$1"
local text="$2"
dialog $DIALOG_OPTS --title "$title" --yesno "$text" 10 70
return $?
}
# Показать меню выбора действия перед запуском
ui_select_action() {
dialog $DIALOG_OPTS --title "Выбор действия" \
--menu "Какую операцию выполнить с найденными файлами?" 15 70 2 \
"MERGE" "Склеить видео и аудио с помощью mkvmerge" \
"SYMLINK" "Создать символические ссылки на видеофайлы" 2>&1 >/dev/tty
}

@ -0,0 +1,102 @@
#!/bin/bash
#==============================================================================
# Универсальный скрипт для обработки медиафайлов с TUI-интерфейсом
#==============================================================================
# --- Подключение модулей ---
# Убедимся, что скрипты-модули находятся в том же каталоге
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)
source "$SCRIPT_DIR/core_ui.sh"
source "$SCRIPT_DIR/core_logic.sh"
source "$SCRIPT_DIR/core_actions.sh"
# --- Конфигурация по умолчанию (можно менять) ---
# Эти пути будут предлагаться по умолчанию в диалогах выбора
DEFAULT_ROOT_PATH="/var/www/nextcloud/data/grayhook/files/"
DEFAULT_TORRENTS_DIR="${DEFAULT_ROOT_PATH}/Torrents"
DEFAULT_ARCHIVE_DIR="${DEFAULT_ROOT_PATH}/Archive/Anime"
# --- Переменные состояния (будут меняться через интерфейс) ---
VIDEO_SRC_DIR=""
AUDIO_SRC_DIR=""
OUTPUT_BASE_DIR=""
OUTPUT_SERIES_NAME=""
SEASON_NUMBER="01"
# Паттерны для поиска файлов (можно использовать find-совместимые wildcards)
VIDEO_FILE_PATTERN="*.mkv"
AUDIO_FILE_PATTERN="*.mka"
# Регулярное выражение для извлечения номера серии из ИМЕНИ ВИДЕОФАЙЛА
# Использует синтаксис ERE (sed -E). Группа захвата (в скобках) должна поймать номер.
EPISODE_NUMBER_REGEX='.* ([0-9]{2}) .*'
# Шаблон для имени выходного файла. Заполнители будут заменены.
# {SERIES_NAME} - Имя сериала
# {SEASON} - Номер сезона (с ведущим нулём)
# {EPISODE} - Номер эпизода (с ведущим нулём, извлечённый regex'ом)
OUTPUT_FILENAME_TEMPLATE="{SERIES_NAME} s{SEASON}e{EPISODE}.mkv"
# --- Главный цикл программы ---
main() {
while true; do
# Формируем пункты меню с текущими значениями
menu_items=(
"V" "Видео каталог : ${VIDEO_SRC_DIR:-_не задан_}"
"A" "Аудио каталог : ${AUDIO_SRC_DIR:-_не задан_}"
"O" "Выходной каталог : ${OUTPUT_BASE_DIR:-_не задан_}"
"N" "Имя для Plex : ${OUTPUT_SERIES_NAME:-_не задано_}"
"S" "Номер сезона : $SEASON_NUMBER"
"" "--- Шаблоны и Regex ---"
"P" "Шаблон видеофайлов : $VIDEO_FILE_PATTERN"
"U" "Шаблон аудиофайлов : $AUDIO_FILE_PATTERN"
"R" "Regex номера серии : $EPISODE_NUMBER_REGEX"
"T" "Шаблон имени вывода : $OUTPUT_FILENAME_TEMPLATE"
"" "--- Действия ---"
"VIEW" "Предпросмотр сопоставления файлов"
"RUN" "ЗАПУСТИТЬ обработку"
)
choice=$(ui_main_menu "${menu_items[@]}")
# Выход из скрипта по кнопке Cancel или Esc
if [[ -z "$choice" ]]; then
clear
echo "Выход."
break
fi
case "$choice" in
V) VIDEO_SRC_DIR=$(ui_get_directory "Выберите каталог с видеофайлами" "$VIDEO_SRC_DIR" "$DEFAULT_TORRENTS_DIR") ;;
A) AUDIO_SRC_DIR=$(ui_get_directory "Выберите каталог с аудиофайлами" "$AUDIO_SRC_DIR" "$VIDEO_SRC_DIR") ;;
O) OUTPUT_BASE_DIR=$(ui_get_directory "Выберите БАЗОВЫЙ каталог для результата" "$OUTPUT_BASE_DIR" "$DEFAULT_ARCHIVE_DIR") ;;
N) OUTPUT_SERIES_NAME=$(ui_get_input "Введите имя сериала для Plex" "$OUTPUT_SERIES_NAME") ;;
S) SEASON_NUMBER=$(ui_get_input "Введите номер сезона (например, 01, 02)" "$SEASON_NUMBER") ;;
P) VIDEO_FILE_PATTERN=$(ui_get_input "Введите шаблон для поиска видео (*.mkv, *ep*.mkv)" "$VIDEO_FILE_PATTERN") ;;
U) AUDIO_FILE_PATTERN=$(ui_get_input "Введите шаблон для поиска аудио (*.mka, *.ac3)" "$AUDIO_FILE_PATTERN") ;;
R) EPISODE_NUMBER_REGEX=$(ui_get_input "Введите ERE-regex для номера серии" "$EPISODE_NUMBER_REGEX") ;;
T) OUTPUT_FILENAME_TEMPLATE=$(ui_get_input "Введите шаблон имени выходного файла" "$OUTPUT_FILENAME_TEMPLATE") ;;
VIEW)
# Вызываем предпросмотр
logic_show_preview
;;
RUN)
# Вызываем меню выбора действия и запускаем обработку
run_processing
;;
esac
done
}
# --- Точка входа ---
# Проверка наличия dialog
if ! command -v dialog &> /dev/null; then
echo "Команда 'dialog' не найдена. Пожалуйста, установите ее."
echo "sudo apt-get install dialog (Debian/Ubuntu)"
exit 1
fi
main
Loading…
Cancel
Save