Normalize timestamp group folder names
This commit is contained in:
+14
-2
@@ -12,11 +12,23 @@ Files are sorted by their current path and moved into one folder named
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ORDERED_TIMESTAMP_STEM_RE = re.compile(r"^(?P<timestamp>\d{8}_\d{6})-[1-9]\d*$")
|
||||||
|
|
||||||
|
|
||||||
|
def group_stem(path: Path) -> str:
|
||||||
|
stem = path.stem
|
||||||
|
match = ORDERED_TIMESTAMP_STEM_RE.match(stem)
|
||||||
|
if match:
|
||||||
|
return match.group("timestamp")
|
||||||
|
return stem
|
||||||
|
|
||||||
|
|
||||||
def unique_path(path: Path) -> Path:
|
def unique_path(path: Path) -> Path:
|
||||||
if not path.exists():
|
if not path.exists():
|
||||||
return path
|
return path
|
||||||
@@ -87,8 +99,8 @@ def group_items(items: list[Path]) -> Path | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
sorted_items = sorted(items, key=lambda item: item.name.lower())
|
sorted_items = sorted(items, key=lambda item: item.name.lower())
|
||||||
first = sorted_items[0].stem
|
first = group_stem(sorted_items[0])
|
||||||
last = sorted_items[-1].stem
|
last = group_stem(sorted_items[-1])
|
||||||
target_dir = unique_path(working_dir_for_items(sorted_items) / f"{first}-{last}")
|
target_dir = unique_path(working_dir_for_items(sorted_items) / f"{first}-{last}")
|
||||||
target_dir.mkdir(parents=True)
|
target_dir.mkdir(parents=True)
|
||||||
|
|
||||||
|
|||||||
+29
-5
@@ -84,6 +84,7 @@ TIME_ONLY_RE = re.compile(
|
|||||||
TZ_RE = re.compile(r"^(?P<sign>[+-])(?P<h>\d{1,2})(?::?(?P<m>\d{2}))?$")
|
TZ_RE = re.compile(r"^(?P<sign>[+-])(?P<h>\d{1,2})(?::?(?P<m>\d{2}))?$")
|
||||||
OFFSET_RE = re.compile(r"^([+-])(?:(\d+):)?(\d{1,2})(?::(\d{2}))?$")
|
OFFSET_RE = re.compile(r"^([+-])(?:(\d+):)?(\d{1,2})(?::(\d{2}))?$")
|
||||||
TOKEN_SHIFT_RE = re.compile(r"(\d+|[a-zA-Z]+)")
|
TOKEN_SHIFT_RE = re.compile(r"(\d+|[a-zA-Z]+)")
|
||||||
|
ORDERED_TIMESTAMP_STEM_RE = re.compile(r"^(?P<timestamp>\d{8}_\d{6})-[1-9]\d*$")
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -917,6 +918,14 @@ def normalized_extension(path: Path) -> str:
|
|||||||
return path.suffix.lower()
|
return path.suffix.lower()
|
||||||
|
|
||||||
|
|
||||||
|
def group_stem_from_name(name: str) -> str:
|
||||||
|
stem = Path(name).stem
|
||||||
|
match = ORDERED_TIMESTAMP_STEM_RE.match(stem)
|
||||||
|
if match:
|
||||||
|
return match.group("timestamp")
|
||||||
|
return stem
|
||||||
|
|
||||||
|
|
||||||
def plan_names(records: list[MediaRecord], choices: UserChoices) -> None:
|
def plan_names(records: list[MediaRecord], choices: UserChoices) -> None:
|
||||||
if not choices.rename_files:
|
if not choices.rename_files:
|
||||||
for record in records:
|
for record in records:
|
||||||
@@ -981,12 +990,27 @@ def assign_groups(records: list[MediaRecord], groups: list[list[MediaRecord]]) -
|
|||||||
record.group_id = index
|
record.group_id = index
|
||||||
|
|
||||||
|
|
||||||
def assign_group_names(groups: list[list[MediaRecord]]) -> None:
|
def unique_group_name(base_name: str, working_dir: Path, used_names: set[str]) -> str:
|
||||||
|
if base_name not in used_names and not (working_dir / base_name).exists():
|
||||||
|
used_names.add(base_name)
|
||||||
|
return base_name
|
||||||
|
|
||||||
|
for index in range(1, 10000):
|
||||||
|
candidate = f"{base_name}-{index}"
|
||||||
|
if candidate not in used_names and not (working_dir / candidate).exists():
|
||||||
|
used_names.add(candidate)
|
||||||
|
return candidate
|
||||||
|
|
||||||
|
raise RuntimeError(f"Could not find an available group directory name for {base_name}")
|
||||||
|
|
||||||
|
|
||||||
|
def assign_group_names(groups: list[list[MediaRecord]], working_dir: Path) -> None:
|
||||||
|
used_names: set[str] = set()
|
||||||
for group in groups:
|
for group in groups:
|
||||||
ordered = sorted(group, key=photo_sort_key)
|
ordered = sorted(group, key=photo_sort_key)
|
||||||
first = Path(ordered[0].final_name or ordered[0].path.name).stem
|
first = group_stem_from_name(ordered[0].final_name or ordered[0].path.name)
|
||||||
last = Path(ordered[-1].final_name or ordered[-1].path.name).stem
|
last = group_stem_from_name(ordered[-1].final_name or ordered[-1].path.name)
|
||||||
group_name = f"{first}-{last}"
|
group_name = unique_group_name(f"{first}-{last}", working_dir, used_names)
|
||||||
for record in ordered:
|
for record in ordered:
|
||||||
record.group_name = group_name
|
record.group_name = group_name
|
||||||
|
|
||||||
@@ -1165,7 +1189,7 @@ def prepare_plan(records: list[MediaRecord], choices: UserChoices) -> list[list[
|
|||||||
|
|
||||||
plan_names(records, choices)
|
plan_names(records, choices)
|
||||||
if groups:
|
if groups:
|
||||||
assign_group_names(groups)
|
assign_group_names(groups, choices.working_dir)
|
||||||
plan_targets(records, choices)
|
plan_targets(records, choices)
|
||||||
return groups
|
return groups
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user