-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create trim-front-of-video-ffmpeg.sh
- Loading branch information
1 parent
708cafd
commit 381de57
Showing
1 changed file
with
199 additions
and
0 deletions.
There are no files selected for viewing
199 changes: 199 additions & 0 deletions
199
Bash/Installer Scripts/FFmpeg/run-scripts/trim-front-of-video-ffmpeg.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
#!/usr/bin/env bash | ||
|
||
# Color variables for easier reading and logging | ||
RED='\033[0;31m' | ||
GREEN='\033[0;32m' | ||
YELLOW='\033[1;33m' | ||
NC='\033[0m' | ||
|
||
overwrite=0 | ||
append_text="-trimmed" | ||
prepend_text="" | ||
file_list="" | ||
single_input_file="" | ||
trim_start=0 | ||
trim_end=0 | ||
verbose=0 | ||
batch_mode=0 | ||
|
||
# Function to display usage | ||
usage() { | ||
echo -e "${GREEN}Usage: $0 [-f <file_list> | -i <input_file>] [--start <trim_start_seconds>] [--end <trim_end_seconds>] [--append <append_text>] [--prepend <prepend_text>] [--overwrite] [--verbose]${NC}" | ||
echo | ||
echo -e "Options:" | ||
echo -e " -h, --help Display this help message." | ||
echo -e " -f, --file Specify the path to the text file containing the list of video files." | ||
echo -e " -i, --input Specify the path to a single video file directly." | ||
echo -e " --start Duration in seconds to trim from the start of the video." | ||
echo -e " --end Duration in seconds to trim from the end of the video." | ||
echo -e " -a, --append Specify text to append to the output file name. Ignored if --overwrite is used." | ||
echo -e " -p, --prepend Specify text to prepend to the output file name. Ignored if --overwrite is used." | ||
echo -e " -o, --overwrite Overwrite the input file instead of creating a new one." | ||
echo -e " -v, --verbose Enable verbose output." | ||
echo | ||
echo "Examples:" | ||
echo "$0 -v -i \"video.mp4\"" | ||
echo "$0 -o -v -i \"video.mp4\"" | ||
echo "$0 -f \"video_list.txt\"" | ||
exit 1 | ||
} | ||
|
||
# Remove log file if it exists | ||
[[ -f video-processing.log ]] && rm video-processing.log | ||
|
||
# Parse options | ||
TEMP=$(getopt -o f:i:a:p:ovh --long file:,input:,start:,end:,append:,prepend:,overwrite,verbose,help -n 'script.sh' -- "$@") | ||
if [ $? != 0 ]; then echo "Failed to parse options... exiting." >&2; exit 1; fi | ||
|
||
eval set -- "$TEMP" | ||
|
||
while true; do | ||
case "$1" in | ||
-f | --file ) file_list="$2"; batch_mode=1; shift 2 ;; | ||
-i | --input ) single_input_file="$2"; shift 2 ;; | ||
--start ) trim_start="$2"; shift 2 ;; | ||
--end ) trim_end="$2"; shift 2 ;; | ||
-a | --append ) append_text="$2"; shift 2 ;; | ||
-p | --prepend ) prepend_text="$2"; shift 2 ;; | ||
-o | --overwrite ) overwrite=1; append_text=""; prepend_text=""; shift ;; | ||
-v | --verbose ) verbose=1; shift ;; | ||
-h | --help ) usage; shift ;; | ||
-- ) shift; break ;; | ||
* ) break ;; | ||
esac | ||
done | ||
|
||
# Function to prompt for input file | ||
prompt_for_input() { | ||
while true; do | ||
read -p "Enter the path to the input video file (or 'q' to quit): " single_input_file | ||
if [[ "$single_input_file" == "q" ]]; then | ||
echo "Quitting..." | ||
exit 0 | ||
elif [[ -f "$single_input_file" ]]; then | ||
video_files+=("$single_input_file") | ||
clear | ||
break | ||
else | ||
echo -e "${RED}Error: The file $single_input_file does not exist. Please try again.${NC}" | ||
fi | ||
done | ||
} | ||
|
||
# Function to process a single video | ||
process_video() { | ||
local input_file="$1" | ||
echo -e "${GREEN}Processing: $input_file${NC}" | ||
|
||
# Calculate total video duration | ||
local total_duration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 -i "$input_file" | awk '{print $1}') | ||
|
||
# Calculate start and end keyframe timestamps | ||
local formatted_start_time formatted_end_time | ||
if [[ $trim_start -gt 0 ]]; then | ||
formatted_start_time=$(ffprobe -v error -select_streams v -of csv=p=0 -show_entries frame=best_effort_timestamp_time -read_intervals $trim_start%+$trim_start -i "$input_file" | head -n1) | ||
if [[ -z "$formatted_start_time" ]]; then | ||
echo -e "${YELLOW}No keyframe found near start time $trim_start, using the exact time instead.${NC}" | ||
formatted_start_time=$trim_start | ||
fi | ||
else | ||
formatted_start_time=$(ffprobe -v error -of default=noprint_wrappers=1:nokey=1 -select_streams v:0 -skip_frame nokey -show_frames -show_entries frame=pkt_dts_time "$input_file" | | ||
grep -E '^[0-9]+\.[0-9]+$' | head -n1) | ||
fi | ||
|
||
if [[ $trim_end -gt 0 ]]; then | ||
local target_end_time=$(echo "$total_duration - $trim_end" | bc) | ||
formatted_end_time=$(ffprobe -v error -select_streams v -of csv=p=0 -show_entries frame=best_effort_timestamp_time -read_intervals -$trim_end%-$trim_end -i "$input_file" | | ||
sort -rV | head -n1) | ||
if [[ -z "$formatted_end_time" ]]; then | ||
echo -e "${YELLOW}No keyframe found near end time $trim_end, using the exact time instead.${NC}" | ||
formatted_end_time="$target_end_time" | ||
fi | ||
else | ||
formatted_end_time="$total_duration" | ||
fi | ||
|
||
if [[ "$verbose" -eq 1 ]]; then | ||
echo -e "${YELLOW}Trimming from $formatted_start_time to $formatted_end_time.${NC}" | ||
fi | ||
|
||
local base_name="${input_file%.*}" | ||
local extension="${input_file##*.}" | ||
local final_output="${prepend_text}${base_name}${append_text}.${extension}" | ||
if [ $overwrite -eq 1 ]; then | ||
final_output="$input_file" | ||
fi | ||
|
||
local trim_start_cmd trim_end_cmd | ||
[[ -n "$formatted_start_time" ]] && trim_start_cmd="-ss \"$formatted_start_time\"" | ||
[[ -n "$formatted_end_time" ]] && trim_end_cmd="-to \"$formatted_end_time\"" | ||
|
||
# Prompt user before processing in interactive mode | ||
if [[ "$verbose" -eq 1 && "$batch_mode" -eq 0 ]]; then | ||
read -p "Proceed with trimming? (y/n) " choice | ||
echo # Move to a new line | ||
if [[ "$choice" != [Yy] ]]; then | ||
echo -e "${YELLOW}Skipping $input_file based on user choice.${NC}" | ||
return | ||
fi | ||
fi | ||
|
||
local temp_output_dir="$(dirname "$input_file")" | ||
if [[ $overwrite -eq 1 ]]; then | ||
local temp_output=$(mktemp "$temp_output_dir/ffmpeg.XXXXXX.$extension") | ||
local command="ffmpeg -hide_banner $trim_start_cmd -y -i \"$input_file\" $trim_end_cmd -c copy \"$temp_output\"" | ||
if eval $command && mv "$temp_output" "$input_file"; then | ||
echo -e "${GREEN}Successfully processed and overwritten $input_file${NC}\\n" | ||
else | ||
echo -e "${RED}Failed to process $input_file${NC}\\n" | ||
return | ||
fi | ||
else | ||
local command="ffmpeg -hide_banner $trim_start_cmd -y -i \"$input_file\" $trim_end_cmd -c copy \"$final_output\"" | ||
if eval $command; then | ||
echo -e "${GREEN}Successfully processed $input_file into $final_output${NC}\\n" | ||
else | ||
echo -e "${RED}Failed to process $input_file${NC}\\n" | ||
return | ||
fi | ||
fi | ||
} | ||
|
||
# Main processing loop | ||
main() { | ||
while true; do | ||
video_files=() | ||
if [[ -z "$single_input_file" && -z "$file_list" ]]; then | ||
prompt_for_input | ||
elif [[ -n "$single_input_file" ]]; then | ||
video_files+=("$single_input_file") | ||
elif [[ -n "$file_list" && -f "$file_list" ]]; then | ||
mapfile -t video_files < "$file_list" | ||
else | ||
echo -e "${RED}Error: No input video or file list provided, or file does not exist.${NC}" | ||
usage | ||
fi | ||
|
||
for input_file in "${video_files[@]}"; do | ||
if [[ ! -f "$input_file" ]]; then | ||
echo -e "${RED}Error: The file $input_file does not exist.${NC}" | ||
continue | ||
fi | ||
process_video "$input_file" | ||
# In interactive mode, prompt user to continue | ||
if [[ "$batch_mode" -eq 0 ]]; then | ||
read -p "Press Enter to continue..." | ||
clear | ||
fi | ||
done | ||
single_input_file="" # Reset single_input_file for next iteration | ||
# If in batch mode, exit after processing all files | ||
if [[ "$batch_mode" -eq 1 ]]; then | ||
break | ||
fi | ||
done | ||
|
||
echo -e "${GREEN}Processing completed.${NC}" | ||
} | ||
|
||
main |