diff --git a/CHANGELOG.md b/CHANGELOG.md index 5682b27..98e15f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to ApplyPilot will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Fixed +- **Duplicate PDF filename collisions** (#11) - Appended MD5 hash of the job URL to the filename prefix for tailored resumes and cover letters to prevent overwriting when multiple jobs have identical titles. + ## [0.2.0] - 2026-02-17 ### Added diff --git a/src/applypilot/scoring/cover_letter.py b/src/applypilot/scoring/cover_letter.py index c16cdd5..a4253dd 100644 --- a/src/applypilot/scoring/cover_letter.py +++ b/src/applypilot/scoring/cover_letter.py @@ -237,10 +237,12 @@ def run_cover_letters(min_score: int = 7, limit: int = 20, letter = generate_cover_letter(resume_text, job, profile, validation_mode=validation_mode) - # Build safe filename prefix + # Build safe filename prefix with job_id to prevent overwrites + import hashlib safe_title = re.sub(r"[^\w\s-]", "", job["title"])[:50].strip().replace(" ", "_") safe_site = re.sub(r"[^\w\s-]", "", job["site"])[:20].strip().replace(" ", "_") - prefix = f"{safe_site}_{safe_title}" + job_id = hashlib.md5(job["url"].encode("utf-8")).hexdigest()[:6] + prefix = f"{safe_site}_{safe_title}_{job_id}" cl_path = COVER_LETTER_DIR / f"{prefix}_CL.txt" cl_path.write_text(letter, encoding="utf-8") diff --git a/src/applypilot/scoring/tailor.py b/src/applypilot/scoring/tailor.py index 352fb5f..cf53fd2 100644 --- a/src/applypilot/scoring/tailor.py +++ b/src/applypilot/scoring/tailor.py @@ -490,10 +490,12 @@ def run_tailoring(min_score: int = 7, limit: int = 20, tailored, report = tailor_resume(resume_text, job, profile, validation_mode=validation_mode) - # Build safe filename prefix + # Build safe filename prefix with job_id to prevent overwrites + import hashlib safe_title = re.sub(r"[^\w\s-]", "", job["title"])[:50].strip().replace(" ", "_") safe_site = re.sub(r"[^\w\s-]", "", job["site"])[:20].strip().replace(" ", "_") - prefix = f"{safe_site}_{safe_title}" + job_id = hashlib.md5(job["url"].encode("utf-8")).hexdigest()[:6] + prefix = f"{safe_site}_{safe_title}_{job_id}" # Save tailored resume text txt_path = TAILORED_DIR / f"{prefix}.txt"