modified pppp

This commit is contained in:
2026-07-01 15:52:29 +08:00
parent 44a9c5a5d5
commit f5c0ecc31f
2 changed files with 464 additions and 299 deletions

View File

@@ -628,8 +628,27 @@ def has_audio_video_files(files_list: List[Dict]) -> bool:
return any(file_entry.get('name', '').lower().endswith(ext) for file_entry in files_list for ext in audio_video_exts)
def create_empty_time_classification_report() -> Dict[str, List[Dict]]:
return {
"single_files": [],
"archives": [],
"same_child_archive_time": [],
"zxxk_child_earlier": [],
"twole_child_earlier": [],
}
def merge_time_classification_reports(target: Dict[str, List[Dict]], source: Dict[str, List[Dict]]) -> None:
for category in create_empty_time_classification_report():
target.setdefault(category, [])
target[category].extend(source.get(category, []))
def build_file_associations(word_content: List[str], twole_folder: Path, zxxk_folder: Path) -> Dict:
"""构建文件关联关系"""
SAME_TIME_THRESHOLD = 300
PAIR_TIME_DIFF_THRESHOLD = 30
def process_file(file_path: Path) -> List[Dict]:
files = []
mtime = file_path.stat().st_mtime
@@ -657,35 +676,94 @@ def build_file_associations(word_content: List[str], twole_folder: Path, zxxk_fo
files.append({"name": f.name, "mtime": mtime, "datetime": format_datetime(mtime), "path": str(f)})
return files
def get_latest_extracted_mtime(file_entries: List[Dict], archive_name: str) -> Optional[float]:
def get_archive_time_summary(file_entries: List[Dict], archive_name: str) -> Dict:
extracted_times = [e["mtime"] for e in file_entries if e.get("name") != archive_name and "mtime" in e]
if not extracted_times:
return None
archive_mtime = next((e["mtime"] for e in file_entries if e.get("name") == archive_name), None)
if not extracted_times:
return {
"archive_mtime": archive_mtime,
"archive_datetime": format_datetime(archive_mtime) if archive_mtime else None,
"latest_child_mtime": None,
"latest_child_datetime": None,
"child_archive_time_relation": "no_child_files",
"child_archive_time_diff_seconds": None,
}
latest_extracted = max(extracted_times)
return None if archive_mtime and abs(latest_extracted - archive_mtime) < 300 else latest_extracted
time_diff = latest_extracted - archive_mtime if archive_mtime is not None else None
is_same_time = time_diff is not None and abs(time_diff) < SAME_TIME_THRESHOLD
return {
"archive_mtime": archive_mtime,
"archive_datetime": format_datetime(archive_mtime) if archive_mtime else None,
"latest_child_mtime": latest_extracted,
"latest_child_datetime": format_datetime(latest_extracted),
"child_archive_time_relation": "same" if is_same_time else "different",
"child_archive_time_diff_seconds": time_diff,
}
def match_group(title: str, url: str, time_val: str, group_name: str, twole_files: List, zxxk_files: List) -> Tuple[Dict, Optional[float]]:
def build_classification_record(row_index: int, group_name: str, entry: Dict, file_kind: str, archive_summary: Optional[Dict] = None) -> Dict:
site = get_url_site(entry.get("url", ""))
record = {
"row_index": row_index,
"group": group_name,
"site": site,
"site_name": "二一教育" if site == "twole" else "学科网" if site == "zxxk" else "",
"file_kind": file_kind,
"title": entry.get("title"),
"url": entry.get("url"),
"time": entry.get("time"),
"source_path": entry.get("source_path"),
"file": entry.get("files", [{}])[0] if entry.get("files") else {},
}
if archive_summary:
record.update(archive_summary)
return record
def build_pair_record(row_index: int, entry: Dict, twole_summary: Dict, zxxk_summary: Dict, earlier_site: str) -> Dict:
twole_entry = twole_summary["entry"]
zxxk_entry = zxxk_summary["entry"]
return {
"row_index": row_index,
"earlier_site": "二一教育" if earlier_site == "twole" else "学科网",
"earlier_site_key": earlier_site,
"twole_latest_child_mtime": twole_summary["archive"]["latest_child_mtime"],
"twole_latest_child_datetime": twole_summary["archive"]["latest_child_datetime"],
"zxxk_latest_child_mtime": zxxk_summary["archive"]["latest_child_mtime"],
"zxxk_latest_child_datetime": zxxk_summary["archive"]["latest_child_datetime"],
"child_time_diff_seconds": zxxk_summary["archive"]["latest_child_mtime"] - twole_summary["archive"]["latest_child_mtime"],
"twole": twole_entry,
"zxxk": zxxk_entry,
"group1": entry.get("group1"),
"group2": entry.get("group2"),
}
def match_group(title: str, url: str, time_val: str, group_name: str, twole_files: List, zxxk_files: List) -> Tuple[Dict, Dict]:
if 'www.21cnjy.com' in url and twole_files:
candidates = twole_files
elif 'www.zxxk.com' in url and zxxk_files:
candidates = zxxk_files
else:
return {}, None
return {}, {}
best_match = find_best_match(title, candidates)
if not best_match:
return {}, None
return {}, {}
candidates.remove(best_match)
file_path, _ = best_match
files = process_file(file_path)
entry = {"files": files, "title": title, "url": url, "time": time_val, "source_path": str(file_path)}
latest = get_latest_extracted_mtime(files, file_path.name) if file_path.suffix.lower() in ('.zip', '.rar', '.7z') else None
return entry, latest
is_archive = file_path.suffix.lower() in ARCHIVE_EXTENSIONS
summary = {
"entry": entry,
"group_name": group_name,
"site": get_url_site(url),
"is_archive": is_archive,
"archive": get_archive_time_summary(files, file_path.name) if is_archive else None,
}
return entry, summary
result = []
problematic_groups = []
problematic_groups = create_empty_time_classification_report()
twole_files = get_files_with_times(twole_folder)
zxxk_files = get_files_with_times(zxxk_folder)
@@ -698,8 +776,8 @@ def build_file_associations(word_content: List[str], twole_folder: Path, zxxk_fo
title2, url2, time2 = parts[3].strip(), parts[4].strip(), parts[5].strip()
entry = {}
group1_entry, group1_latest = match_group(title1, url1, time1, "group1", twole_files, zxxk_files)
group2_entry, group2_latest = match_group(title2, url2, time2, "group2", twole_files, zxxk_files)
group1_entry, group1_summary = match_group(title1, url1, time1, "group1", twole_files, zxxk_files)
group2_entry, group2_summary = match_group(title2, url2, time2, "group2", twole_files, zxxk_files)
if group1_entry:
entry["group1"] = group1_entry
@@ -707,13 +785,44 @@ def build_file_associations(word_content: List[str], twole_folder: Path, zxxk_fo
entry["group2"] = group2_entry
if entry:
pair_sites = {get_url_site(entry.get("group1", {}).get("url", "")), get_url_site(entry.get("group2", {}).get("url", ""))}
if (pair_sites == {'twole', 'zxxk'} and group1_latest is not None and group2_latest is not None and
group1_latest < group2_latest and (group2_latest - group1_latest) > 30):
problematic_groups.append({
"row_index": i, "group1_latest_extracted_mtime": group1_latest, "group2_latest_extracted_mtime": group2_latest,
"group1": entry.get("group1"), "group2": entry.get("group2")
})
archive_summaries_by_site = {}
for summary in (group1_summary, group2_summary):
if not summary:
continue
record = build_classification_record(
i,
summary["group_name"],
summary["entry"],
"archive" if summary["is_archive"] else "single_file",
summary["archive"],
)
if summary["is_archive"]:
problematic_groups["archives"].append(record)
archive_summaries_by_site[summary["site"]] = summary
if summary["archive"]["child_archive_time_relation"] == "same":
problematic_groups["same_child_archive_time"].append(record)
else:
problematic_groups["single_files"].append(record)
twole_summary = archive_summaries_by_site.get("twole")
zxxk_summary = archive_summaries_by_site.get("zxxk")
if twole_summary and zxxk_summary:
twole_archive = twole_summary["archive"]
zxxk_archive = zxxk_summary["archive"]
if (twole_archive["child_archive_time_relation"] == "different" and
zxxk_archive["child_archive_time_relation"] == "different" and
twole_archive["latest_child_mtime"] is not None and
zxxk_archive["latest_child_mtime"] is not None):
child_time_diff = zxxk_archive["latest_child_mtime"] - twole_archive["latest_child_mtime"]
if abs(child_time_diff) > PAIR_TIME_DIFF_THRESHOLD:
if child_time_diff < 0:
problematic_groups["zxxk_child_earlier"].append(
build_pair_record(i, entry, twole_summary, zxxk_summary, "zxxk")
)
else:
problematic_groups["twole_child_earlier"].append(
build_pair_record(i, entry, twole_summary, zxxk_summary, "twole")
)
result.append(entry)
return {"items": result, "problematic_groups": problematic_groups}
@@ -929,7 +1038,7 @@ def main():
total_failures = 0
total_conflicts = 0
total_duplicates = 0
all_problem_groups = []
all_problem_groups = create_empty_time_classification_report()
all_write_reports = []
for source_item in source_items:
@@ -964,10 +1073,12 @@ def main():
print(f" 关联目录:{base_dir}")
associations = build_file_associations(word_content, twole_folder, zxxk_folder)
for group in associations.get("problematic_groups", []):
group["source_folder"] = source_item.name
group["word_doc"] = word_doc.name
all_problem_groups.extend(associations.get("problematic_groups", []))
classification_report = associations.get("problematic_groups", create_empty_time_classification_report())
for records in classification_report.values():
for record in records:
record["source_folder"] = source_item.name
record["word_doc"] = word_doc.name
merge_time_classification_reports(all_problem_groups, classification_report)
if not associations.get("items"):
print("⚠️ 未构建出有效关联")