Guest User

Plex/MKVToolNix mp4 to mkv Converter v3

a guest
Apr 10th, 2024
160
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.21 KB | None | 0 0
  1. import os
  2. import subprocess
  3. import time
  4. import threading
  5. import queue
  6.  
  7. # Config variables - EDIT & MAKE SURE THESE ARE CORRECT
  8. SOURCE_DIR = r'\\PlexBox\data\movies'
  9. MKVMERGE_EXE = r'C:\Program Files\MKVToolNix\mkvmerge.exe'
  10.  
  11. # Clear the screen before starting the script
  12. os.system('cls' if os.name == 'nt' else 'clear')
  13.  
  14. alien_art = r'''
  15.     _                      _______                      _
  16.  _dMMMb._              .adOOOOOOOOOba.              _,dMMMb_
  17. dP'  ~YMMb            dOOOOOOOOOOOOOOOb            aMMP~  `Yb
  18. V      ~"Mb          dOOOOOOOOOOOOOOOOOb          dM"~      V
  19.          `Mb.       dOOOOOOOOOOOOOOOOOOOb       ,dM'
  20.           `YMb._   |OOOOOOOOOOOOOOOOOOOOO|   _,dMP'
  21.      __     `YMMM| OP'~"YOOOOOOOOOOOP"~`YO |MMMP'     __
  22.    ,dMMMb.     ~~' OO     `YOOOOOP'     OO `~~     ,dMMMb.
  23. _,dP~  `YMba_      OOb      `OOO'      dOO      _aMMP'  ~Yb._
  24.             `YMMMM\`OOOo     OOO     oOOO'/MMMMP'
  25.     ,aa.     `~YMMb `OOOb._,dOOOb._,dOOO'dMMP~'       ,aa.
  26.   ,dMYYMba._         `OOOOOOOOOOOOOOOOO'          _,adMYYMb.
  27.  ,MP'   `YMMba._      OOOOOOOOOOOOOOOOO       _,adMMP'   `YM.
  28.  MP'        ~YMMMba._ YOOOOPVVVVVYOOOOP  _,adMMMMP~       `YM
  29.  YMb           ~YMMMM\`OOOOI`````IOOOOO'/MMMMP~           dMP
  30.   `Mb.           `YMMMb`OOOI,,,,,IOOOO'dMMMP'           ,dM'
  31.     `'                  `OObNNNNNdOO'                   `'
  32.                           `~OOOOO~'   CHILLUMINATI
  33. '''
  34. print(alien_art)
  35.  
  36. print(f"""
  37. This script automates the conversion of MP4 files to MKV format using mkvmerge.
  38. It continuously monitors the directory {SOURCE_DIR} for MP4 files, converting them to MKV using mkvmerge located at {MKVMERGE_EXE}.
  39.  
  40. Before running the script, please ensure that the following directories are correct for your system:
  41. - SOURCE_DIR: Path to the directory containing your MP4 files.
  42. - MKVMERGE_EXE: Path to the mkvmerge executable (usually located in the MKVToolNix installation directory).
  43.  
  44. During processing, the script listens for user commands to stop the conversion:
  45. You can halt the script at any time with 'n', 'no', 'exit', 'end', 'quit'.
  46. The script will finish the current file conversion before halting.
  47. """)
  48.  
  49. def input_thread_func(input_queue, halt_flag):
  50.     """
  51.    Continuously checks for user input to potentially halt the conversion process.
  52.    """
  53.     while not halt_flag.is_set():
  54.         user_input = input().strip().lower()
  55.         input_queue.put(user_input)
  56.         if user_input in ['n', 'no', 'exit', 'end', 'quit']:
  57.             print("\nThe script will stop after completing the current file conversion.")
  58.             halt_flag.set()
  59.  
  60. LOG_FILE = os.path.join(SOURCE_DIR, '!conversion_log.txt')
  61.  
  62. def convert_to_mkv(source_dir, mp4_file, mkvmerge_exe):
  63.     """
  64.    Converts an MP4 file to an MKV file using mkvmerge.
  65.    """
  66.     mp4_path = os.path.join(source_dir, mp4_file)
  67.     mkv_file = mp4_file[:-4] + '.mkv'
  68.     mkv_path = os.path.join(source_dir, mkv_file)
  69.     convert_command = f'"{mkvmerge_exe}" -o "{mkv_path}" "{mp4_path}"'
  70.     try:
  71.         start_time = time.time()
  72.         result = subprocess.run(convert_command, shell=True, capture_output=True)
  73.         end_time = time.time()
  74.         if result.returncode != 0:
  75.             error_message = result.stderr.decode('utf-8') if result.stderr else 'Unknown error'
  76.             raise Exception(f"Error in conversion: {error_message}")
  77.         if os.path.isfile(mkv_path):
  78.             os.remove(mp4_path)
  79.             return True, mkv_file, end_time - start_time
  80.         return False, mp4_file, end_time - start_time
  81.     except Exception as e:
  82.         print(f"Error converting file {mp4_file}: {e}")
  83.         return False, mp4_file, 0
  84.  
  85. def log_converted_files(log_file, converted_files, total_time, conclusion_type):
  86.     """
  87.    Logs the conversion results to a file.
  88.    """
  89.     with open(log_file, 'a') as log:
  90.         timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
  91.         log.write(f"=== {timestamp} ===\n")
  92.         log.write(f"Conclusion Type: {conclusion_type}\n")
  93.         for file_name in converted_files:
  94.             log.write(f"- {file_name}\n")
  95.         log.write(f"Total Time Taken: {total_time:.2f} seconds\n")
  96.         log.write(f"Total Number of Files Converted: {len(converted_files)}\n")
  97.         log.write("=== End of Log Entry ===\n\n")
  98.  
  99. def format_duration(seconds):
  100.     """Converts time in seconds to a formatted string DD:HH:MM:SS."""
  101.     days, remainder = divmod(seconds, 86400)
  102.     hours, remainder = divmod(remainder, 3600)
  103.     minutes, seconds = divmod(remainder, 60)
  104.     return f"{int(days):02d}:{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}"
  105.  
  106. def process_files():
  107.     mp4_files = sorted([f for f in os.listdir(SOURCE_DIR) if f.lower().endswith('.mp4')])
  108.     total_files = len(mp4_files)
  109.     input_queue = queue.Queue()
  110.     halt_flag = threading.Event()
  111.     input_thread = threading.Thread(target=input_thread_func, args=(input_queue, halt_flag))
  112.     input_thread.daemon = True
  113.     input_thread.start()
  114.  
  115.     converted_files = []
  116.     total_time = 0
  117.     file_count = 0
  118.     start_global_time = time.time()
  119.  
  120.     try:
  121.         for mp4_file in mp4_files:
  122.             file_path = os.path.join(SOURCE_DIR, mp4_file)
  123.             file_size = os.path.getsize(file_path) / (1024 * 1024 * 1024)  # File size in GB
  124.  
  125.             if halt_flag.is_set():
  126.                 log_converted_files(LOG_FILE, converted_files, total_time, "Halted")
  127.                 break
  128.  
  129.             file_count += 1
  130.             print(f"\nFile {file_count} of {total_files}: {mp4_file} ({file_size:.2f} GB)")
  131.            
  132.             conversion_start_time = time.time()
  133.             conversion_successful, processed_file, conversion_time = convert_to_mkv(SOURCE_DIR, mp4_file, MKVMERGE_EXE)
  134.             total_time += conversion_time
  135.            
  136.             if conversion_successful:
  137.                 converted_files.append(processed_file)
  138.                 print(f"Conversion successful: {processed_file}")
  139.                 print(f"- Time Taken for This File: {conversion_time:.2f} seconds")
  140.  
  141.             elapsed_time = time.time() - start_global_time
  142.             conversion_rate = file_count / elapsed_time * 60  # Conversion rate in files per minute
  143.             estimated_time_remaining = (total_files - file_count) / conversion_rate * 60 if conversion_rate > 0 else 0
  144.             average_time_per_file = total_time / file_count if file_count > 0 else 0  # Average time per file in seconds
  145.  
  146.             print(f"- Conversion Rate: {conversion_rate:.2f} files/minute")
  147.             print(f"- Average Time per File: {average_time_per_file:.2f} seconds")
  148.             print(f"- Estimated Time Remaining: {format_duration(estimated_time_remaining)}")
  149.             print("-" * 50)
  150.  
  151.             if not input_queue.empty():
  152.                 user_input = input_queue.get()
  153.                 if user_input in ['n', 'no', 'exit', 'end', 'quit']:
  154.                     print("\nHalting MKV multiplexing per user request.")
  155.                     halt_flag.set()
  156.                     log_converted_files(LOG_FILE, converted_files, total_time, "User Halted")
  157.                     break
  158.  
  159.             if file_count % 20 == 0:
  160.                 log_converted_files(LOG_FILE, converted_files, total_time, "Periodic Update")
  161.                 converted_files = []
  162.  
  163.     except KeyboardInterrupt:
  164.         print("\nScript halted by KeyboardInterrupt.")
  165.         halt_flag.set()
  166.         average_time_per_file = total_time / file_count if file_count > 0 else 0
  167.         print(f"\nTotal Time Taken: {total_time:.2f} seconds")
  168.         print(f"Average Time per File: {average_time_per_file:.2f} seconds")
  169.         print(f"Total Number of Files Converted: {len(converted_files)}")
  170.         log_converted_files(LOG_FILE, converted_files, total_time, "Keyboard Interrupt")
  171.  
  172.     if not halt_flag.is_set():
  173.         print("\nAll files processed successfully.")
  174.         log_converted_files(LOG_FILE, converted_files, total_time, "Completed")
  175.  
  176.     average_time_per_file = total_time / file_count if file_count > 0 else 0
  177.     print(f"\nTotal Time Taken: {total_time:.2f} seconds")
  178.     print(f"Average Time per File: {average_time_per_file:.2f} seconds")
  179.     print(f"Total Number of Files Converted: {len(converted_files)}")
  180.  
  181. if __name__ == "__main__":
  182.     process_files()
  183.  
Tags: Plex
Add Comment
Please, Sign In to add comment