Advertisement
MaxDjently

Ziggle Wump Media Compressor 0.2-beta.08.27.2024

Aug 26th, 2024
55
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 16.81 KB | Source Code | 0 0
  1. #!/data/data/com.termux/files/usr/bin/bash
  2.  
  3. # --------------------
  4. #     Licence
  5. # --------------------
  6.  
  7. # 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.
  8.  
  9. # 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.
  10.  
  11. # You should have received a copy of the GNU General Public License along with  this program. If not, see <https://www.gnu.org/licenses/>.
  12.  
  13. # -----------------
  14. #     About
  15. # -----------------
  16.  
  17. # This script is for Termux on Android and is not associated with the apps it uses.
  18.  
  19. # Copyright Joshua Hansen and contributors: Microsoft Co-Pilot and ChatGPT.
  20.  
  21. # 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.
  22.  
  23. # -----------------------
  24. #   Instructions
  25. # -----------------------
  26.  
  27. # Usage: ./ziggle_wump.sh [-r resolution] [-f "ffmpeg_options"] [-h|--help]
  28. #   -r resolution        Custom resolution height for video conversion preserving aspect ratio (default: original resolution)  Downscaling your videos will significantly reduce the file size, but may introduce artifacts and shimmering.  Upscaling will only result in larger file sizes.  It will not make your video look better.
  29. #   -f "ffmpeg_options" Override default FFmpeg options with custom command line options.  ex. bash ./ziggle_wump.sh -f "-c:v libx265 -c:a libopus -x265-params "aq-mode=1:psy-rd=0.75:psy-rdoq=4.0:rd=4:rdoq-level=1:rect=0:strong-intra-smoothing=0""
  30. #   -h, --help           Display this help message
  31.  
  32. # 1. Download or Copy this script to a file, and rename it if you want.  e.g., ziggle_wump.sh.  Putting it in your Movies folder will make it easy to find on both Android and Termux, although it's possible to put this in your /usr/bin to use it as a system app.  Your mileage may vary.
  33. # 2. Make it executable: chmod +x ziggle_wump.sh
  34. # 3. Run the script: bash ./ziggle_wump.sh [options]
  35.  
  36. # -------------------
  37. #    README
  38. # -------------------
  39.  
  40. # Ziggle Wump: The Simple FFmpeg Command Line Companion Script for Termux on Android
  41.  
  42. # DISCLAIMER:  THE SCRIPT DOES NOT ALLOW YOU TO CONVERT ENCRYPTED FILES, COPYRIGHTED CONTENT IS GENERALLY ENCRYPTED. THE SCRIPT IN ITSELF DOES NOT VIOLATE COPYRIGHT BUT THE USER MIGHT.  CODE TO PREVENT CIRCUMVENTION IS BEYOND MY CAPABILITY.  NOR SHOULD IT BE MY RESPONSIBILITY, IT'S THE COPYRIGHT HOLDERS RESPONSIBILITY TO ENCRYPT THEIR MEDIA.  IT IS NOT RECOMMENDED TO USE THE SCRIPT TO VIOLATE COPYRIGHT LAW.  US COPYRIGHT LAW ALLOWS FOR SPACESHIFTING, AND FAIR USE OF COPYRIGHTED MATERIAL
  43.  
  44. # NOTE:  Some phones have a battery saving feature such as the Galaxy S24, that can impact the encoding process and leave you with partially encoded files.  Please make sure Termux is in focus otherwise, either full screen or split screen if you want to do other things, and keep the screen on while encoding.
  45.  
  46. # Check out https://dontkillmyapp.com/ for more information and perhaps find a fix for your particular phone.
  47.  
  48. # -----------------------------
  49. #             Title
  50. # -----------------------------
  51.  
  52. # Ziggle Wump Media Compressor 0.2-beta1
  53.  
  54. # The Simple FFmpeg Command Line Companion Script for Termux on Android
  55.  
  56. # -----------------------------
  57. #        Variables
  58. # -----------------------------
  59.  
  60. # Full Log file path
  61. log_file="$HOME/storage/shared/Movies/VideoDrop/convert.log"
  62.  
  63. # Shortened log file path for terminal output
  64. log_file_echo=$(echo "$log_file" | sed 's|/data/data/com.termux/files/home|.../home|g')
  65.  
  66. # Default resolution (empty implies original resolution)
  67. default_resolution=""
  68.  
  69. # Full directory paths
  70. video_drop_dir="$HOME/storage/shared/Movies/VideoDrop"
  71. video_processing_dir="$HOME/storage/shared/Movies/VideoProcessing"
  72. output_dir_base="$HOME/storage/shared/Movies/VideoConverted"
  73.  
  74. # Shortened directory paths for terminal output
  75. video_drop_dir_echo=$(echo "$video_drop_dir" | sed 's|/data/data/com.termux/files/home|.../home|g')
  76. video_processing_dir_echo=$(echo "$video_processing_dir" | sed 's|/data/data/com.termux/files/home|.../home|g')
  77. output_dir_base_echo=$(echo "$output_dir_base" | sed 's|/data/data/com.termux/files/home|.../home|g')
  78.  
  79. # Initialize optional variables
  80. resolution="$default_resolution"
  81. ffmpeg_custom_options=""
  82.  
  83. # -----------------------------
  84. #    Command Flags
  85. # -----------------------------
  86.  
  87. # Function to display help message
  88. show_help() {
  89.     width=$(tput cols)
  90.     echo "Ziggle Wump will create $video_drop_dir_echo the first time if it doesn't exist.  Place your media files here." | tee -a "$log_file" | fmt -w $width
  91.     echo "Usage: $0 [-r resolution] [-f \"ffmpeg_options\"] [-h|--help]" | fmt -w $width
  92.     echo "  -r resolution ex. bash ./ziggle_wump.sh -r 720                      Custom resolution height for video conversion preserving aspect ratio (default: original resolution)  Downscaling your videos will significantly reduce the file size, but may introduce artifacts and shimmering.  Upscaling will only result in larger file sizes.  It will not make your video look better." | fmt -w $width
  93.     echo "  -f \"ffmpeg_options\"  Override default FFmpeg options with custom command line options.  ex. bash ./ziggle_wump.sh -f \""-c:v libx265 -c:a libopus\"\" | fmt -w $width
  94.     echo "  -h, --help           Display this help message" | fmt -w $width
  95.     exit 0
  96. }
  97.  
  98. # Parse command-line options
  99. while getopts "r:f:h" opt; do
  100.     case $opt in
  101.         r) resolution="$OPTARG" ;;  # Set custom resolution by height
  102.         f) ffmpeg_custom_options="$OPTARG" ;;  # Set custom FFmpeg options
  103.         h) show_help ;;  # Display help
  104.         *) show_help ;;  # Display help for invalid options
  105.     esac
  106. done
  107.  
  108. shift $((OPTIND -1))
  109.  
  110. # ---------------------------------
  111. #       Dependencies
  112. # ---------------------------------
  113.  
  114. # Ensure dependencies are installed and all packages are up to date.
  115.     echo "Updating, please wait..."
  116.     sleep 1
  117.     pkg update && pkg upgrade -y
  118.     if ! command -v ffmpeg &> /dev/null; then
  119.         pkg install ffmpeg -y
  120.     fi
  121.     if ! command -v ncurses-utils &> /dev/null; then
  122.         pkg install ncurses-utils -y
  123.     fi
  124. echo "Update complete."
  125.     sleep 1
  126.  
  127. # -----------------------------------------------------
  128. #     Create Directories and log file
  129. # -----------------------------------------------------
  130.  
  131. # Create necessary directories if they don't exist
  132. mkdir -p "$video_drop_dir" "$video_processing_dir" "$output_dir_base"
  133.  
  134. # Change to the VideoDrop directory
  135. cd "$video_drop_dir" || { echo "Directory change failed"; exit 1; }
  136.  
  137. # Check if log file exists
  138. if [ -f "$log_file" ]; then
  139.     echo "Old log file found.  Deleting..."
  140.     rm "$log_file"
  141.     echo "File deleted."
  142. else
  143.     echo "Log File does not exist.  The script will create $log_file_echo"
  144. fi
  145.  
  146. # ------------------------
  147. #     Start script
  148. # ------------------------
  149.  
  150. width=$(tput cols)
  151.  
  152. echo "Running... Press Ctrl+C to stop."
  153.     sleep 1
  154.  
  155. echo ""
  156. echo "Ziggle Wump will create $video_drop_dir_echo the first time if it doesn't exist.  Place your media files here." | tee -a "$log_file" | fmt -w $width
  157.  
  158. echo ""
  159. echo "NOTE:  Some phones have a battery saving feature such as the Galaxy S24, that can impact the encoding process and leave you with partially encoded files.  Please make sure Termux is in  focus, either full screen or split screen if you want to do other things, and keep the screen on while encoding." | tee -a "$log_file" | fmt -w $width
  160.  
  161. echo ""
  162. echo "Check out https://dontkillmyapp.com/ for more information and perhaps find a fix for your particular phone." | tee -a "$log_file" | fmt -w $width
  163.  
  164. echo ""
  165. # Function to prompt the user to continue or quit
  166. prompt_continue_or_quit() {
  167.     while true; do
  168. # Recursively find and process videos and audio
  169. video_count=$(find "$video_drop_dir" -type f \( -iname '*.mp4' -o -iname '*.mkv' -o -iname '*.avi' -o -iname '*.mov' -o -iname '*.flv' -o -iname '*.wmv' -o -iname '*.webm' -o -iname '*.mp3' -o -iname '*.wav' -o -iname '*.flac' -o -iname '*.aac' -o -iname '*.ogg' -o -iname '*.m4a' \) | wc -l)
  170.  
  171. if [ "$video_count" -eq 0 ]; then
  172.     echo "No videos or audio found. $video_drop_dir_echo folder created. Place your videos and audio here including in folders using your favorite file manager for Android, and then run the script again." | tee -a "$log_file" | fmt -w $width
  173.     exit 0
  174. fi
  175.  
  176. # Prompt text
  177. prompt_text="Compatible media files detected in $video_drop_dir_echo. You can start encoding now. Do you wish to proceed? (Y/N): "
  178.  
  179. # Format the prompt text
  180. formatted_prompt=$(echo "$prompt_text" | fmt -w $width)
  181.  
  182. # Read user input with formatted prompt
  183. read -p "$formatted_prompt" yn
  184. case $yn in
  185.     [Yy]* ) return 0;;  # Continue
  186.     [Nn]* ) echo "Exiting script."; exit 0;;  # Quit
  187.     * ) echo "Please answer Y or N.";;
  188. esac
  189. done
  190. }
  191.  
  192.     # Prompt the user to continue or quit
  193.     prompt_continue_or_quit
  194.  
  195. echo "Starting conversion process..." | tee -a "$log_file"
  196. sleep 1
  197.  
  198. # -----------------------------
  199. #    Audio Encoder
  200. # -----------------------------
  201.  
  202. width=$(tput cols)
  203.  
  204. # Function to check the log file for "Killed" message
  205. check_for_killed_message() {
  206.     if grep -q " Killed     " "$log_file"; then
  207.         echo "$(date '+%Y-%m-%d %H:%M:%S') Error: Process was killed. Check log file for details." | tee -a "$log_file"
  208.         return 1
  209.     fi
  210.     return 0
  211. }
  212.  
  213. # Function to process audio files
  214. process_audio() {
  215.     local audio="$1"
  216.     local audio_echo=$(echo "$audio" | sed 's|/data/data/com.termux/files/home|/home|g')
  217.     local relative_path="${audio#$video_drop_dir/}"
  218.     local dir_path=$(dirname "$relative_path")
  219.     local base_name=$(basename "$relative_path" | tr -cd '[:alnum:]._ -')
  220.     local output_dir="$output_dir_base/$dir_path"
  221.     local output_file="$output_dir/${base_name}_converted.opus"
  222.     local temp_output_file="$output_file.tmp"
  223.  
  224.     mkdir -p "$output_dir"  # Create output directory
  225.  
  226.     echo "$(date '+%Y-%m-%d %H:%M:%S') Processing $audio to $output_file" | tee -a "$log_file"
  227.  
  228.     # Construct the FFmpeg command for audio processing
  229.     local ffmpeg_command="ffmpeg -nostdin -loglevel verbose -y -i \"$audio\" -c:a libopus -f opus \"$temp_output_file\""
  230.  
  231.     # Execute the FFmpeg command
  232.     eval $ffmpeg_command 2>&1 | tee -a "$log_file"
  233.  
  234.     # Check for "Killed" message in the log file
  235.     if ! check_for_killed_message; then
  236.         echo "$(date '+%Y-%m-%d %H:%M:%S') Error: Process was killed. Exiting." | tee -a "$log_file"
  237.         exit 1
  238.     fi
  239.  
  240.     if [ $? -eq 0 ]; then
  241.         mv "$temp_output_file" "$output_file"  # Rename the temporary file to the final output file
  242.         mkdir -p "$video_processing_dir/$dir_path"  # Create processing directory
  243.         mv "$audio" "$video_processing_dir/$relative_path"
  244.         echo ""
  245.         echo "$(date '+%Y-%m-%d %H:%M:%S') Converted $audio_echo. Your original files will be in the $video_processing_dir_echo folder for comparison. Your new files are in $output_dir_base_echo" | tee -a "$log_file" | fmt -w $width
  246.     else
  247.         echo ""
  248.         echo "$(date '+%Y-%m-%d %H:%M:%S') Error processing \"$audio\". Check log file for details." | tee -a "$log_file"
  249.         exit 1
  250.     fi
  251. }
  252.  
  253. # ------------------------------
  254. #      Video Encoder
  255. # ------------------------------
  256.  
  257. width=$(tput cols)
  258.  
  259. # Function to check the log file for "Killed" message
  260. check_for_killed_message() {
  261.     if grep -q " Killed     " "$log_file"; then
  262.         echo "$(date '+%Y-%m-%d %H:%M:%S') Error: Process was killed. Check log file for details." | tee -a "$log_file" | fmt -w $width
  263.         exit 1
  264.     fi
  265. }
  266.  
  267. # Function to process videos
  268. process_video() {
  269.     local video="$1"
  270.     local video_echo=$(echo "$video" | sed 's|/data/data/com.termux/files/home|.../home|g')
  271.     local relative_path="${video#$video_drop_dir/}"
  272.     local dir_path=$(dirname "$relative_path")
  273.     local base_name=$(basename "$relative_path" | tr -cd '[:alnum:]._ -')
  274.     local output_dir="$output_dir_base/$dir_path"
  275.     local output_file="$output_dir/${base_name}_converted.mkv"
  276.     local temp_output_file="$output_file.tmp"
  277.     local scale_filter=""
  278.     [ -n "$resolution" ] && scale_filter="-vf \"scale=trunc(oh*a/2)*2:$resolution,setsar=1\""
  279.  
  280.     mkdir -p "$output_dir"  # Create output directory
  281.  
  282.     echo "$(date '+%Y-%m-%d %H:%M:%S') Processing $video to $output_file" | tee -a "$log_file"
  283.    
  284.     # Construct the FFmpeg command
  285.     local ffmpeg_command
  286.     if [ -n "$ffmpeg_custom_options" ]; then
  287.         ffmpeg_command="ffmpeg -nostdin -loglevel verbose -y -i \"$video\" $ffmpeg_custom_options -vsync 2 -f matroska \"$temp_output_file\""
  288.     else
  289.         ffmpeg_command="ffmpeg -nostdin -loglevel verbose -y -i \"$video\" -c:v libx265 -c:a libopus $scale_filter -x265-params \"keyint=250:aq-mode=1:psy-rd=0.75:psy-rdoq=4.0:rd=4:rdoq-level=1:rect=0:strong-intra-smoothing=0\" -vsync 2 -f matroska \"$temp_output_file\""
  290.     fi
  291.  
  292.     # Execute the FFmpeg command
  293.     eval $ffmpeg_command 2>&1 | tee -a "$log_file"
  294.  
  295.     # Check for "Killed" message in the log file
  296.     check_for_killed_message
  297.  
  298.     if [ $? -eq 0 ]; then
  299.         mv "$temp_output_file" "$output_file"  # Rename the temporary file to the final output file
  300.         mkdir -p "$video_processing_dir/$dir_path"  # Create processing directory
  301.         mv "$video" "$video_processing_dir/$relative_path"
  302.         echo ""
  303.         echo "$(date '+%Y-%m-%d %H:%M:%S') Converted $video_echo. Your original files will be in the $video_processing_dir_echo folder for comparison. Your new files are in $output_dir_base_echo" | tee -a "$log_file" | fmt -w $width
  304.     else
  305.         echo ""
  306.         echo "$(date '+%Y-%m-%d %H:%M:%S') Error processing \"$video\". Check log file for details." | tee -a "$log_file"
  307.         exit 1
  308.     fi
  309. }
  310.  
  311. # --------------------------------------
  312. #    Start Batch Encoding
  313. # --------------------------------------
  314.  
  315. width=$(tput cols)
  316.  
  317. # Recursively find and process videos and audio
  318. video_count=$(find "$video_drop_dir" -type f \( -iname '*.mp4' -o -iname '*.mkv' -o -iname '*.avi' -o -iname '*.mov' -o -iname '*.flv' -o -iname '*.wmv' -o -iname '*.webm' -o -iname '*.mp3' -o -iname '*.wav' -o -iname '*.flac' -o -iname '*.aac' -o -iname '*.ogg' -o -iname '*.m4a' \) | wc -l)
  319.  
  320. # Process each audio file found
  321. find "$video_drop_dir" -type f \( -iname '*.mp3' -o -iname '*.wav' -o -iname '*.flac' -o -iname '*.aac' -o -iname '*.ogg' -o -iname '*.m4a' \) | while read -r audio; do
  322.  
  323.     stop_processing=false
  324.  
  325. # Function to handle SIGINT (Ctrl+C)
  326. handle_sigint() {
  327.     echo ""
  328.     echo "Caught SIGINT (Ctrl+C). Exiting immediately." | fmt -w $width
  329.     exit 1  # Exit immediately without performing cleanup
  330. }
  331.  
  332. # Trap SIGINT and call the handle_sigint function
  333. trap handle_sigint SIGINT
  334.  
  335.     if [ "$stop_processing" = true ]; then
  336.         echo "Stopping processing due to SIGINT."
  337.         exit 1
  338.     fi
  339.     process_audio "$audio" || exit 1
  340. done
  341.  
  342. # Process each video found
  343. find "$video_drop_dir" -type f \( -iname '*.mp4' -o -iname '*.mkv' -o -iname '*.avi' -o -iname '*.mov' -o -iname '*.flv' -o -iname '*.wmv' -o -iname '*.webm' \) | while read -r video; do
  344.  
  345.     stop_processing=false
  346.  
  347. # Function to handle SIGINT (Ctrl+C)
  348. handle_sigint() {
  349.     echo ""
  350.     echo "Caught SIGINT (Ctrl+C). Exiting immediately." | fmt -w $width
  351.     exit 1  # Exit immediately without performing cleanup
  352. }
  353.  
  354. # Trap SIGINT and call the handle_sigint function
  355. trap handle_sigint SIGINT
  356.  
  357.     if [ "$stop_processing" = true ]; then
  358.         echo "Stopping processing due to SIGINT."
  359.         exit 1
  360.     fi
  361.     process_video "$video" || exit 1
  362. done
  363.  
  364. # -----------------------------
  365. #     Finishing Up
  366. # -----------------------------
  367.  
  368. width=$(tput cols)
  369.  
  370. # Check for empty directories and remove them, except for the VideoDrop folder itself
  371.  
  372. # Set a maximum number of iterations to prevent hanging, this will remove up to 10 levels of subdirectories
  373. max_iterations=10
  374. iteration=0
  375.  
  376. while find "$video_drop_dir" -depth -type d -empty -not -path "$video_drop_dir" -exec rmdir "{}" \; > /dev/null 2>&1; do
  377.     iteration=$((iteration + 1))
  378.     if [ "$iteration" -ge "$max_iterations" ]; then
  379.         break
  380.     fi
  381.     : # No-op, just repeat the loop
  382. done
  383.  
  384. # final output message
  385. echo ""
  386. echo "Log file is in $video_drop_dir_echo.  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
  387. exit 0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement