sync_media.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import os
  2. import shutil
  3. import sys
  4. def sync_media_from_b_to_a(dir_a, dir_b, dry_run=False, dry_run_file="sync_dry_run.txt", error_file="sync_errors.txt"):
  5. """
  6. For each subdirectory in A, use its name to search B for a media file (.mkv or .mp4) with the same base name.
  7. If found, move all files from that B subdirectory into the corresponding A subdirectory.
  8. If dry_run is True, only print and save what would be moved.
  9. Also record directories where no match or exceptions occur.
  10. """
  11. media_exts = ('.mkv', '.mp4')
  12. dry_run_lines = []
  13. error_lines = []
  14. for subdir_a in os.listdir(dir_a):
  15. path_a = os.path.join(dir_a, subdir_a)
  16. if not os.path.isdir(path_a):
  17. continue
  18. base_name = subdir_a
  19. found = False
  20. try:
  21. for root_b, dirs_b, files_b in os.walk(dir_b):
  22. for file_b in files_b:
  23. name_b, ext_b = os.path.splitext(file_b)
  24. if ext_b.lower() in media_exts and name_b == base_name:
  25. found = True
  26. msg = f"Found match for '{base_name}' in '{root_b}'."
  27. print(msg)
  28. dry_run_lines.append(msg)
  29. for src_file in os.listdir(root_b):
  30. src_file_path = os.path.join(root_b, src_file)
  31. dest_file_path = os.path.join(path_a, src_file)
  32. if dry_run:
  33. line = f"[DRY-RUN] Would move: {src_file_path} -> {dest_file_path}"
  34. print(line)
  35. dry_run_lines.append(line)
  36. else:
  37. shutil.move(src_file_path, dest_file_path)
  38. print(f"Moved: {src_file_path} -> {dest_file_path}")
  39. break
  40. if found:
  41. break
  42. if not found:
  43. msg = f"No match found in B for '{base_name}' in '{path_a}'."
  44. print(msg)
  45. error_lines.append(msg)
  46. except Exception as e:
  47. msg = f"Exception for '{base_name}' in '{path_a}': {e}"
  48. print(msg)
  49. error_lines.append(msg)
  50. # Save dry run and error logs if dry_run
  51. if dry_run:
  52. with open(dry_run_file, "w", encoding="utf-8") as f:
  53. for line in dry_run_lines:
  54. f.write(line + "\n")
  55. print(f"Dry run output saved to {dry_run_file}")
  56. if error_lines:
  57. with open(error_file, "w", encoding="utf-8") as f:
  58. for line in error_lines:
  59. f.write(line + "\n")
  60. print(f"Errors/unmatched directories saved to {error_file}")
  61. if __name__ == "__main__":
  62. # python3 sync_media.py <dir_A> <dir_B> [--dry-run]
  63. if len(sys.argv) < 3:
  64. print("Usage: python sync_media.py <dir_A> <dir_B> [--dry-run]")
  65. else:
  66. dry_run = "--dry-run" in sys.argv
  67. sync_media_from_b_to_a(
  68. sys.argv[1],
  69. sys.argv[2],
  70. dry_run=dry_run,
  71. dry_run_file="sync_dry_run.txt",
  72. error_file="sync_errors.txt"
  73. )