feat(file_renamer): Support more formats
This commit is contained in:
File diff suppressed because it is too large
Load Diff
+29
-29
@@ -62,7 +62,9 @@ def parse_date(filename: str) -> ParsedDate | None:
|
|||||||
def from_us_format():
|
def from_us_format():
|
||||||
match = re_date_us.search(filename)
|
match = re_date_us.search(filename)
|
||||||
m, d, y = map(int, match.groups())
|
m, d, y = map(int, match.groups())
|
||||||
return ParsedDate(datetime.date(y + 2000, m, d), start=match.start(), end=match.end())
|
return ParsedDate(
|
||||||
|
datetime.date(y + 2000, m, d), start=match.start(), end=match.end()
|
||||||
|
)
|
||||||
|
|
||||||
def from_iso():
|
def from_iso():
|
||||||
match = re_date_iso.search(filename)
|
match = re_date_iso.search(filename)
|
||||||
@@ -72,7 +74,9 @@ def parse_date(filename: str) -> ParsedDate | None:
|
|||||||
def from_iso_short():
|
def from_iso_short():
|
||||||
match = re_date_iso_short.search(filename)
|
match = re_date_iso_short.search(filename)
|
||||||
y, m, d = map(int, match.groups())
|
y, m, d = map(int, match.groups())
|
||||||
return ParsedDate(datetime.date(y + 2000, m, d), start=match.start(), end=match.end())
|
return ParsedDate(
|
||||||
|
datetime.date(y + 2000, m, d), start=match.start(), end=match.end()
|
||||||
|
)
|
||||||
|
|
||||||
def from_iso_reversed():
|
def from_iso_reversed():
|
||||||
match = re_date_iso_rev.search(filename)
|
match = re_date_iso_rev.search(filename)
|
||||||
@@ -82,7 +86,9 @@ def parse_date(filename: str) -> ParsedDate | None:
|
|||||||
def from_iso_reversed_short():
|
def from_iso_reversed_short():
|
||||||
match = re_date_iso_rev_short.search(filename)
|
match = re_date_iso_rev_short.search(filename)
|
||||||
d, m, y = map(int, match.groups())
|
d, m, y = map(int, match.groups())
|
||||||
return ParsedDate(datetime.date(y + 2000, m, d), start=match.start(), end=match.end())
|
return ParsedDate(
|
||||||
|
datetime.date(y + 2000, m, d), start=match.start(), end=match.end()
|
||||||
|
)
|
||||||
|
|
||||||
candidates = []
|
candidates = []
|
||||||
for fn in [
|
for fn in [
|
||||||
@@ -101,7 +107,9 @@ def parse_date(filename: str) -> ParsedDate | None:
|
|||||||
today = datetime.date.today()
|
today = datetime.date.today()
|
||||||
future_threshold = today + datetime.timedelta(days=60)
|
future_threshold = today + datetime.timedelta(days=60)
|
||||||
past_threshold = datetime.date(2010, 1, 1)
|
past_threshold = datetime.date(2010, 1, 1)
|
||||||
candidates = [it for it in candidates if past_threshold < it.date < future_threshold]
|
candidates = [
|
||||||
|
it for it in candidates if past_threshold < it.date < future_threshold
|
||||||
|
]
|
||||||
|
|
||||||
if not candidates:
|
if not candidates:
|
||||||
return
|
return
|
||||||
@@ -139,23 +147,9 @@ def trash(path: Path):
|
|||||||
subprocess.run(cmd).check_returncode()
|
subprocess.run(cmd).check_returncode()
|
||||||
|
|
||||||
|
|
||||||
def filenames_to_actors():
|
def parse_release(
|
||||||
sources = [
|
filename: str, known_actors: set[str] | None = None
|
||||||
Path(r"/Users/abdus/Downloads/temp/"),
|
) -> Release | None:
|
||||||
Path(r"/Volumes/BANDAID/_temp/__reenc/"),
|
|
||||||
Path(r"/Volumes/BANDAID/_temp/"),
|
|
||||||
]
|
|
||||||
actors = set()
|
|
||||||
for it in sources:
|
|
||||||
for f in it.glob("*.mp4"):
|
|
||||||
if not f.is_file():
|
|
||||||
continue
|
|
||||||
if r := parse_release(f.name):
|
|
||||||
actors.update(r.actors)
|
|
||||||
return actors
|
|
||||||
|
|
||||||
|
|
||||||
def parse_release(filename: str, known_actors: set[str] | None = None) -> Release | None:
|
|
||||||
if not known_actors:
|
if not known_actors:
|
||||||
known_actors = set()
|
known_actors = set()
|
||||||
if any(filename.lower().endswith(ext) for ext in [".mp4", ".mkv"]):
|
if any(filename.lower().endswith(ext) for ext in [".mp4", ".mkv"]):
|
||||||
@@ -174,7 +168,9 @@ def parse_release(filename: str, known_actors: set[str] | None = None) -> Releas
|
|||||||
title=title,
|
title=title,
|
||||||
released_at=datetime.date.fromisoformat(date),
|
released_at=datetime.date.fromisoformat(date),
|
||||||
)
|
)
|
||||||
case [actors, studio, date] if studio.startswith("@") and (parsed := parse_date(date)):
|
case [actors, studio, date] if studio.startswith("@") and (
|
||||||
|
parsed := parse_date(date)
|
||||||
|
):
|
||||||
return Release(
|
return Release(
|
||||||
actors=sorted(actors.split(", ")),
|
actors=sorted(actors.split(", ")),
|
||||||
studio=studio.removeprefix("@"),
|
studio=studio.removeprefix("@"),
|
||||||
@@ -210,14 +206,20 @@ def parse_release(filename: str, known_actors: set[str] | None = None) -> Releas
|
|||||||
# assert '.PRT' in filename
|
# assert '.PRT' in filename
|
||||||
remaining = re.sub(r"\.(720p|1080p|HEVC|x265|PRT|XXX)", " ", filename)
|
remaining = re.sub(r"\.(720p|1080p|HEVC|x265|PRT|XXX)", " ", filename)
|
||||||
studio = remaining[: remaining.index(".")]
|
studio = remaining[: remaining.index(".")]
|
||||||
|
remaining = remaining[len(studio) :]
|
||||||
parsed_date = parse_date(remaining)
|
parsed_date = parse_date(remaining)
|
||||||
remaining = remaining[parsed_date.end :]
|
if parsed_date:
|
||||||
|
remaining = remaining[parsed_date.end :]
|
||||||
remaining = re.sub(r"[. ]+", " ", remaining).strip()
|
remaining = re.sub(r"[. ]+", " ", remaining).strip()
|
||||||
|
|
||||||
actors = []
|
actors = []
|
||||||
title = None
|
title = None
|
||||||
|
|
||||||
|
# PornFidelity.E1109.Uma.Jolie
|
||||||
match remaining.split(" "):
|
match remaining.split(" "):
|
||||||
|
case [episode, *names] if episode.startswith("E") and episode[1:].isdigit():
|
||||||
|
title = episode
|
||||||
|
actors = [" ".join(names)]
|
||||||
case [a_first, a_last, "And", b_first, b_last]:
|
case [a_first, a_last, "And", b_first, b_last]:
|
||||||
actors = [f"{a_first} {a_last}", f"{b_first} {b_last}"]
|
actors = [f"{a_first} {a_last}", f"{b_first} {b_last}"]
|
||||||
case [a_first, a_last, "And", b_first, b_last, *rest]:
|
case [a_first, a_last, "And", b_first, b_last, *rest]:
|
||||||
@@ -235,16 +237,12 @@ def parse_release(filename: str, known_actors: set[str] | None = None) -> Releas
|
|||||||
studio=studio,
|
studio=studio,
|
||||||
actors=sorted(actors),
|
actors=sorted(actors),
|
||||||
title=title,
|
title=title,
|
||||||
released_at=parsed_date.date,
|
released_at=parsed_date.date if parsed_date else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
def from_galaxxxy():
|
|
||||||
pass
|
|
||||||
|
|
||||||
for fn in [
|
for fn in [
|
||||||
from_own,
|
from_own,
|
||||||
from_prt,
|
from_prt,
|
||||||
from_galaxxxy,
|
|
||||||
]:
|
]:
|
||||||
try:
|
try:
|
||||||
if res := fn():
|
if res := fn():
|
||||||
@@ -255,7 +253,9 @@ def parse_release(filename: str, known_actors: set[str] | None = None) -> Releas
|
|||||||
|
|
||||||
def parse_args():
|
def parse_args():
|
||||||
arger = argparse.ArgumentParser()
|
arger = argparse.ArgumentParser()
|
||||||
arger.add_argument("filenames", nargs="+", type=lambda v: Path(v).resolve(), help="Filenames")
|
arger.add_argument(
|
||||||
|
"filenames", nargs="+", type=lambda v: Path(v).resolve(), help="Filenames"
|
||||||
|
)
|
||||||
return arger.parse_args()
|
return arger.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+148
-62
@@ -43,8 +43,8 @@ from file_renamer import Release
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
"DadCrush.21.10.09.Ailee.Anne.My.Stepdaughters.Hot.XXX.1080p.HEVC.x265.PRT.mp4",
|
"DadCrush.21.10.09.Ailee.Anne.My.Stepdaughters.Hot.XXX.1080p.HEVC.x265.PRT.mp4",
|
||||||
datetime.date(2021, 10, 9)
|
datetime.date(2021, 10, 9),
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_parse_date(filename: str, date: datetime.date | None):
|
def test_parse_date(filename: str, date: datetime.date | None):
|
||||||
@@ -57,68 +57,154 @@ def test_parse_date(filename: str, date: datetime.date | None):
|
|||||||
assert parsed.date == date
|
assert parsed.date == date
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(['filename', 'expected'], [
|
@pytest.mark.parametrize(
|
||||||
|
["filename", "expected"],
|
||||||
[
|
[
|
||||||
'PenthouseGold.23.02.05.Tiffany.Tatum.XXX.720p.HEVC.x265.PRT',
|
[
|
||||||
Release(studio='DoctorAdventures', actors=['Jamie Michelle'], title='Nurse Jamie Knows Best', released_at=datetime.date(2021, 5, 26)),
|
"PornFidelity.E1109.Uma.Jolie.XXX.720p.HEVC.x265.PRT",
|
||||||
|
Release(
|
||||||
|
studio="PornFidelity",
|
||||||
|
actors=["Uma Jolie"],
|
||||||
|
title="E1109",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"PenthouseGold.23.02.05.Tiffany.Tatum.XXX.720p.HEVC.x265.PRT",
|
||||||
|
Release(
|
||||||
|
studio="DoctorAdventures",
|
||||||
|
actors=["Jamie Michelle"],
|
||||||
|
title="Nurse Jamie Knows Best",
|
||||||
|
released_at=datetime.date(2021, 5, 26),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Rebecca Volpetti -- @RealityKings -- Driving Him Crazy [1080p, x265] -- 2019-04-10",
|
||||||
|
Release(
|
||||||
|
actors=["Rebecca Volpetti"],
|
||||||
|
studio="RealityKings",
|
||||||
|
title="Driving Him Crazy",
|
||||||
|
released_at=datetime.date(2019, 4, 10),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Liz Jordan -- @Lubed -- Sopping Oil -- 2023-02-07 [1080p, x265]",
|
||||||
|
Release(
|
||||||
|
actors=["Liz Jordan"],
|
||||||
|
studio="Lubed",
|
||||||
|
title="Sopping Oil",
|
||||||
|
released_at=datetime.date(2023, 2, 7),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Liz Jordan--@Lubed--Sopping Oil--2023-02-07 [1080p, x265]",
|
||||||
|
Release(
|
||||||
|
actors=["Liz Jordan"],
|
||||||
|
studio="Lubed",
|
||||||
|
title="Sopping Oil",
|
||||||
|
released_at=datetime.date(2023, 2, 7),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Liz Jordan -- @Lubed -- 2023-02-07 [1080p, x265]",
|
||||||
|
Release(
|
||||||
|
actors=["Liz Jordan"],
|
||||||
|
studio="Lubed",
|
||||||
|
title=None,
|
||||||
|
released_at=datetime.date(2023, 2, 7),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Liz Jordan -- Sopping Oil -- 2023-02-07 [1080p, x265]",
|
||||||
|
Release(
|
||||||
|
actors=["Liz Jordan"],
|
||||||
|
studio=None,
|
||||||
|
title="Sopping Oil",
|
||||||
|
released_at=datetime.date(2023, 2, 7),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Liz Jordan -- Sopping Oil",
|
||||||
|
Release(
|
||||||
|
actors=["Liz Jordan"],
|
||||||
|
studio=None,
|
||||||
|
title="Sopping Oil",
|
||||||
|
released_at=None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"DadCrush.21.10.09.Ailee.Anne.My.Stepdaughters.Hot.XXX.1080p.HEVC.x265.PRT.mp4",
|
||||||
|
Release(
|
||||||
|
studio="DadCrush",
|
||||||
|
actors=["Ailee Anne"],
|
||||||
|
title="My Stepdaughters Hot",
|
||||||
|
released_at=datetime.date(2021, 10, 9),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Deeper.21.11.11.Kenzie.Anne.XXX.1080p.HEVC.x265.PRT.mkv",
|
||||||
|
Release(
|
||||||
|
studio="Deeper",
|
||||||
|
actors=["Kenzie Anne"],
|
||||||
|
title=None,
|
||||||
|
released_at=datetime.date(2021, 11, 11),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"DevilsFilm.22.03.19.Kira.Noir.Wife.Swap.Schemes.2.XXX.1080p.HEVC.x265.PRT.mkv",
|
||||||
|
Release(
|
||||||
|
studio="DevilsFilm",
|
||||||
|
actors=["Kira Noir"],
|
||||||
|
title="Wife Swap Schemes 2",
|
||||||
|
released_at=datetime.date(2022, 3, 19),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"DogHouseDigital.22.04.06.Maddy.May.Full.Service.Massage.XXX.1080p.HEVC.x265.PRT.mkv",
|
||||||
|
Release(
|
||||||
|
studio="DogHouseDigital",
|
||||||
|
actors=["Maddy May"],
|
||||||
|
title="Full Service Massage",
|
||||||
|
released_at=datetime.date(2022, 4, 6),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"EvilAngel.22.04.05.Diana.Grace.XXX.1080p.HEVC.x265.PRT.mkv",
|
||||||
|
Release(
|
||||||
|
studio="EvilAngel",
|
||||||
|
actors=["Diana Grace"],
|
||||||
|
title=None,
|
||||||
|
released_at=datetime.date(2022, 4, 5),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Slayed.21.10.07.Izzy.Lush.And.Aidra.Fox.XXX.1080p.HEVC.x265.PRT.mkv",
|
||||||
|
Release(
|
||||||
|
studio="Slayed",
|
||||||
|
actors=["Aidra Fox", "Izzy Lush"],
|
||||||
|
title=None,
|
||||||
|
released_at=datetime.date(2021, 10, 7),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ExploitedCollegeGirls.22.06.30.Gaby.XXX.1080p.HEVC.x265.PRT.mkv",
|
||||||
|
Release(
|
||||||
|
studio="ExploitedCollegeGirls",
|
||||||
|
actors=["Gaby"],
|
||||||
|
title=None,
|
||||||
|
released_at=datetime.date(2022, 6, 30),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"DoctorAdventures.21.05.26.Jamie.Michelle.Nurse.Jamie.Knows.Best.PRT.mp4",
|
||||||
|
Release(
|
||||||
|
studio="DoctorAdventures",
|
||||||
|
actors=["Jamie Michelle"],
|
||||||
|
title="Nurse Jamie Knows Best",
|
||||||
|
released_at=datetime.date(2021, 5, 26),
|
||||||
|
),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
[
|
)
|
||||||
'Rebecca Volpetti -- @RealityKings -- Driving Him Crazy [1080p, x265] -- 2019-04-10',
|
|
||||||
Release(actors=['Rebecca Volpetti'], studio='RealityKings', title='Driving Him Crazy', released_at=datetime.date(2019, 4, 10)),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'Liz Jordan -- @Lubed -- Sopping Oil -- 2023-02-07 [1080p, x265]',
|
|
||||||
Release(actors=['Liz Jordan'], studio='Lubed', title='Sopping Oil', released_at=datetime.date(2023, 2, 7)),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'Liz Jordan--@Lubed--Sopping Oil--2023-02-07 [1080p, x265]',
|
|
||||||
Release(actors=['Liz Jordan'], studio='Lubed', title='Sopping Oil', released_at=datetime.date(2023, 2, 7)),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'Liz Jordan -- @Lubed -- 2023-02-07 [1080p, x265]',
|
|
||||||
Release(actors=['Liz Jordan'], studio='Lubed', title=None, released_at=datetime.date(2023, 2, 7)),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'Liz Jordan -- Sopping Oil -- 2023-02-07 [1080p, x265]',
|
|
||||||
Release(actors=['Liz Jordan'], studio=None, title='Sopping Oil', released_at=datetime.date(2023, 2, 7)),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'Liz Jordan -- Sopping Oil',
|
|
||||||
Release(actors=['Liz Jordan'], studio=None, title='Sopping Oil', released_at=None),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'DadCrush.21.10.09.Ailee.Anne.My.Stepdaughters.Hot.XXX.1080p.HEVC.x265.PRT.mp4',
|
|
||||||
Release(studio='DadCrush', actors=['Ailee Anne'], title='My Stepdaughters Hot', released_at=datetime.date(2021, 10, 9))
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'Deeper.21.11.11.Kenzie.Anne.XXX.1080p.HEVC.x265.PRT.mkv',
|
|
||||||
Release(studio='Deeper', actors=['Kenzie Anne'], title=None, released_at=datetime.date(2021, 11, 11)),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'DevilsFilm.22.03.19.Kira.Noir.Wife.Swap.Schemes.2.XXX.1080p.HEVC.x265.PRT.mkv',
|
|
||||||
Release(studio='DevilsFilm', actors=['Kira Noir'], title='Wife Swap Schemes 2', released_at=datetime.date(2022, 3, 19)),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'DogHouseDigital.22.04.06.Maddy.May.Full.Service.Massage.XXX.1080p.HEVC.x265.PRT.mkv',
|
|
||||||
Release(studio='DogHouseDigital', actors=['Maddy May'], title='Full Service Massage', released_at=datetime.date(2022, 4, 6)),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'EvilAngel.22.04.05.Diana.Grace.XXX.1080p.HEVC.x265.PRT.mkv',
|
|
||||||
Release(studio='EvilAngel', actors=['Diana Grace'], title=None, released_at=datetime.date(2022, 4, 5)),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'Slayed.21.10.07.Izzy.Lush.And.Aidra.Fox.XXX.1080p.HEVC.x265.PRT.mkv',
|
|
||||||
Release(studio='Slayed', actors=['Aidra Fox', 'Izzy Lush'], title=None, released_at=datetime.date(2021, 10, 7)),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'ExploitedCollegeGirls.22.06.30.Gaby.XXX.1080p.HEVC.x265.PRT.mkv',
|
|
||||||
Release(studio='ExploitedCollegeGirls', actors=['Gaby'], title=None, released_at=datetime.date(2022, 6, 30)),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'DoctorAdventures.21.05.26.Jamie.Michelle.Nurse.Jamie.Knows.Best.PRT.mp4',
|
|
||||||
Release(studio='DoctorAdventures', actors=['Jamie Michelle'], title='Nurse Jamie Knows Best', released_at=datetime.date(2021, 5, 26)),
|
|
||||||
],
|
|
||||||
])
|
|
||||||
def test_parse_release(filename: str, expected):
|
def test_parse_release(filename: str, expected):
|
||||||
parsed = file_renamer.parse_release(filename)
|
parsed = file_renamer.parse_release(filename)
|
||||||
assert parsed == expected
|
assert parsed == expected
|
||||||
|
|||||||
Reference in New Issue
Block a user