Merge branch 'feature/scene-naming-option'

This commit is contained in:
Andy
2025-08-03 00:48:22 +00:00
5 changed files with 166 additions and 134 deletions

View File

@@ -80,6 +80,7 @@ class Config:
self.tmdb_api_key: str = kwargs.get("tmdb_api_key") or "" self.tmdb_api_key: str = kwargs.get("tmdb_api_key") or ""
self.update_checks: bool = kwargs.get("update_checks", True) self.update_checks: bool = kwargs.get("update_checks", True)
self.update_check_interval: int = kwargs.get("update_check_interval", 24) self.update_check_interval: int = kwargs.get("update_check_interval", 24)
self.scene_naming: bool = kwargs.get("scene_naming", True)
@classmethod @classmethod
def from_yaml(cls, path: Path) -> Config: def from_yaml(cls, path: Path) -> Config:

View File

@@ -107,75 +107,86 @@ class Episode(Title):
name=self.name or "", name=self.name or "",
).strip() ).strip()
# Resolution if config.scene_naming:
if primary_video_track: # Resolution
resolution = primary_video_track.height if primary_video_track:
aspect_ratio = [int(float(plane)) for plane in primary_video_track.other_display_aspect_ratio[0].split(":")] resolution = primary_video_track.height
if len(aspect_ratio) == 1: aspect_ratio = [
# e.g., aspect ratio of 2 (2.00:1) would end up as `(2.0,)`, add 1 int(float(plane)) for plane in primary_video_track.other_display_aspect_ratio[0].split(":")
aspect_ratio.append(1) ]
if aspect_ratio[0] / aspect_ratio[1] not in (16 / 9, 4 / 3): if len(aspect_ratio) == 1:
# We want the resolution represented in a 4:3 or 16:9 canvas. # e.g., aspect ratio of 2 (2.00:1) would end up as `(2.0,)`, add 1
# If it's not 4:3 or 16:9, calculate as if it's inside a 16:9 canvas, aspect_ratio.append(1)
# otherwise the track's height value is fine. if aspect_ratio[0] / aspect_ratio[1] not in (16 / 9, 4 / 3):
# We are assuming this title is some weird aspect ratio so most # We want the resolution represented in a 4:3 or 16:9 canvas.
# likely a movie or HD source, so it's most likely widescreen so # If it's not 4:3 or 16:9, calculate as if it's inside a 16:9 canvas,
# 16:9 canvas makes the most sense. # otherwise the track's height value is fine.
resolution = int(primary_video_track.width * (9 / 16)) # We are assuming this title is some weird aspect ratio so most
name += f" {resolution}p" # likely a movie or HD source, so it's most likely widescreen so
# 16:9 canvas makes the most sense.
resolution = int(primary_video_track.width * (9 / 16))
name += f" {resolution}p"
# Service # Service
if show_service: if show_service:
name += f" {self.service.__name__}" name += f" {self.service.__name__}"
# 'WEB-DL' # 'WEB-DL'
name += " WEB-DL" name += " WEB-DL"
# DUAL # DUAL
if unique_audio_languages == 2: if unique_audio_languages == 2:
name += " DUAL" name += " DUAL"
# MULTi # MULTi
if unique_audio_languages > 2: if unique_audio_languages > 2:
name += " MULTi" name += " MULTi"
# Audio Codec + Channels (+ feature) # Audio Codec + Channels (+ feature)
if primary_audio_track: if primary_audio_track:
codec = primary_audio_track.format codec = primary_audio_track.format
channel_layout = primary_audio_track.channel_layout or primary_audio_track.channellayout_original channel_layout = primary_audio_track.channel_layout or primary_audio_track.channellayout_original
if channel_layout: if channel_layout:
channels = float(sum({"LFE": 0.1}.get(position.upper(), 1) for position in channel_layout.split(" "))) channels = float(
else: sum({"LFE": 0.1}.get(position.upper(), 1) for position in channel_layout.split(" "))
channel_count = primary_audio_track.channel_s or primary_audio_track.channels or 0 )
channels = float(channel_count)
features = primary_audio_track.format_additionalfeatures or ""
name += f" {AUDIO_CODEC_MAP.get(codec, codec)}{channels:.1f}"
if "JOC" in features or primary_audio_track.joc:
name += " Atmos"
# Video (dynamic range + hfr +) Codec
if primary_video_track:
codec = primary_video_track.format
hdr_format = primary_video_track.hdr_format_commercial
trc = primary_video_track.transfer_characteristics or primary_video_track.transfer_characteristics_original
frame_rate = float(primary_video_track.frame_rate)
if hdr_format:
if (primary_video_track.hdr_format or "").startswith("Dolby Vision"):
if (primary_video_track.hdr_format_commercial) != "Dolby Vision":
name += f" DV {DYNAMIC_RANGE_MAP.get(hdr_format)} "
else: else:
name += f" {DYNAMIC_RANGE_MAP.get(hdr_format)} " channel_count = primary_audio_track.channel_s or primary_audio_track.channels or 0
elif trc and "HLG" in trc: channels = float(channel_count)
name += " HLG"
if frame_rate > 30:
name += " HFR"
name += f" {VIDEO_CODEC_MAP.get(codec, codec)}"
if config.tag: features = primary_audio_track.format_additionalfeatures or ""
name += f"-{config.tag}" name += f" {AUDIO_CODEC_MAP.get(codec, codec)}{channels:.1f}"
if "JOC" in features or primary_audio_track.joc:
name += " Atmos"
return sanitize_filename(name) # Video (dynamic range + hfr +) Codec
if primary_video_track:
codec = primary_video_track.format
hdr_format = primary_video_track.hdr_format_commercial
trc = (
primary_video_track.transfer_characteristics
or primary_video_track.transfer_characteristics_original
)
frame_rate = float(primary_video_track.frame_rate)
if hdr_format:
if (primary_video_track.hdr_format or "").startswith("Dolby Vision"):
if (primary_video_track.hdr_format_commercial) != "Dolby Vision":
name += f" DV {DYNAMIC_RANGE_MAP.get(hdr_format)} "
else:
name += f" {DYNAMIC_RANGE_MAP.get(hdr_format)} "
elif trc and "HLG" in trc:
name += " HLG"
if frame_rate > 30:
name += " HFR"
name += f" {VIDEO_CODEC_MAP.get(codec, codec)}"
if config.tag:
name += f"-{config.tag}"
return sanitize_filename(name)
else:
# Simple naming style without technical details - use spaces instead of dots
return sanitize_filename(name, " ")
class Series(SortedKeyList, ABC): class Series(SortedKeyList, ABC):

