fix: Add 3D layout extraction from filename and update proposed filename generation

This commit is contained in:
sha
2026-04-13 18:15:37 +03:00
parent dfe3f9fe11
commit 274ce4d451
4 changed files with 40 additions and 1 deletions
+1
View File
@@ -123,6 +123,7 @@ class MediaExtractor:
"3d_layout": { "3d_layout": {
"sources": [ "sources": [
("MediaInfo", "extract_3d_layout"), ("MediaInfo", "extract_3d_layout"),
("Filename", "extract_3d_layout"),
("Default", "extract_3d_layout"), ("Default", "extract_3d_layout"),
], ],
}, },
+27
View File
@@ -251,6 +251,33 @@ class FilenameExtractor:
return None return None
@cached_method()
def extract_3d_layout(self) -> str | None:
"""Extract 3D stereoscopic layout from filename or extension"""
# Ordered by specificity: most specific patterns first
patterns = [
(r'\b3D-SBS\b', '3D-SBS'),
(r'\b3D-OU\b', '3D-OU'),
(r'\b3D-HSBS\b', '3D-HSBS'),
(r'\b3D-HOU\b', '3D-HOU'),
(r'\bHalf[-.]?SBS\b', '3D-HSBS'),
(r'\bHalf[-.]?OU\b', '3D-HOU'),
(r'\bHSBS\b', '3D-HSBS'),
(r'\bHOU\b', '3D-HOU'),
(r'\bSBS\b', '3D-SBS'),
(r'\bOU\b', '3D-OU'),
(r'\b3D\b', '3D'),
]
for pattern, result in patterns:
if re.search(pattern, self.file_name, re.IGNORECASE):
return result
# Fall back to mk3d extension as a 3D indicator
if self.file_path.suffix.lower() == '.mk3d':
return '3D'
return None
@cached_method() @cached_method()
def extract_movie_db(self) -> list[str] | None: def extract_movie_db(self) -> list[str] | None:
"""Extract movie database identifier from filename""" """Extract movie database identifier from filename"""
+5
View File
@@ -389,6 +389,11 @@ class MediaInfoExtractor:
# Use the constants function to get extension from format # Use the constants function to get extension from format
ext = get_extension_from_format(format_) ext = get_extension_from_format(format_)
# Preserve mk3d extension when the source file already has it,
# even if MediaInfo doesn't report stereoscopic metadata
if self.file_path.suffix.lower() == '.mk3d':
return 'mk3d'
# Special case: Matroska 3D uses mk3d extension # Special case: Matroska 3D uses mk3d extension
if ext == "mkv" and self.is_3d(): if ext == "mkv" and self.is_3d():
return "mk3d" return "mk3d"
+7 -1
View File
@@ -48,6 +48,12 @@ class ProposedFilenameView:
"""Get the frame class""" """Get the frame class"""
return self._extractor.get("frame_class") or "" return self._extractor.get("frame_class") or ""
@property
@conditional_decorators.wrap(",")
def _3d_layout(self) -> str:
"""Get the 3D layout formatted with a leading comma if present"""
return self._extractor.get("3d_layout")
@property @property
@conditional_decorators.wrap(",") @conditional_decorators.wrap(",")
def _hdr(self) -> str: def _hdr(self) -> str:
@@ -81,7 +87,7 @@ class ProposedFilenameView:
@property @property
def rename_line(self) -> str: def rename_line(self) -> str:
"""Generate the proposed filename.""" """Generate the proposed filename."""
result = f"{self._order}{self._title}{self._year}{self._special_info}{self._source} [{self._frame_class}{self._hdr},{self._audio_langs}]{self._db_info}.{self._extension}" result = f"{self._order}{self._title}{self._year}{self._special_info}{self._source} [{self._frame_class}{self._3d_layout}{self._hdr},{self._audio_langs}]{self._db_info}.{self._extension}"
return result.replace("/", "-").replace("\\", "-") return result.replace("/", "-").replace("\\", "-")
def rename_line_formatted(self, file_path) -> str: def rename_line_formatted(self, file_path) -> str: