files.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import csv
  2. import os
  3. import xml.etree.ElementTree as ET
  4. from datetime import datetime
  5. from pathlib import Path
  6. def find_xml_files(directory: Path) -> list[Path]:
  7. return sorted(
  8. path
  9. for path in directory.rglob("*")
  10. if path.is_file() and path.suffix.lower() == ".xml" and not path.name.lower().startswith("sessions")
  11. )
  12. def is_file_from_session_day(file_path: Path, session_start_time: str) -> bool:
  13. try:
  14. session_date = datetime.fromisoformat(session_start_time.replace("Z", "+00:00")).date()
  15. except ValueError:
  16. return False
  17. return datetime.fromtimestamp(file_path.stat().st_birthtime).date() == session_date
  18. def is_in_pc_visit_directory(file_path: Path, desktop_directory: Path) -> bool:
  19. try:
  20. relative_parts = file_path.relative_to(desktop_directory).parts
  21. except ValueError:
  22. return False
  23. return bool(relative_parts) and relative_parts[0].casefold() == "pc-visit"
  24. def find_file_on_desktop(
  25. file_path: str,
  26. session_start_time: str,
  27. desktop_directory: Path | None = None,
  28. ignore_timestamp: bool = False,
  29. ) -> Path | None:
  30. desktop_directory = desktop_directory or Path(os.environ.get("USERPROFILE", str(Path.home()))) / "Desktop"
  31. path_parts = [part for part in file_path.replace("\\", "/").split("/") if part]
  32. desktop_index = next(
  33. (index for index, part in enumerate(path_parts) if part.casefold() == "desktop"),
  34. None,
  35. )
  36. if desktop_index is not None:
  37. relative_path = Path(*path_parts[desktop_index + 1 :])
  38. exact_match = desktop_directory / relative_path
  39. if (
  40. exact_match.is_file()
  41. and not is_in_pc_visit_directory(exact_match, desktop_directory)
  42. and (ignore_timestamp or is_file_from_session_day(exact_match, session_start_time))
  43. ):
  44. return exact_match
  45. file_name = Path(path_parts[-1]).name if path_parts else ""
  46. if not file_name or not desktop_directory.is_dir():
  47. return None
  48. return next(
  49. (
  50. path
  51. for path in desktop_directory.rglob(file_name)
  52. if path.is_file()
  53. and not is_in_pc_visit_directory(path, desktop_directory)
  54. and (ignore_timestamp or is_file_from_session_day(path, session_start_time))
  55. ),
  56. None,
  57. )
  58. def extract_received_files(xml_path: Path, ignore_timestamp: bool = False) -> list[dict[str, str]]:
  59. root = ET.parse(xml_path).getroot()
  60. session = root.find("Session")
  61. if session is None:
  62. return []
  63. participant_names = [
  64. participant.get("Name", "").strip()
  65. for participant in session.findall("Participant")
  66. if participant.get("Role") not in {"ROLE_SUPPORTER", "ROLE_UNKNOWN"} and participant.get("Name", "").strip()
  67. ]
  68. if not participant_names:
  69. return []
  70. rows = []
  71. for received_file in session.findall("ReceivedFile"):
  72. original_path = received_file.get("Name", "").strip()
  73. start_time = received_file.get("DateTime", "").strip()
  74. local_path = find_file_on_desktop(original_path, start_time, ignore_timestamp=ignore_timestamp)
  75. if local_path is not None:
  76. rows.append({"ParticipantName": participant_names[0], "FilePath": str(local_path)})
  77. return rows
  78. def write_files_csv(rows: list[dict[str, str]], csv_path: Path) -> None:
  79. csv_path.parent.mkdir(parents=True, exist_ok=True)
  80. with csv_path.open("w", newline="", encoding="latin-1", errors="replace") as csv_file:
  81. writer = csv.DictWriter(csv_file, fieldnames=["ParticipantName", "FilePath"], delimiter=";")
  82. writer.writeheader()
  83. writer.writerows(rows)
  84. def run(directory: Path, output: Path, ignore_timestamp: bool = False) -> tuple[int, int]:
  85. if not directory.is_dir():
  86. raise ValueError(f"Das Verzeichnis existiert nicht: {directory}")
  87. xml_files = find_xml_files(directory)
  88. rows = [
  89. row for xml_file in xml_files for row in extract_received_files(xml_file, ignore_timestamp=ignore_timestamp)
  90. ]
  91. unique_rows = {(row["ParticipantName"], row["FilePath"]): row for row in rows}
  92. write_files_csv(
  93. sorted(unique_rows.values(), key=lambda row: (row["ParticipantName"].casefold(), row["FilePath"].casefold())),
  94. output,
  95. )
  96. return len(xml_files), len(unique_rows)