合并视频和字幕然后删除现有文件的脚本(非递归)

Sum*_*ukh 7 command-line video nautilus-script

我一直在使用mkvmerge合并视频文件和字幕,我正在使用以下命令

mkvmerge -o output.mkv video.mp4 subtitles.srt
Run Code Online (Sandbox Code Playgroud)

哪个工作正常,但您可能会猜到这真的很慢

  • 我必须在存储电影的每个目录中打开终端。
  • 然后我必须在命令中复制并粘贴文件的名称
  • 然后我必须重命名输出文件
  • 然后删除我使用的原始文件

这是一个漫长的过程。


我想要的理想情况。

  • 我将进入包含同名电影文件和字幕文件的文件夹。
  • 我选择一个电影文件和一个字幕文件,右键单击并在它们上运行 nautilus 脚本。
  • 他们合并了
  • 原始文件被删除。
  • 使用带有mkv扩展名的原始文件的名称重命名合并的文件

这不需要递归,我不希望我的硬盘创建和删除 100 个文件。电影文件和字幕文件通常具有相同的名称,但有时会在字幕文件中固定“_en”后缀。如果您有其他方法可以做到这一点,我也同意。

pa4*_*080 7

我决定获得一些使用 Bash 的经验并编写了以下脚本,该脚本具有以下功能:

  • 它可以处理所有文件和文件夹,放入当前目录。
  • 如果有多个字幕或视频文件(示例文件除外),脚本将要求手动交互。
  • 在所有其他情况下,脚本会自动将所有文件和文件夹移动到备份目录(请注意运行它的位置!),该目录将移动到用户的垃圾文件夹中,而不是被删除。
  • 它可以处理多种类型的视频和字幕扩展。
  • 它用于mkvmerge将视频与字幕文件合并,也用于notify-send在 GUI 中显示一些消息。它还用于gvfs-trash移动用户垃圾文件夹中的文件。
  • 它可以用作Nautilus 脚本或常规 shell 脚本,但需要 GIU 环境,而notify-send命令存在于脚本主体中。
  • 输出文件的名称可以基于目录名称(默认)或源视频文件的名称。
  • 此外,当仅选择两个文件一个视频和一个字幕文件)时,它们将被合并,文件夹的其余内容将被保留。输出文件将以源视频文件命名。此选项仅在脚本用作 Nautilus 脚本时可用。

剧本:

#!/bin/bash -e

# Check if all tools are available
[ -x /usr/bin/notify-send ] || (echo "Please, install 'notify-send'"; exit 1)
[ -x /usr/bin/mkvmerge ] || (echo "Please, install 'mkvmerge'"; exit 1)

# Allowed video and subtitle file extensions
EXT_VIDEO=("mp4 avi mpg mov mkv wmv")
EXT_SUB=("sub str srt vtt")

# Files, which names contains some of next strings will be removed in auto mode
FILTER=("sample Sample SAMPLE")

# Log file
MERGE_LOG="/tmp/merge-video-sub.log" 
echo > "$MERGE_LOG"

#
# Functions
#

