A Dockerized Python application that monitors a folder for magazine PDFs, identifies them by filename pattern, renames them with a standardized format, and organizes them into folders.
Drop lmnd06032026.pdf into ./import/ and it will be moved to:
./processed/Le Monde/Le Monde - 2026-03-06.pdf
docker compose up --buildThis creates two local folders:
./import/— drop PDFs here./processed/— organized output (subfolders per magazine)
Edit config/magazines.yaml and add an entry:
- name: "Magazine Display Name"
pattern: "^prefix(\\d{2})(\\d{2})(\\d{4})\\.pdf$"
date_groups: [day, month, year]
template: "{name} - {date}.pdf" # optional, this is the default- name: the display name used for the folder and renamed file
- pattern: a regex matching the original filename, with capture groups for date components
- date_groups: an ordered list mapping each capture group to
day,month, oryear - template: output filename format (optional). Available placeholders:
{name},{date}(YYYY-MM-DD),{year},{month},{day},{month_name}(e.g. March)
Template examples by frequency:
| Frequency | Template | Result |
|---|---|---|
| Daily | {name} - {date}.pdf |
Le Monde - 2026-03-06.pdf |
| Monthly | {name} - {year}-{month}.pdf |
National Geographic - 2026-03.pdf |
| Monthly (named) | {name} - {month_name} {year}.pdf |
Science & Vie - March 2026.pdf |
Restart the container after changes:
docker compose restartpip install -r requirements.txt
python -m app.mainWhen running locally, the app uses /import and /processed as absolute paths. You can test by creating those directories or adjusting the paths in app/main.py.
- On startup, any PDFs already in
/importare processed immediately - The app then watches
/importfor new files usingwatchdog - Each filename is matched against the regex patterns defined in
config/magazines.yaml - On match, the date is extracted, the file is renamed using the magazine's output template, and moved to
/processed/<Magazine Name>/ - Unrecognized files are logged as warnings and left in place
- Duplicate destinations (file already exists) are skipped