diff --git a/render/src/pixelrag_render/render.py b/render/src/pixelrag_render/render.py index 35a4753..4ac043b 100644 --- a/render/src/pixelrag_render/render.py +++ b/render/src/pixelrag_render/render.py @@ -193,8 +193,8 @@ def main() -> None: # Single URL, default CDP backend pixelshot https://example.com --output ./tiles - # Multiple inputs with 4 workers - pixelshot https://a.com https://b.com --output ./tiles --workers 4 + # Multiple inputs + pixelshot https://a.com https://b.com --output ./tiles # PDF pixelshot report.pdf --output ./tiles @@ -202,8 +202,8 @@ def main() -> None: # Local HTML pixelshot index.html --output ./tiles --backend playwright - # Pipe URLs from a file - cat urls.txt | xargs pixelshot --output ./tiles --workers 8 + # URL file + pixelshot urls.txt --output ./tiles # Chrome management (folded from the former `pixelrag-chrome`) pixelshot install-chrome # download the patched headless Chrome @@ -294,18 +294,25 @@ def main() -> None: args = parser.parse_args() output_dir = Path(args.output) - # Partition inputs into URLs and files for batch processing urls = [] files = [] for inp in args.inputs: - if inp.startswith("http://") or inp.startswith("https://"): + if inp.lower().endswith(".txt"): + try: + with open(inp, encoding="utf-8") as f: + for line in f: + url = line.strip() + if url: + urls.append(url) + except FileNotFoundError: + parser.error(f"URL file not found: {inp}") + elif inp.startswith("http://") or inp.startswith("https://"): urls.append(inp) else: files.append(Path(inp)) results: list[Path] = [] - # Batch-render URLs together for efficiency if urls: logger.info( "Rendering %d URL(s) with backend=%s workers=%d", diff --git a/tests/test_cli.py b/tests/test_cli.py index 1c43df2..a3b7177 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -8,6 +8,8 @@ import sys from pathlib import Path +import pytest + # Console scripts live next to the interpreter running the tests (works whether # invoked via `uv run pytest` or `.venv/bin/python -m pytest`). _BIN = Path(sys.executable).parent @@ -23,6 +25,57 @@ def test_pixelshot_help(): assert "pixelshot" in r.stdout +def test_pixelshot_txt_input_uses_batch_render(monkeypatch, tmp_path, capsys): + from pixelrag_render import render as render_mod + + urls_file = tmp_path / "urls.txt" + urls_file.write_text( + "\n https://example.com/a \n\nhttps://example.com/b\nhttps://example.com/c\n" + ) + calls = [] + + def fake_render_urls(urls, output_dir, **kwargs): + calls.append((list(urls), kwargs["workers"])) + return [Path(output_dir) / "a.png.tiles", Path(output_dir) / "c.png.tiles"] + + monkeypatch.setattr(render_mod, "render_urls", fake_render_urls) + monkeypatch.setattr( + sys, + "argv", + ["pixelshot", str(urls_file), "-o", str(tmp_path / "out"), "-w", "8"], + ) + + render_mod.main() + + assert calls == [ + ( + [ + "https://example.com/a", + "https://example.com/b", + "https://example.com/c", + ], + 8, + ) + ] + stdout = capsys.readouterr().out + assert "a.png.tiles" in stdout + assert "b.png.tiles" not in stdout + assert "c.png.tiles" in stdout + + +def test_pixelshot_missing_txt_input(monkeypatch, tmp_path, capsys): + from pixelrag_render import render as render_mod + + missing = tmp_path / "missing.txt" + monkeypatch.setattr(sys, "argv", ["pixelshot", str(missing)]) + + with pytest.raises(SystemExit) as exc: + render_mod.main() + + assert exc.value.code == 2 + assert "URL file not found" in capsys.readouterr().err + + def test_pixelrag_umbrella_help(): r = _run("pixelrag", "--help") assert r.returncode == 0