#!/usr/bin/env python3 import argparse import subprocess import os from datetime import datetime from playsound import playsound import time import re def parse_args(): parser = argparse.ArgumentParser( description="Rip content of dvds" # , formatter_class=argparse.RawTextHelpFormatter ) parser.add_argument( "type", choices=("movie", "series"), help="If the dvd contains one movie, or multiple episodes of a series", ) parser.add_argument( "title", help='The title of the movie. Series must end with "Sx Ex-x". E.g.: "Lost S01 E1-04"', ) parser.add_argument( "--dev", help=f"Dvd device to rip from. Defaults to {DEFAULT_DVD_DEVICE}", default=DEFAULT_DVD_DEVICE, ) return parser.parse_args() def validate_series_title(title): if not is_series_title_valid(title): print("Invalid series title!") exit(1) def is_series_title_valid(title): try: episode_matches = re.search(SERIES_TITLE_REGEX, title) if episode_matches is None: return False episode_from = int(episode_matches.group(1)) episode_to = int(episode_matches.group(2)) if episode_from < episode_to: return True except: return False return False def chdir_to_script_dir(): os.chdir(os.path.dirname(__file__)) def mkdirs(): os.makedirs(LOGS_DIR, exist_ok=True) os.makedirs(RIPPED_DIR, exist_ok=True) def create_log_line(args): date = datetime.now().strftime("%d/%m/%Y %H:%M:%S") return f'{date} - {args.type} - "{args.title}"' def write_line_to_logfile(line, filename): with open(filename, "a") as file: file.write(line + "\n") def do_rip(args) -> bool: """Returns: success of command""" command = create_rip_command(args) proc = subprocess.run(command, shell=True, capture_output=False) return proc.returncode == 0 def create_rip_command(args): dest = RIPPED_DIR dev = args.dev title = args.title if args.type == "movie": return f"dvdbackup -i '{dev}' -o '{dest}' -F -n '{title}'" else: return f"dvdbackup -i '{dev}' -o '{dest}' -M -n '{title}'" def notify_ripping_success(args, program_execution_time_str): print("Success!") print(f"Ripping took {program_execution_time_str}") send_notification( f'{args.type.capitalize()} "{args.title}" ripped successfully in {program_execution_time_str}!' ) playsound(NOTIFICATION_SOUND) def notify_ripping_error(args, program_execution_time_str): print(f"Ripping failure after {program_execution_time_str}") send_notification( f'Error ripping {args.type.capitalize()} "{args.title}" after {program_execution_time_str}!' ) playsound(NOTIFICATION_SOUND) def send_notification(text): subprocess.run( ["notify-send", text], shell=False, ) def transfer_ripped_to_transcoder(args) -> bool: """Returns: success of command""" src = os.path.join(RIPPED_DIR, args.title) destination = None if args.type == "movie": destination = f"{TRANSCODER_INPUT_FOLDER}/movies/" else: destination = f"{TRANSCODER_INPUT_FOLDER}/series/" proc = subprocess.run(["rsync", "-azv", src, destination]) success = proc.returncode == 0 if success: print("Transfer successful") else: print("Transfer failed!") return success def delete_ripped(args): try: os.rmdir(os.path.join(RIPPED_DIR, args.title)) except FileNotFoundError: pass TRANSCODER_FOLDER = "transcode" # pi@192.168.xxx:/home/pi/transcode TRANSCODER_INPUT_FOLDER = f"{TRANSCODER_FOLDER}/raw" DEFAULT_DVD_DEVICE = "/dev/cdrom" SERIES_TITLE_REGEX = r"S\d+[ _]?E(\d+)-(\d+)$" RIPPED_DIR = "rip/ripped" LOGS_DIR = "rip/logs" RIP_LOGFILE = f"{LOGS_DIR}/rip.log" RIP_ERR_LOGFILE = f"{LOGS_DIR}/rip-err.log" RIP_SUCCESS_LOGFILE = f"{LOGS_DIR}/rip-success.log" NOTIFICATION_SOUND = "bell.oga" if __name__ == "__main__": program_start_time = time.time() args = parse_args() if args.type == "series": validate_series_title(args.title) chdir_to_script_dir() mkdirs() log_line = create_log_line(args) write_line_to_logfile(log_line, RIP_LOGFILE) success = do_rip(args) program_execution_time_minutes = (program_start_time - time.time()) / 60.0 program_execution_time_minutes = max(0.0, program_execution_time_minutes) program_execution_time_str = f"{program_execution_time_minutes:.1f} minutes" if success: write_line_to_logfile(log_line, RIP_SUCCESS_LOGFILE) notify_ripping_success(args, program_execution_time_str) transfer_success = transfer_ripped_to_transcoder(args) if transfer_success: print("Deleting output") delete_ripped(args) else: write_line_to_logfile(log_line, RIP_ERR_LOGFILE) notify_ripping_error(args, program_execution_time_str) print("Deleting partial output") delete_ripped(args)