Refactor code structure for improved readability and maintainability
This commit is contained in:
BIN
dist/renamer-0.8.11-py3-none-any.whl
vendored
Normal file
BIN
dist/renamer-0.8.11-py3-none-any.whl
vendored
Normal file
Binary file not shown.
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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]:
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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,24 +265,32 @@ 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_]
|
|
||||||
if format_ == 'Matroska':
|
|
||||||
if self.is_3d() and 'mk3d' in exts:
|
|
||||||
return 'mk3d'
|
|
||||||
else:
|
|
||||||
return 'mkv'
|
|
||||||
else:
|
|
||||||
return exts[0] if exts else None
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# Use the constants function to get extension from format
|
||||||
|
ext = get_extension_from_format(format_)
|
||||||
|
|
||||||
|
# Special case: Matroska 3D uses mk3d extension
|
||||||
|
if ext == 'mkv' and self.is_3d():
|
||||||
|
return 'mk3d'
|
||||||
|
|
||||||
|
return ext
|
||||||
|
|
||||||
@cached_method()
|
@cached_method()
|
||||||
def extract_3d_layout(self) -> str | None:
|
def extract_3d_layout(self) -> str | None:
|
||||||
"""Extract 3D stereoscopic layout from MediaInfo"""
|
"""Extract 3D stereoscopic layout from MediaInfo"""
|
||||||
|
|||||||
Reference in New Issue
Block a user