Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Print Every Page (Local Auto-Printer)

This program watches a folder on your laptop and automatically prints each new supported file it sees.

## What it prints
- `.pdf`
- `.txt`
- `.png`
- `.jpg`
- `.jpeg`

## Usage

```bash
python3 print_every_page.py ~/to-print
```

Optional flags:

```bash
python3 print_every_page.py ~/to-print --interval 1.0 --dry-run
```

- `--interval`: how often to check the folder.
- `--dry-run`: preview only (no actual printing).

## Notes
- Linux/macOS: uses `lp`.
- Windows: uses PowerShell `Start-Process ... -Verb Print`.
- Ensure your default printer is configured before running.
100 changes: 100 additions & 0 deletions print_every_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/usr/bin/env python3
"""Automatically print every supported file from a chosen folder.

This script watches a folder and sends each new file to the default printer.
It is intended for local, opt-in automation only.
"""

from __future__ import annotations

import argparse
import platform
import subprocess
import time
from pathlib import Path

SUPPORTED_EXTENSIONS = {".pdf", ".txt", ".png", ".jpg", ".jpeg"}


def print_file(file_path: Path, dry_run: bool = False) -> None:
"""Send one file to the default system printer."""
system = platform.system().lower()

if dry_run:
print(f"[dry-run] Would print: {file_path}")
return

if system == "windows":
# Uses the file association print action on Windows.
cmd = ["powershell", "-Command", f"Start-Process -FilePath '{file_path}' -Verb Print"]
elif system == "darwin":
# macOS printing via CUPS.
cmd = ["lp", str(file_path)]
else:
# Linux and most Unix-like systems with CUPS installed.
cmd = ["lp", str(file_path)]

subprocess.run(cmd, check=True)
print(f"Printed: {file_path}")


def watch_and_print(folder: Path, interval_seconds: float, dry_run: bool = False) -> None:
"""Continuously watch a folder and print new supported files."""
printed: set[Path] = set()

if not folder.exists() or not folder.is_dir():
raise ValueError(f"Folder does not exist or is not a directory: {folder}")

print(f"Watching: {folder}")
print(f"Supported types: {', '.join(sorted(SUPPORTED_EXTENSIONS))}")
print("Press Ctrl+C to stop.\n")

while True:
for file_path in sorted(folder.iterdir()):
if not file_path.is_file():
continue
if file_path.suffix.lower() not in SUPPORTED_EXTENSIONS:
continue
if file_path in printed:
continue

try:
print_file(file_path, dry_run=dry_run)
printed.add(file_path)
except subprocess.CalledProcessError as exc:
print(f"Failed to print {file_path}: {exc}")

time.sleep(interval_seconds)


def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Watch a folder and print every new page/file using your default printer."
)
parser.add_argument(
"folder",
nargs="?",
default=".",
help="Folder to watch for files (default: current directory).",
)
parser.add_argument(
"--interval",
type=float,
default=2.0,
help="Polling interval in seconds (default: 2.0).",
)
parser.add_argument(
"--dry-run",
action="store_true",
help="Show which files would be printed without sending print jobs.",
)
return parser.parse_args()


def main() -> None:
args = parse_args()
watch_and_print(Path(args.folder).expanduser().resolve(), args.interval, args.dry_run)


if __name__ == "__main__":
main()