mirror of
https://github.com/shadoll/moma.git
synced 2026-08-28 11:33:25 +00:00
chore: Bump version to 0.6.1 and update decorators to use new cache system
This commit is contained in:
@@ -23,6 +23,12 @@ from .track_formatter import TrackFormatter
|
||||
from .special_info_formatter import SpecialInfoFormatter
|
||||
from .formatter import FormatterApplier
|
||||
|
||||
# Decorator instances
|
||||
from .date_decorators import date_decorators, DateDecorators
|
||||
from .special_info_decorators import special_info_decorators, SpecialInfoDecorators
|
||||
from .text_decorators import text_decorators, TextDecorators
|
||||
from .conditional_decorators import conditional_decorators, ConditionalDecorators
|
||||
|
||||
__all__ = [
|
||||
# Base classes
|
||||
'Formatter',
|
||||
@@ -41,4 +47,14 @@ __all__ = [
|
||||
'TrackFormatter',
|
||||
'SpecialInfoFormatter',
|
||||
'FormatterApplier',
|
||||
|
||||
# Decorator instances and classes
|
||||
'date_decorators',
|
||||
'DateDecorators',
|
||||
'special_info_decorators',
|
||||
'SpecialInfoDecorators',
|
||||
'text_decorators',
|
||||
'TextDecorators',
|
||||
'conditional_decorators',
|
||||
'ConditionalDecorators',
|
||||
]
|
||||
@@ -0,0 +1,88 @@
|
||||
"""Conditional formatting decorators.
|
||||
|
||||
Provides decorators for conditional formatting (wrap, replace_slashes, default):
|
||||
|
||||
@conditional_decorators.wrap("[", "]")
|
||||
def get_order(self):
|
||||
return self.extractor.get('order')
|
||||
"""
|
||||
|
||||
from functools import wraps
|
||||
from typing import Callable, Any
|
||||
|
||||
|
||||
class ConditionalDecorators:
|
||||
"""Conditional formatting decorators (wrap, replace_slashes, default)."""
|
||||
|
||||
@staticmethod
|
||||
def wrap(left: str, right: str = "") -> Callable:
|
||||
"""Decorator to wrap value with delimiters if it exists.
|
||||
|
||||
Can be used for prefix-only (right=""), suffix-only (left=""), or both.
|
||||
|
||||
Usage:
|
||||
@conditional_decorators.wrap("[", "]")
|
||||
def get_order(self):
|
||||
return self.extractor.get('order')
|
||||
|
||||
# Prefix only
|
||||
@conditional_decorators.wrap(" ")
|
||||
def get_source(self):
|
||||
return self.extractor.get('source')
|
||||
|
||||
# Suffix only
|
||||
@conditional_decorators.wrap("", ",")
|
||||
def get_hdr(self):
|
||||
return self.extractor.get('hdr')
|
||||
"""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
result = func(*args, **kwargs)
|
||||
return f"{left}{result}{right}" if result else ""
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@staticmethod
|
||||
def replace_slashes() -> Callable:
|
||||
"""Decorator to replace forward and back slashes with dashes.
|
||||
|
||||
Usage:
|
||||
@conditional_decorators.replace_slashes()
|
||||
def get_title(self):
|
||||
return self.extractor.get('title')
|
||||
"""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
result = func(*args, **kwargs)
|
||||
if result:
|
||||
return str(result).replace("/", "-").replace("\\", "-")
|
||||
return result or ""
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@staticmethod
|
||||
def default(default_value: Any) -> Callable:
|
||||
"""Decorator to provide a default value if result is None or empty.
|
||||
|
||||
NOTE: It's better to handle defaults in the extractor itself rather than
|
||||
using this decorator. This decorator should only be used when the extractor
|
||||
cannot provide a sensible default.
|
||||
|
||||
Usage:
|
||||
@conditional_decorators.default("Unknown")
|
||||
def get_value(self):
|
||||
return self.extractor.get('value')
|
||||
"""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> Any:
|
||||
result = func(*args, **kwargs)
|
||||
return result if result else default_value
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
# Singleton instance
|
||||
conditional_decorators = ConditionalDecorators()
|
||||
@@ -0,0 +1,37 @@
|
||||
"""Date formatting decorators.
|
||||
|
||||
Provides decorator versions of DateFormatter methods for cleaner code:
|
||||
|
||||
@date_decorators.year()
|
||||
def get_year(self):
|
||||
return self.extractor.get('year')
|
||||
"""
|
||||
|
||||
from functools import wraps
|
||||
from typing import Callable
|
||||
from .date_formatter import DateFormatter
|
||||
|
||||
|
||||
class DateDecorators:
|
||||
"""Date and time formatting decorators."""
|
||||
|
||||
@staticmethod
|
||||
def modification_date() -> Callable:
|
||||
"""Decorator to format modification dates.
|
||||
|
||||
Usage:
|
||||
@date_decorators.modification_date()
|
||||
def get_mtime(self):
|
||||
return self.file_path.stat().st_mtime
|
||||
"""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
result = func(*args, **kwargs)
|
||||
return DateFormatter.format_modification_date(result)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
# Singleton instance
|
||||
date_decorators = DateDecorators()
|
||||
@@ -1,37 +1,99 @@
|
||||
from rich.markup import escape
|
||||
from .text_formatter import TextFormatter
|
||||
from .date_formatter import DateFormatter
|
||||
from .special_info_formatter import SpecialInfoFormatter
|
||||
from .special_info_decorators import special_info_decorators
|
||||
from .conditional_decorators import conditional_decorators
|
||||
from .text_decorators import text_decorators
|
||||
|
||||
|
||||
class ProposedNameFormatter:
|
||||
"""Class for formatting proposed filenames"""
|
||||
"""Class for formatting proposed filenames using decorator pattern with properties."""
|
||||
|
||||
def __init__(self, extractor):
|
||||
"""Initialize with media extractor data"""
|
||||
|
||||
self.__order = f"[{extractor.get('order')}] " if extractor.get("order") else ""
|
||||
self.__title = (extractor.get("title") or "Unknown Title").replace("/", "-").replace("\\", "-")
|
||||
self.__year = DateFormatter.format_year(extractor.get("year"))
|
||||
self.__source = f" {extractor.get('source')}" if extractor.get("source") else ""
|
||||
self.__frame_class = extractor.get("frame_class") or None
|
||||
self.__hdr = f",{extractor.get('hdr')}" if extractor.get("hdr") else ""
|
||||
self.__audio_langs = extractor.get("audio_langs") or None
|
||||
self.__special_info = f" [{SpecialInfoFormatter.format_special_info(extractor.get('special_info'))}]" if extractor.get("special_info") else ""
|
||||
self.__db_info = f" [{SpecialInfoFormatter.format_database_info(extractor.get('movie_db'))}]" if extractor.get("movie_db") else ""
|
||||
self.__extension = extractor.get("extension") or "ext"
|
||||
self._extractor = extractor
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Convert the proposed name to string"""
|
||||
return self.rename_line()
|
||||
return self.rename_line
|
||||
|
||||
@property
|
||||
@conditional_decorators.wrap("[", "] ")
|
||||
def _order(self) -> str:
|
||||
"""Get the order number formatted as [XX] """
|
||||
return self._extractor.get("order")
|
||||
|
||||
@property
|
||||
@conditional_decorators.replace_slashes()
|
||||
def _title(self) -> str:
|
||||
"""Get the title with slashes replaced"""
|
||||
return self._extractor.get("title")
|
||||
|
||||
@property
|
||||
@conditional_decorators.wrap(" (", ")")
|
||||
def _year(self) -> str:
|
||||
"""Get the year formatted as (YYYY)"""
|
||||
return self._extractor.get("year")
|
||||
|
||||
@property
|
||||
@conditional_decorators.wrap(" ")
|
||||
def _source(self) -> str:
|
||||
"""Get the source"""
|
||||
return self._extractor.get("source")
|
||||
|
||||
@property
|
||||
def _frame_class(self) -> str:
|
||||
"""Get the frame class"""
|
||||
return self._extractor.get("frame_class") or ""
|
||||
|
||||
@property
|
||||
@conditional_decorators.wrap(",")
|
||||
def _hdr(self) -> str:
|
||||
"""Get the HDR info formatted with a trailing comma if present"""
|
||||
return self._extractor.get("hdr")
|
||||
|
||||
@property
|
||||
def _audio_langs(self) -> str:
|
||||
"""Get the audio languages formatted with a trailing comma if present"""
|
||||
return self._extractor.get("audio_langs") or ""
|
||||
|
||||
@property
|
||||
@conditional_decorators.wrap(" [", "]")
|
||||
@special_info_decorators.special_info()
|
||||
def _special_info(self) -> str:
|
||||
"""Get the special info formatted within brackets"""
|
||||
return self._extractor.get("special_info")
|
||||
|
||||
@property
|
||||
@conditional_decorators.wrap(" [", "]")
|
||||
@special_info_decorators.database_info()
|
||||
def _db_info(self) -> str:
|
||||
"""Get the database info formatted within brackets"""
|
||||
return self._extractor.get("movie_db")
|
||||
|
||||
@property
|
||||
def _extension(self) -> str:
|
||||
"""Get the file extension"""
|
||||
return self._extractor.get("extension")
|
||||
|
||||
@property
|
||||
def rename_line(self) -> str:
|
||||
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}"
|
||||
"""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}"
|
||||
return result.replace("/", "-").replace("\\", "-")
|
||||
|
||||
def rename_line_formatted(self, file_path) -> str:
|
||||
"""Format the proposed name for display with color"""
|
||||
proposed = escape(str(self))
|
||||
if file_path.name == str(self):
|
||||
return f">> {TextFormatter.green(proposed)} <<"
|
||||
return f">> {TextFormatter.bold_yellow(proposed)} <<"
|
||||
return self.rename_line_similar
|
||||
return self.rename_line_different
|
||||
|
||||
@property
|
||||
@text_decorators.green()
|
||||
def rename_line_similar(self) -> str:
|
||||
"""Generate a simplified proposed filename for similarity checks."""
|
||||
return escape(str(self))
|
||||
|
||||
@property
|
||||
@text_decorators.orange()
|
||||
def rename_line_different(self) -> str:
|
||||
"""Generate a detailed proposed filename for difference checks."""
|
||||
return escape(str(self))
|
||||
@@ -0,0 +1,54 @@
|
||||
"""Special info formatting decorators.
|
||||
|
||||
Provides decorator versions of SpecialInfoFormatter methods:
|
||||
|
||||
@special_info_decorators.special_info()
|
||||
def get_special_info(self):
|
||||
return self.extractor.get('special_info')
|
||||
"""
|
||||
|
||||
from functools import wraps
|
||||
from typing import Callable
|
||||
from .special_info_formatter import SpecialInfoFormatter
|
||||
|
||||
|
||||
class SpecialInfoDecorators:
|
||||
"""Special info and database formatting decorators."""
|
||||
|
||||
@staticmethod
|
||||
def special_info() -> Callable:
|
||||
"""Decorator to format special info lists.
|
||||
|
||||
Usage:
|
||||
@special_info_decorators.special_info()
|
||||
def get_special_info(self):
|
||||
return self.extractor.get('special_info')
|
||||
"""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
result = func(*args, **kwargs)
|
||||
return SpecialInfoFormatter.format_special_info(result)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@staticmethod
|
||||
def database_info() -> Callable:
|
||||
"""Decorator to format database info.
|
||||
|
||||
Usage:
|
||||
@special_info_decorators.database_info()
|
||||
def get_db_info(self):
|
||||
return self.extractor.get('movie_db')
|
||||
"""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
result = func(*args, **kwargs)
|
||||
return SpecialInfoFormatter.format_database_info(result)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
# Singleton instance
|
||||
special_info_decorators = SpecialInfoDecorators()
|
||||
@@ -0,0 +1,130 @@
|
||||
"""Text formatting decorators.
|
||||
|
||||
Provides decorator versions of TextFormatter methods:
|
||||
|
||||
@text_decorators.bold()
|
||||
def get_title(self):
|
||||
return self.title
|
||||
"""
|
||||
|
||||
from functools import wraps
|
||||
from typing import Callable
|
||||
from .text_formatter import TextFormatter
|
||||
|
||||
|
||||
class TextDecorators:
|
||||
"""Text styling and color decorators."""
|
||||
|
||||
@staticmethod
|
||||
def bold() -> Callable:
|
||||
"""Decorator to make text bold."""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
result = func(*args, **kwargs)
|
||||
return TextFormatter.bold(str(result))
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@staticmethod
|
||||
def italic() -> Callable:
|
||||
"""Decorator to make text italic."""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
result = func(*args, **kwargs)
|
||||
return TextFormatter.italic(str(result))
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@staticmethod
|
||||
def green() -> Callable:
|
||||
"""Decorator to color text green."""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
result = func(*args, **kwargs)
|
||||
return TextFormatter.green(str(result))
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@staticmethod
|
||||
def yellow() -> Callable:
|
||||
"""Decorator to color text yellow."""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
result = func(*args, **kwargs)
|
||||
return TextFormatter.yellow(str(result))
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@staticmethod
|
||||
def cyan() -> Callable:
|
||||
"""Decorator to color text cyan."""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
result = func(*args, **kwargs)
|
||||
return TextFormatter.cyan(str(result))
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@staticmethod
|
||||
def magenta() -> Callable:
|
||||
"""Decorator to color text magenta."""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
result = func(*args, **kwargs)
|
||||
return TextFormatter.magenta(str(result))
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@staticmethod
|
||||
def red() -> Callable:
|
||||
"""Decorator to color text red."""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
result = func(*args, **kwargs)
|
||||
return TextFormatter.red(str(result))
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@staticmethod
|
||||
def orange() -> Callable:
|
||||
"""Decorator to color text orange."""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
result = func(*args, **kwargs)
|
||||
return TextFormatter.orange(str(result))
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@staticmethod
|
||||
def uppercase() -> Callable:
|
||||
"""Decorator to convert text to uppercase."""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
result = func(*args, **kwargs)
|
||||
return TextFormatter.uppercase(str(result))
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@staticmethod
|
||||
def lowercase() -> Callable:
|
||||
"""Decorator to convert text to lowercase."""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs) -> str:
|
||||
result = func(*args, **kwargs)
|
||||
return TextFormatter.lowercase(str(result))
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
# Singleton instance
|
||||
text_decorators = TextDecorators()
|
||||
@@ -78,6 +78,10 @@ class TextFormatter:
|
||||
def yellow(text: str) -> str:
|
||||
return f"[yellow]{text}[/yellow]"
|
||||
|
||||
@staticmethod
|
||||
def orange(text: str) -> str:
|
||||
return f"[orange]{text}[/orange]"
|
||||
|
||||
@staticmethod
|
||||
def magenta(text: str) -> str:
|
||||
return f"[magenta]{text}[/magenta]"
|
||||
|
||||
Reference in New Issue
Block a user