Last active
January 5, 2025 19:43
-
-
Save cleverdevil/3517f75cca4f94bc4256a8f3ab007156 to your computer and use it in GitHub Desktop.
Dolby Vision Tagger for Plex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
Dolby Vision Tagger for Plex | |
============================ | |
This script walks your Plex server's libraries and tags Dolby Vision Profile | |
and Enhancement Layer details by attaching a label. The label will be of | |
format: | |
Dolby Vision P{profile number} {enhancement layer} | |
For example, a video with DV P7 FEL would receive the label: | |
Dolby Vision P7 FEL | |
Optionally, the script will attach a general "Dolby Vision" label in addition | |
to the detailed label. | |
In order to use the script you need to set configuration variables: | |
Plex Token: | |
https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/ | |
Plex Server URL: | |
If run on your Plex server, you can usually use the default, http://127.0.0.1:32400 | |
Binaries Path | |
The full path to the directory containing your `ffmpeg6` and `dovi_tool` | |
binaries. You can find `dovi_tool` here: https://github.com/quietvoid/dovi_tool | |
General Label | |
True if you want to tag all Dolby Vision videos with a general 'Dolby | |
Vision' label, otherwise False | |
This script requires a Python 3.7+ environment with the `plexapi` library | |
installed and has only been tested on Linux, specifically on a Synology NAS | |
running DSM7. | |
''' | |
import os | |
import pathlib | |
import subprocess | |
import json | |
from plexapi.server import PlexServer | |
# Configuration - Set your values here | |
PLEX_TOKEN = 'xxxxx-xxxxx-xxxxxx' | |
PLEX_SERVER_URL = 'http://127.0.0.1:32400' | |
BINARIES_PATH = '/path/to/binaries' | |
LIBRARIES = ['Movies'] | |
GENERAL_LABEL = True | |
# Open Plex API and prepare for tagging | |
plex = PlexServer(PLEX_SERVER_URL, PLEX_TOKEN) | |
binaries = pathlib.Path(BINARIES_PATH) | |
# Loop through library sections as specified in our configuration | |
for library in LIBRARIES: | |
# Get reference to the library with the specified name | |
videos = plex.library.section(library) | |
# Iterate through all videos in the library section and tag them | |
for video in videos.all(): | |
# First, run `ffmpeg6` on the file, extracting the first second | |
# of the video to stdout, capturing the output | |
path = video.locations[0] | |
ffmpeg = [ | |
binaries / 'ffmpeg6', | |
'-i', f'{path}', '-c:v', 'copy', '-to', '1', '-f', 'hevc', '-y', '-' | |
] | |
ffmpeg_result = subprocess.run(ffmpeg, capture_output=True) | |
# Feed the output from `ffmpeg6` into `dovi_tool` to extract the RPU | |
dovi_tool = [binaries / 'dovi_tool', 'extract-rpu', '-', '-o', '/tmp/RPU.bin'] | |
dovi_result = subprocess.run(dovi_tool, input=ffmpeg_result.stdout, capture_output=True) | |
# If the file does not have Dolby Vision, skip it | |
if dovi_result.returncode != 0: | |
continue | |
# Extract Dolby Vision detail from the RPU file | |
dovi_tool = [binaries / 'dovi_tool', 'info', '-i', '/tmp/RPU.bin', '-f', '0'] | |
dovi_result = subprocess.run(dovi_tool, capture_output=True) | |
# If we are unable to extract any detail, skip the file | |
if dovi_result.returncode != 0: | |
continue | |
# Get the output from `dovi_tool` and parse it | |
output = dovi_result.stdout.decode('utf-8') | |
metadata = json.loads(output.split('\n', 1)[1]) | |
# Collect any existing labels attached to the video in Plex | |
labels = [l.tag.lower() for l in video.labels] | |
# Identify Dolby Vision Profile number and Enhancement Layer type, if any | |
dv_profile = metadata['dovi_profile'] | |
dv_el_type = metadata.get('el_type', '') | |
# Generate the label for this profile and enhancement layer | |
label = f'Dolby Vision P{dv_profile} {dv_el_type}'.strip() | |
# Attach the label to the video if necessary | |
if label.lower() not in labels: | |
print(f'Tagging {video.title} -> {label}') | |
video.addLabel(label) | |
# Attach the general label to the video if necessary | |
if GENERAL_LABEL and 'dolby vision' not in labels: | |
print(f'Tagging {video.title} -> Dolby Vision') | |
video.addLabel('Dolby Vision') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment