Refactor code structure for improved readability and maintainability

This commit is contained in:
sHa
2026-01-05 17:11:42 +00:00
parent b4b7709f25
commit 2e5cef4424
8 changed files with 96 additions and 23 deletions

BIN
dist/renamer-0.8.11-py3-none-any.whl vendored Normal file

Binary file not shown.

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "renamer" name = "renamer"
version = "0.8.10" version = "0.8.11"
description = "Terminal-based media file renamer and metadata viewer" description = "Terminal-based media file renamer and metadata viewer"
readme = "README.md" readme = "README.md"
requires-python = ">=3.11" requires-python = ">=3.11"

View File

@@ -12,7 +12,11 @@ This package contains constants split into logical modules:
""" """
# Import from all constant modules # Import from all constant modules
from .media_constants import MEDIA_TYPES, META_TYPE_TO_EXTENSIONS from .media_constants import (
MEDIA_TYPES,
META_TYPE_TO_EXTENSIONS,
get_extension_from_format
)
from .source_constants import SOURCE_DICT from .source_constants import SOURCE_DICT
from .frame_constants import FRAME_CLASSES, NON_STANDARD_QUALITY_INDICATORS from .frame_constants import FRAME_CLASSES, NON_STANDARD_QUALITY_INDICATORS
from .moviedb_constants import MOVIE_DB_DICT from .moviedb_constants import MOVIE_DB_DICT
@@ -25,6 +29,7 @@ __all__ = [
# Media types # Media types
'MEDIA_TYPES', 'MEDIA_TYPES',
'META_TYPE_TO_EXTENSIONS', 'META_TYPE_TO_EXTENSIONS',
'get_extension_from_format',
# Source types # Source types
'SOURCE_DICT', 'SOURCE_DICT',
# Frame classes # Frame classes

View File

@@ -1,6 +1,7 @@
"""Media type constants for supported video formats. """Media type constants for supported video formats.
This module defines all supported video container formats and their metadata. This module defines all supported video container formats and their metadata.
Each entry includes the MediaInfo format name for proper detection.
""" """
MEDIA_TYPES = { MEDIA_TYPES = {
@@ -8,50 +9,79 @@ MEDIA_TYPES = {
"description": "Matroska multimedia container", "description": "Matroska multimedia container",
"meta_type": "Matroska", "meta_type": "Matroska",
"mime": "video/x-matroska", "mime": "video/x-matroska",
"mediainfo_format": "Matroska",
}, },
"mk3d": { "mk3d": {
"description": "Matroska 3D multimedia container", "description": "Matroska 3D multimedia container",
"meta_type": "Matroska", "meta_type": "Matroska",
"mime": "video/x-matroska", "mime": "video/x-matroska",
"mediainfo_format": "Matroska",
}, },
"avi": { "avi": {
"description": "Audio Video Interleave", "description": "Audio Video Interleave",
"meta_type": "AVI", "meta_type": "AVI",
"mime": "video/x-msvideo", "mime": "video/x-msvideo",
"mediainfo_format": "AVI",
}, },
"mov": { "mov": {
"description": "QuickTime movie", "description": "QuickTime movie",
"meta_type": "QuickTime", "meta_type": "QuickTime",
"mime": "video/quicktime", "mime": "video/quicktime",
"mediainfo_format": "QuickTime",
}, },
"mp4": { "mp4": {
"description": "MPEG-4 video container", "description": "MPEG-4 video container",
"meta_type": "MP4", "meta_type": "MP4",
"mime": "video/mp4", "mime": "video/mp4",
"mediainfo_format": "MPEG-4",
}, },
"wmv": { "wmv": {
"description": "Windows Media Video", "description": "Windows Media Video",
"meta_type": "ASF", "meta_type": "ASF",
"mime": "video/x-ms-wmv", "mime": "video/x-ms-wmv",
"mediainfo_format": "Windows Media",
},
"flv": {
"description": "Flash Video",
"meta_type": "FLV",
"mime": "video/x-flv",
"mediainfo_format": "Flash Video",
}, },
"flv": {"description": "Flash Video", "meta_type": "FLV", "mime": "video/x-flv"},
"webm": { "webm": {
"description": "WebM multimedia", "description": "WebM multimedia",
"meta_type": "WebM", "meta_type": "WebM",
"mime": "video/webm", "mime": "video/webm",
"mediainfo_format": "WebM",
},
"m4v": {
"description": "MPEG-4 video",
"meta_type": "MP4",
"mime": "video/mp4",
"mediainfo_format": "MPEG-4",
},
"3gp": {
"description": "3GPP multimedia",
"meta_type": "MP4",
"mime": "video/3gpp",
"mediainfo_format": "MPEG-4",
},
"ogv": {
"description": "Ogg Video",
"meta_type": "Ogg",
"mime": "video/ogg",
"mediainfo_format": "Ogg",
}, },
"m4v": {"description": "MPEG-4 video", "meta_type": "MP4", "mime": "video/mp4"},
"3gp": {"description": "3GPP multimedia", "meta_type": "MP4", "mime": "video/3gpp"},
"ogv": {"description": "Ogg Video", "meta_type": "Ogg", "mime": "video/ogg"},
"mpg": { "mpg": {
"description": "MPEG video", "description": "MPEG video",
"meta_type": "MPEG-PS", "meta_type": "MPEG-PS",
"mime": "video/mpeg", "mime": "video/mpeg",
"mediainfo_format": "MPEG-PS",
}, },
"mpeg": { "mpeg": {
"description": "MPEG video", "description": "MPEG video",
"meta_type": "MPEG-PS", "meta_type": "MPEG-PS",
"mime": "video/mpeg", "mime": "video/mpeg",
"mediainfo_format": "MPEG-PS",
}, },
} }
@@ -64,3 +94,31 @@ for ext, info in MEDIA_TYPES.items():
if meta_type not in META_TYPE_TO_EXTENSIONS: if meta_type not in META_TYPE_TO_EXTENSIONS:
META_TYPE_TO_EXTENSIONS[meta_type] = [] META_TYPE_TO_EXTENSIONS[meta_type] = []
META_TYPE_TO_EXTENSIONS[meta_type].append(ext) META_TYPE_TO_EXTENSIONS[meta_type].append(ext)
# Reverse mapping: MediaInfo format name -> extension
# Built from MEDIA_TYPES at module load
MEDIAINFO_FORMAT_TO_EXTENSION = {}
for ext, info in MEDIA_TYPES.items():
mediainfo_format = info.get('mediainfo_format')
if mediainfo_format:
# Store only the first (primary) extension for each format
if mediainfo_format not in MEDIAINFO_FORMAT_TO_EXTENSION:
MEDIAINFO_FORMAT_TO_EXTENSION[mediainfo_format] = ext
def get_extension_from_format(format_name: str) -> str | None:
"""Get file extension from MediaInfo format name.
Args:
format_name: Format name as reported by MediaInfo (e.g., "MPEG-4", "Matroska")
Returns:
File extension (e.g., "mp4", "mkv") or None if format is unknown
Example:
>>> get_extension_from_format("MPEG-4")
'mp4'
>>> get_extension_from_format("Matroska")
'mkv'
"""
return MEDIAINFO_FORMAT_TO_EXTENSION.get(format_name)

View File

@@ -101,7 +101,7 @@ class DefaultExtractor:
return None return None
def extract_extension(self) -> Optional[str]: def extract_extension(self) -> Optional[str]:
"""Return file extension. Returns None as no extension is available.""" """Return file extension. Returns 'ext' as default placeholder."""
return "ext" return "ext"
def extract_tmdb_url(self) -> Optional[str]: def extract_tmdb_url(self) -> Optional[str]:

View File

@@ -83,10 +83,12 @@ class FileInfoExtractor:
return str(self._file_path) return str(self._file_path)
@cached_method() @cached_method()
def extract_extension(self) -> str: def extract_extension(self) -> str | None:
"""Extract file extension without the dot. """Extract file extension without the dot.
Returns: Returns:
File extension in lowercase without leading dot (e.g., "mkv", "mp4") File extension in lowercase without leading dot (e.g., "mkv", "mp4"),
or None if no extension exists
""" """
return self._file_path.suffix.lower().lstrip('.') ext = self._file_path.suffix.lower().lstrip('.')
return ext if ext else None

View File

@@ -1,7 +1,7 @@
from pathlib import Path from pathlib import Path
from pymediainfo import MediaInfo from pymediainfo import MediaInfo
from collections import Counter from collections import Counter
from ..constants import FRAME_CLASSES, META_TYPE_TO_EXTENSIONS from ..constants import FRAME_CLASSES, get_extension_from_format
from ..cache import cached_method, Cache from ..cache import cached_method, Cache
import langcodes import langcodes
import logging import logging
@@ -265,23 +265,31 @@ class MediaInfoExtractor:
@cached_method() @cached_method()
def extract_extension(self) -> str | None: def extract_extension(self) -> str | None:
"""Extract file extension based on container format""" """Extract file extension based on container format.
Uses MediaInfo's format field to determine the appropriate file extension.
Handles special cases like Matroska 3D (mk3d vs mkv).
Returns:
File extension (e.g., "mp4", "mkv") or None if format is unknown
"""
if not self.media_info: if not self.media_info:
return None return None
general_track = next((t for t in self.media_info.tracks if t.track_type == 'General'), None) general_track = next((t for t in self.media_info.tracks if t.track_type == 'General'), None)
if not general_track: if not general_track:
return None return None
format_ = getattr(general_track, 'format', None) format_ = getattr(general_track, 'format', None)
if format_ in META_TYPE_TO_EXTENSIONS: if not format_:
exts = META_TYPE_TO_EXTENSIONS[format_] return None
if format_ == 'Matroska':
if self.is_3d() and 'mk3d' in exts: # Use the constants function to get extension from format
return 'mk3d' ext = get_extension_from_format(format_)
else:
return 'mkv' # Special case: Matroska 3D uses mk3d extension
else: if ext == 'mkv' and self.is_3d():
return exts[0] if exts else None return 'mk3d'
return None
return ext
@cached_method() @cached_method()
def extract_3d_layout(self) -> str | None: def extract_3d_layout(self) -> str | None:

2
uv.lock generated
View File

@@ -462,7 +462,7 @@ wheels = [
[[package]] [[package]]
name = "renamer" name = "renamer"
version = "0.8.10" version = "0.8.11"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "langcodes" }, { name = "langcodes" },