add grouped needs-attention summary at the end of each rename run
This commit is contained in:
1 parent
f0525dcefa
commit
03f1c07f50
1 file changed
+49
-5
+49
-5
@@ -3230,7 +3230,9 @@ def list_loose_subtitle_files(share):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def process_loose_movie_files(share, api_key, log, test_mode, test_limit, args):
|
def process_loose_movie_files(share, api_key, log, test_mode, test_limit, args, needs_attention=None):
|
||||||
|
if needs_attention is None:
|
||||||
|
needs_attention = []
|
||||||
files = list_loose_video_files(share)
|
files = list_loose_video_files(share)
|
||||||
if not files:
|
if not files:
|
||||||
return 0, 0, 0, 0
|
return 0, 0, 0, 0
|
||||||
@@ -3262,6 +3264,7 @@ def process_loose_movie_files(share, api_key, log, test_mode, test_limit, args):
|
|||||||
print(error)
|
print(error)
|
||||||
shown += 1
|
shown += 1
|
||||||
folders_skipped += 1
|
folders_skipped += 1
|
||||||
|
needs_attention.append(("No TMDb match", item.name))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
folder_name = folder_target_name("movie", final_name, match_year, item.stem)
|
folder_name = folder_target_name("movie", final_name, match_year, item.stem)
|
||||||
@@ -3287,6 +3290,7 @@ def process_loose_movie_files(share, api_key, log, test_mode, test_limit, args):
|
|||||||
if dest.exists() and not same_existing_path(dest, item):
|
if dest.exists() and not same_existing_path(dest, item):
|
||||||
print(f"Skipping (target already exists): {item.name}")
|
print(f"Skipping (target already exists): {item.name}")
|
||||||
folders_skipped += 1
|
folders_skipped += 1
|
||||||
|
needs_attention.append(("Target already exists", item.name))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
target_folder.mkdir(exist_ok=True)
|
target_folder.mkdir(exist_ok=True)
|
||||||
@@ -3294,6 +3298,7 @@ def process_loose_movie_files(share, api_key, log, test_mode, test_limit, args):
|
|||||||
if not ok:
|
if not ok:
|
||||||
print(f"Skipping ({err}): {item.name}")
|
print(f"Skipping ({err}): {item.name}")
|
||||||
folders_skipped += 1
|
folders_skipped += 1
|
||||||
|
needs_attention.append(("Error", f"{item.name} ({err})"))
|
||||||
continue
|
continue
|
||||||
log.record(item, dest)
|
log.record(item, dest)
|
||||||
print(f"Moved: {item.name} -> {folder_name}/{new_name}")
|
print(f"Moved: {item.name} -> {folder_name}/{new_name}")
|
||||||
@@ -3305,7 +3310,9 @@ def process_loose_movie_files(share, api_key, log, test_mode, test_limit, args):
|
|||||||
return folders_renamed, folders_skipped, files_renamed, files_skipped
|
return folders_renamed, folders_skipped, files_renamed, files_skipped
|
||||||
|
|
||||||
|
|
||||||
def process_loose_tv_files(share, api_key, log, test_mode, test_limit, args):
|
def process_loose_tv_files(share, api_key, log, test_mode, test_limit, args, needs_attention=None):
|
||||||
|
if needs_attention is None:
|
||||||
|
needs_attention = []
|
||||||
files = list_loose_video_files(share)
|
files = list_loose_video_files(share)
|
||||||
if not files:
|
if not files:
|
||||||
return 0, 0, 0, 0
|
return 0, 0, 0, 0
|
||||||
@@ -3337,6 +3344,7 @@ def process_loose_tv_files(share, api_key, log, test_mode, test_limit, args):
|
|||||||
print(error)
|
print(error)
|
||||||
shown += 1
|
shown += 1
|
||||||
files_skipped += 1
|
files_skipped += 1
|
||||||
|
needs_attention.append(("No TMDb match", item.name))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
se = parse_season_episode(item.name)
|
se = parse_season_episode(item.name)
|
||||||
@@ -3348,6 +3356,7 @@ def process_loose_tv_files(share, api_key, log, test_mode, test_limit, args):
|
|||||||
print(f"No season/episode found, skipping: {item.name}")
|
print(f"No season/episode found, skipping: {item.name}")
|
||||||
shown += 1
|
shown += 1
|
||||||
files_skipped += 1
|
files_skipped += 1
|
||||||
|
needs_attention.append(("Unresolved season/episode", item.name))
|
||||||
continue
|
continue
|
||||||
season, episode = resolved
|
season, episode = resolved
|
||||||
|
|
||||||
@@ -3375,6 +3384,7 @@ def process_loose_tv_files(share, api_key, log, test_mode, test_limit, args):
|
|||||||
if dest.exists() and not same_existing_path(dest, item):
|
if dest.exists() and not same_existing_path(dest, item):
|
||||||
print(f"Skipping (target already exists): {item.name}")
|
print(f"Skipping (target already exists): {item.name}")
|
||||||
files_skipped += 1
|
files_skipped += 1
|
||||||
|
needs_attention.append(("Target already exists", item.name))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
(target_folder / target_season_folder_name).mkdir(parents=True, exist_ok=True)
|
(target_folder / target_season_folder_name).mkdir(parents=True, exist_ok=True)
|
||||||
@@ -3382,6 +3392,7 @@ def process_loose_tv_files(share, api_key, log, test_mode, test_limit, args):
|
|||||||
if not ok:
|
if not ok:
|
||||||
print(f"Skipping ({err}): {item.name}")
|
print(f"Skipping ({err}): {item.name}")
|
||||||
files_skipped += 1
|
files_skipped += 1
|
||||||
|
needs_attention.append(("Error", f"{item.name} ({err})"))
|
||||||
continue
|
continue
|
||||||
log.record(item, dest)
|
log.record(item, dest)
|
||||||
print(f"Moved: {item.name} -> {folder_name}/{target_season_folder_name}/{new_name}")
|
print(f"Moved: {item.name} -> {folder_name}/{target_season_folder_name}/{new_name}")
|
||||||
@@ -3393,7 +3404,9 @@ def process_loose_tv_files(share, api_key, log, test_mode, test_limit, args):
|
|||||||
return folders_renamed, folders_skipped, files_renamed, files_skipped
|
return folders_renamed, folders_skipped, files_renamed, files_skipped
|
||||||
|
|
||||||
|
|
||||||
def process_loose_subtitle_files(share, media_type, log, test_mode, args):
|
def process_loose_subtitle_files(share, media_type, log, test_mode, args, needs_attention=None):
|
||||||
|
if needs_attention is None:
|
||||||
|
needs_attention = []
|
||||||
files = list_loose_subtitle_files(share)
|
files = list_loose_subtitle_files(share)
|
||||||
if not files:
|
if not files:
|
||||||
return 0, 0
|
return 0, 0
|
||||||
@@ -3422,6 +3435,7 @@ def process_loose_subtitle_files(share, media_type, log, test_mode, args):
|
|||||||
if not query:
|
if not query:
|
||||||
print(f"Skipping (could not determine title): {item.name}")
|
print(f"Skipping (could not determine title): {item.name}")
|
||||||
skipped += 1
|
skipped += 1
|
||||||
|
needs_attention.append(("Subtitle not placed", item.name))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
video = None
|
video = None
|
||||||
@@ -3432,28 +3446,33 @@ def process_loose_subtitle_files(share, media_type, log, test_mode, args):
|
|||||||
if not folder:
|
if not folder:
|
||||||
print(f"No matching movie found, skipping: {item.name}")
|
print(f"No matching movie found, skipping: {item.name}")
|
||||||
skipped += 1
|
skipped += 1
|
||||||
|
needs_attention.append(("Subtitle not placed", item.name))
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
se = parse_season_episode(item.name)
|
se = parse_season_episode(item.name)
|
||||||
if not se:
|
if not se:
|
||||||
print(f"No season/episode found, skipping: {item.name}")
|
print(f"No season/episode found, skipping: {item.name}")
|
||||||
skipped += 1
|
skipped += 1
|
||||||
|
needs_attention.append(("Subtitle not placed", item.name))
|
||||||
continue
|
continue
|
||||||
season, episode, _ = se
|
season, episode, _ = se
|
||||||
folder = match_show_from_index(show_index, query, year)
|
folder = match_show_from_index(show_index, query, year)
|
||||||
if not folder:
|
if not folder:
|
||||||
print(f"No matching show found, skipping: {item.name}")
|
print(f"No matching show found, skipping: {item.name}")
|
||||||
skipped += 1
|
skipped += 1
|
||||||
|
needs_attention.append(("Subtitle not placed", item.name))
|
||||||
continue
|
continue
|
||||||
season_dir = folder / season_folder_name(season)
|
season_dir = folder / season_folder_name(season)
|
||||||
if not season_dir.is_dir():
|
if not season_dir.is_dir():
|
||||||
print(f"No matching season in '{folder.name}', skipping: {item.name}")
|
print(f"No matching season in '{folder.name}', skipping: {item.name}")
|
||||||
skipped += 1
|
skipped += 1
|
||||||
|
needs_attention.append(("Subtitle not placed", item.name))
|
||||||
continue
|
continue
|
||||||
video = find_matching_episode_video(season_dir, episode)
|
video = find_matching_episode_video(season_dir, episode)
|
||||||
if not video:
|
if not video:
|
||||||
print(f"No matching episode in '{folder.name}', skipping: {item.name}")
|
print(f"No matching episode in '{folder.name}', skipping: {item.name}")
|
||||||
skipped += 1
|
skipped += 1
|
||||||
|
needs_attention.append(("Subtitle not placed", item.name))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if test_mode:
|
if test_mode:
|
||||||
@@ -3520,6 +3539,22 @@ def prefetch_lookups(api_key, media_type, folders):
|
|||||||
return lookup_cache
|
return lookup_cache
|
||||||
|
|
||||||
|
|
||||||
|
def print_needs_attention(needs_attention):
|
||||||
|
if not needs_attention:
|
||||||
|
return
|
||||||
|
|
||||||
|
by_category = {}
|
||||||
|
for category, name in needs_attention:
|
||||||
|
by_category.setdefault(category, []).append(name)
|
||||||
|
|
||||||
|
print(f"=== Needs attention ({len(needs_attention)}) ===")
|
||||||
|
for category, names in by_category.items():
|
||||||
|
print(f"{category}:")
|
||||||
|
for name in names:
|
||||||
|
print(f" {name}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
def run_scan(args, log):
|
def run_scan(args, log):
|
||||||
path_arg = args.rename if isinstance(args.rename, str) else None
|
path_arg = args.rename if isinstance(args.rename, str) else None
|
||||||
share = resolve_share(path_arg)
|
share = resolve_share(path_arg)
|
||||||
@@ -3586,6 +3621,7 @@ def run_scan(args, log):
|
|||||||
files_renamed = 0
|
files_renamed = 0
|
||||||
files_skipped = 0
|
files_skipped = 0
|
||||||
simulated_tv_folder_names = set()
|
simulated_tv_folder_names = set()
|
||||||
|
needs_attention = []
|
||||||
|
|
||||||
total_folders = len(subfolders)
|
total_folders = len(subfolders)
|
||||||
|
|
||||||
@@ -3615,6 +3651,7 @@ def run_scan(args, log):
|
|||||||
print(error)
|
print(error)
|
||||||
examples_shown += 1
|
examples_shown += 1
|
||||||
folders_skipped += 1
|
folders_skipped += 1
|
||||||
|
needs_attention.append(("No TMDb match", raw_name))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
folder_name = folder_target_name(media_type, final_name, match_year, raw_name)
|
folder_name = folder_target_name(media_type, final_name, match_year, raw_name)
|
||||||
@@ -3634,6 +3671,7 @@ def run_scan(args, log):
|
|||||||
print(f"Would move duplicate folder to {DUPLICATES_FOLDER_NAME}/: {raw_name} (already exists as {folder_name})")
|
print(f"Would move duplicate folder to {DUPLICATES_FOLDER_NAME}/: {raw_name} (already exists as {folder_name})")
|
||||||
else:
|
else:
|
||||||
print(f"Skipping (target already exists): {raw_name} -> {folder_name}")
|
print(f"Skipping (target already exists): {raw_name} -> {folder_name}")
|
||||||
|
needs_attention.append(("Target already exists", raw_name))
|
||||||
examples_shown += 1
|
examples_shown += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -3682,18 +3720,21 @@ def run_scan(args, log):
|
|||||||
else:
|
else:
|
||||||
print(f"Skipping (could not move to {DUPLICATES_FOLDER_NAME}/: {err}): {raw_name}")
|
print(f"Skipping (could not move to {DUPLICATES_FOLDER_NAME}/: {err}): {raw_name}")
|
||||||
folders_skipped += 1
|
folders_skipped += 1
|
||||||
|
needs_attention.append(("Error", f"{raw_name} ({err})"))
|
||||||
else:
|
else:
|
||||||
print(f"Skipped: {raw_name}")
|
print(f"Skipped: {raw_name}")
|
||||||
folders_skipped += 1
|
folders_skipped += 1
|
||||||
else:
|
else:
|
||||||
print(f"Skipping (target already exists): {raw_name} -> {folder_name}")
|
print(f"Skipping (target already exists): {raw_name} -> {folder_name}")
|
||||||
folders_skipped += 1
|
folders_skipped += 1
|
||||||
|
needs_attention.append(("Target already exists", raw_name))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
ok, err = safe_rename(folder, new_folder)
|
ok, err = safe_rename(folder, new_folder)
|
||||||
if not ok:
|
if not ok:
|
||||||
print(f"Skipping ({err}): {raw_name} -> {folder_name}")
|
print(f"Skipping ({err}): {raw_name} -> {folder_name}")
|
||||||
folders_skipped += 1
|
folders_skipped += 1
|
||||||
|
needs_attention.append(("Error", f"{raw_name} ({err})"))
|
||||||
continue
|
continue
|
||||||
log.record(folder, new_folder)
|
log.record(folder, new_folder)
|
||||||
print(f"Renamed folder: {raw_name} -> {folder_name}")
|
print(f"Renamed folder: {raw_name} -> {folder_name}")
|
||||||
@@ -3717,7 +3758,7 @@ def run_scan(args, log):
|
|||||||
if loose_files:
|
if loose_files:
|
||||||
loose_processor = process_loose_movie_files if media_type == "movie" else process_loose_tv_files
|
loose_processor = process_loose_movie_files if media_type == "movie" else process_loose_tv_files
|
||||||
loose_folders_renamed, loose_folders_skipped, loose_files_renamed, loose_files_skipped = loose_processor(
|
loose_folders_renamed, loose_folders_skipped, loose_files_renamed, loose_files_skipped = loose_processor(
|
||||||
share, api_key, log, test_mode, test_limit, args
|
share, api_key, log, test_mode, test_limit, args, needs_attention
|
||||||
)
|
)
|
||||||
folders_renamed += loose_folders_renamed
|
folders_renamed += loose_folders_renamed
|
||||||
folders_skipped += loose_folders_skipped
|
folders_skipped += loose_folders_skipped
|
||||||
@@ -3725,18 +3766,21 @@ def run_scan(args, log):
|
|||||||
files_skipped += loose_files_skipped
|
files_skipped += loose_files_skipped
|
||||||
|
|
||||||
if not (is_single_show or is_single_movie):
|
if not (is_single_show or is_single_movie):
|
||||||
sub_renamed, sub_skipped = process_loose_subtitle_files(share, media_type, log, test_mode, args)
|
sub_renamed, sub_skipped = process_loose_subtitle_files(share, media_type, log, test_mode, args, needs_attention)
|
||||||
files_renamed += sub_renamed
|
files_renamed += sub_renamed
|
||||||
files_skipped += sub_skipped
|
files_skipped += sub_skipped
|
||||||
|
|
||||||
print()
|
print()
|
||||||
if test_mode:
|
if test_mode:
|
||||||
|
print_needs_attention(needs_attention)
|
||||||
print("Test mode: no changes were made.")
|
print("Test mode: no changes were made.")
|
||||||
return
|
return
|
||||||
|
|
||||||
print("=== Summary ===")
|
print("=== Summary ===")
|
||||||
print(f"Folders renamed: {folders_renamed}, skipped: {folders_skipped}")
|
print(f"Folders renamed: {folders_renamed}, skipped: {folders_skipped}")
|
||||||
print(f"Files renamed: {files_renamed}, skipped: {files_skipped}")
|
print(f"Files renamed: {files_renamed}, skipped: {files_skipped}")
|
||||||
|
print()
|
||||||
|
print_needs_attention(needs_attention)
|
||||||
|
|
||||||
log_path = log.save(label=Path(share).name)
|
log_path = log.save(label=Path(share).name)
|
||||||
if log_path:
|
if log_path:
|
||||||
|
|||||||
Reference in new issue
Block a user