Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mnamer/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def tmdb_movies(
def tmdb_search_movies(
api_key: str,
title: str,
year: int | str | None = None,
year: int | None = None,
language: Language | None = None,
region: str | None = None,
adult: bool = False,
Expand Down
19 changes: 13 additions & 6 deletions mnamer/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
str_fix_padding,
str_replace_slashes,
str_title_case,
year_parse,
)


Expand Down Expand Up @@ -111,21 +110,25 @@ class MetadataMovie(Metadata):
"""

name: str | None = None
year: str | None = None
date: dt.date | None = None
id_imdb: str | None = None
id_tmdb: str | None = None

def __post_init__(self):
if isinstance(self.date, str):
self.date = parse_date(self.date)

def __format__(self, format_spec: str | None):
default = "{name} ({year})"
re_pattern = r"({(\w+)(?:\[[\w:]+\])?(?:\:\d{1,2})?})"
default = "{name} ({date.year})"
re_pattern = r"({(\w+)(?:\[[\w:]+\]|\.\w+)?(?:\:\d{1,2})?})"
s = re.sub(re_pattern, self._format_repl, format_spec or default)
s = str_fix_padding(s)
return s

def __setattr__(self, key: str, value: Any):
converter_map: dict[str, Callable] = {
"name": fn_pipe(str_replace_slashes, str_title_case),
"year": year_parse,
"date": parse_date,
}
converter: Callable | None = converter_map.get(key)
if value is not None and converter:
Expand All @@ -141,6 +144,7 @@ class MetadataEpisode(Metadata):
"""

series: str | None = None
series_date: dt.date | None = None
season: int | None = None
episode: int | None = None
date: dt.date | None = None
Expand All @@ -155,10 +159,12 @@ def __post_init__(self):
self.episode = int(self.episode)
if isinstance(self.date, str):
self.date = parse_date(self.date)
if isinstance(self.series_date, str):
self.series_date = parse_date(self.series_date)

def __format__(self, format_spec: str | None):
default = "{series} - {season:02}x{episode:02} - {title}"
re_pattern = r"({(\w+)(?:\[[\w:]+\])?(?:\:\d{1,2})?})"
re_pattern = r"({(\w+)(?:\[[\w:]+\]|\.\w+)?(?:\:\d{1,2})?})"
s = re.sub(re_pattern, self._format_repl, format_spec or default)
s = str_fix_padding(s)
return s
Expand All @@ -169,6 +175,7 @@ def __setattr__(self, key: str, value: Any):
"episode": int,
"season": int,
"series": fn_pipe(str_replace_slashes, str_title_case),
"series_date": parse_date,
"title": fn_pipe(str_replace_slashes, str_title_case),
}
converter: Callable | None = converter_map.get(key)
Expand Down
28 changes: 16 additions & 12 deletions mnamer/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from mnamer.metadata import Metadata, MetadataEpisode, MetadataMovie
from mnamer.setting_store import SettingStore
from mnamer.types import MediaType, ProviderType
from mnamer.utils import parse_date, year_range_parse
from mnamer.utils import parse_date


class Provider(ABC):
Expand Down Expand Up @@ -83,7 +83,7 @@ def search(self, query: MetadataMovie) -> Iterator[MetadataMovie]:
if query.id_imdb:
results = self._lookup_movie(query.id_imdb)
elif query.name:
results = self._search_movie(query.name, query.year)
results = self._search_movie(query.name, None if query.date is None else query.date.year)
else:
raise MnamerNotFoundException
yield from results
Expand All @@ -94,25 +94,27 @@ def _lookup_movie(self, id_imdb: str) -> Iterator[MetadataMovie]:
try:
release_date = dt.datetime.strptime(
response["Released"], "%d %b %Y"
).strftime("%Y-%m-%d")
)
except (KeyError, ValueError):
if response.get("Year") in (None, "N/A"):
release_date = None
else:
release_date = "{}-01-01".format(response["Year"])
release_date = dt.datetime.strptime(
"{}-01-01".format(response["Year"]), "%Y-%m-%d"
)
meta = MetadataMovie(
name=response["Title"],
year=release_date,
date=release_date,
synopsis=response["Plot"],
id_imdb=response["imdbID"],
)
if meta.synopsis == "N/A":
meta.synopsis = None
yield meta

