Advertisement
MaxDjently

Ziggle Wump Media Compressor Testing 0.2-beta.10.07.2024

Oct 7th, 2024
194
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 41.81 KB | Source Code | 0 0
  1. #!/data/data/com.termux/files/usr/bin/bash
  2.  
  3. # ATTENTION:
  4.  
  5. # Copying and pasting the script can introduce formatting that is improper to bash.
  6. # If the script doesn't run, you may need to use the dos2unix command to fix it.
  7. # Example: dos2unix ziggle_wump.sh
  8.  
  9. # --------------------
  10. #     Licence
  11. # --------------------
  12.  
  13. # This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
  14.  
  15. # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  16. # You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
  17.  
  18. # -----------------
  19. #     About
  20. # -----------------
  21.  
  22. # This script is for Termux on Android and is not associated with the apps it uses.
  23.  
  24. # Copyright Joshua Hansen and contributors: Microsoft Co-Pilot, OpenAI ChatGPT and Google Gemini.
  25.  
  26. # Shout out to Webernets https://youtu.be/0aeCfDKLfbs?si=58y58eWSiXurcHpj who gave me the inspiration for this, the one who did the heavy lifting figuring out the command line options. And this video helping me figure out how to do it in Handbrake, but I needed it all in a one-line command line option and this was it, I had to write it myself.
  27.  
  28. # The hub for Ziggle Wump Media Compressor is on the r/termux Subreddit,
  29.  
  30. # https://www.reddit.com/r/termux/comments/1eqrvdj/reintroducing_ziggle_wump_the_simple_ffmpeg/
  31.  
  32. # The nightlies are on Pastebin,
  33.  
  34. # https://pastebin.com/u/MaxDjently/1/KW1gv2RJ
  35.  
  36. # the testing version  is on archive.org along with sample videos created with it,
  37.  
  38. # https://archive.org/details/ziggle_wump
  39.  
  40. # and watch demonstration videos on YouTube.
  41.  
  42. # https://youtube.com/playlist?list=PL01x3JnisDqojbe8z-DHcN1YBtkOg7uFJ&si=9mNBkHDs1tQxN6Tv
  43.  
  44. # -----------------------
  45. #   Instructions
  46. # -----------------------
  47.  
  48. instructions="Ziggle Wump: The Simple FFmpeg Command Line Companion Script for Termux on Android
  49.  
  50. Disclaimer
  51.  
  52. * This script does not allow conversion of encrypted files, typically indicating copyrighted material.
  53.  
  54. * The script itself does not violate copyright, but user actions might. The script cannot prevent users from circumventing copyright protection, nor is it the script's responsibility to do so. The onus lies with the copyright holder to encrypt their media.
  55.  
  56. * It is not recommended to use the script to violate copyright law. US copyright law allows for spaceshifting and fair use of copyrighted material.
  57.  
  58. Note
  59.  
  60. * Some phones, like the Galaxy S24, have battery-saving features that can impact encoding. Ensure Termux is in focus (full screen or split-screen) while encoding, and keep the screen on during the process.
  61.  
  62. * For more information and potential fixes for specific phones, visit https://dontkillmyapp.com/.
  63.  
  64. Getting Started
  65.  
  66. * Download or Copy: Download or copy this script to a file and rename it if desired (e.g., ziggle_wump.sh). Placing it in your Movies folder makes it easily accessible on both Android and Termux, although you can also put it in /data/data/com.termux/files/usr/bin to use it system-wide.
  67.  
  68. * Install Termux and Termux:Widget (Optional): Grab Termux from F-Droid if you haven't already. Termux:Widget is optional for a more user-friendly interface.
  69.  
  70. * Obtain Storage Access: Run termux-setup-storage and allow access.
  71.  
  72. * Run the Script: Execute the script using bash ./ziggle_wump.sh [options]. (FIRST TIME RUN: Use bash ./ziggle_wump.sh -d to install dependencies.)
  73.  
  74. Termux:Widget (Optional):
  75.  
  76. * Install Termux:Widget and grant it permissions.
  77.  
  78. * Place the widget on your Home Screen.
  79.  
  80. * Run bash ziggle_wump.sh -i to install the script to /data/data/com.termux/files/usr/bin and create a widget in $HOME/.shortcuts.
  81.  
  82. * Reload the Widget to see 'Ziggle Wump Media Compressor.sh.'
  83.  
  84. * Place your media files in The VideoDrop directory in /storage/emulated/0/Movies or whichever directory you use for the \$video_drop_dir variable.
  85.  
  86. Options:
  87.  
  88. * -r resolution: Sets a custom resolution height while preserving aspect ratio for both videos and images (e.g., bash ziggle_wump.sh -r 720).
  89.  
  90. * -d: Checks and upgrades dependencies.
  91.  
  92. * -y: Automatically confirms prompts.
  93.  
  94. * -o output_fps: Sets a custom output video frames per second. (e.g., bash ziggle_wump.sh -o 60).
  95.  
  96. * -b max_video_bitrate: Sets a custom maximum video bitrate in kilobits per second. (e.g., bash ziggle_wump.sh -b 2000).
  97.  
  98. * -a avg_audio_bitrate: Sets a custom average audio bitrate in kilobits per second for both videos and audio files. (e.g., bash ziggle_wump.sh -a 128).
  99.  
  100. * -p preset: Sets encoding speed preset for videos. (0=slowest, 8=fastest) (e.g., bash ziggle_wump.sh -p 4).
  101.  
  102. * -P video_encoding_profile: Sets the profile found in profiles.conf
  103.  
  104. * -L: Lists all profiles found in profiles.conf
  105.  
  106. * -i: Installs the script to /data/data/com.termux/files/usr/bin/zwmc. Installs widget to ~/.shortcuts.
  107.  
  108. * -u: Uninstalls the script from /data/data/com.termux/files/usr/bin/zwmc. Removes widget.
  109.  
  110. * -m: Shows the menu for setting options.
  111.  
  112. * -h, --help: Displays help message."
  113.  
  114. # -----------------------------
  115. #        Variables
  116. # -----------------------------
  117.  
  118. # Supported File Types
  119. video_ext="mp4 mkv avi mov flv wmv webm mts 3gp mpeg ogv rmvb m4v f4v vob ts m2ts asf swf m2v divx xvid mpg mpe m1v dvr-ms mxf gxf bink mng nsv"
  120. audio_ext="mp3 aac wav flac ogg m4a wma ac3 eac3 opus amr aiff alac caf dts mka mp2 ra tta voc"
  121. img_ext="jpg jpeg png bmp tiff gif webp heic heif jxl ppm pgm pbm pam tga sgi pcx ras xbm xpm ico dds exr hdr svg"
  122.  
  123. # Define an array named 'profiles' containing various video encoding profiles
  124. profiles=(
  125.     # Profile format: "Profile_Name Height Frame_Rate Video_Bit_Rate Audio_Bit_Rate CRF Preset"
  126.  
  127.     "2_hour_CD 600 24 600 64 20 2"
  128.     "2_hour_DVD 1200 24 3500 128 18 2"
  129.     "2_hour_DL_DVD 1440 24 7000 192 18 2"
  130.     "4_hour_CD 480 24 250 64 25 2"
  131.     "4_hour_DVD 900 24 1750 96 23 2"
  132.     "4_hour_DL_DVD 1080 24 3500 128 23 2"
  133.     "6_hour_CD 360 24 140 64 28 4"
  134.     "6_hour_DVD 720 24 850 64 28 4"
  135.     "6_hour_DL_DVD 900 24 1700 96 28 4"
  136.     "8_hour_DVD 600 24 700 64 26 4"
  137.     "8_hour_DL_DVD 720 24 1400 96 26 4"
  138.     "12_hour_DVD 480 24 470 64 27 4"
  139.     "12_hour_DL_DVD 600 24 940 96 27 4"
  140.     "16_hour_DVD 360 20 350 64 28 4"
  141.     "16_hour_DL_DVD 480 20 700 64 28 4"
  142.     "24_hour_DVD 240 15 235 64 28 4"
  143.     "24_hour_DL_DVD 360 15 470 64 28 4"
  144.     "2160p_Video 2160 60 10000 256 18 2"
  145.     "1440p_Video 1440 60 6000 192 20 2"
  146.     "1080p_Video 1080 60 4000 128 23 3"
  147.     "900p_Video 900 60 3000 128 24 3"
  148.     "720p_Video 720 30 2500 96 24 3"
  149.     "600p_Video 600 30 2000 96 25 3"
  150.     "480p_Video 480 30 1500 64 26 3"
  151.     "360p_Video 360 30 1000 64 28 3"
  152.     "240p_Video 240 30 500 48 30 4"
  153.     "160p_Video 160 30 300 48 32 5"
  154.     "10Mbps_Streaming 2160 60 9500 256 18 2"
  155.     "5Mbps_Streaming 1440 60 4800 192 20 2"
  156.     "3Mbps_Streaming 1080 60 2700 128 24 3"
  157.     "1.5Mbps_Streaming 720 30 1300 96 24 3"
  158.     "1Mbps_Streaming 480 30 900 64 26 3"
  159.     "500kbps_Streaming 360 15 400 48 30 3"
  160.     "128kbps_Streaming 240 15 110 32 32 5"
  161.     "56kbps_Streaming 128 12 30 16 34 5"
  162.     "90s_game_console 240 15 200 48 30 4"
  163.     "Cinema_Quality 2160 24 7000 192 18 2"
  164.     "Desktop_High-End 2160 60 10000 256 20 2"
  165.     "Desktop_Low-End 1080 30 1500 96 24 3"
  166.     "Desktop_Mid-Range 1440 60 3500 128 22 2"
  167.     "DVD_Quality 480 24 1000 64 28 3"
  168.     "Low_Bandwidth_Stream 270 15 100 48 32 5"
  169.     "Low_Res_Mobile 360 24 300 48 28 4"
  170.     "Mobile_High-End 1080 60 1500 96 24 3"
  171.     "Mobile_Low_End 360 15 150 48 32 5"
  172.     "Mobile_Mid-Range 720 30 800 64 26 3"
  173.     "Modern_Laptop 1080 60 1500 96 24 3"
  174.     "Old_Smartphone 360 24 300 64 28 4"
  175.     "Retro_Computer_16-bit 320 30 150 32 32 5"
  176.     "Retro_Computer_8-bit 240 15 100 32 32 5"
  177.     "Retro_PC 480 15 200 64 30 4"
  178.     "Tablet_Profile 720 30 800 64 26 3"
  179.     "VHS_Quality 240 30 250 64 30 4"
  180. )
  181. default_profile="2_hour_CD"
  182.  
  183. # Define an array of presets from slowest to fastest
  184. presets=("veryslow" "slower" "slow" "medium" "fast" "faster" "veryfast" "superfast" "ultrafast")
  185. preset=slow # Default Speed Preset
  186. profile="" # custom Ziggle Wump profile.
  187.  
  188. # Full Log file path
  189. log_file="/storage/emulated/0/Movies/VideoDrop/convert.log"
  190.  
  191. # Full directory paths
  192. video_drop_dir="/storage/emulated/0/Movies/VideoDrop"
  193. video_processing_dir="/storage/emulated/0/Movies/VideoProcessing"
  194. output_dir_base="/storage/emulated/0/Movies/VideoConverted"
  195.  
  196. # combine audio and video extension variables to pass to find command.
  197. filetypes=""
  198. for ext in $audio_ext $video_ext $img_ext; do
  199.     filetypes="$filetypes -iname '*.$ext' -o"
  200. done
  201. # Remove the trailing ' -o'
  202. filetypes="${filetypes% -o}"
  203.  
  204. # Define a lock file
  205. LOCKFILE="/data/data/com.termux/files/usr/var/lock/zwmc.lock"
  206. LOCKDIR=$(dirname "$LOCKFILE")
  207.  
  208. # Ensure the lock directory exists
  209. mkdir -p "$LOCKDIR"
  210.  
  211. # Cleanup function to remove the lock file
  212. cleanup() {
  213.     rm -f "$LOCKFILE"
  214. }
  215.  
  216. # Set the trap to call cleanup on script exit
  217. trap cleanup EXIT
  218.  
  219. # Try to acquire the lock
  220. exec 200>"$LOCKFILE"
  221. flock -n 200 || { echo "Script is already running"; exit 1; }
  222.  
  223. # The lock file will be removed when the script exits, thanks to the trap
  224.  
  225. # --------------------------------------------------
  226. #    Setting up files and folders
  227. # --------------------------------------------------
  228.  
  229. width=$(tput cols)
  230.  
  231. # Create necessary directories if they don't exist
  232. mkdir -p "$video_drop_dir" "$video_processing_dir" "$output_dir_base"
  233.  
  234. # Check if log file exists
  235. if [ -f "$log_file" ]; then
  236.     echo "Old log file found.  Deleting..."
  237.     rm "$log_file"
  238.     echo "File deleted."
  239. else
  240.     echo "Log File does not exist.  The script will create $log_file"
  241. fi
  242.  
  243. echo "Generating profiles.conf in $video_drop_dir..." | tee -a "$log_file"
  244.  
  245. # Define the instructions for profiles.conf
  246. profile_instructions="# This file contains various video encoding profiles. Each profile specifies the resolution (Lowest between input and user specified resolution), frame rate (Lowest between input and user specified FPS), maximum video bitrate (Target bitrate for x265, high quality videos may exceed this value, try using a higher CRF), average audio bitrate (Target bitrate for Opus, high quality audio may exceed this value, use a lower bitrate), Constant Rate Factor/CRF (0=highest quality/file size, 51=Lowest quality/file size), and preset for encoding (0=slowest/higher quality 8=fastest/lower quality). These profiles are configured for x265 video codec and Opus audio codec. You can modify these profiles, or add your own as needed for your specific use case."
  247.  
  248. # Function to check if the first line matches the instructions
  249. instructions_match() {
  250.     local first_line
  251.     first_line=$(head -n 1 "$video_drop_dir/profiles.conf")
  252.     [[ "$first_line" == "$profile_instructions" ]]
  253. }
  254.  
  255. # Check if profiles.conf exists, if not, create it
  256. if [ ! -f "$video_drop_dir/profiles.conf" ]; then
  257.     echo "$profile_instructions" > "$video_drop_dir/profiles.conf"
  258.     echo "" >> "$video_drop_dir/profiles.conf"
  259. else
  260.     # Update instructions only if the first line doesn't match
  261.     if ! instructions_match; then
  262.         # Remove the existing instructions block
  263.         sed -i '/^# /,/^$/d' "$video_drop_dir/profiles.conf"
  264.         # Insert new instructions at the top
  265.         sed -i "1i $profile_instructions\n" "$video_drop_dir/profiles.conf"
  266.     fi
  267. fi
  268.  
  269. # Function to check if a profile exists
  270. profile_exists() {
  271.     local profile_name=$1
  272.     grep -q "^\[$profile_name\]" "$video_drop_dir/profiles.conf"
  273. }
  274.  
  275. # Add profiles if they don't exist
  276. for profile in "${profiles[@]}"; do
  277.     IFS=' ' read -r -a profile_params <<< "$profile"
  278.     profile_name=${profile_params[0]}
  279.    
  280.     if ! profile_exists "$profile_name"; then
  281.         echo "[${profile_name}]" >> "$video_drop_dir/profiles.conf"
  282.         echo "resolution=${profile_params[1]}" >> "$video_drop_dir/profiles.conf"
  283.         echo "frame_rate=${profile_params[2]}" >> "$video_drop_dir/profiles.conf"
  284.         echo "video_bitrate=${profile_params[3]}" >> "$video_drop_dir/profiles.conf"
  285.         echo "audio_bitrate=${profile_params[4]}" >> "$video_drop_dir/profiles.conf"
  286.         echo "crf=${profile_params[5]}" >> "$video_drop_dir/profiles.conf"
  287.         echo "preset=${profile_params[6]}" >> "$video_drop_dir/profiles.conf"
  288.         echo "" >> "$video_drop_dir/profiles.conf"
  289.     fi
  290. done
  291.  
  292. # Function to read profile from profiles.conf
  293. read_profile() {
  294.     local profile_name=$1
  295.     resolution=$(awk -F "=" "/^\[$profile_name\]/ {a=1} a==1 && \$1~/resolution/ {print \$2; exit}" $video_drop_dir/profiles.conf)
  296.     output_fps=$(awk -F "=" "/^\[$profile_name\]/ {a=1} a==1 && \$1~/frame_rate/ {print \$2; exit}" $video_drop_dir/profiles.conf)
  297.     max_video_bitrate=$(awk -F "=" "/^\[$profile_name\]/ {a=1} a==1 && \$1~/video_bitrate/ {print \$2; exit}" $video_drop_dir/profiles.conf)
  298.     avg_audio_bitrate=$(awk -F "=" "/^\[$profile_name\]/ {a=1} a==1 && \$1~/audio_bitrate/ {print \$2; exit}" $video_drop_dir/profiles.conf)
  299.     crf=$(awk -F "=" "/^\[$profile_name\]/ {a=1} a==1 && \$1~/crf/ {print \$2; exit}" $video_drop_dir/profiles.conf)
  300.     preset=$(awk -F "=" "/^\[$profile_name\]/ {a=1} a==1 && \$1~/preset/ {print \$2; exit}" $video_drop_dir/profiles.conf)
  301.     preset=${presets[$preset]}
  302. }
  303.  
  304. # Function to list profiles from profiles.conf
  305. list_profiles() {
  306.     awk -F "=" '/^\[.*\]/ {gsub(/[\[\]]/, "", $1); print $1}' $video_drop_dir/profiles.conf
  307. }
  308.  
  309. # --------------------------------
  310. #     Command Flags
  311. # --------------------------------
  312.  
  313. read_profile "$default_profile"
  314.  
  315. show_menu() {
  316.     auto_yes=true  # Turn on auto_yes when the menu is shown
  317.     while true; do
  318.         deps_status="Off"
  319.         if [ "$check_deps" = true ]; then
  320.             deps_status="On"
  321.         fi
  322.  
  323.         menu_choice=$(dialog --menu "Ziggle Wump Media Compressor Chooser" 17 50 11 \
  324.             1 "Set Max Resolution ($resolution)" \
  325.             2 "Set Max Output FPS ($output_fps)" \
  326.             3 "Set Max Video Bitrate ($max_video_bitrate)" \
  327.             4 "Set Average Audio Bitrate ($avg_audio_bitrate)" \
  328.             5 "Set Constant Rate Factor ($crf)" \
  329.             6 "Set Encoding Speed ($preset)" \
  330.             7 "Check Dependencies ($deps_status)" \
  331.             8 "Install Script" \
  332.             9 "Uninstall Script" \
  333.             10 "Set Conversion Profile" \
  334.             11 "Compress Files in $(basename $video_drop_dir)" 2>&1 >/dev/tty)
  335.  
  336.         case $menu_choice in
  337.             1)
  338.                 new_resolution=$(dialog --inputbox "Enter resolution maximum height in pixels ($resolution):" 8 40 "$resolution" 2>&1 >/dev/tty)
  339.                 if [ $? -eq 0 ]; then
  340.                     resolution="$new_resolution"
  341.                 fi
  342.                 ;;
  343.             2)
  344.                 new_output_fps=$(dialog --inputbox "Enter maximum output FPS ($output_fps):" 8 40 "$output_fps" 2>&1 >/dev/tty)
  345.                 if [ $? -eq 0 ]; then
  346.                     output_fps="$new_output_fps"
  347.                 fi
  348.                 ;;
  349.             3)
  350.                 new_max_video_bitrate=$(dialog --inputbox "Enter maximum video bitrate ($max_video_bitrate):" 8 40 "$max_video_bitrate" 2>&1 >/dev/tty)
  351.                 if [ $? -eq 0 ]; then
  352.                     max_video_bitrate="$new_max_video_bitrate"
  353.                 fi
  354.                 ;;
  355.             4)
  356.                 new_avg_audio_bitrate=$(dialog --inputbox "Enter average audio bitrate ($avg_audio_bitrate):" 8 40 "$avg_audio_bitrate" 2>&1 >/dev/tty)
  357.                 if [ $? -eq 0 ]; then
  358.                     avg_audio_bitrate="$new_avg_audio_bitrate"
  359.                 fi
  360.                 ;;
  361.             5)
  362.                 dialog --msgbox "CRF (Constant Rate Factor) is a quality setting for video encoding. It ranges from 0 (lossless) to 51 (worst quality). Lower values mean better quality and larger files, while higher values mean lower quality and smaller files." 10 50
  363.                 new_crf=$(dialog --inputbox "Enter CRF value (0-51) ($crf):" 8 40 "$crf" 2>&1 >/dev/tty)
  364.                 if [ $? -eq 0 ]; then
  365.                     echo "User entered CRF: $new_crf" >&2  # Debug message
  366.                     if [ "$new_crf" -ge 0 ] && [ "$new_crf" -le 51 ]; then
  367.                         crf="$new_crf"
  368.                         echo "CRF set to: $crf" >&2  # Debug message
  369.                     else
  370.                         dialog --msgbox "Invalid CRF value. Please enter a value between 0 and 51." 6 40
  371.                         echo "Invalid CRF value entered: $new_crf" >&2  # Debug message
  372.                     fi
  373.                 fi
  374.                 ;;
  375.             6)
  376.                 dialog --msgbox "Choose an x265 speed preset. The preset determines the encoding speed and compression efficiency. Choose a preset that best fits your needs. Slower presets will provide better compression and quality but take longer to encode." 10 50
  377.  
  378.                 # Your original preset selection dialog
  379.                 new_preset=$(dialog --menu "Choose x265 Speed Preset" 15 50 9 \
  380.                     ultrafast "8" \
  381.                     superfast "7" \
  382.                     veryfast "6" \
  383.                     faster "5" \
  384.                     fast "4" \
  385.                     medium "3" \
  386.                     slow "2" \
  387.                     slower "1" \
  388.                     veryslow "0" 2>&1 >/dev/tty)
  389.  
  390.                 # Check if a new preset was selected
  391.                 if [ $? -eq 0 ]; then
  392.                     preset=$new_preset
  393.                 fi
  394.                 ;;
  395.             7)
  396.                 while true; do
  397.                     if [ "$check_deps" = true ]; then
  398.                         check_deps=false
  399.                     else
  400.                         check_deps=true
  401.                     fi
  402.                     deps_status="Off"
  403.                     if [ "$check_deps" = true ]; then
  404.                         deps_status="On"
  405.                     fi
  406.                     dialog --msgbox "Dependencies are now $deps_status" 6 40
  407.                     break
  408.                 done
  409.                 ;;
  410.             8)
  411.                 clear
  412.                 install_script
  413.                 ;;
  414.             9)
  415.                 clear
  416.                 uninstall_script
  417.                 ;;
  418.             10)
  419.                 profile_list=$(list_profiles)
  420.                 selected_profile=$(dialog --menu "Choose Profile" 15 50 9 $(echo "$profile_list" | awk '{print NR, $0}') 2>&1 >/dev/tty)
  421.                 if [ $? -eq 0 ]; then
  422.                     read_profile "$(echo "$profile_list" | sed -n "${selected_profile}p")"
  423.                 fi
  424.                 ;;
  425.             11)
  426.                 break
  427.                 ;;
  428.             *)
  429.                 tput sgr0  # Reset terminal colors
  430.                 clear
  431.                 exit 0
  432.                 ;;
  433.         esac
  434.     done
  435. }
  436.  
  437. # Function to display help message
  438. show_help() {
  439.     width=$(tput cols)
  440.     script_name=$(basename "$0")
  441.     echo "Place your media files in $video_drop_dir." | tee -a "$log_file" | fmt -w $width
  442.     echo "Usage: bash $script_name [-r resolution] [-d] [-y] [-o output_fps] [-b max_video_bitrate] [-a avg_audio_bitrate] [-p preset] [-i] [-u] [-m] [-P] [-L] [-h|--help]" | fmt -w $width
  443.     echo "  -r resolution ex. bash $script_name -r 720 Custom resolution height preserving aspect ratio" | fmt -w $width
  444.     echo "  -d Check and upgrade dependencies." | fmt -w $width
  445.     echo "  -y Automatically say yes to prompts." | fmt -w $width
  446.     echo "  -o output_fps Set custom output FPS. ex. bash $script_name -o 60" | fmt -w $width
  447.     echo "  -b max_video_bitrate Set custom max video bitrate in kilobits per second. ex. bash $script_name -b 2000" | fmt -w $width
  448.     echo "  -a avg_audio_bitrate Set custom average audio bitrate in kilobits per second. ex. bash $script_name -a 128" | fmt -w $width
  449.     echo "  -p preset Set encoding speed preset for x265 (0=slowest, 8=fastest). ex. bash $script_name -p 4" | fmt -w $width
  450.     echo "  -i Install the script to /data/data/com.termux/files/usr/bin/zwmc" | fmt -w $width
  451.     echo "  -u Uninstall the script from /data/data/com.termux/files/usr/bin/zwmc" | fmt -w $width
  452.     echo "  -m Shows the menu for setting options." | fmt -w $width
  453.     echo " -P video_encoding_profile Sets the profile found in profiles.conf" | fmt -w $width
  454.     echo " -L List encoding profiles."
  455.     echo "  -h, --help Display this help message" | fmt -w $width
  456.     exit 0
  457. }
  458.  
  459. # Install Ziggle Wump to /data/data/com.termux/files/usr/bin folder and widget script to ~/.shortcuts
  460. install_script() {
  461.     if [ -f /data/data/com.termux/files/usr/bin/zwmc ]; then
  462.         current_dir=$(dirname "$0")
  463.         if [ "$current_dir" != "/data/data/com.termux/files/usr/bin" ]; then
  464.             echo "Script is installed but not running from the bin directory. Reinstalling..." | tee -a "$log_file" | fmt -w $width
  465.             cp "$(readlink -f "$0")" /data/data/com.termux/files/usr/bin/zwmc
  466.             chmod +x /data/data/com.termux/files/usr/bin/zwmc
  467.             if whereis zwmc | grep -q "/data/data/com.termux/files/usr/bin/zwmc"; then
  468.                 echo "Script reinstalled to /data/data/com.termux/files/usr/bin/zwmc"
  469.             else
  470.                 echo "Reinstallation failed" | tee -a "$log_file" | fmt -w $width
  471.             fi
  472.         else
  473.             echo "Script is already installed and running from the bin directory." | tee -a "$log_file" | fmt -w $width
  474.         fi
  475.     else
  476.         cp "$(readlink -f "$0")" /data/data/com.termux/files/usr/bin/zwmc
  477.         chmod +x /data/data/com.termux/files/usr/bin/zwmc
  478.         if whereis zwmc | grep -q "/data/data/com.termux/files/usr/bin/zwmc"; then
  479.             echo "Script installed to /data/data/com.termux/files/usr/bin/zwmc" | tee -a "$log_file" | fmt -w $width
  480.         else
  481.             echo "Installation failed" | tee -a "$log_file" | fmt -w $width
  482.         fi
  483.     fi
  484.  
  485.     # Create the shortcut script
  486.     mkdir -p $HOME/.shortcuts
  487.     echo '#!/data/data/com.termux/files/usr/bin/bash' > $HOME/.shortcuts/Ziggle\ Wump\ Media\ Compressor.sh
  488.     echo 'zwmc -m' >> $HOME/.shortcuts/Ziggle\ Wump\ Media\ Compressor.sh
  489.     echo 'read -p "Press Enter to continue.  Bye!"' >> $HOME/.shortcuts/Ziggle\ Wump\ Media\ Compressor.sh
  490.     echo 'case $return in' >> $HOME/.shortcuts/Ziggle\ Wump\ Media\ Compressor.sh
  491.     echo '    * ) echo "Exiting script."' >> $HOME/.shortcuts/Ziggle\ Wump\ Media\ Compressor.sh
  492.     echo 'esac' >> $HOME/.shortcuts/Ziggle\ Wump\ Media\ Compressor.sh
  493.     chmod +x $HOME/.shortcuts/Ziggle\ Wump\ Media\ Compressor.sh
  494.  
  495.     exit 0
  496. }
  497.  
  498. uninstall_script() {
  499.     if [ ! -f /data/data/com.termux/files/usr/bin/zwmc ]; then
  500.         echo "Script is not installed." | tee -a "$log_file" | fmt -w $width
  501.         exit 0
  502.     else
  503.         rm -f /data/data/com.termux/files/usr/bin/zwmc
  504.         if ! whereis zwmc | grep -q "/data/data/com.termux/files/usr/bin/zwmc"; then
  505.             echo "Script uninstalled from /data/data/com.termux/files/usr/bin/zwmc" | tee -a "$log_file" | fmt -w $width
  506.         else
  507.             echo "Uninstallation failed" | tee -a "$log_file" | fmt -w $width
  508.         fi
  509.     fi
  510.  
  511.     # Remove the shortcut script
  512.     rm -f $HOME/.shortcuts/Ziggle\ Wump\ Media\ Compressor.sh
  513.  
  514.     exit 0
  515. }
  516.  
  517. # Parse command-line options
  518. check_deps=false
  519. auto_yes=false  # Set auto_yes to false by default
  520. while getopts "r:dyho:b:a:c:iump:P:L" opt; do
  521.     case $opt in
  522.         r) resolution="$OPTARG" ;;  # Set custom resolution by height
  523.         d) check_deps=true ;;  # Check and upgrade dependencies
  524.         y) auto_yes=true ;;  # Automatically say yes to prompts
  525.         o) output_fps="$OPTARG" ;;  # Set custom output FPS
  526.         b) max_video_bitrate="$OPTARG" ;;  # Set custom max video bitrate
  527.         a) avg_audio_bitrate="$OPTARG" ;;  # Set custom average audio bitrate
  528.         c) crf="$OPTARG" ;;  # Set custom CRF value
  529.         i) install_script ;;  # Install the script
  530.         u) uninstall_script ;;  # Uninstall the script
  531.         m) auto_yes=true; show_menu ;;  # Show menu and turn on auto_yes
  532.         p) preset="${presets[$OPTARG]}" ;;  # Set preset based on number 0-8
  533.         P) profile="$OPTARG"; read_profile "$profile" ;;
  534.         L) list_profiles # List encoding profiles.
  535.         exit 0 ;;
  536.         h) show_help ;;  # Display help
  537.         *) show_help ;;  # Display help for invalid options
  538.     esac
  539. done
  540.  
  541. shift $((OPTIND -1))
  542.  
  543. # ------------------------------
  544. #     Dependencies
  545. # ------------------------------
  546.  
  547. if $check_deps; then
  548.     echo "Checking and upgrading dependencies, please wait..."
  549.     pkg update && pkg upgrade -y
  550.     if ! command -v bc &> /dev/null; then
  551.         pkg install bc -y
  552.     fi
  553.     if ! command -v ffmpeg &> /dev/null; then
  554.         pkg install ffmpeg -y
  555.     fi
  556.     if ! command -v ncurses-utils &> /dev/null; then
  557.         pkg install ncurses-utils -y
  558.     fi
  559.     echo "Update complete."
  560. fi
  561.  
  562. # ------------------------
  563. #     Start script
  564. # ------------------------
  565.  
  566. echo ""
  567. echo "$instructions" | tee -a "$log_file" | fmt -w $width
  568.  
  569. echo "Running... Press Ctrl+C to stop."
  570.  
  571. echo ""
  572. # Function to prompt the user to continue or quit
  573. prompt_continue_or_quit() {
  574.     while true; do
  575.         # Recursively find and process videos and audio
  576.         video_count=$(eval "find \"$video_drop_dir\" -type f \( $filetypes \) | wc -l")
  577.         echo "Detected $video_count compatible video and/or audio file(s) in:" | tee -a "$log_file" | fmt -w $width
  578.    
  579.         if [ "$video_count"  -eq 0 ]; then
  580.             echo "$video_drop_dir folder created. Place your videos and audio here including files in folders using your favorite file manager for Android, and then run  the script again.  
  581.  
  582. Supported File Types:
  583.  
  584. Video: $video_ext
  585.  
  586. Audio: $audio_ext
  587.  
  588. Images: $img_ext" | tee -a "$log_file" | fmt -w $width
  589.             exit 0
  590.         fi
  591.  
  592.         # Prompt text
  593.         prompt_text="$video_drop_dir. You can start encoding now. Do you wish to proceed? (Y/N): "
  594.  
  595.         # Format the prompt text
  596.         formatted_prompt=$(echo "$prompt_text" | fmt -w $width)
  597.  
  598.         if $auto_yes; then
  599.             echo "$formatted_prompt"
  600.             echo "Y"
  601.             return 0  # Automatically continue
  602.         else
  603.             # Read user input with formatted prompt
  604.             read -p "$formatted_prompt" yn
  605.             case $yn in
  606.                 [Yy]* ) return 0;;  # Continue
  607.                 [Nn]* ) echo "Exiting script."; exit 0;;  # Quit
  608.                 * ) echo "Please answer Y or N.";;
  609.             esac
  610.         fi
  611.     done
  612. }
  613.  
  614. # Function to clean up file names
  615. clean_file_names() {
  616.     eval "find \"$video_drop_dir\" -type f \( $filetypes \)" | while read -r file; do
  617.         dir=$(dirname "$file")
  618.         base=$(basename "$file")
  619.         new_base=$(echo "$base" | sed 's/[^a-zA-Z0-9 ._-]//g' | tr -s ' ')
  620.         new_file="$dir/$new_base"
  621.         if [ "$file" != "$new_file" ]; then
  622.             mv "$file" "$new_file"
  623.         fi
  624.     done
  625. }
  626.  
  627. # Clean up file names before processing
  628. clean_file_names
  629.  
  630. # Prompt the user to continue or quit?
  631. prompt_continue_or_quit
  632.  
  633. # Initialize ffmpeg_custom_options
  634. ffmpeg_custom_options="-c:v libx265 -x265-params \"deblock=-1:no-sao=1:keyint=250:aq-mode=3:psy-r=0.75:psy-rdoq=2.0:rd=4:rdoq-level=1:rect=0:strong-intra-smoothing=0\" -crf $crf -preset $preset -c:a libopus -vbr on -ac 2 -af \"loudnorm=I=-23:LRA=7:TP=-2\""
  635.  
  636. # Add avg audio bitrate if avg_audio_bitrate is set
  637. if [ -n "$avg_audio_bitrate" ]; then
  638.     ffmpeg_custom_options="$ffmpeg_custom_options -b:a ${avg_audio_bitrate}k"
  639. fi
  640.  
  641. # Add maxrate and bufsize options if max_video_bitrate is set
  642. if [ -n "$max_video_bitrate" ]; then
  643.     ffmpeg_custom_options="$ffmpeg_custom_options -maxrate ${max_video_bitrate}k -bufsize 60M"
  644. fi
  645.  
  646. # Function to check the log file for "Killed" message
  647. check_for_killed_message() {
  648.     if grep -q " Killed     " "$log_file"; then
  649.         echo "$(date '+%Y-%m-%d %H:%M:%S') Error: Process was killed. Check log file for details." | tee -a "$log_file"
  650.         return 1
  651.     fi
  652.     return 0
  653. }
  654.  
  655. echo "Starting conversion process..." | tee -a "$log_file"
  656.  
  657. # -----------------------------
  658. #    Image Encoder
  659. # -----------------------------
  660.  
  661. width=$(tput cols)
  662.  
  663. # Function to process image files
  664. process_image() {
  665.     local image="$1"
  666.     local relative_path="${image#$video_drop_dir/}"
  667.     local dir_path=$(dirname "$relative_path")
  668.     local base_name=$(basename "$relative_path" | tr -cd '[:alnum:]._ -')
  669.     local output_dir="$output_dir_base/$dir_path"
  670.     local output_file="$output_dir/${base_name}_converted.png"
  671.  
  672.     mkdir -p "$output_dir"  # Create output directory
  673.  
  674.     echo "$(date '+%Y-%m-%d %H:%M:%S') Processing $image to $output_file" | tee -a "$log_file"
  675.  
  676.     # Get input image resolution
  677.     input_resolution=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of csv=p=0 "$image" | tr -d '[:space:],')
  678.  
  679.     if [ -n "$resolution" ]; then
  680.         if [ "$input_resolution" -gt "$resolution" ]; then
  681.             scale_filter="scale=-2:$resolution:flags=lanczos"
  682.             echo "Input resolution ($input_resolution) is higher than user-defined resolution ($resolution). Using user-defined resolution." | tee -a "$log_file"
  683.     else
  684.             echo "Input resolution ($input_resolution) is lower or equal to user-defined resolution ($resolution). Keeping original resolution." | tee -a "$log_file"
  685.         fi
  686.     else
  687.         echo "Resolution set to: original" | tee -a "$log_file"
  688.     fi
  689.  
  690.     # Construct the FFmpeg command for image processing
  691.     ffmpeg_command="ffmpeg -nostdin -loglevel error -stats -y -i \"$image\" -compression_level 100 -vf \"$scale_filter\" \"$output_file\""
  692.  
  693.     echo "$ffmpeg_command" | tee -a "$log_file"
  694.  
  695.     # Execute the FFmpeg command
  696.     eval $ffmpeg_command 2>&1 | tee -a "$log_file"
  697.  
  698.     # Check for "Killed" message in the log file
  699.     if ! check_for_killed_message; then
  700.         echo "$(date '+%Y-%m-%d %H:%M:%S') Error: Process was killed. Exiting." | tee -a "$log_file"
  701.         exit 1
  702.     fi
  703.  
  704.     if [ $? -eq 0 ]; then
  705.       #  mv "$temp_output_file" "$output_file"  # Rename the temporary file to the final output file
  706.         mkdir -p "$video_processing_dir/$dir_path"  # Create processing directory
  707.         mv "$image" "$video_processing_dir/$relative_path"
  708.         echo ""
  709.         echo "$(date '+%Y-%m-%d %H:%M:%S') Converted $image. Your original files will be in the $video_processing_dir folder for comparison. Your new files are in $output_dir_base" | tee -a "$log_file" | fmt -w $width
  710.     else
  711.         echo ""
  712.         echo "$(date '+%Y-%m-%d %H:%M:%S') Error processing \"$image\". Check log file for details." | tee -a "$log_file"
  713.         exit 1
  714.     fi
  715. }
  716.  
  717. # -----------------------------
  718. #    Audio Encoder
  719. # -----------------------------
  720.  
  721. width=$(tput cols)
  722.  
  723. # Function to process audio files
  724. process_audio() {
  725.     local audio="$1"
  726.     local relative_path="${audio#$video_drop_dir/}"
  727.     local dir_path=$(dirname "$relative_path")
  728.     local base_name=$(basename "$relative_path" | tr -cd '[:alnum:]._ -')
  729.     local output_dir="$output_dir_base/$dir_path"
  730.     local output_file="$output_dir/${base_name}_converted.opus"
  731.     local temp_output_file="$output_file.tmp"
  732.  
  733.     mkdir -p "$output_dir"  # Create output directory
  734.  
  735.     echo "$(date '+%Y-%m-%d %H:%M:%S') Processing $audio to $output_file" | tee -a "$log_file"
  736.  
  737.     # Construct the FFmpeg command for audio processing
  738.     local ffmpeg_command="ffmpeg -nostdin -loglevel error -stats -stats_period 1 -y -i \"$audio\" -c:a libopus -b:a ${avg_audio_bitrate}k -vbr on -ac 2 -af \"loudnorm=I=-23:LRA=7:TP=-2\" -f opus \"$temp_output_file\""
  739.  
  740.     echo "$ffmpeg_command" | tee -a "$log_file"
  741.  
  742.     # Execute the FFmpeg command
  743.     eval $ffmpeg_command 2>&1 | tee -a "$log_file"
  744.  
  745.     # Check for "Killed" message in the log file
  746.     if ! check_for_killed_message; then
  747.         echo "$(date '+%Y-%m-%d %H:%M:%S') Error: Process was killed. Exiting." | tee -a "$log_file"
  748.         exit 1
  749.     fi
  750.  
  751.     if [ $? -eq 0 ]; then
  752.         mv "$temp_output_file" "$output_file"  # Rename the temporary file to the final output file
  753.         mkdir -p "$video_processing_dir/$dir_path"  # Create processing directory
  754.         mv "$audio" "$video_processing_dir/$relative_path"
  755.         echo ""
  756.         echo "$(date '+%Y-%m-%d %H:%M:%S') Converted $audio. Your original files will be in the $video_processing_dir folder for comparison. Your new files are in $output_dir_base" | tee -a "$log_file" | fmt -w $width
  757.     else
  758.         echo ""
  759.         echo "$(date '+%Y-%m-%d %H:%M:%S') Error processing \"$audio\". Check log file for details." | tee -a "$log_file"
  760.         exit 1
  761.     fi
  762. }
  763.  
  764. # ------------------------------
  765. #      Video Encoder
  766. # ------------------------------
  767.  
  768. width=$(tput cols)
  769.  
  770. # Function to check the log file for "Killed" message
  771. check_for_killed_message() {
  772.     if grep -q " Killed     " "$log_file"; then
  773.         echo "$(date '+%Y-%m-%d %H:%M:%S') Error: Process was killed. Check log file for details." | tee -a "$log_file" | fmt -w $width
  774.         exit 1
  775.     fi
  776. }
  777.  
  778. process_video() {
  779.     local video="$1"
  780.     local relative_path="${video#$video_drop_dir/}"
  781.     local dir_path=$(dirname "$relative_path")
  782.     local base_name=$(basename "$relative_path" | tr -cd '[:alnum:]._ -')
  783.     local output_dir="$output_dir_base/$dir_path"
  784.     local output_file="$output_dir/${base_name}_converted.mkv"
  785.  
  786.    
  787.     # Get input video resolution
  788.     input_resolution=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of csv=p=0 "$video" | tr -d '[:space:],')
  789.  
  790.     if [ -n "$resolution" ]; then
  791.         if [ "$input_resolution" -lt "$resolution" ]; then
  792.             local scale_filter="scale=-2:$input_resolution:flags=lanczos"
  793.             echo "Input resolution ($input_resolution) is lower than user-defined resolution ($resolution). Keeping original resolution." | tee -a "$log_file"
  794.         else
  795.             local scale_filter="scale=-2:$resolution:flags=lanczos"
  796.             echo "Input resolution ($input_resolution) is higher or equal to user-defined resolution ($resolution). Using user-defined resolution." | tee -a "$log_file"
  797.         fi
  798.     else
  799.         echo "Resolution set to: original" | tee -a "$log_file"
  800.     fi
  801.  
  802.     mkdir -p "$output_dir"  # Create output directory
  803.  
  804.     echo "$(date '+%Y-%m-%d %H:%M:%S') Processing $video to $output_file" | tee -a "$log_file"
  805.  
  806.     # Get the frame rate of the input video
  807.     input_fps=$(ffprobe -v error -select_streams v:0 -show_entries stream=avg_frame_rate,r_frame_rate -of csv=p=0 "$video" | awk -F'/' '{if ($2) print $1/$2; else print $1}' | bc -l)
  808.  
  809.     # Define common frame rates
  810.     common_fps=(23.976 24 25 29.97 30 50 59.94 60)
  811.  
  812.     # Function to find the nearest valid frame rate
  813.     nearest_fps() {
  814.         local fps=$1
  815.         local nearest=${common_fps[0]}
  816.         local min_diff=$(echo "scale=5; $fps - ${common_fps[0]}" | bc | awk '{print ($1 >= 0) ? $1 : -$1}')
  817.         for rate in "${common_fps[@]}"; do
  818.             local diff=$(echo "scale=5; $fps - $rate" | bc | awk '{print ($1 >= 0) ? $1 : -$1}')
  819.             if (( $(echo "$diff < $min_diff" | bc -l) )); then
  820.                 min_diff=$diff
  821.                 nearest=$rate
  822.             fi
  823.         done
  824.         echo $nearest
  825.     }
  826.  
  827.     # Round the frame rate to the nearest valid frame rate
  828.     rounded_fps=$(nearest_fps $input_fps)
  829.  
  830.     # Determine the lower frame rate
  831.     if (( $(echo "$rounded_fps > $output_fps" | bc -l) )); then
  832.         final_fps=$output_fps
  833.     else
  834.         final_fps=$rounded_fps
  835.     fi
  836.  
  837. # Set the initial video filter option
  838. video_filter_option="yadif=2,fps=$final_fps,noise=alls=10:allf=t+u"
  839.  
  840. # Check if scale_filter is not empty
  841. if [ -n "$scale_filter" ]; then
  842.     video_filter_option="${video_filter_option},${scale_filter}"
  843. fi
  844.  
  845. echo "Video filter option: $video_filter_option" | tee -a "$log_file"
  846.  
  847. # Detect the pixel format using ffprobe
  848. input_file="$video"
  849. pix_fmt=$(ffprobe -v repeat+level+error -select_streams v:0 -show_entries stream=pix_fmt -of default=noprint_wrappers=1:nokey=1 "$input_file" | awk 'NR==1{print $1}')
  850.  
  851. echo "Pixel format: $pix_fmt"
  852.  
  853. # Validate the pixel format
  854. valid_pix_fmt=$(ffmpeg -pix_fmts | grep -w "$pix_fmt")
  855.  
  856. # Check if 10-bit encoding is selected
  857. if [[ "$pix_fmt" == *"10le"* || "$pix_fmt" == *"10be"* ]]; then
  858.     video_filter_option="$video_filter_option,deband=1thr=0.01:2thr=0.01:3thr=0.01:4thr=0.01:range=4:direction=-3.14:blur=1:coupling=0"
  859. fi
  860.  
  861. # Define a variable for probe size and analyze duration
  862. probe_analyze_opts="-probesize 2147483647 -analyzeduration 2147483647"
  863.  
  864. # Detect subtitle codecs and convert unsupported ones
  865. subtitle_codecs=$(ffprobe -v error $probe_analyze_opts -select_streams s -show_entries stream=codec_name -of csv=p=0 "$input_file")
  866. subtitle_map=""
  867. if [ -n "$subtitle_codecs" ]; then
  868.     subtitle_map="-map 0:s"  # Include all subtitle streams
  869.     i=0
  870.     while read -r codec; do
  871.         case "$codec" in
  872.             # Text-based subtitles to be copied directly
  873.             srt)
  874.                 subtitle_map="$subtitle_map -c:s:$i copy"
  875.                 ;;
  876.             # Other text-based subtitles to be converted to SRT
  877.             ass|ssa|webvtt|eia_608|eia_708|scc|sami|ttml|smi|teletext|mov_text|microdvd|subviewer)
  878.                 subtitle_map="$subtitle_map -c:s:$i srt"
  879.                 ;;
  880.             # Bitmap-based subtitles to be converted to DVD subtitles
  881.             dvdsub|pgs|vobsub|hdmv_pgs_subtitle|dvd_subtitle)
  882.                 subtitle_map="$subtitle_map -c:s:$i dvdsub"
  883.                 ;;
  884.             # Copy other compatible subtitles
  885.             *)
  886.                 subtitle_map="$subtitle_map -c:s:$i copy"
  887.                 ;;
  888.         esac
  889.         i=$((i + 1))
  890.     done <<< "$subtitle_codecs"
  891. else
  892.     echo "No subtitle streams detected." | tee -a "$log_file"
  893. fi
  894.  
  895. # Combine common and custom FFmpeg options
  896. combined_ffmpeg_options="-nostdin -loglevel error -stats -stats_period 5 $probe_analyze_opts -y -fix_sub_duration -i \"$video\" -map 0:v:0 -map 0:a:? -map_chapters 0 $ffmpeg_custom_options"
  897.  
  898. # Construct the FFmpeg command
  899. local ffmpeg_command
  900. if [ -n "$valid_pix_fmt" ]; then
  901.     if [ -n "$subtitle_map" ]; then
  902.         ffmpeg_command="ffmpeg $combined_ffmpeg_options -vf \"$video_filter_option\" -pix_fmt $pix_fmt $subtitle_map"
  903.     else
  904.         ffmpeg_command="ffmpeg $combined_ffmpeg_options -vf \"$video_filter_option\" -pix_fmt $pix_fmt"
  905.     fi
  906. else
  907.     if [ -n "$subtitle_map" ]; then
  908.         ffmpeg_command="ffmpeg $combined_ffmpeg_options -vf \"$video_filter_option\" $subtitle_map"
  909.     else
  910.         ffmpeg_command="ffmpeg $combined_ffmpeg_options -vf \"$video_filter_option\""
  911.     fi
  912. fi
  913.  
  914. # Ensure all subtitle streams are marked as "default: off"
  915. subtitle_streams=$(ffprobe -v error $probe_analyze_opts -select_streams s -show_entries stream=index -of csv=p=0 "$input_file")
  916. if [ -n "$subtitle_streams" ]; then
  917.     for stream_index in $subtitle_streams; do
  918.         ffmpeg_command="$ffmpeg_command -disposition:s:$stream_index 0"
  919.     done
  920. fi
  921.  
  922. # Add the output file name at the end
  923. ffmpeg_command="$ffmpeg_command \"$output_file\""
  924.  
  925. echo "FFmpeg command: $ffmpeg_command" | tee -a "$log_file"
  926.  
  927. # Execute the FFmpeg command
  928. if ! eval $ffmpeg_command 2>&1 | tee -a "$log_file"; then
  929.     echo "FFmpeg command failed. Check the log for details." | tee -a "$log_file"
  930.     exit 1
  931. fi
  932.  
  933.     # Check for "Killed" message in the log file
  934.     check_for_killed_message
  935.  
  936.    if [ $? -eq 0 ]; then
  937.         mkdir -p "$video_processing_dir/$dir_path"  # Create processing directory
  938.         mv "$video" "$video_processing_dir/$relative_path"
  939.         echo ""
  940.         echo "$(date '+%Y-%m-%d %H:%M:%S') Complete.  Your original files are in $video_processing_dir.  Your new files are in $output_dir_base" | tee -a "$log_file" | fmt -w $width
  941.     else
  942.         echo ""
  943.         echo "$(date '+%Y-%m-%d %H:%M:%S') Error processing \"$video\". Check log file for details." | tee -a "$log_file"
  944.         exit 1
  945.     fi
  946. }
  947.  
  948. # --------------------------------------
  949. #    Start Batch Encoding
  950. # --------------------------------------
  951.  
  952. width=$(tput cols)
  953.  
  954. stop_processing=false
  955.  
  956. # Function to handle SIGINT (Ctrl+C)
  957. handle_sigint() {
  958.     echo ""
  959.     echo "Caught SIGINT (Ctrl+C). Exiting immediately." | fmt -w $width
  960.     stop_processing=true
  961.     exit 1  # Exit immediately without performing cleanup
  962. }
  963.  
  964. # Trap SIGINT and call the handle_sigint function
  965. trap handle_sigint SIGINT
  966.  
  967. # Process each file found
  968. eval "find \"$video_drop_dir\" -type f \( $filetypes \)" | while read -r file; do
  969.     if [ "$stop_processing" = true ]; then
  970.         echo "Stopping processing due to SIGINT."
  971.         exit 1
  972.     fi
  973.  
  974.     case "$file" in
  975.         *.mp3|*.aac|*.wav|*.flac|*.ogg|*.m4a|*.wma|*.ac3|*.eac3|*.opus|*.amr|*.aiff|*.alac|*.caf|*.dts|*.mka|*.mp2|*.ra|*.tta|*.voc)
  976.             process_audio "$file" || exit 1
  977.             ;;
  978.  
  979.         *.mp4|*.mkv|*.avi|*.mov|*.flv|*.wmv|*.webm|*.mts|*.3gp|*.mpeg|*.ogv|*.rmvb|*.m4v|*.f4v|*.vob|*.ts|*.m2ts|*.asf|*.swf|*.m2v|*.divx|*.xvid|*.mpg|*.mpe|*.m1v|*.dvr-ms|*.mxf|*.gxf|*.bink|*.mng|*.nsv)
  980.             process_video "$file" || exit 1
  981.             ;;
  982.  
  983.         *.jpg|*.jpeg|*.png|*.bmp|*.tiff|*.gif|*.webp|*.heic|*.heif|*.jxl|*.ppm|*.pgm|*.pbm|*.pam|*.tga|*.sgi|*.pcx|*.ras|*.xbm|*.xpm|*.ico|*.dds|*.exr|*.hdr|*.svg)
  984.             process_image "$file" || exit 1
  985.             ;;
  986.     esac
  987. done
  988.  
  989. # -----------------------------
  990. #     Finishing Up
  991. # -----------------------------
  992.  
  993. width=$(tput cols)
  994.  
  995. find "$video_drop_dir" -type d -empty -delete
  996. echo "removed empty folders in $video_drop_dir directory"
  997.  
  998. # final output message
  999. echo ""
  1000. echo "Log file is in $video_drop_dir.  There may be unprocessed media files or other incompatible files.  Some files may need to be remuxed for compatibility." | tee -a "$log_file" | fmt -w $width
  1001. exit 0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement