Example #1
0
def main(logfile, job):
    """main dvd processing function"""
    logging.info("Starting Disc identification")

    identify.identify(job, logfile)
    # Check db for entries matching the crc and successful
    have_dupes, crc_jobs = utils.job_dupe_check(job)
    if crc_jobs is not None:
        # This might need some tweaks to because of title/year manual
        job.title = crc_jobs[0][
            'title'] if crc_jobs[0]['title'] != "" else job.label
        job.year = crc_jobs[0]['year'] if crc_jobs[0]['year'] != "" else ""
        job.poster_url = crc_jobs[0][
            'poster_url'] if crc_jobs[0]['poster_url'] != "" else None
        crc_jobs[0]['hasnicetitle'] = bool(crc_jobs[0]['hasnicetitle'])
        job.hasnicetitle = crc_jobs[0]['hasnicetitle'] if crc_jobs[0][
            'hasnicetitle'] else False
        job.video_type = crc_jobs[0][
            'video_type'] if crc_jobs[0]['hasnicetitle'] != "" else "unknown"
        db.session.commit()
    #  DVD disk entry
    if job.disctype in ["dvd", "bluray"]:
        #  Send the notifications
        utils.notify(
            job, "ARM notification",
            f"Found disc: {job.title}. Disc type is {job.disctype}. Main Feature is {job.config.MAINFEATURE}"
            f".  Edit entry here: http://" + str(check_ip()) + ":"
            f"{job.config.WEBSERVER_PORT}/jobdetail?job_id={job.job_id}")
    elif job.disctype == "music":
        utils.notify(job, "ARM notification",
                     f"Found music CD: {job.label}. Ripping all tracks")
    elif job.disctype == "data":
        utils.notify(job, "ARM notification",
                     "Found data disc.  Copying data.")
    else:
        utils.notify(job, "ARM Notification",
                     "Could not identify disc.  Exiting.")
        sys.exit()

    #  If we have have waiting for user input enabled
    """if job.config.MANUAL_WAIT:
        logging.info("Waiting " + str(job.config.MANUAL_WAIT_TIME) + " seconds for manual override.")
        job.status = "waiting"
        db.session.commit()
        time.sleep(job.config.MANUAL_WAIT_TIME)
        db.session.refresh(job)
        db.session.refresh(config)
        job.status = "active"
        db.session.commit()
    """

    # TODO: Update function that will look for the best match with most data
    #  If we have have waiting for user input enabled
    if job.config.MANUAL_WAIT:
        logging.info(
            f"Waiting {job.config.MANUAL_WAIT_TIME} seconds for manual override."
        )
        job.status = "waiting"
        db.session.commit()
        sleep_time = 0
        while sleep_time < job.config.MANUAL_WAIT_TIME:
            time.sleep(5)
            sleep_time += 5
            db.session.refresh(job)
            db.session.refresh(config)
            if job.title_manual:
                break
        job.status = "active"
        db.session.commit()

    #  If the user has set info manually update database and hasnicetitle
    if job.title_manual:
        logging.info(
            "Manual override found.  Overriding auto identification values.")
        job.updated = True
        #  We need to let arm know we have a nice title so it can use the MEDIA folder and not the ARM folder
        job.hasnicetitle = True
    else:
        logging.info("No manual override found.")

    log_arm_params(job)
    check_fstab()

    if job.config.HASHEDKEYS:
        logging.info("Getting MakeMKV hashed keys for UHD rips")
        grabkeys()

    #  Entry point for dvd/bluray
    if job.disctype in ["dvd", "bluray"]:
        # get filesystem in order
        #  If we have a nice title/confirmed name use the MEDIA_DIR and not the ARM unidentified folder
        if job.hasnicetitle:
            if job.year != "0000" or job.year != "":
                hboutpath = os.path.join(
                    job.config.MEDIA_DIR,
                    str(job.title) + " (" + str(job.year) + ")")
            else:
                hboutpath = os.path.join(job.config.MEDIA_DIR, str(job.title))
        else:
            hboutpath = os.path.join(job.config.ARMPATH, str(job.title))

        #  The dvd directory already exists - Lets make a new one using random numbers
        if (utils.make_dir(hboutpath)) is False:
            logging.info("Directory exist.")
            #  Only begin ripping if we are allowed to make duplicates
            # Or the successful rip of the disc is not found in our database
            if job.config.ALLOW_DUPLICATES or not have_dupes:
                ts = round(time.time() * 100)
                #  if we have a nice title, set the folder to MEDIA_DIR and not the unidentified ARMPATH
                if job.hasnicetitle:
                    #  Dont use the year if its  0000
                    if job.year != "0000" or job.year != "":
                        hboutpath = os.path.join(
                            job.config.MEDIA_DIR,
                            f"{job.title} ({job.year}) {ts}")
                    else:
                        hboutpath = os.path.join(job.config.MEDIA_DIR,
                                                 f"{job.title} {ts}")
                else:
                    hboutpath = os.path.join(job.config.ARMPATH,
                                             str(job.title) + "_" + str(ts))

                #  We failed to make a random directory, most likely a permission issue
                if (utils.make_dir(hboutpath)) is False:
                    logging.exception(
                        "A fatal error has occurred and ARM is exiting.  "
                        "Couldn't create filesystem. Possible permission error"
                    )
                    utils.notify(
                        job, "ARM notification",
                        "ARM encountered a fatal error processing " +
                        str(job.title) +
                        ".  Couldn't create filesystem. Possible permission error. "
                    )
                    job.status = "fail"
                    db.session.commit()
                    sys.exit()
            else:
                #  We arent allowed to rip dupes, notify and exit
                logging.info("Duplicate rips are disabled.")
                utils.notify(
                    job, "ARM notification",
                    "ARM Detected a duplicate disc. For " + str(job.title) +
                    ".  Duplicate rips are disabled. You can re-enable them from your config file. "
                )
                job.status = "fail"
                db.session.commit()
                sys.exit()

        logging.info("Processing files to: " + hboutpath)

        #  entry point for bluray or dvd with MAINFEATURE off and RIPMETHOD mkv
        hbinpath = str(job.devpath)
        if job.disctype == "bluray" or (not job.config.MAINFEATURE
                                        and job.config.RIPMETHOD == "mkv"):
            # send to makemkv for ripping
            # run MakeMKV and get path to output
            job.status = "ripping"
            db.session.commit()
            try:
                mkvoutpath = makemkv.makemkv(logfile, job)
            except:  # noqa: E722
                raise

            if mkvoutpath is None:
                logging.error(
                    "MakeMKV did not complete successfully.  Exiting ARM!")
                job.status = "fail"
                db.session.commit()
                sys.exit()
            if job.config.NOTIFY_RIP:
                # Fixed bug line below
                utils.notify(
                    job, "ARM notification",
                    str(job.title) + " rip complete.  Starting transcode. ")
            # point HB to the path MakeMKV ripped to
            hbinpath = mkvoutpath

            # Entry point for not transcoding
            if job.config.SKIP_TRANSCODE and job.config.RIPMETHOD == "mkv":
                logging.info("SKIP_TRANSCODE is true.  Moving raw mkv files.")
                logging.info(
                    "NOTE: Identified main feature may not be actual main feature"
                )
                files = os.listdir(mkvoutpath)
                final_directory = hboutpath
                if job.video_type == "movie":
                    logging.debug("Videotype: " + job.video_type)
                    # if videotype is movie, then move biggest title to media_dir
                    # move the rest of the files to the extras folder

                    # find largest filesize
                    logging.debug("Finding largest file")
                    largest_file_name = ""
                    for f in files:
                        # initialize largest_file_name
                        if largest_file_name == "":
                            largest_file_name = f
                        temp_path_f = os.path.join(hbinpath, f)
                        temp_path_largest = os.path.join(
                            hbinpath, largest_file_name)
                        # os.path.join(cfg['MEDIA_DIR'] + videotitle)
                        # if cur file size > largest_file size
                        if (os.stat(temp_path_f).st_size >
                                os.stat(temp_path_largest).st_size):
                            largest_file_name = f
                    # largest_file should be largest file
                    logging.debug("Largest file is: " + largest_file_name)
                    temp_path = os.path.join(hbinpath, largest_file_name)
                    if (os.stat(temp_path).st_size >
                            0):  # sanity check for filesize
                        for f in files:
                            # move main into media_dir
                            # move others into extras folder
                            if (f == largest_file_name):
                                # largest movie
                                # Encorporating Rajlaud's fix #349
                                utils.move_files(hbinpath, f, job, True)
                            else:
                                # other extras
                                if not str(job.config.EXTRAS_SUB).lower(
                                ) == "none":
                                    # Incorporating Rajlaud's fix #349
                                    utils.move_files(hbinpath, f, job, False)
                                else:
                                    logging.info("Not moving extra: " + f)
                    # Change final path (used to set permissions)
                    final_directory = os.path.join(
                        job.config.MEDIA_DIR,
                        str(job.title) + " (" + str(job.year) + ")")
                    # Clean up
                    #  TODO: fix this so it doesnt remove everything
                    logging.debug(
                        "Attempting to remove extra folder in ARMPATH: " +
                        hboutpath)
                    if hboutpath != final_directory:
                        try:
                            shutil.rmtree(hboutpath)
                            logging.debug("Removed sucessfully: " + hboutpath)
                        except Exception:
                            logging.debug("Failed to remove: " + hboutpath)
                else:
                    # if videotype is not movie, then move everything
                    # into 'Unidentified' folder
                    logging.debug("Videotype: " + job.video_type)

                    for f in files:
                        mkvoutfile = os.path.join(mkvoutpath, f)
                        logging.debug("Moving file: " + mkvoutfile + " to: " +
                                      mkvoutpath + f)
                        shutil.move(mkvoutfile, hboutpath)
                # remove raw files, if specified in config
                if job.config.DELRAWFILES:
                    logging.info("Removing raw files")
                    shutil.rmtree(mkvoutpath)
                # set file to default permissions '777'
                if job.config.SET_MEDIA_PERMISSIONS:
                    perm_result = utils.set_permissions(job, final_directory)
                    logging.info("Permissions set successfully: " +
                                 str(perm_result))
                utils.notify(job, "ARM notification",
                             str(job.title) + " processing complete. ")
                logging.info("ARM processing complete")
                # WARN  : might cause issues
                # We need to update our job before we quit
                # It should be safe to do this as we arent waiting for transcode
                job.status = "success"
                db.session.commit()
                # exit
                job.eject()
                sys.exit()

        job.status = "transcoding"
        db.session.commit()
        if job.disctype == "bluray" and job.config.RIPMETHOD == "mkv":
            handbrake.handbrake_mkv(hbinpath, hboutpath, logfile, job)
        elif job.disctype == "dvd" and (not job.config.MAINFEATURE
                                        and job.config.RIPMETHOD == "mkv"):
            handbrake.handbrake_mkv(hbinpath, hboutpath, logfile, job)
        elif job.video_type == "movie" and job.config.MAINFEATURE and job.hasnicetitle:
            handbrake.handbrake_mainfeature(hbinpath, hboutpath, logfile, job)
            job.eject()
        else:
            handbrake.handbrake_all(hbinpath, hboutpath, logfile, job)
            job.eject()

        # check if there is a new title and change all filenames
        # time.sleep(60)
        db.session.refresh(job)
        logging.debug("New Title is " + str(job.title_manual))
        if job.title_manual and not job.updated:
            newpath = utils.rename_files(hboutpath, job)
            p = newpath
        else:
            p = hboutpath

        # move to media directory
        if job.video_type == "movie" and job.hasnicetitle:
            # tracks = job.tracks.all()
            tracks = job.tracks.filter_by(ripped=True)
            for track in tracks:
                logging.info("Moving Movie " + str(track.filename) + " to " +
                             str(p))
                utils.move_files(p, track.filename, job, track.main_feature)
        # move to media directory
        elif job.video_type == "series" and job.hasnicetitle:
            # tracks = job.tracks.all()
            tracks = job.tracks.filter_by(ripped=True)
            for track in tracks:
                logging.info("Moving Series " + str(track.filename) + " to " +
                             str(p))
                utils.move_files(p, track.filename, job, False)
        else:
            logging.info("job type is " + str(job.video_type) +
                         "not movie or series, not moving.")
            utils.scan_emby(job)

        #  Test for dvd fail permissions
        final_directory = p
        if job.config.SET_MEDIA_PERMISSIONS:
            perm_result = utils.set_permissions(job, final_directory)
            logging.info("Permissions set successfully: " + str(perm_result))

        # remove empty directories
        #  Same issue of removing files that have already been identified
        #  TODO: fully fix this, this is only a temp fix
        if hboutpath != final_directory:
            try:
                os.rmdir(hboutpath)
            except OSError:
                logging.info(hboutpath +
                             " directory is not empty.  Skipping removal. ")
                pass

        try:
            newpath
        except NameError:
            logging.debug("'newpath' directory not found")
        else:
            logging.info("Found path " + newpath +
                         ".  Attempting to remove it. ")
            try:
                os.rmdir(p)
            except OSError:
                logging.info(newpath +
                             " directory is not empty.  Skipping removal. ")
                pass

        # Clean up bluray backup
        # if job.disctype == "bluray" and cfg["DELRAWFILES"]:
        if job.config.DELRAWFILES:
            try:
                shutil.rmtree(mkvoutpath)
            except UnboundLocalError:
                logging.debug("No raw files found to delete. ")
            except OSError:
                logging.debug("No raw files found to delete. ")

        # report errors if any
        if job.errors:
            errlist = ', '.join(job.errors)
            if job.config.NOTIFY_TRANSCODE:
                utils.notify(
                    job, "ARM notification",
                    str(job.title) +
                    " processing completed with errors. Title(s) " +
                    str(errlist) + " failed to complete. ")
            logging.info("Transcoding completed with errors.  Title(s) " +
                         str(errlist) + " failed to complete. ")
        else:
            if job.config.NOTIFY_TRANSCODE:
                utils.notify(job, "ARM notification",
                             str(job.title) + " processing complete. ")
            logging.info("ARM processing complete")

    elif job.disctype == "music":
        if utils.rip_music(job, logfile):
            utils.notify(
                job, "ARM notification",
                "Music CD: " + str(job.label) + " processing complete. ")
            utils.scan_emby(job)
            #  This shouldnt be needed. but to be safe
            job.status = "success"
            db.session.commit()
        else:
            logging.info("Music rip failed.  See previous errors.  Exiting. ")
            job.eject()
            job.status = "fail"
            db.session.commit()

    elif job.disctype == "data":
        # get filesystem in order
        datapath = os.path.join(job.config.ARMPATH, str(job.label))
        if (utils.make_dir(datapath)) is False:
            ts = str(round(time.time() * 100))
            datapath = os.path.join(job.config.ARMPATH,
                                    str(job.label) + "_" + ts)

            if (utils.make_dir(datapath)) is False:
                logging.info("Could not create data directory: " +
                             str(datapath) + ".  Exiting ARM. ")
                sys.exit()

        if utils.rip_data(job, datapath, logfile):
            utils.notify(
                job, "ARM notification",
                "Data disc: " + str(job.label) + " copying complete. ")
            job.eject()
        else:
            logging.info("Data rip failed.  See previous errors.  Exiting.")
            job.eject()

    else:
        logging.info(
            "Couldn't identify the disc type. Exiting without any action.")
Example #2
0
        else:
            logging.info("Job #" + str(j.job_id) + " with PID " + str(j.pid) +
                         " has been abandoned.  Updating job status to fail.")
            j.status = "fail"
            db.session.commit()

    log_udev_params()

    try:
        main(logfile, job)
    except Exception as e:
        logging.exception(
            "A fatal error has occurred and ARM is exiting.  See traceback below for details."
        )
        utils.notify(
            job, "ARM notification",
            "ARM encountered a fatal error processing " + str(job.title) +
            ". Check the logs for more details. " + str(e))
        job.status = "fail"
        job.eject()
    else:
        job.status = "success"
    finally:
        job.stop_time = datetime.datetime.now()
        joblength = job.stop_time - job.start_time
        minutes, seconds = divmod(joblength.seconds + joblength.days * 86400,
                                  60)
        hours, minutes = divmod(minutes, 60)
        total_len = '{:d}:{:02d}:{:02d}'.format(hours, minutes, seconds)
        job.job_length = total_len
        db.session.commit()
def skip_transcode(job, hb_out_path, hb_in_path, mkv_out_path,
                   type_sub_folder):
    """
    For when skipping transcode in enabled
    """
    logging.info("SKIP_TRANSCODE is true.  Moving raw mkv files.")
    logging.info(
        "NOTE: Identified main feature may not be actual main feature")
    files = os.listdir(mkv_out_path)
    final_directory = hb_out_path
    if job.video_type == "movie":
        logging.debug(f"Videotype: {job.video_type}")
        # if videotype is movie, then move biggest title to media_dir
        # move the rest of the files to the extras folder

        # find largest filesize
        logging.debug("Finding largest file")
        largest_file_name = ""
        for f in files:
            # initialize largest_file_name
            if largest_file_name == "":
                largest_file_name = f
            temp_path_f = os.path.join(hb_in_path, f)
            temp_path_largest = os.path.join(hb_in_path, largest_file_name)
            if os.stat(temp_path_f).st_size > os.stat(
                    temp_path_largest).st_size:
                largest_file_name = f
        # largest_file should be largest file
        logging.debug(f"Largest file is: {largest_file_name}")
        temp_path = os.path.join(hb_in_path, largest_file_name)
        if os.stat(temp_path).st_size > 0:  # sanity check for filesize
            for file in files:
                # move main into media_dir
                # move others into extras folder
                if file == largest_file_name:
                    # largest movie
                    utils.move_files(hb_in_path, file, job, True)
                else:
                    # other extras
                    if not str(cfg["EXTRAS_SUB"]).lower() == "none":
                        utils.move_files(hb_in_path, file, job, False)
                    else:
                        logging.info(f"Not moving extra: {file}")
        # Change final path (used to set permissions)
        final_directory = os.path.join(cfg["COMPLETED_PATH"],
                                       str(type_sub_folder),
                                       f"{job.title} ({job.year})")
        # Clean up
        logging.debug(
            f"Attempting to remove extra folder in TRANSCODE_PATH: {hb_out_path}"
        )
        if hb_out_path != final_directory:
            try:
                shutil.rmtree(hb_out_path)
                logging.debug(f"Removed sucessfully: {hb_out_path}")
            except Exception:
                logging.debug(f"Failed to remove: {hb_out_path}")
    else:
        # if videotype is not movie, then move everything
        # into 'Unidentified' folder
        logging.debug("Videotype: " + job.video_type)

        for f in files:
            mkvoutfile = os.path.join(mkv_out_path, f)
            logging.debug(f"Moving file: {mkvoutfile} to: {hb_out_path} {f}")
            utils.move_files(mkv_out_path, f, job, False)
    # remove raw files, if specified in config
    if cfg["DELRAWFILES"]:
        logging.info("Removing raw files")
        shutil.rmtree(mkv_out_path)

    utils.set_permissions(job, final_directory)
    utils.notify(job, NOTIFY_TITLE, str(job.title) + PROCESS_COMPLETE)
    logging.info("ARM processing complete")
    # WARN  : might cause issues
    # We need to update our job before we quit
    # It should be safe to do this as we aren't waiting for transcode
    job.status = "success"
    job.path = hb_out_path
    db.session.commit()
    job.eject()
    sys.exit()
def main(logfile, job):
    """main disc processing function"""
    logging.info("Starting Disc identification")

    identify.identify(job, logfile)
    # Check db for entries matching the crc and successful
    have_dupes, crc_jobs = utils.job_dupe_check(job)
    logging.debug(f"Value of have_dupes: {have_dupes}")

    utils.notify_entry(job)

    #  If we have have waiting for user input enabled
    if cfg["MANUAL_WAIT"]:
        logging.info(
            f"Waiting {cfg['MANUAL_WAIT_TIME']} seconds for manual override.")
        job.status = "waiting"
        db.session.commit()
        sleep_time = 0
        while sleep_time < cfg["MANUAL_WAIT_TIME"]:
            time.sleep(5)
            sleep_time += 5
            db.session.refresh(job)
            db.session.refresh(config)
            if job.title_manual:
                break
        job.status = "active"
        db.session.commit()

    # If the user has set info manually update database and hasnicetitle
    if job.title_manual:
        logging.info(
            "Manual override found.  Overriding auto identification values.")
        job.updated = True
        # We need to let arm know we have a nice title so it can use the MEDIA folder and not the ARM folder
        job.hasnicetitle = True
    else:
        logging.info("No manual override found.")

    log_arm_params(job)
    check_fstab()
    grabkeys(cfg["HASHEDKEYS"])

    # Entry point for dvd/bluray
    if job.disctype in ["dvd", "bluray"]:
        # get filesystem in order
        # If we have a nice title/confirmed name use the MEDIA_DIR and not the ARM unidentified folder
        # if job.hasnicetitle:
        type_sub_folder = utils.convert_job_type(job.video_type)

        if job.year and job.year != "0000" and job.year != "":
            hb_out_path = os.path.join(
                cfg["TRANSCODE_PATH"], str(type_sub_folder),
                str(job.title) + " (" + str(job.year) + ")")
        else:
            hb_out_path = os.path.join(cfg["TRANSCODE_PATH"],
                                       str(type_sub_folder), str(job.title))

        # The dvd directory already exists - Lets make a new one using random numbers
        if (utils.make_dir(hb_out_path)) is False:
            logging.info(
                f"Handbrake Output directory \"{hb_out_path}\" already exists."
            )
            # Only begin ripping if we are allowed to make duplicates
            # Or the successful rip of the disc is not found in our database
            logging.debug(f"Value of ALLOW_DUPLICATES: {0}".format(
                cfg["ALLOW_DUPLICATES"]))
            logging.debug(f"Value of have_dupes: {have_dupes}")
            if cfg["ALLOW_DUPLICATES"] or not have_dupes:
                ts = round(time.time() * 100)
                hb_out_path = hb_out_path + "_" + str(ts)

                if (utils.make_dir(hb_out_path)) is False:
                    # We failed to make a random directory, most likely a permission issue
                    logging.exception(
                        "A fatal error has occurred and ARM is exiting.  "
                        "Couldn't create filesystem. Possible permission error"
                    )
                    utils.notify(
                        job, NOTIFY_TITLE,
                        "ARM encountered a fatal error processing " +
                        str(job.title) +
                        ".  Couldn't create filesystem. Possible permission error. "
                    )
                    job.status = "fail"
                    db.session.commit()
                    sys.exit()
            else:
                # We arent allowed to rip dupes, notify and exit
                logging.info("Duplicate rips are disabled.")
                utils.notify(
                    job, NOTIFY_TITLE,
                    "ARM Detected a duplicate disc. For " + str(job.title) +
                    ".  Duplicate rips are disabled. You can re-enable them from your config file. "
                )
                job.eject()
                job.status = "fail"
                db.session.commit()
                sys.exit()

        # Use FFMPeg to convert Large Poster if enabled in config
        if job.disctype == "dvd" and cfg["RIP_POSTER"]:
            os.system("mount " + job.devpath)
            if os.path.isfile(job.mountpoint + "/JACKET_P/J00___5L.MP2"):
                logging.info("Converting NTSC Poster Image")
                os.system('ffmpeg -i "' + job.mountpoint +
                          '/JACKET_P/J00___5L.MP2" "' + hb_out_path +
                          '/poster.png"')
            elif os.path.isfile(job.mountpoint + "/JACKET_P/J00___6L.MP2"):
                logging.info("Converting PAL Poster Image")
                os.system('ffmpeg -i "' + job.mountpoint +
                          '/JACKET_P/J00___6L.MP2" "' + hb_out_path +
                          '/poster.png"')
            os.system("umount " + job.devpath)

        logging.info(f"Processing files to: {hb_out_path}")
        mkvoutpath = None
        # entry point for bluray
        # or
        # dvd with MAINFEATURE off and RIPMETHOD mkv
        hb_in_path = str(job.devpath)
        if job.disctype == "bluray" or (not cfg["MAINFEATURE"]
                                        and cfg["RIPMETHOD"] == "mkv"):
            # send to makemkv for ripping
            # run MakeMKV and get path to output
            job.status = "ripping"
            db.session.commit()
            try:
                mkvoutpath = makemkv.makemkv(logfile, job)
            except:  # noqa: E722
                raise

            if mkvoutpath is None:
                logging.error(
                    "MakeMKV did not complete successfully.  Exiting ARM!")
                job.status = "fail"
                db.session.commit()
                sys.exit()
            if cfg["NOTIFY_RIP"]:
                utils.notify(
                    job, NOTIFY_TITLE,
                    f"{job.title} rip complete. Starting transcode. ")
            # point HB to the path MakeMKV ripped to
            hb_in_path = mkvoutpath

            # Entry point for not transcoding
            if cfg["SKIP_TRANSCODE"] and cfg["RIPMETHOD"] == "mkv":
                skip_transcode(job, hb_out_path, hb_in_path, mkvoutpath,
                               type_sub_folder)
        job.path = hb_out_path
        job.status = "transcoding"
        db.session.commit()
        if job.disctype == "bluray" and cfg["RIPMETHOD"] == "mkv":
            handbrake.handbrake_mkv(hb_in_path, hb_out_path, logfile, job)
        elif job.disctype == "dvd" and (not cfg["MAINFEATURE"]
                                        and cfg["RIPMETHOD"] == "mkv"):
            handbrake.handbrake_mkv(hb_in_path, hb_out_path, logfile, job)
        elif job.video_type == "movie" and cfg[
                "MAINFEATURE"] and job.hasnicetitle:
            handbrake.handbrake_mainfeature(hb_in_path, hb_out_path, logfile,
                                            job)
            job.eject()
        else:
            handbrake.handbrake_all(hb_in_path, hb_out_path, logfile, job)
            job.eject()

        # check if there is a new title and change all filenames
        # time.sleep(60)
        db.session.refresh(job)
        logging.debug(f"New Title is {job.title}")
        if job.year and job.year != "0000" and job.year != "":
            final_directory = os.path.join(job.config.COMPLETED_PATH,
                                           str(type_sub_folder),
                                           f'{job.title} ({job.year})')
        else:
            final_directory = os.path.join(job.config.COMPLETED_PATH,
                                           str(type_sub_folder),
                                           str(job.title))

        # move to media directory
        tracks = job.tracks.filter_by(ripped=True)

        if job.video_type == "movie":
            for track in tracks:
                logging.info(
                    f"Moving Movie {track.filename} to {final_directory}")
                if tracks.count() == 1:
                    utils.move_files(hb_out_path, track.filename, job, True)
                else:
                    utils.move_files(hb_out_path, track.filename, job,
                                     track.main_feature)
        # move to media directory
        elif job.video_type == "series":
            for track in tracks:
                logging.info(
                    f"Moving Series {track.filename} to {final_directory}")
                utils.move_files(hb_out_path, track.filename, job, False)
        else:
            for track in tracks:
                logging.info(
                    f"Type is 'unknown' or we dont have a nice title - "
                    f"Moving {track.filename} to {final_directory}")
                if tracks.count() == 1:
                    utils.move_files(hb_out_path, track.filename, job, True)
                else:
                    utils.move_files(hb_out_path, track.filename, job,
                                     track.main_feature)

        # move movie poster
        src_poster = os.path.join(hb_out_path, "poster.png")
        dst_poster = os.path.join(final_directory, "poster.png")
        if os.path.isfile(src_poster):
            if not os.path.isfile(dst_poster):
                try:
                    shutil.move(src_poster, dst_poster)
                except Exception as e:
                    logging.error(
                        f"Unable to move poster.png to '{final_directory}' - Error: {e}"
                    )
            else:
                logging.info("File: poster.png already exists.  Not moving.")

        utils.scan_emby(job)
        utils.set_permissions(job, final_directory)

        # Clean up bluray backup
        if cfg["DELRAWFILES"]:
            raw_list = [mkvoutpath, hb_out_path, hb_in_path]
            for raw_folder in raw_list:
                try:
                    logging.info(f"Removing raw path - {raw_folder}")
                    if raw_folder != final_directory:
                        shutil.rmtree(raw_folder)
                except UnboundLocalError as e:
                    logging.debug(
                        f"No raw files found to delete in {raw_folder}- {e}")
                except OSError as e:
                    logging.debug(
                        f"No raw files found to delete in {raw_folder} - {e}")
                except TypeError as e:
                    logging.debug(
                        f"No raw files found to delete in {raw_folder} - {e}")
        # report errors if any
        if cfg["NOTIFY_TRANSCODE"]:
            if job.errors:
                errlist = ', '.join(job.errors)
                utils.notify(
                    job, NOTIFY_TITLE,
                    f" {job.title} processing completed with errors. "
                    f"Title(s) {errlist} failed to complete. ")
                logging.info(
                    f"Transcoding completed with errors.  Title(s) {errlist} failed to complete. "
                )
            else:
                utils.notify(job, NOTIFY_TITLE,
                             str(job.title) + PROCESS_COMPLETE)

        logging.info("ARM processing complete")

    elif job.disctype == "music":
        if utils.rip_music(job, logfile):
            utils.notify(job, NOTIFY_TITLE,
                         f"Music CD: {job.label} {PROCESS_COMPLETE}")
            utils.scan_emby(job)
            # This shouldnt be needed. but to be safe
            job.status = "success"
            db.session.commit()
        else:
            logging.info("Music rip failed.  See previous errors.  Exiting. ")
            job.eject()
            job.status = "fail"
            db.session.commit()

    elif job.disctype == "data":
        # get filesystem in order
        datapath = os.path.join(cfg["RAW_PATH"], str(job.label))
        if (utils.make_dir(datapath)) is False:
            ts = str(round(time.time() * 100))
            datapath = os.path.join(cfg["RAW_PATH"], str(job.label) + "_" + ts)

            if (utils.make_dir(datapath)) is False:
                logging.info(
                    f"Could not create data directory: {datapath}  Exiting ARM. "
                )
                sys.exit()

        if utils.rip_data(job, datapath, logfile):
            utils.notify(job, NOTIFY_TITLE,
                         f"Data disc: {job.label} copying complete. ")
            job.eject()
        else:
            logging.info("Data rip failed.  See previous errors.  Exiting.")
            job.eject()

    else:
        logging.info(
            "Couldn't identify the disc type. Exiting without any action.")
    job.arm_version = version
    logging.info(("Python version: " + sys.version).replace('\n', ""))
    logging.info(f"User is: {getpass.getuser()}")
    logger.clean_up_logs(cfg["LOGPATH"], cfg["LOGLIFE"])
    logging.info(f"Job: {job.label}")
    utils.clean_old_jobs()
    log_udev_params(devpath)

    try:
        main(logfile, job)
    except Exception as e:
        logging.exception(
            "A fatal error has occurred and ARM is exiting.  See traceback below for details."
        )
        utils.notify(
            job, NOTIFY_TITLE, "ARM encountered a fatal error processing "
            f"{job.title}. Check the logs for more details. {e}")
        job.status = "fail"
        job.eject()
    else:
        job.status = "success"
    finally:
        job.stop_time = datetime.datetime.now()
        joblength = job.stop_time - job.start_time
        minutes, seconds = divmod(joblength.seconds + joblength.days * 86400,
                                  60)
        hours, minutes = divmod(minutes, 60)
        total_len = '{:d}:{:02d}:{:02d}'.format(hours, minutes, seconds)
        job.job_length = total_len
        db.session.commit()
Example #6
0
def main(logfile, job):
    """main dvd processing function"""
    logging.info("Starting Disc identification")

    identify.identify(job, logfile)

    if job.disctype in ["dvd", "bluray"]:
        utils.notify(
            job, "ARM notification", "Found disc: " + str(job.title) +
            ". Video type is " + str(job.video_type) + ". Main Feature is " +
            str(job.config.MAINFEATURE) + ".  Edit entry here: http://" +
            job.config.WEBSERVER_IP + ":" + str(job.config.WEBSERVER_PORT))
    elif job.disctype == "music":
        utils.notify(job, "ARM notification",
                     "Found music CD: " + job.label + ". Ripping all tracks")
    elif job.disctype == "data":
        utils.notify(job, "ARM notification",
                     "Found data disc.  Copying data.")
    else:
        utils.notify(job, "ARM Notification",
                     "Could not identify disc.  Exiting.")
        sys.exit()

    if job.config.MANUAL_WAIT:
        logging.info("Waiting " + str(job.config.MANUAL_WAIT_TIME) +
                     " seconds for manual override.")
        job.status = "waiting"
        db.session.commit()
        time.sleep(job.config.MANUAL_WAIT_TIME)
        db.session.refresh(job)
        db.session.refresh(config)
        job.status = "active"
        db.session.commit()

    if job.title_manual:
        logging.info(
            "Manual override found.  Overriding auto identification values.")
        job.updated = True
        job.hasnicetitle = True
    else:
        logging.info("No manual override found.")

    log_arm_params(job)

    check_fstab()

    if job.config.HASHEDKEYS:
        logging.info("Getting MakeMKV hashed keys for UHD rips")
        grabkeys()

    if job.disctype in ["dvd", "bluray"]:
        # get filesystem in order
        hboutpath = os.path.join(job.config.ARMPATH, str(job.title))

        if (utils.make_dir(hboutpath)) is False:
            ts = round(time.time() * 100)
            hboutpath = os.path.join(job.config.ARMPATH,
                                     str(job.title) + "_" + str(ts))
            if (utils.make_dir(hboutpath)) is False:
                logging.info("Failed to create base directory.  Exiting ARM.")
                sys.exit()

        logging.info("Processing files to: " + hboutpath)

        # Do the work!
        hbinpath = str(job.devpath)
        if job.disctype == "bluray" or (not job.config.MAINFEATURE
                                        and job.config.RIPMETHOD == "mkv"):
            # send to makemkv for ripping
            # run MakeMKV and get path to ouput
            job.status = "ripping"
            db.session.commit()
            try:
                mkvoutpath = makemkv.makemkv(logfile, job)
            except:  # noqa: E772
                raise

            if mkvoutpath is None:
                logging.error(
                    "MakeMKV did not complete successfully.  Exiting ARM!")
                sys.exit()
            if job.config.NOTIFY_RIP:
                utils.notify(
                    job, "ARM notification",
                    str(job.title + " rip complete.  Starting transcode."))
            # point HB to the path MakeMKV ripped to
            hbinpath = mkvoutpath

            if job.config.SKIP_TRANSCODE and job.config.RIPMETHOD == "mkv":
                logging.info("SKIP_TRANSCODE is true.  Moving raw mkv files.")
                logging.info(
                    "NOTE: Identified main feature may not be actual main feature"
                )
                files = os.listdir(mkvoutpath)
                final_directory = hboutpath
                if job.video_type == "movie":
                    logging.debug("Videotype: " + job.video_type)
                    # if videotype is movie, then move biggest title to media_dir
                    # move the rest of the files to the extras folder

                    # find largest filesize
                    logging.debug("Finding largest file")
                    largest_file_name = ""
                    for f in files:
                        # initialize largest_file_name
                        if largest_file_name == "":
                            largest_file_name = f
                        temp_path_f = os.path.join(hbinpath, f)
                        temp_path_largest = os.path.join(
                            hbinpath, largest_file_name)
                        # os.path.join(cfg['MEDIA_DIR'] + videotitle)
                        # if cur file size > largest_file size
                        if (os.stat(temp_path_f).st_size >
                                os.stat(temp_path_largest).st_size):
                            largest_file_name = f
                    # largest_file should be largest file
                    logging.debug("Largest file is: " + largest_file_name)
                    temp_path = os.path.join(hbinpath, largest_file_name)
                    if (os.stat(temp_path).st_size >
                            0):  # sanity check for filesize
                        for f in files:
                            # move main into media_dir
                            # move others into extras folder
                            if (f == largest_file_name):
                                # largest movie
                                utils.move_files(hbinpath, f, job.hasnicetitle,
                                                 job, True)
                            else:
                                # other extras
                                if not str(job.config.EXTRAS_SUB).lower(
                                ) == "none":
                                    utils.move_files(hbinpath, f,
                                                     job.hasnicetitle, job,
                                                     False)
                                else:
                                    logging.info("Not moving extra: " + f)
                    # Change final path (used to set permissions)
                    final_directory = os.path.join(
                        job.config.MEDIA_DIR,
                        job.title + " (" + str(job.year) + ")")
                    # Clean up
                    logging.debug(
                        "Attempting to remove extra folder in ARMPATH: " +
                        hboutpath)
                    try:
                        shutil.rmtree(hboutpath)
                        logging.debug("Removed sucessfully: " + hboutpath)
                    except Exception:
                        logging.debug("Failed to remove: " + hboutpath)
                else:
                    # if videotype is not movie, then move everything
                    # into 'Unidentified' folder
                    logging.debug("Videotype: " + job.video_type)

                    for f in files:
                        mkvoutfile = os.path.join(mkvoutpath, f)
                        logging.debug("Moving file: " + mkvoutfile + " to: " +
                                      mkvoutpath + f)
                        shutil.move(mkvoutfile, hboutpath)
                # remove raw files, if specified in config
                if job.config.DELRAWFILES:
                    logging.info("Removing raw files")
                    shutil.rmtree(mkvoutpath)
                # set file to default permissions '777'
                if job.config.SET_MEDIA_PERMISSIONS:
                    perm_result = utils.set_permissions(job, final_directory)
                    logging.info("Permissions set successfully: " +
                                 str(perm_result))
                utils.notify(job, "ARM notification",
                             str(job.title) + " processing complete.")
                logging.info("ARM processing complete")
                # exit
                sys.exit()

        job.status = "transcoding"
        db.session.commit()
        if job.disctype == "bluray" and job.config.RIPMETHOD == "mkv":
            handbrake.handbrake_mkv(hbinpath, hboutpath, logfile, job)
        elif job.disctype == "dvd" and (not job.config.MAINFEATURE
                                        and job.config.RIPMETHOD == "mkv"):
            handbrake.handbrake_mkv(hbinpath, hboutpath, logfile, job)
        elif job.video_type == "movie" and job.config.MAINFEATURE and job.hasnicetitle:
            handbrake.handbrake_mainfeature(hbinpath, hboutpath, logfile, job)
            job.eject()
        else:
            handbrake.handbrake_all(hbinpath, hboutpath, logfile, job)
            job.eject()

        # get rid of this
        # if not titles_in_out:
        #     pass

        # check if there is a new title and change all filenames
        # time.sleep(60)
        db.session.refresh(job)
        logging.debug("New Title is " + str(job.title_manual))
        if job.title_manual and not job.updated:
            newpath = utils.rename_files(hboutpath, job)
            p = newpath
        else:
            p = hboutpath

        # move to media directory
        if job.video_type == "movie" and job.hasnicetitle:
            # tracks = job.tracks.all()
            tracks = job.tracks.filter_by(ripped=True)
            for track in tracks:
                utils.move_files(p, track.filename, job, track.main_feature)

            utils.scan_emby(job)

        # remove empty directories
        try:
            os.rmdir(hboutpath)
        except OSError:
            logging.info(hboutpath +
                         " directory is not empty.  Skipping removal.")
            pass

        try:
            newpath
        except NameError:
            logging.debug("'newpath' directory not found")
        else:
            logging.info("Found path " + newpath +
                         ".  Attempting to remove it.")
            try:
                os.rmdir(p)
            except OSError:
                logging.info(newpath +
                             " directory is not empty.  Skipping removal.")
                pass

        # Clean up bluray backup
        # if job.disctype == "bluray" and cfg["DELRAWFILES"]:
        if job.config.DELRAWFILES:
            try:
                shutil.rmtree(mkvoutpath)
            except UnboundLocalError:
                logging.debug("No raw files found to delete.")
            except OSError:
                logging.debug("No raw files found to delete.")

        # report errors if any
        if job.errors:
            errlist = ', '.join(job.errors)
            if job.config.NOTIFY_TRANSCODE:
                utils.notify(
                    job, "ARM notification",
                    str(job.title) +
                    " processing completed with errors. Title(s) " + errlist +
                    " failed to complete.")
            logging.info("Transcoding completed with errors.  Title(s) " +
                         errlist + " failed to complete.")
        else:
            if job.config.NOTIFY_TRANSCODE:
                utils.notify(job, "ARM notification",
                             str(job.title) + " processing complete.")
            logging.info("ARM processing complete")

    elif job.disctype == "music":
        if utils.rip_music(job, logfile):
            utils.notify(job, "ARM notification",
                         "Music CD: " + job.label + " processing complete.")
            utils.scan_emby(job)
        else:
            logging.info("Music rip failed.  See previous errors.  Exiting.")

    elif job.disctype == "data":
        # get filesystem in order
        datapath = os.path.join(job.config.ARMPATH, str(job.label))
        if (utils.make_dir(datapath)) is False:
            ts = round(time.time() * 100)
            datapath = os.path.join(job.config.ARMPATH,
                                    str(job.label) + "_" + str(ts))

            if (utils.make_dir(datapath)) is False:
                logging.info("Could not create data directory: " + datapath +
                             ".  Exiting ARM.")
                sys.exit()

        if utils.rip_data(job, datapath, logfile):
            utils.notify(job, "ARM notification",
                         "Data disc: " + job.label + " copying complete.")
            job.eject()
        else:
            logging.info("Data rip failed.  See previous errors.  Exiting.")
            job.eject()

    else:
        logging.info(
            "Couldn't identify the disc type. Exiting without any action.")