82 lines
2.4 KiB
Python
82 lines
2.4 KiB
Python
"""Build canonical filenames: ``Title (Region) (tags) (Serial).iso``.
|
|
|
|
Revision (``(v1.03)``), disc (``(Disc 1)``) and edition tags are preserved;
|
|
language tags (``(En,Fr,De)``) are dropped; leading articles are moved back in
|
|
front (``Sims 2, The`` -> ``The Sims 2``).
|
|
"""
|
|
import re
|
|
|
|
_ILLEGAL = re.compile(r'[<>:"/\\|?*\x00-\x1f]')
|
|
_TAG_RE = re.compile(r"\s*\(([^()]*)\)\s*$")
|
|
_ARTICLE_RE = re.compile(r"^(.+),\s*(The|A|An)(?:\s+-\s+(.+))?$", re.IGNORECASE)
|
|
|
|
_LANG_CODES = {
|
|
"en", "fr", "de", "es", "it", "nl", "pt", "sv", "no", "da", "fi",
|
|
"ja", "ko", "zh", "pl", "ru", "el", "tr", "cs", "hu", "hi", "ar", "th",
|
|
}
|
|
|
|
|
|
def _is_language_tag(inner):
|
|
parts = [p.strip().lower() for p in inner.split(",")]
|
|
return bool(parts) and all(p in _LANG_CODES for p in parts)
|
|
|
|
|
|
def _split_tags(name):
|
|
"""Split trailing parenthetical tags; keep non-language tags, drop languages."""
|
|
title = name
|
|
kept = []
|
|
while True:
|
|
m = _TAG_RE.search(title)
|
|
if not m:
|
|
break
|
|
inner = m.group(1).strip()
|
|
if _is_language_tag(inner):
|
|
title = title[: m.start()]
|
|
else:
|
|
kept.insert(0, f"({inner})")
|
|
title = title[: m.start()]
|
|
return title.strip(), kept
|
|
|
|
|
|
def region_from_name(name):
|
|
"""Extract the region from a release name (first non-language tag).
|
|
|
|
Used when a DAT leaves the region field empty and embeds it in the name
|
|
(e.g. ``Oceans 11 (Japan, Europe)``).
|
|
"""
|
|
_, kept = _split_tags(str(name))
|
|
if not kept:
|
|
return ""
|
|
inner = kept[0][1:-1].strip()
|
|
return inner
|
|
|
|
|
|
def _reorder_article(title):
|
|
m = _ARTICLE_RE.match(title)
|
|
if m:
|
|
prefix, article, suffix = m.group(1), m.group(2), m.group(3)
|
|
result = f"{article} {prefix}"
|
|
if suffix:
|
|
result += f" - {suffix}"
|
|
return result
|
|
return title
|
|
|
|
|
|
def canonical_name(release, serial):
|
|
name = release["name"]
|
|
region = release.get("region")
|
|
if region:
|
|
for r in [x.strip() for x in region.split(",") if x.strip()]:
|
|
name = re.sub(rf"\s*\(\s*{re.escape(r)}\s*\)", "", name, flags=re.IGNORECASE)
|
|
title, tags = _split_tags(name)
|
|
title = _reorder_article(title)
|
|
parts = [title]
|
|
if region and region != "World":
|
|
parts.append(f"({region})")
|
|
parts.extend(tags)
|
|
if serial:
|
|
parts.append(f"({serial})")
|
|
name = _ILLEGAL.sub(" ", " ".join(parts)).strip()
|
|
name = re.sub(r"\s+", " ", name)
|
|
return f"{name}.iso"
|