fancymerge.sh

Browser view only. Use the download link if you want to save the file.

Back to Toolbox
#!/bin/bash

source ./launch_random_terminal.sh

# Source the load_video_files.sh script
source load_video_files.sh

# Store the list of video files
videofiles_original=("${videofiles[@]}")

# Outer loop to allow resetting
while true; do
    # Initialize variables
    declare -a file_groups  # Array to hold group assignment for each file
    declare -A group_names  # Associative array to hold group names
    current_line=0          # Cursor position starts at the top
    message=""

    # Initialize file_groups with zeros (unassigned)
    for ((i=0; i<${#videofiles[@]}; i++)); do
        file_groups[i]=0
    done

    # Define colors for groups
    group_colors[1]="\e[31m"  # Red
    group_colors[2]="\e[32m"  # Green
    group_colors[3]="\e[33m"  # Yellow
    group_colors[4]="\e[34m"  # Blue
    group_colors[5]="\e[35m"  # Magenta
    bar_color="\e[7m"         # Reverse video for bar
    default_color="\e[0m"     # Default color

    # Hide cursor
    tput civis

    # Main interactive loop
    while true; do
        # Clear screen
        tput clear

        # Check if any MOV files are present in the current group
        mov_detected=false
        for ((i=0; i<${#videofiles[@]}; i++)); do
            if [ "${file_groups[i]}" != "0" ] && [ "${file_groups[i]}" != "d" ]; then
                ext="${videofiles[i]##*.}"
                ext="${ext,,}"
                if [ "$ext" = "mov" ]; then
                    mov_detected=true
                    break
                fi
            fi
        done

        # Display MOV rename mode banner if MOV files are detected
        if $mov_detected; then
            cols=$(tput cols)
            banner=" MOV rename mode "
            banner_length=${#banner}
            # Position cursor at top right minus banner length
            tput cup 0 $((cols - banner_length))
            echo -ne "\e[1;97;41m$banner\e[0m"
        fi

        # Display the list of files with group assignments
        for ((i=0; i<${#videofiles[@]}; i++)); do
            # Skip dropped files
            if [ "${file_groups[i]}" == "d" ]; then
                continue
            fi

            # Get filename without './'
            filename_display="${videofiles[i]#./}"

            # Apply group color if assigned
            group_num=${file_groups[i]}
            if [ "$group_num" != "0" ]; then
                color="${group_colors[$group_num]}"
                group_name=${group_names[$group_num]}
                if [ -z "$group_name" ]; then
                    group_name="Group $group_num"
                fi
            else
                color="$default_color"
            fi

            # Highlight the current line
            if [ $i -eq $current_line ]; then
                printf "$bar_color"
            else
                printf "$color"
            fi

            # Display file name and group assignment
            if [ "$group_num" != "0" ]; then
                printf "%-60s - %s\n" "$filename_display" "$group_name"
            else
                printf "%s\n" "$filename_display"
            fi

            # Reset text formatting
            printf "$default_color"
        done

        # Display the key menu at the bottom
        tput cup $(( $(tput lines) - 3 )) 0
        echo -e "${default_color}[Arrow Keys]=Navigate  [1-5]=Assign Group  [W]=Witness Name"
        echo -e "[0/D]=Drop File  [R]=Reset  [Q]=Quit  [Enter]=Proceed"
        # Move cursor to status line and display any messages
        tput cup $(tput lines) 0
        echo -n "$message"
        message=""

        # Read user input
        read -rsn1 key
        key=${key,,}  # Convert key to lowercase for case-insensitive input

        if [[ $key == $'\e' ]]; then
            read -rsn2 -t 0.1 key
            case "$key" in
                '[A')  # Up arrow
                    # Find the previous non-dropped file
                    while [ $current_line -gt 0 ]; do
                        current_line=$((current_line - 1))
                        if [ "${file_groups[current_line]}" != "d" ]; then
                            break
                        fi
                    done
                    ;;
                '[B')  # Down arrow
                    # Find the next non-dropped file
                    while [ $current_line -lt $((${#videofiles[@]} - 1)) ]; do
                        current_line=$((current_line + 1))
                        if [ "${file_groups[current_line]}" != "d" ]; then
                            break
                        fi
                    done
                    ;;
            esac
        else
            case "$key" in
                '1'|'2'|'3'|'4'|'5')
                    group_num=$key
                    # Assign current file and all files below to group $group_num
                    for ((j=$current_line; j<${#videofiles[@]}; j++)); do
                        if [ "${file_groups[j]}" != "d" ]; then
                            file_groups[j]=$group_num
                        fi
                    done
                    message="Assigned files from line $current_line to end to Group $group_num"
                    ;;
                'w')
                    # Assign witness name
                    group_num=${file_groups[current_line]}
                    if [[ $group_num =~ ^[1-5]$ ]]; then
                        # Suggest witness name based on previous group if applicable
                        suggested_name=""
                        if [ $group_num -ge 2 ]; then
                            prev_group_num=$((group_num -1))
                            prev_group_name=${group_names[$prev_group_num]}
                            if [[ $prev_group_name =~ (.*[^\d])([0-9]+)$ ]]; then
                                base_name="${BASH_REMATCH[1]}"
                                prev_num="${BASH_REMATCH[2]}"
                                next_num=$((prev_num + 1))
                                suggested_name="$base_name$next_num"
                            fi
                        fi
                        # Prompt for witness name
                        tput cup $(tput lines) 0
                        echo -n "Enter witness name for Group $group_num [${suggested_name}]: "
                        tput cnorm  # Show cursor
                        read group_name
                        tput civis  # Hide cursor
                        if [ -z "$group_name" ]; then
                            group_name="$suggested_name"
                        fi
                        group_names[$group_num]="$group_name"
                        message="Assigned witness name '$group_name' to Group $group_num"
                    else
                        message="Current file is not assigned to any group."
                    fi
                    ;;
                '0'|'d')
                    # Drop current file from the list (exclude it)
                    file_groups[current_line]="d"
                    message="Dropped file '${videofiles[current_line]}' from the list"

                    # Move to the next non-dropped file
                    while [ $current_line -lt $((${#videofiles[@]} - 1)) ]; do
                        current_line=$((current_line + 1))
                        if [ "${file_groups[current_line]}" != "d" ]; then
                            break
                        fi
                    done
                    ;;
                'q')
                    # Quit the program
                    message="Quitting..."
                    kill -- "$PPID"
                    exit 0
                    ;;
                'r')
                    # Reset all group assignments and witness names
                    for ((i=0; i<${#videofiles[@]}; i++)); do
                        if [ "${file_groups[i]}" != "d" ]; then
                            file_groups[i]=0
                        fi
                    done
                    group_names=()
                    message="All group assignments and witness names have been reset."
                    ;;
                '')
                    # Enter pressed, finish
                    break
                    ;;
                *)
                    message="Invalid key."
                    ;;
            esac
        fi
    done

    # Show cursor again
    tput cnorm

    # Display summary before processing
    tput clear
    if $mov_detected; then
        echo -e "${default_color}Summary of files to be renamed:"
    else
        echo -e "${default_color}Summary of files to be processed:"
    fi
    
    echo

    for group_num in {1..5}; do
        files_in_group=()
        # Removed resetting group_extension here
        for ((i=0; i<${#videofiles[@]}; i++)); do
            if [ "${file_groups[i]}" = "$group_num" ]; then
                files_in_group+=("${videofiles[i]}")
                # Get the extension of the first file in the group
                if [ -z "$group_extension" ]; then
                    ext="${videofiles[i]##*.}"
                    group_extension="${ext,,}"
                fi
            fi
        done
        if [ ${#files_in_group[@]} -gt 0 ]; then
            group_name=${group_names[$group_num]}
            if [ -z "$group_name" ]; then
                group_name="Group $group_num"
            fi
            echo -e "${group_colors[$group_num]}$group_name${default_color}"
            for f in "${files_in_group[@]}"; do
                # Remove './' from filename
                filename_display="${f#./}"
                echo -e "    ↳ $filename_display"
            done
            echo
        fi
    done

    echo "Press Enter to proceed, 'r' to reset, or 'q' to quit."
    read -n1 user_choice
    user_choice=${user_choice,,}  # Convert to lowercase

    if [ "$user_choice" = 'q' ]; then
        # Quit the program
        kill -- "$PPID"
        exit 0
    elif [ "$user_choice" = 'r' ]; then
        # Reset and restart the process
        message="All group assignments and witness names have been reset."
        continue  # Restart the outer while loop
    else
        # Proceed to processing
        break  # Exit the outer while loop
    fi
done

# Proceed to process files
merged_files=()
group_extension=""  # Initialize outside the loop

for group_num in {1..5}; do
    files_in_group=()
    # Removed resetting group_extension here
    for ((i=0; i<${#videofiles[@]}; i++)); do
        if [ "${file_groups[i]}" = "$group_num" ]; then
            files_in_group+=("${videofiles[i]}")
            # Get the extension of the first file in the group
            if [ -z "$group_extension" ]; then
                ext="${videofiles[i]##*.}"
                group_extension="${ext,,}"
            fi
        fi
    done
    if [ ${#files_in_group[@]} -gt 0 ]; then
        # Determine the output file extension based on the input files
        extension="$group_extension"

        # Check if all files have the same extension
        consistent_extension=true
        for f in "${files_in_group[@]}"; do
            ext="${f##*.}"
            ext="${ext,,}"
            if [ "$ext" != "$extension" ]; then
                consistent_extension=false
                break
            fi
        done

        if ! $consistent_extension; then
            echo "Warning: Files in Group $group_num have different extensions."
            echo "Using the extension of the first file: .$extension"
        fi

        group_name=${group_names[$group_num]}
        if [ -z "$group_name" ]; then
            group_name="Group_$group_num"
        fi

        if [ "${#files_in_group[@]}" -eq 1 ]; then
            # Only one file in group, rename it
            single_file="${files_in_group[0]}"
            base_dir=$(dirname "$single_file")
            new_filename="${group_name}.${extension}"
            new_filepath="${base_dir}/${new_filename}"

            # Check if the new filename already exists
            if [ -e "$new_filepath" ]; then
                echo "Error: File $new_filepath already exists. Skipping rename."
            else
                mv "$single_file" "$new_filepath"
                echo "Renamed '$single_file' to '$new_filepath'"
            fi

            # Add the source file to merged_files
            merged_files+=("$single_file")
        elif [ "$extension" = "mov" ]; then
            # For MOV files, rename them
            index=1
            for f in "${files_in_group[@]}"; do
                base_dir=$(dirname "$f")
                new_filename="${group_name} ${index}.${extension}"
                new_filepath="${base_dir}/${new_filename}"

                # Check if the new filename already exists
                if [ -e "$new_filepath" ]; then
                    echo "Error: File $new_filepath already exists. Skipping rename."
                else
                    mv "$f" "$new_filepath"
                    echo "Renamed '$f' to '$new_filepath'"
                fi
                index=$((index + 1))
            done
            # Add the source files to merged_files
            merged_files+=("${files_in_group[@]}")
        else
            # Merge files in files_in_group using ffmpeg
            # Create a temporary file list for ffmpeg
            list_file="list_$group_num.txt"
            rm -f "$list_file"
            for f in "${files_in_group[@]}"; do
                echo "file '$(realpath "$f")'" >> "$list_file"
            done

            output_file="${group_name}.${extension}"

            echo "Merging files for $group_name into $output_file..."
            ffmpeg -y -f concat -safe 0 -i "$list_file" -c copy "$output_file"

            # Remove temporary list file
            rm "$list_file"

            # Add the source files to merged_files
            merged_files+=("${files_in_group[@]}")
        fi
    fi
done

# Determine group_extension from merged_files
if [ ${#merged_files[@]} -gt 0 ]; then
    # Get the extension of the first merged file
    ext="${merged_files[0]##*.}"
    group_extension="${ext,,}"

    # Check if all merged files have the same extension
    consistent_extension=true
    for f in "${merged_files[@]}"; do
        ext="${f##*.}"
        ext="${ext,,}"
        if [ "$ext" != "$group_extension" ]; then
            consistent_extension=false
            break
        fi
    done

    if ! $consistent_extension; then
        group_extension="mixed"
    fi
else
    group_extension="unknown"
fi

# Reset text attributes
tput sgr0

# Prompt user to move original files
read -rsn1 -p $'\e[1;97;44m Do you want to move the original files to a subfolder? (Y/N) ' move_choice
echo -e "\e[0m"  # Ensures prompt is reset correctly

# Handle Y/N or y/n
if [[ "$move_choice" =~ [Yy] ]]; then
    # Create the destination folder if it doesn't exist
    if [[ -n "$group_extension" && "$group_extension" != "unknown" ]]; then
        dest_folder="orig ${group_extension^^} files"  # Convert extension to uppercase
    else
        dest_folder="orig files"  # Fallback in case no extension is detected
    fi
    mkdir -p "$dest_folder"

    # Move the source files that were actually merged or renamed
    for f in "${merged_files[@]}"; do
        if [ -e "$f" ]; then
            mv "$f" "$dest_folder"
        else
            echo -e "\e[91mWarning: File '$f' not found, skipping.\e[0m"
        fi
    done

    echo -e "\n\e[92mFiles moved to '$dest_folder'\e[0m"
else
    echo -e "\n\e[93mFiles were not moved.\e[0m"
fi

# Prompt the user to press any key to exit
echo "Press any key to exit..."
read -n1  # This will wait for a single keypress
kill -- "$PPID"
exit 0