View File

@@ -58,75 +58,86 @@ class Movie(Title):
# Name (Year) # Name (Year)
name = str(self).replace("$", "S") # e.g., Arli$$ name = str(self).replace("$", "S") # e.g., Arli$$
# Resolution if config.scene_naming:
if primary_video_track: # Resolution
resolution = primary_video_track.height if primary_video_track:
aspect_ratio = [int(float(plane)) for plane in primary_video_track.other_display_aspect_ratio[0].split(":")] resolution = primary_video_track.height
if len(aspect_ratio) == 1: aspect_ratio = [
# e.g., aspect ratio of 2 (2.00:1) would end up as `(2.0,)`, add 1 int(float(plane)) for plane in primary_video_track.other_display_aspect_ratio[0].split(":")
aspect_ratio.append(1) ]
if aspect_ratio[0] / aspect_ratio[1] not in (16 / 9, 4 / 3): if len(aspect_ratio) == 1:
# We want the resolution represented in a 4:3 or 16:9 canvas. # e.g., aspect ratio of 2 (2.00:1) would end up as `(2.0,)`, add 1
# If it's not 4:3 or 16:9, calculate as if it's inside a 16:9 canvas, aspect_ratio.append(1)
# otherwise the track's height value is fine. if aspect_ratio[0] / aspect_ratio[1] not in (16 / 9, 4 / 3):
# We are assuming this title is some weird aspect ratio so most # We want the resolution represented in a 4:3 or 16:9 canvas.
# likely a movie or HD source, so it's most likely widescreen so # If it's not 4:3 or 16:9, calculate as if it's inside a 16:9 canvas,
# 16:9 canvas makes the most sense. # otherwise the track's height value is fine.
resolution = int(primary_video_track.width * (9 / 16)) # We are assuming this title is some weird aspect ratio so most
name += f" {resolution}p" # likely a movie or HD source, so it's most likely widescreen so
# 16:9 canvas makes the most sense.
resolution = int(primary_video_track.width * (9 / 16))
name += f" {resolution}p"
# Service # Service
if show_service: if show_service:
name += f" {self.service.__name__}" name += f" {self.service.__name__}"
# 'WEB-DL' # 'WEB-DL'
name += " WEB-DL" name += " WEB-DL"
# DUAL # DUAL
if unique_audio_languages == 2: if unique_audio_languages == 2:
name += " DUAL" name += " DUAL"
# MULTi # MULTi
if unique_audio_languages > 2: if unique_audio_languages > 2:
name += " MULTi" name += " MULTi"
# Audio Codec + Channels (+ feature) # Audio Codec + Channels (+ feature)
if primary_audio_track: if primary_audio_track:
codec = primary_audio_track.format codec = primary_audio_track.format
channel_layout = primary_audio_track.channel_layout or primary_audio_track.channellayout_original channel_layout = primary_audio_track.channel_layout or primary_audio_track.channellayout_original
if channel_layout: if channel_layout:
channels = float(sum({"LFE": 0.1}.get(position.upper(), 1) for position in channel_layout.split(" "))) channels = float(
else: sum({"LFE": 0.1}.get(position.upper(), 1) for position in channel_layout.split(" "))
channel_count = primary_audio_track.channel_s or primary_audio_track.channels or 0 )
channels = float(channel_count)
features = primary_audio_track.format_additionalfeatures or ""
name += f" {AUDIO_CODEC_MAP.get(codec, codec)}{channels:.1f}"
if "JOC" in features or primary_audio_track.joc:
name += " Atmos"
# Video (dynamic range + hfr +) Codec
if primary_video_track:
codec = primary_video_track.format
hdr_format = primary_video_track.hdr_format_commercial
trc = primary_video_track.transfer_characteristics or primary_video_track.transfer_characteristics_original
frame_rate = float(primary_video_track.frame_rate)
if hdr_format:
if (primary_video_track.hdr_format or "").startswith("Dolby Vision"):
if (primary_video_track.hdr_format_commercial) != "Dolby Vision":
name += f" DV {DYNAMIC_RANGE_MAP.get(hdr_format)} "
else: else:
name += f" {DYNAMIC_RANGE_MAP.get(hdr_format)} " channel_count = primary_audio_track.channel_s or primary_audio_track.channels or 0
elif trc and "HLG" in trc: channels = float(channel_count)
name += " HLG"
if frame_rate > 30:
name += " HFR"
name += f" {VIDEO_CODEC_MAP.get(codec, codec)}"
if config.tag: features = primary_audio_track.format_additionalfeatures or ""
name += f"-{config.tag}" name += f" {AUDIO_CODEC_MAP.get(codec, codec)}{channels:.1f}"
if "JOC" in features or primary_audio_track.joc:
name += " Atmos"
return sanitize_filename(name) # Video (dynamic range + hfr +) Codec
if primary_video_track:
codec = primary_video_track.format
hdr_format = primary_video_track.hdr_format_commercial
trc = (
primary_video_track.transfer_characteristics
or primary_video_track.transfer_characteristics_original
)
frame_rate = float(primary_video_track.frame_rate)
if hdr_format:
if (primary_video_track.hdr_format or "").startswith("Dolby Vision"):
if (primary_video_track.hdr_format_commercial) != "Dolby Vision":
name += f" DV {DYNAMIC_RANGE_MAP.get(hdr_format)} "
else:
name += f" {DYNAMIC_RANGE_MAP.get(hdr_format)} "
elif trc and "HLG" in trc:
name += " HLG"
if frame_rate > 30:
name += " HFR"
name += f" {VIDEO_CODEC_MAP.get(codec, codec)}"
if config.tag:
name += f"-{config.tag}"
return sanitize_filename(name)
else:
# Simple naming style without technical details - use spaces instead of dots
return sanitize_filename(name, " ")
class Movies(SortedKeyList, ABC): class Movies(SortedKeyList, ABC):

