mirror of
https://github.com/shadoll/moma.git
synced 2026-08-28 03:27:34 +00:00
This commit introduces a new module `logging_config.py` that implements a singleton pattern for logging configuration. The logger is initialized only once and can be configured based on an environment variable to log to a file or to the console. This centralizes logging setup and ensures consistent logging behavior throughout the application.
117 lines
4.0 KiB
Python
117 lines
4.0 KiB
Python
"""Embedded metadata extractor using Mutagen.
|
|
|
|
This module provides the MetadataExtractor class for reading embedded
|
|
metadata tags from media files using the Mutagen library.
|
|
"""
|
|
|
|
import mutagen
|
|
import logging
|
|
from pathlib import Path
|
|
from ..constants import MEDIA_TYPES
|
|
from ..cache import cached_method, Cache
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class MetadataExtractor:
|
|
"""Extractor for embedded metadata tags from media files.
|
|
|
|
This class uses the Mutagen library to read embedded metadata tags
|
|
such as title, artist, and duration. Falls back to MIME type detection
|
|
when Mutagen cannot read the file.
|
|
|
|
Attributes:
|
|
file_path: Path object pointing to the file
|
|
info: Mutagen file info object, or None if file cannot be read
|
|
_cache: Internal cache for method results
|
|
|
|
Example:
|
|
>>> from pathlib import Path
|
|
>>> extractor = MetadataExtractor(Path("movie.mkv"))
|
|
>>> title = extractor.extract_title()
|
|
>>> duration = extractor.extract_duration()
|
|
"""
|
|
|
|
def __init__(self, file_path: Path, use_cache: bool = True):
|
|
"""Initialize the MetadataExtractor.
|
|
|
|
Args:
|
|
file_path: Path object pointing to the media file
|
|
use_cache: Whether to use caching (default: True)
|
|
"""
|
|
self.file_path = file_path
|
|
self.cache = Cache() if use_cache else None # Singleton cache for @cached_method decorator
|
|
self.settings = None # Will be set by Settings singleton if needed
|
|
self._cache: dict[str, any] = {} # Internal cache for method results
|
|
try:
|
|
self.info = mutagen.File(file_path) # type: ignore
|
|
except Exception as e:
|
|
logger.debug(f"Failed to read metadata from {file_path}: {e}")
|
|
self.info = None
|
|
|
|
@cached_method()
|
|
def extract_title(self) -> str | None:
|
|
"""Extract title from embedded metadata tags.
|
|
|
|
Returns:
|
|
Title string if found in metadata, None otherwise
|
|
"""
|
|
if self.info:
|
|
return getattr(self.info, 'title', None) or getattr(self.info, 'get', lambda x, default=None: default)('title', [None])[0] # type: ignore
|
|
return None
|
|
|
|
@cached_method()
|
|
def extract_duration(self) -> float | None:
|
|
"""Extract duration from metadata.
|
|
|
|
Returns:
|
|
Duration in seconds as a float, or None if not available
|
|
"""
|
|
if self.info:
|
|
return getattr(self.info, 'length', None)
|
|
return None
|
|
|
|
@cached_method()
|
|
def extract_artist(self) -> str | None:
|
|
"""Extract artist from embedded metadata tags.
|
|
|
|
Returns:
|
|
Artist string if found in metadata, None otherwise
|
|
"""
|
|
if self.info:
|
|
return getattr(self.info, 'artist', None) or getattr(self.info, 'get', lambda x, default=None: default)('artist', [None])[0] # type: ignore
|
|
return None
|
|
|
|
@cached_method()
|
|
def extract_meta_type(self) -> str:
|
|
"""Extract metadata container type.
|
|
|
|
Returns the Mutagen class name (e.g., "FLAC", "MP4") if available,
|
|
otherwise falls back to MIME type detection.
|
|
|
|
Returns:
|
|
Container type name, or "Unknown" if cannot be determined
|
|
"""
|
|
if self.info:
|
|
return type(self.info).__name__
|
|
return self._detect_by_mime()
|
|
|
|
def _detect_by_mime(self) -> str:
|
|
"""Detect metadata type by MIME type.
|
|
|
|
Uses python-magic library to detect file MIME type and maps it
|
|
to a metadata container type.
|
|
|
|
Returns:
|
|
Container type name based on MIME type, or "Unknown" if detection fails
|
|
"""
|
|
try:
|
|
import magic
|
|
mime = magic.from_file(str(self.file_path), mime=True)
|
|
for ext, info in MEDIA_TYPES.items():
|
|
if info['mime'] == mime:
|
|
return info['meta_type']
|
|
return 'Unknown'
|
|
except Exception as e:
|
|
logger.debug(f"Failed to detect MIME type for {self.file_path}: {e}")
|
|
return 'Unknown' |