def _search_movie(self, name: str, year: str | None) -> Iterator[MetadataMovie]:
def _search_movie(self, name: str, year: int | None) -> Iterator[MetadataMovie]:
assert self.api_key
year_from, year_to = year_range_parse(year, 5)
year_from, year_to = year - 5, year + 5
found = False
page = 1
page_max = 10 # each page yields a maximum of 10 results
Expand Down Expand Up @@ -153,7 +155,7 @@ def search(self, query: MetadataMovie) -> Iterator[MetadataMovie]:
if query.id_tmdb:
results = self._search_id(query.id_tmdb, query.language)
elif query.name:
results = self._search_name(query.name, query.year, query.language)
results = self._search_name(query.name, None if query.date is None else query.date.year, query.language)
else:
raise MnamerNotFoundException
yield from results
Expand All @@ -166,13 +168,13 @@ def _search_id(
yield MetadataMovie(
name=response["title"],
language=language,
year=response["release_date"],
date=response["release_date"],
synopsis=response["overview"],
id_tmdb=response["id"],
id_imdb=response["imdb_id"],
)

def _search_name(self, name: str, year: str | None, language: Language | None):
def _search_name(self, name: str, year: int | None, language: Language | None):
assert self.api_key
page = 1
page_max = 5 # each page yields a maximum of 20 results
Expand All @@ -193,9 +195,9 @@ def _search_name(self, name: str, year: str | None, language: Language | None):
name=entry["title"],
language=language,
synopsis=entry["overview"],
year=entry["release_date"],
date=entry["release_date"],
)
if not meta.year:
if not meta.date:
continue
yield meta
found = True
Expand Down Expand Up @@ -275,6 +277,7 @@ def _search_id(
id_tvdb=id_tvdb,
season=entry["airedSeason"],
series=series_data["data"]["seriesName"],
series_date=series_data["data"]["firstAired"],
language=language,
synopsis=(entry["overview"] or "")
.replace("\r\n", "")
Expand Down Expand Up @@ -480,6 +483,7 @@ def _transform_meta(
id_tvmaze=id_tvmaze or None,
season=episode_entry["season"],
series=series_entry["name"],
series_date=series_entry["premiered"],
synopsis=episode_entry["summary"] or None,
title=episode_entry["name"] or None,
)
2 changes: 1 addition & 1 deletion mnamer/setting_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ class SettingStore:
).as_dict(),
)
movie_format: str = dataclasses.field(
default="{name} ({year}).{extension}",
default="{name} ({date.year}).{extension}",
metadata=SettingSpec(
dest="movie_format",
flags=["--movie_format", "--movie-format", "--movieformat"],
Expand Down
6 changes: 4 additions & 2 deletions mnamer/target.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ def _parse(self, file_path: Path):
self.metadata.language = path_data.get("language")
self.metadata.group = path_data.get("release_group")
self.metadata.container = file_path.suffix or None
if "date" in path_data:
self.metadata.date = path_data.get("date")
elif "year" in path_data:
self.metadata.date = "{}-01-01".format(path_data.get("year"))
if not self.metadata.language:
try:
self.metadata.language = path_data.get("language")
Expand All @@ -178,9 +182,7 @@ def _parse(self, file_path: Path):
pass
if isinstance(self.metadata, MetadataMovie):
self.metadata.name = path_data.get("title")
self.metadata.year = path_data.get("year")
elif isinstance(self.metadata, MetadataEpisode):
self.metadata.date = path_data.get("date")
self.metadata.episode = path_data.get("episode")
self.metadata.season = path_data.get("season")
self.metadata.series = path_data.get("title")
Expand Down
27 changes: 0 additions & 27 deletions mnamer/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,30 +476,3 @@ def str_title_case(s: str) -> str:
s = s[:pos] + exception.upper() + s[pos + word_length :]

return s


def year_parse(s: str) -> int | None:
"""Parses a year from a string."""
regex = r"((?:19|20)\d{2})(?:$|[-/]\d{2}[-/]\d{2})"
try:
return int(re.findall(regex, str(s))[0])
except IndexError:
return None


def year_range_parse(years: str | int | None, tolerance: int = 1) -> tuple[int, int]:
"""Parses a year or dash-delimited year range."""
regex = r"^((?:19|20)\d{2})?([-,: ]*)?((?:19|20)\d{2})?$"
default_start = 1900
default_end = CURRENT_YEAR
try:
start, dash, end = re.match(regex, str(years).strip()).groups() # type: ignore
except AttributeError:
start, end, dash = None, None, True
if not start and not end:
start, end, dash = None, None, True
start = int(start or default_start)
end = int(end or default_end)
if not dash:
end = start
return start - tolerance, end + tolerance
Loading