View File

@@ -100,22 +100,26 @@ class Song(Title):
# NN. Song Name # NN. Song Name
name = str(self).split(" / ")[1] name = str(self).split(" / ")[1]
# Service if config.scene_naming:
if show_service: # Service
name += f" {self.service.__name__}" if show_service:
name += f" {self.service.__name__}"
# 'WEB-DL' # 'WEB-DL'
name += " WEB-DL" name += " WEB-DL"
# Audio Codec + Channels (+ feature) # Audio Codec + Channels (+ feature)
name += f" {AUDIO_CODEC_MAP.get(codec, codec)}{channels:.1f}" name += f" {AUDIO_CODEC_MAP.get(codec, codec)}{channels:.1f}"
if "JOC" in features or audio_track.joc: if "JOC" in features or audio_track.joc:
name += " Atmos" name += " Atmos"
if config.tag: if config.tag:
name += f"-{config.tag}" name += f"-{config.tag}"
return sanitize_filename(name, " ") return sanitize_filename(name, " ")
else:
# Simple naming style without technical details
return sanitize_filename(name, " ")
class Album(SortedKeyList, ABC): class Album(SortedKeyList, ABC):

View File

@@ -4,6 +4,11 @@ tag: user_tag
# Set terminal background color (custom option not in CONFIG.md) # Set terminal background color (custom option not in CONFIG.md)
set_terminal_bg: false set_terminal_bg: false
# Set file naming convention
# true for style - Prime.Suspect.S07E01.The.Final.Act.Part.One.1080p.ITV.WEB-DL.AAC2.0.H.264
# false for style - Prime Suspect S07E01 The Final Act - Part One
scene_naming: true
# Check for updates from GitHub repository on startup (default: true) # Check for updates from GitHub repository on startup (default: true)
update_checks: true update_checks: true