Add decorators for formatting various media attributes

- Introduced `DurationDecorators` for full and short duration formatting.
- Added `ExtensionDecorators` for formatting extension information.
- Created `ResolutionDecorators` for formatting resolution dimensions.
- Implemented `SizeDecorators` for full and short size formatting.
- Enhanced `TextDecorators` with additional formatting options including blue and grey text, URL formatting, and escaping rich markup.
- Developed `TrackDecorators` for formatting video, audio, and subtitle track data.
- Refactored `MediaPanelView` to utilize a new `MediaPanelProperties` class for cleaner property management and formatting.
- Updated `media_panel_properties.py` to include formatted properties for file info, TMDB data, metadata extraction, media info extraction, and filename extraction.
- Bumped version to 0.6.5 in `uv.lock`.
This commit is contained in:
sha
2026-01-03 10:13:17 +00:00
parent 6bca3c224d
commit 917d25b360
15 changed files with 894 additions and 422 deletions
+113 -407
View File
@@ -1,14 +1,5 @@
from pathlib import Path
from rich.markup import escape
from ..formatters.size_formatter import SizeFormatter
from ..formatters.date_formatter import DateFormatter
from ..formatters.extension_formatter import ExtensionFormatter
from ..formatters.text_formatter import TextFormatter
from ..formatters.track_formatter import TrackFormatter
from ..formatters.resolution_formatter import ResolutionFormatter
from ..formatters.duration_formatter import DurationFormatter
from ..formatters.special_info_formatter import SpecialInfoFormatter
from ..formatters.formatter import FormatterApplier
from .media_panel_properties import MediaPanelProperties
from ..formatters.conditional_decorators import conditional_decorators
class MediaPanelView:
@@ -20,410 +11,125 @@ class MediaPanelView:
def __init__(self, extractor):
self.extractor = extractor
self._props = MediaPanelProperties(extractor)
def file_info_panel(self) -> str:
"""Return formatted file info panel string"""
sections = [
self.file_info(),
self.selected_data(),
self.tmdb_data(),
self.tracks_info(),
self.filename_extracted_data(),
self.metadata_extracted_data(),
self.mediainfo_extracted_data(),
]
return "\n\n".join("\n".join(section) for section in sections)
return "\n".join(
[
self.fileinfo_section(),
self.selected_section(),
self.tmdb_section(),
self.tracksinfo_section(),
self.filename_section(),
self.metadata_section(),
self.mediainfo_section(),
]
)
def file_info(self) -> list[str]:
data = [
{
"group": "File Info",
"label": "File Info",
"label_formatters": [TextFormatter.bold, TextFormatter.uppercase],
},
{
"group": "File Info",
"label": "Path",
"label_formatters": [TextFormatter.bold],
"value": escape(str(self.extractor.get("file_path", "FileInfo"))),
"display_formatters": [TextFormatter.blue],
},
{
"group": "File Info",
"label": "Size",
"value": self.extractor.get("file_size", "FileInfo"),
"value_formatters": [SizeFormatter.format_size_full],
"display_formatters": [TextFormatter.bold, TextFormatter.green],
},
{
"group": "File Info",
"label": "Name",
"label_formatters": [TextFormatter.bold],
"value": escape(str(self.extractor.get("file_name", "FileInfo"))),
"display_formatters": [TextFormatter.cyan],
},
{
"group": "File Info",
"label": "Modified",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("modification_time", "FileInfo"),
"value_formatters": [DateFormatter.format_modification_date],
"display_formatters": [TextFormatter.bold, TextFormatter.magenta],
},
{
"group": "File Info",
"label": "Extension",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("extension", "FileInfo"),
"value_formatters": [ExtensionFormatter.format_extension_info],
"display_formatters": [TextFormatter.green],
},
]
return FormatterApplier.format_data_items(data)
@conditional_decorators.wrap("", "\n")
def fileinfo_section(self) -> str:
"""Return formatted file info"""
return "\n".join(
[
self._props.title("File Info"),
self._props.file_path,
self._props.file_size,
self._props.file_name,
self._props.modification_time,
self._props.extension_fileinfo,
]
)
def tmdb_data(self) -> list[str]:
@conditional_decorators.wrap("", "\n")
def selected_section(self) -> str:
"""Return formatted selected data"""
return "\n".join(
[
self._props.title("Selected Data"),
self._props.selected_order,
self._props.selected_title,
self._props.selected_year,
self._props.selected_special_info,
self._props.selected_source,
self._props.selected_frame_class,
self._props.selected_hdr,
self._props.selected_audio_langs,
self._props.selected_database_info,
]
)
@conditional_decorators.wrap("", "\n")
def tmdb_section(self) -> str:
"""Return formatted TMDB data"""
data = [
{
"label": "TMDB Data",
"label_formatters": [TextFormatter.bold, TextFormatter.uppercase],
},
{
"label": "ID",
"label_formatters": [TextFormatter.bold, TextFormatter.blue],
"value": self.extractor.get("tmdb_id", "TMDB") or "<None>",
"value_formatters": [TextFormatter.yellow],
},
{
"label": "Title",
"label_formatters": [TextFormatter.bold, TextFormatter.blue],
"value": self.extractor.get("title", "TMDB") or "<None>",
"value_formatters": [TextFormatter.yellow],
},
{
"label": "Original Title",
"label_formatters": [TextFormatter.bold, TextFormatter.blue],
"value": self.extractor.get("original_title", "TMDB") or "<None>",
"value_formatters": [TextFormatter.yellow],
},
{
"label": "Year",
"label_formatters": [TextFormatter.bold, TextFormatter.blue],
"value": self.extractor.get("year", "TMDB") or "<None>",
"value_formatters": [TextFormatter.yellow,],
},
{
"label": "Database Info",
"label_formatters": [TextFormatter.bold, TextFormatter.blue],
"value": self.extractor.get("movie_db", "TMDB") or "<None>",
"value_formatters": [SpecialInfoFormatter.format_database_info, TextFormatter.yellow],
},
{
"label": "URL",
"label_formatters": [TextFormatter.bold, TextFormatter.blue],
"value": self.extractor.get("tmdb_url", "TMDB") or "<None>",
"value_formatters": [TextFormatter.format_url],
}
]
return FormatterApplier.format_data_items(data)
return "\n".join(
[
self._props.title("TMDB Data"),
self._props.tmdb_id,
self._props.tmdb_title,
self._props.tmdb_original_title,
self._props.tmdb_year,
self._props.tmdb_database_info,
self._props.tmdb_url,
]
)
def tracks_info(self) -> list[str]:
"""Return formatted tracks information"""
data = [
{
"group": "Tracks Info",
"label": "Tracks Info",
"label_formatters": [TextFormatter.bold, TextFormatter.uppercase],
}
]
@conditional_decorators.wrap("", "\n")
def tracksinfo_section(self) -> str:
"""Return formatted tracks information panel"""
return "\n".join(
[
self._props.title("Tracks Info"),
*self._props.video_tracks,
*self._props.audio_tracks,
*self._props.subtitle_tracks,
]
)
# Get video tracks
video_tracks = self.extractor.get("video_tracks", "MediaInfo") or []
for item in video_tracks:
data.append(
{
"group": "Tracks Info",
"label": "Video Track",
"value": item,
"value_formatters": TrackFormatter.format_video_track,
"display_formatters": [TextFormatter.green],
}
)
# Get audio tracks
audio_tracks = self.extractor.get("audio_tracks", "MediaInfo") or []
for i, item in enumerate(audio_tracks, start=1):
data.append(
{
"group": "Tracks Info",
"label": f"Audio Track {i}",
"value": item,
"value_formatters": TrackFormatter.format_audio_track,
"display_formatters": [TextFormatter.yellow],
}
)
# Get subtitle tracks
subtitle_tracks = self.extractor.get("subtitle_tracks", "MediaInfo") or []
for i, item in enumerate(subtitle_tracks, start=1):
data.append(
{
"group": "Tracks Info",
"label": f"Subtitle Track {i}",
"value": item,
"value_formatters": TrackFormatter.format_subtitle_track,
"display_formatters": [TextFormatter.magenta],
}
)
return FormatterApplier.format_data_items(data)
def metadata_extracted_data(self) -> list[str]:
"""Format metadata extraction data for the metadata panel"""
data = [
{
"label": "Metadata Extraction",
"label_formatters": [TextFormatter.bold, TextFormatter.uppercase],
},
{
"label": "Title",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("title", "Metadata") or "Not extracted",
"display_formatters": [TextFormatter.grey],
},
{
"label": "Duration",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("duration", "Metadata") or "Not extracted",
"value_formatters": [DurationFormatter.format_full],
"display_formatters": [TextFormatter.grey],
},
{
"label": "Artist",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("artist", "Metadata") or "Not extracted",
"display_formatters": [TextFormatter.grey],
},
]
return FormatterApplier.format_data_items(data)
def mediainfo_extracted_data(self) -> list[str]:
"""Format media info extraction data for the mediainfo panel"""
data = [
{
"label": "Media Info Extraction",
"label_formatters": [TextFormatter.bold, TextFormatter.uppercase],
},
{
"label": "Duration",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("duration", "MediaInfo") or "Not extracted",
"value_formatters": [DurationFormatter.format_full],
"display_formatters": [TextFormatter.grey],
},
{
"label": "Frame Class",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("frame_class", "MediaInfo")
or "Not extracted",
"display_formatters": [TextFormatter.grey],
},
{
"label": "Resolution",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("resolution", "MediaInfo")
or "Not extracted",
"value_formatters": [ResolutionFormatter.format_resolution_dimensions],
"display_formatters": [TextFormatter.grey],
},
{
"label": "Aspect Ratio",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("aspect_ratio", "MediaInfo")
or "Not extracted",
"display_formatters": [TextFormatter.grey],
},
{
"label": "HDR",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("hdr", "MediaInfo") or "Not extracted",
"display_formatters": [TextFormatter.grey],
},
{
"label": "Audio Languages",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("audio_langs", "MediaInfo")
or "Not extracted",
"display_formatters": [TextFormatter.grey],
},
{
"label": "Anamorphic",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("anamorphic", "MediaInfo") or "Not extracted",
"display_formatters": [TextFormatter.grey],
},
{
"label": "Extension",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("extension", "MediaInfo") or "Not extracted",
"value_formatters": [ExtensionFormatter.format_extension_info],
"display_formatters": [TextFormatter.grey],
},
{
"label": "3D Layout",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("3d_layout", "MediaInfo") or "Not extracted",
"display_formatters": [TextFormatter.grey],
},
]
return FormatterApplier.format_data_items(data)
def filename_extracted_data(self) -> list[str]:
@conditional_decorators.wrap("", "\n")
def filename_section(self) -> str:
"""Return formatted filename extracted data"""
data = [
{
"label": "Filename Extracted Data",
"label_formatters": [TextFormatter.bold, TextFormatter.uppercase],
},
{
"label": "Order",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("order", "Filename") or "Not extracted",
"display_formatters": [TextFormatter.yellow],
},
{
"label": "Movie title",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("title", "Filename"),
"display_formatters": [TextFormatter.grey],
},
{
"label": "Year",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("year", "Filename"),
"display_formatters": [TextFormatter.grey],
},
{
"label": "Video source",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("source", "Filename") or "Not extracted",
"display_formatters": [TextFormatter.grey],
},
{
"label": "Frame class",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("frame_class", "Filename")
or "Not extracted",
"display_formatters": [TextFormatter.grey],
},
{
"label": "HDR",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("hdr", "Filename") or "Not extracted",
"display_formatters": [TextFormatter.grey],
},
{
"label": "Audio langs",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("audio_langs", "Filename")
or "Not extracted",
"display_formatters": [TextFormatter.grey],
},
{
"label": "Special info",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("special_info", "Filename")
or "Not extracted",
"value_formatters": [
SpecialInfoFormatter.format_special_info,
TextFormatter.blue,
],
"display_formatters": [TextFormatter.grey],
},
{
"label": "Movie DB",
"label_formatters": [TextFormatter.bold],
"value": self.extractor.get("movie_db", "Filename") or "Not extracted",
"display_formatters": [TextFormatter.grey],
},
]
return "\n".join(
[
self._props.title("Filename Extracted Data"),
self._props.filename_order,
self._props.filename_title,
self._props.filename_year,
self._props.filename_source,
self._props.filename_frame_class,
self._props.filename_hdr,
self._props.filename_audio_langs,
self._props.filename_special_info,
self._props.filename_movie_db,
]
)
return FormatterApplier.format_data_items(data)
@conditional_decorators.wrap("", "\n")
def metadata_section(self) -> str:
"""Return formatted metadata extraction data"""
return "\n".join(
[
self._props.title("Metadata Extraction"),
self._props.metadata_title,
self._props.metadata_duration,
self._props.metadata_artist,
]
)
def selected_data(self) -> list[str]:
"""Return formatted selected data string"""
import logging
import os
if os.getenv("FORMATTER_LOG"):
frame_class = self.extractor.get("frame_class")
audio_langs = self.extractor.get("audio_langs")
logging.info(f"Selected data - frame_class: {frame_class!r}, audio_langs: {audio_langs!r}")
# Also check from Filename source
frame_class_filename = self.extractor.get("frame_class", "Filename")
audio_langs_filename = self.extractor.get("audio_langs", "Filename")
logging.info(f"From Filename - frame_class: {frame_class_filename!r}, audio_langs: {audio_langs_filename!r}")
data = [
{
"label": "Selected Data",
"label_formatters": [TextFormatter.bold, TextFormatter.uppercase],
},
{
"label": "Order",
"label_formatters": [TextFormatter.bold, TextFormatter.blue],
"value": self.extractor.get("order") or "<None>",
"value_formatters": [TextFormatter.yellow],
},
{
"label": "Title",
"label_formatters": [TextFormatter.bold, TextFormatter.blue],
"value": self.extractor.get("title") or "<None>",
"value_formatters": [TextFormatter.yellow],
},
{
"label": "Year",
"label_formatters": [TextFormatter.bold, TextFormatter.blue],
"value": self.extractor.get("year") or "<None>",
"value_formatters": [TextFormatter.yellow],
},
{
"label": "Special info",
"label_formatters": [TextFormatter.bold, TextFormatter.blue],
"value": self.extractor.get("special_info") or "<None>",
"value_formatters": [
SpecialInfoFormatter.format_special_info,
TextFormatter.yellow,
],
},
{
"label": "Source",
"label_formatters": [TextFormatter.bold, TextFormatter.blue],
"value": self.extractor.get("source") or "<None>",
"value_formatters": [TextFormatter.yellow],
},
{
"label": "Frame class",
"label_formatters": [TextFormatter.bold, TextFormatter.blue],
"value": self.extractor.get("frame_class") or "<None>",
"value_formatters": [TextFormatter.yellow],
},
{
"label": "HDR",
"label_formatters": [TextFormatter.bold, TextFormatter.blue],
"value": self.extractor.get("hdr") or "<None>",
"value_formatters": [TextFormatter.yellow],
},
{
"label": "Audio langs",
"label_formatters": [TextFormatter.bold, TextFormatter.blue],
"value": self.extractor.get("audio_langs") or "<None>",
"value_formatters": [TextFormatter.yellow],
},
{
"label": "Database Info",
"label_formatters": [TextFormatter.bold, TextFormatter.blue],
"value": self.extractor.get("movie_db") or "<None>",
"value_formatters": [SpecialInfoFormatter.format_database_info, TextFormatter.yellow],
}
]
return FormatterApplier.format_data_items(data)
@conditional_decorators.wrap("", "\n")
def mediainfo_section(self) -> str:
"""Return formatted media info extraction data"""
return "\n".join(
[
self._props.title("Media Info Extraction"),
self._props.mediainfo_duration,
self._props.mediainfo_frame_class,
self._props.mediainfo_resolution,
self._props.mediainfo_aspect_ratio,
self._props.mediainfo_hdr,
self._props.mediainfo_audio_langs,
self._props.mediainfo_anamorphic,
self._props.mediainfo_extension,
self._props.mediainfo_3d_layout,
]
)
+456
View File
@@ -0,0 +1,456 @@
"""Media panel property methods using decorator pattern.
This module contains all the formatted property methods that return
display-ready values for the media panel view. Each property uses
decorators to apply formatting, similar to ProposedFilenameView.
"""
from ..formatters import (
date_decorators,
text_decorators,
conditional_decorators,
size_decorators,
extension_decorators,
duration_decorators,
resolution_decorators,
special_info_decorators,
track_decorators,
)
class MediaPanelProperties:
"""Formatted properties for media panel display.
This class provides @property methods that return formatted values
ready for display in the media panel. Each property applies the
appropriate decorators for styling and formatting.
"""
def __init__(self, extractor):
self._extractor = extractor
# ============================================================
# Section Title Formatter
# ============================================================
@text_decorators.bold()
@text_decorators.uppercase()
def title(self, title: str) -> str:
"""Format section title with bold and uppercase styling."""
return title
# ============================================================
# File Info Properties
# ============================================================
@property
@conditional_decorators.wrap("Path: ")
@text_decorators.blue()
@text_decorators.escape()
def file_path(self) -> str:
"""Get file path formatted with label."""
return self._extractor.get("file_path")
@property
@conditional_decorators.wrap("Size: ")
@text_decorators.green()
@size_decorators.size_full()
def file_size(self) -> str:
"""Get file size formatted with label."""
return self._extractor.get("file_size")
@property
@conditional_decorators.wrap("Name: ")
@text_decorators.cyan()
@text_decorators.escape()
def file_name(self) -> str:
"""Get file name formatted with label."""
return self._extractor.get("file_name")
@property
@conditional_decorators.wrap("Modified: ")
@text_decorators.magenta()
@date_decorators.modification_date()
def modification_time(self) -> str:
"""Get modification time formatted with label."""
return self._extractor.get("modification_time")
@property
@conditional_decorators.wrap("Extension: ")
@text_decorators.green()
@extension_decorators.extension_info()
def extension_fileinfo(self) -> str:
"""Get extension from FileInfo formatted with label."""
return self._extractor.get("extension")
# ============================================================
# TMDB Properties
# ============================================================
@property
@text_decorators.blue()
@conditional_decorators.wrap("ID: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
def tmdb_id(self) -> str:
"""Get TMDB ID formatted with label."""
return self._extractor.get("tmdb_id", "TMDB")
@property
@text_decorators.blue()
@conditional_decorators.wrap("Title: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
def tmdb_title(self) -> str:
"""Get TMDB title formatted with label."""
return self._extractor.get("title", "TMDB")
@property
@text_decorators.blue()
@conditional_decorators.wrap("Original Title: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
def tmdb_original_title(self) -> str:
"""Get TMDB original title formatted with label."""
return self._extractor.get("original_title", "TMDB")
@property
@text_decorators.blue()
@conditional_decorators.wrap("Year: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
def tmdb_year(self) -> str:
"""Get TMDB year formatted with label."""
return self._extractor.get("year", "TMDB")
@property
@text_decorators.blue()
@conditional_decorators.wrap("Database Info: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
@special_info_decorators.database_info()
def tmdb_database_info(self) -> str:
"""Get TMDB database info formatted with label."""
return self._extractor.get("movie_db", "TMDB")
@property
# @text_decorators.blue()
@conditional_decorators.default("")
@text_decorators.url()
def tmdb_url(self) -> str:
"""Get TMDB URL formatted with label."""
return self._extractor.get("tmdb_url", "TMDB")
# ============================================================
# Metadata Extraction Properties
# ============================================================
@property
@conditional_decorators.wrap("Title: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
def metadata_title(self) -> str:
"""Get metadata title formatted with label."""
return self._extractor.get("title", "Metadata")
@property
@conditional_decorators.wrap("Duration: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
@duration_decorators.duration_full()
def metadata_duration(self) -> str:
"""Get metadata duration formatted with label."""
return self._extractor.get("duration", "Metadata")
@property
@conditional_decorators.wrap("Artist: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
def metadata_artist(self) -> str:
"""Get metadata artist formatted with label."""
return self._extractor.get("artist", "Metadata")
# ============================================================
# MediaInfo Extraction Properties
# ============================================================
@property
@conditional_decorators.wrap("Duration: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
@duration_decorators.duration_full()
def mediainfo_duration(self) -> str:
"""Get MediaInfo duration formatted with label."""
return self._extractor.get("duration", "MediaInfo")
@property
@conditional_decorators.wrap("Frame Class: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
def mediainfo_frame_class(self) -> str:
"""Get MediaInfo frame class formatted with label."""
return self._extractor.get("frame_class", "MediaInfo")
@property
@conditional_decorators.wrap("Resolution: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
@resolution_decorators.resolution_dimensions()
def mediainfo_resolution(self) -> str:
"""Get MediaInfo resolution formatted with label."""
return self._extractor.get("resolution", "MediaInfo")
@property
@conditional_decorators.wrap("Aspect Ratio: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
def mediainfo_aspect_ratio(self) -> str:
"""Get MediaInfo aspect ratio formatted with label."""
return self._extractor.get("aspect_ratio", "MediaInfo")
@property
@conditional_decorators.wrap("HDR: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
def mediainfo_hdr(self) -> str:
"""Get MediaInfo HDR formatted with label."""
return self._extractor.get("hdr", "MediaInfo")
@property
@conditional_decorators.wrap("Audio Languages: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
def mediainfo_audio_langs(self) -> str:
"""Get MediaInfo audio languages formatted with label."""
return self._extractor.get("audio_langs", "MediaInfo")
@property
@conditional_decorators.wrap("Anamorphic: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
def mediainfo_anamorphic(self) -> str:
"""Get MediaInfo anamorphic formatted with label."""
return self._extractor.get("anamorphic", "MediaInfo")
@property
@conditional_decorators.wrap("Extension: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
@extension_decorators.extension_info()
def mediainfo_extension(self) -> str:
"""Get MediaInfo extension formatted with label."""
return self._extractor.get("extension", "MediaInfo")
@property
@conditional_decorators.wrap("3D Layout: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
def mediainfo_3d_layout(self) -> str:
"""Get MediaInfo 3D layout formatted with label."""
return self._extractor.get("3d_layout", "MediaInfo")
# ============================================================
# Filename Extraction Properties
# ============================================================
@property
@conditional_decorators.wrap("Order: ")
@text_decorators.yellow()
@conditional_decorators.default("Not extracted")
def filename_order(self) -> str:
"""Get filename order formatted with label."""
return self._extractor.get("order", "Filename")
@property
@conditional_decorators.wrap("Movie title: ")
@text_decorators.grey()
@conditional_decorators.default("")
def filename_title(self) -> str:
"""Get filename title formatted with label."""
return self._extractor.get("title", "Filename")
@property
@conditional_decorators.wrap("Year: ")
@text_decorators.grey()
@conditional_decorators.default("")
def filename_year(self) -> str:
"""Get filename year formatted with label."""
return self._extractor.get("year", "Filename")
@property
@conditional_decorators.wrap("Video source: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
def filename_source(self) -> str:
"""Get filename source formatted with label."""
return self._extractor.get("source", "Filename")
@property
@conditional_decorators.wrap("Frame class: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
def filename_frame_class(self) -> str:
"""Get filename frame class formatted with label."""
return self._extractor.get("frame_class", "Filename")
@property
@conditional_decorators.wrap("HDR: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
def filename_hdr(self) -> str:
"""Get filename HDR formatted with label."""
return self._extractor.get("hdr", "Filename")
@property
@conditional_decorators.wrap("Audio langs: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
def filename_audio_langs(self) -> str:
"""Get filename audio languages formatted with label."""
return self._extractor.get("audio_langs", "Filename")
@property
@conditional_decorators.wrap("Special info: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
@text_decorators.blue()
@special_info_decorators.special_info()
def filename_special_info(self) -> str:
"""Get filename special info formatted with label."""
return self._extractor.get("special_info", "Filename")
@property
@conditional_decorators.wrap("Movie DB: ")
@text_decorators.grey()
@conditional_decorators.default("Not extracted")
def filename_movie_db(self) -> str:
"""Get filename movie DB formatted with label."""
return self._extractor.get("movie_db", "Filename")
# ============================================================
# Selected Data Properties
# ============================================================
@property
@text_decorators.blue()
@conditional_decorators.wrap("Order: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
def selected_order(self) -> str:
"""Get selected order formatted with label."""
return self._extractor.get("order")
@property
@text_decorators.blue()
@conditional_decorators.wrap("Title: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
def selected_title(self) -> str:
"""Get selected title formatted with label."""
return self._extractor.get("title")
@property
@text_decorators.blue()
@conditional_decorators.wrap("Year: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
def selected_year(self) -> str:
"""Get selected year formatted with label."""
return self._extractor.get("year")
@property
@text_decorators.blue()
@conditional_decorators.wrap("Special info: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
@special_info_decorators.special_info()
def selected_special_info(self) -> str:
"""Get selected special info formatted with label."""
return self._extractor.get("special_info")
@property
@text_decorators.blue()
@conditional_decorators.wrap("Source: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
def selected_source(self) -> str:
"""Get selected source formatted with label."""
return self._extractor.get("source")
@property
@text_decorators.blue()
@conditional_decorators.wrap("Frame class: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
def selected_frame_class(self) -> str:
"""Get selected frame class formatted with label."""
return self._extractor.get("frame_class")
@property
@text_decorators.blue()
@conditional_decorators.wrap("HDR: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
def selected_hdr(self) -> str:
"""Get selected HDR formatted with label."""
return self._extractor.get("hdr")
@property
@text_decorators.blue()
@conditional_decorators.wrap("Audio langs: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
def selected_audio_langs(self) -> str:
"""Get selected audio languages formatted with label."""
return self._extractor.get("audio_langs")
@property
@text_decorators.blue()
@conditional_decorators.wrap("Database Info: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
@special_info_decorators.database_info()
def selected_database_info(self) -> str:
"""Get selected database info formatted with label."""
return self._extractor.get("movie_db")
@property
def video_tracks(self) -> list[str]:
"""Return formatted video track data"""
tracks = self._extractor.get("video_tracks", "MediaInfo") or []
return [self.video_track(track, i) for i, track in enumerate(tracks, start=1)]
@text_decorators.green()
@conditional_decorators.wrap("Video Track {index}: ")
@track_decorators.video_track()
def video_track(self, track, index) -> str:
"""Get video track info formatted with label."""
return track
@property
def audio_tracks(self) -> list[str]:
"""Return formatted audio track data"""
tracks = self._extractor.get("audio_tracks", "MediaInfo") or []
return [self.audio_track(track, i) for i, track in enumerate(tracks, start=1)]
@text_decorators.yellow()
@conditional_decorators.wrap("Audio Track {index}: ")
@track_decorators.audio_track()
def audio_track(self, track, index) -> str:
"""Get audio track info formatted with label."""
return track
@property
def subtitle_tracks(self) -> list[str]:
"""Return formatted subtitle track data"""
tracks = self._extractor.get("subtitle_tracks", "MediaInfo") or []
return [
self.subtitle_track(track, i) for i, track in enumerate(tracks, start=1)
]
@text_decorators.magenta()
@conditional_decorators.wrap("Subtitle Track {index}: ")
@track_decorators.subtitle_track()
def subtitle_track(self, track, index) -> str:
"""Get subtitle track info formatted with label."""
return track