function get-video-and-sub-file-names {
    # Get the names of the video and subtitle files and move the rest of the files into the Backup directory
    for ((i=0; i<${#FILE_LIST[@]}; i++)); do
        FILE_NAME="${FILE_LIST[$i]%.*}"
        FILE_EXT="${FILE_LIST[$i]##*.}"

        if   [[ "${EXT_SUB[@]}" == *"$FILE_EXT"* ]]; then
            SUB_FULL_FILE_NAME="${FILE_LIST[$i]}"
            SUB_FILE_NAME="${FILE_NAME}"
            SUB_FILE_EXT="${FILE_EXT}"
        elif [[ "${EXT_VIDEO[@]}" == *"$FILE_EXT"* ]]; then
            VIDEO_FULL_FILE_NAME="${FILE_LIST[$i]}"
            VIDEO_FILE_NAME="${FILE_NAME}"
            VIDEO_FILE_EXT="${FILE_EXT}"
        else
            # We need 'find' to manipulate only with files, because "$BACKUP_DIR" is in the queue
            find ./* -maxdepth 0 -type f -name "${FILE_LIST[$i]}" -exec mv "{}" "$BACKUP_DIR" \; -exec echo -e "The file {} was REMOVED.\n" >> "$MERGE_LOG" \;
        fi
    done
}

function get-the-content-of-the-current-directory {
    # Get the content of the current directory
    shopt -s nullglob
    FILE_LIST=(*)
    shopt -u nullglob
}

function mkvmerge-video-and-sub-files {
    # Create merged file
    mkvmerge -o "$OUTPUT_FILE" "$VIDEO_FULL_FILE_NAME" "$SUB_FULL_FILE_NAME"
    sleep 3
}

#
# Scenario 1: If exactly two files are selected in Nautilus! Then check if they are 1 video and 1 subtitle files, if yes - merge and remove them
# Scenario 2: Else run the standard procedure
#

# Get the files, selected in Nautilus as file list. Use next command to check the result: notify-send "MESSAGE" "`echo -e "${#FILE_LIST[@]}"; printf '%s\n' "${FILE_LIST[@]}"`"
IFS_BAK=$IFS
IFS=$'\t\n'
FILE_LIST=($NAUTILUS_SCRIPT_SELECTED_FILE_PATHS)
IFS=$IFS_BAK


if [ "${#FILE_LIST[@]}" -eq "2" ]
then # Scenario 1

    # Get the names of the video and subtitle files
    get-video-and-sub-file-names

    if   [[ "${EXT_SUB[@]}" == *" $SUB_FILE_EXT "* ]] && [[ "${EXT_VIDEO[@]}" == *" $VIDEO_FILE_EXT "* ]]
    then
        notify-send "OK" "`echo -e "The following files will be MERGED and MOVED to trash:"; printf '\t-\ %s\n' "${FILE_LIST[@]##*/}"`"

        # Construct the name of the merged file. 
        OUTPUT_FILE="${VIDEO_FILE_NAME}.sub.mkv"

        # Merge the files
        mkvmerge-video-and-sub-files        

        # Move video and subtitle files into user's trash directory and create trash infofile
        if [ -f "$OUTPUT_FILE" ]
        then
            gvfs-trash "$VIDEO_FULL_FILE_NAME"
            gvfs-trash "$SUB_FULL_FILE_NAME"            
            notify-send "OK" "`echo -e "THE NAME OF THE NEW MERGED FILE IS:\n${OUTPUT_FILE##*/}"`"
        else
            notify-send "ERROR 1" "`echo "Something went wrong!"`"
        fi
    else
        notify-send "ERROR" "`echo -e "\n\t\nTo use this function, please select exactly:\n\t- 1 video file and\n\t- 1 subtitle file!\n\t\nYou are selected these files:"; printf '\t-\ %s\n' "${FILE_LIST[@]##*/}"`"
    fi

else # Scenario 2

    # Get the current directory name
    DIR_NAME="${PWD##*/}"

    # Create Backup sub-directory 
    BACKUP_DIR="${DIR_NAME}.backup"
    [ -d "${BACKUP_DIR}" ] || mkdir "$BACKUP_DIR" && echo "The directory $BACKUP_DIR was CREATED.\n" > "$MERGE_LOG"

    # Move all sub-directories into the Backup directory
    shopt -s dotglob
    find ./* -maxdepth 0 -type d ! -name "*$BACKUP_DIR*" -prune -exec mv "{}" "$BACKUP_DIR" \; -exec echo "The directory {} was REMOVED.\n" >> "$MERGE_LOG" \;
    shopt -u dotglob

    # Move all files and folders, whose names contains a string, that exists in $FILTER[@]
    for f in $FILTER; do
        shopt -s dotglob
        find ./* -maxdepth 0 ! -name "*$BACKUP_DIR*" -type f -name "*$f*" -exec mv "{}" "$BACKUP_DIR" \; -exec echo "The file {} was REMOVED.\n" >> "$MERGE_LOG" \;
        shopt -u dotglob
    done

    # Get the entire content of the current directory
    get-the-content-of-the-current-directory

    # Get the names of the video and subtitle files and move the rest of the files into the Backup directory
    get-video-and-sub-file-names

    # Construct the name of the merged file. It could be based on the parent directory or on the video file name Make your choice and comment/uncomment next lines
    #OUTPUT_FILE="${VIDEO_FILE_NAME}.sub.mkv"
    OUTPUT_FILE="${DIR_NAME}.sub.mkv"

    # Get the entire content of the current directory after the filtering
    get-the-content-of-the-current-directory

    echo -e "$(cat $MERGE_LOG)" && notify-send "OK" "`echo -e "$(cat $MERGE_LOG)"`" && echo > "$MERGE_LOG"

    # Check the current structure of the directory
    if [ "${#FILE_LIST[@]}" -ne "3" ]; then
        echo "The content structure must consists of next 3 items:" > "$MERGE_LOG"
        echo "\t- 1 movie file,\n\t- 1 subtitle file and\n\t- 1 backup directory." >> "$MERGE_LOG"
        echo "\n\t\nThe current number of contained items is ${#FILE_LIST[@]}." >> "$MERGE_LOG" && echo >> "$MERGE_LOG"
        echo "\n\t\nPLEASE RESOLVE THIS MANUALLY!" >> "$MERGE_LOG"
        echo -e "$(cat $MERGE_LOG)" && notify-send "ERROR" "`echo -e "$(cat $MERGE_LOG)"`"
    else
        echo "The directory structure looks good, is contains ${#FILE_LIST[@]} items." > "$MERGE_LOG"
        echo " - The source VIDEO file is: ${VIDEO_FULL_FILE_NAME::21}... .${VIDEO_FULL_FILE_NAME##*.}" >> "$MERGE_LOG"
        echo " - The source SUB file is: ${SUB_FULL_FILE_NAME::25}... .${SUB_FULL_FILE_NAME##*.}" >> "$MERGE_LOG"
        echo "They has been merged and removed!" | tr /a-z/ /A-Z/ >> "$MERGE_LOG"

        # Merge the files
        mkvmerge-video-and-sub-files

        # Move video and subtitle files into the Backup directory
        mv "$VIDEO_FULL_FILE_NAME" "$BACKUP_DIR" 
        mv "$SUB_FULL_FILE_NAME" "$BACKUP_DIR" 

        # Move the Backup directory to trash and create trash infofile
        if [ -f "$OUTPUT_FILE" ]; then
            gvfs-trash "$BACKUP_DIR" 

            echo "\n\t\nThe Backup directory has been MOVED to Trash!\n\t\n" >> "$MERGE_LOG"
            echo "The name of the new merged file is:"  | tr /a-z/ /A-Z/ >> "$MERGE_LOG"
            echo "${OUTPUT_FILE##*/}" >> "$MERGE_LOG"
            echo -e "$(cat $MERGE_LOG)" && notify-send "OK" "`echo -e "$(cat $MERGE_LOG)"`"
        else
            echo "Something went wrong!" && notify-send "ERROR 2" "`echo "Something went wrong!"`"
        fi

    fi
fi

rm "$MERGE_LOG"
exit 1
Run Code Online (Sandbox Code Playgroud)

设置:

  • 创建可执行文件并将上述内容粘贴到其中。让我们调用这个文件merge-video-sub

    touch merge-video-sub 
    chmod +x merge-video-sub
    nano merge-video-sub
    
    Run Code Online (Sandbox Code Playgroud)
  • ln -s将此文件复制(或)到文件夹中~/.local/share/nautilus/scripts,使其可用作当前用户的 Nautilus 脚本。

  • 目前我找不到如何使它在系统范围内作为 Nautilus 脚本可用的方法。

  • 将文件复制到~/bin(并添加export PATH=$PATH:~/bin~/.bashrcif的底部)以使其可用作当前用户的 shell 命令。

  • 将文件复制到其中/usr/local/bin以使其可用作 shell 命令系统范围。

  • 简短的方法curl将脚本从我的 PasteBin直接放入nautilus/scripts文件夹:

    curl https://pastebin.com/raw/HrLTibuR | sed -e 's/\r$//' > $HOME/.local/share/nautilus/scripts/merge-video-sub
    chmod +x $HOME/.local/share/nautilus/scripts/merge-video-sub
    
    Run Code Online (Sandbox Code Playgroud)

演示:

在此处输入图片说明

补充参考: