**A python script that is used to automatically re-encode TV show episodes using h265. **

The script is run from cron once per week to re-encode any episodes that sonarr has downloaded in the preceding week and has the following features:

  • Uses a file called handbrake-preset.txt in the show folder to determine the preset used for that show
  • Falls back to a top-level handbrake-preset.txt if one does not exist for the show
  • Does not re-encode files that have already been re-encoded, including files that have yet to be post-processed
  • Sends an email when all the episodes for a show have been re-encoded
  • Allows calling with one or more folder names, useful to limit the shows it will process while re-encoding a backlog of shows

Once the episodes have been re-encoded using this script I pass them through FileBot to rename them to a Plex supported format and then I manually replace the files in the Plex folders with the re-encoded versions. This allows me to keep an eye on the process and correct any errors.

The FileBot name format string is {n} - {s00e00} - {t} [h265-{vf}]

#!/usr/bin/env python3
#
# Encode TV shows using HandbrakeCLI to the pre-determined quality profile for each show.
#
# Darryl Ross <d@vk3go.au>, April 2022
#

import pathlib
import smtplib
import subprocess
import sys


BASE_PATH = pathlib.Path("<REPLACE WITH TOP LEVEL SHOW FOLDER>")
OUTPUT_PATH = pathlib.Path("<REPLACE WITH FOLDER TO SAVE ENCODED FILES>")
EMAIL_FROM = "<REPLACE>"
EMAIL_TO = "<REPLACE>"
EMAIL_HOST = "<REPLACE>"
EMAIL_PORT = 587
EMAIL_USER = "<REPLACE>"
EMAIL_PASS = "<REPLACE>"


if len(sys.argv) > 1:  # One or more folders passed in
    show_folder_list = sorted([pathlib.Path(p) for p in sys.argv[1:]])
else:  # No folders passed in, just process all the TV shows
    show_folder_list = sorted(BASE_PATH.iterdir())


for show_folder in show_folder_list:
    if not show_folder.is_dir():
        continue

    file_list = [
        f
        for f in sorted(show_folder.rglob("*.*"))
        if (
            not f.match("*[[]h265-*[]]*")
            and not f.match("*.nfo")
            and not f.match("*.srt")
            and not f.match("handbrake-preset.txt")
        )
    ]

    if not file_list:
        continue

    if show_folder.joinpath("handbrake-preset.txt").exists():
        handbrake_preset = show_folder.joinpath("handbrake-preset.txt").read_text().strip()
    else:
        handbrake_preset = BASE_PATH.joinpath("handbrake-preset.txt").read_text().strip()

    processed_list = []
    for file_name in file_list:
        output_file = OUTPUT_PATH.joinpath(f"{file_name.stem} [{handbrake_preset}].mkv")
        if output_file.exists():
            continue

        retval = subprocess.call(
            [
                "flatpak",
                "run",
                "--command=HandBrakeCLI",
                "fr.handbrake.ghb",
                "-i",
                file_name,
                "-o",
                output_file,
                "--preset",
                handbrake_preset,
                "--encoder",
                "qsv_h265_10bit",
                "--aencoder",
                "copy",
                "--all-audio",
            ]
        )
        if retval == 0:
            processed_list.append(file_name.stem)

    if processed_list:
        body = "\n".join(
            [
                f"From: {EMAIL_FROM}",
                f"To: {EMAIL_TO}",
                f"Subject: Finished Encoding Episodes for '{show_folder.stem}'",
                "",
                f"Encoded the following files using preset {handbrake_preset}:",
                "",
            ]
            + processed_list
        )

        conn = smtplib.SMTP(EMAIL_HOST, EMAIL_PORT)
        conn.starttls()
        conn.login(EMAIL_USER, EMAIL_PASS)
        conn.sendmail(EMAIL_FROM, [EMAIL_TO], body)
        conn.quit()

Comments

There are no comments yet. Please log in to post a comment.
Written By
vk3go
Tags
handbrake
Posted
24 Apr 2022

Previous Article:
VK3GO APRS Fill-In Digipeater