Root cause of "0 results on every run": an unhandled crash in pin-ID parsing
aborted the entire batch. _extract_pin_id() did
re.search(r"/pin/(\d+)", val).group(1) if "/" in val else val - if the regex
didn't match (any URL without a literal /pin/<digits> segment, most notably a
Pinterest share short-link, https://pin.it/xxxxx, which is what Pinterest's
own mobile/desktop "Share" button produces and is a completely normal way for a
user to paste a pin), re.search(...) returned None and .group(1) raised an
AttributeError. This call sat outside the per-pin try/except retry block
in main(), so the exception propagated out of the URL loop and out of main()
entirely - killing the whole actor run, including every other valid URL already
queued in the batch, before a single request was made. Reproduced locally with a
bare traceback; verified fixed by confirming a batch containing one pin.it link
now logs a warning and skips just that entry while the remaining pins are
processed normally end-to-end against live Pinterest.
(src/main.py, _extract_pin_id, main())
_extract_pin_id() now returns Optional[str] (None on anything it can't
parse) instead of raising. Added _resolve_pin_id(), which follows the HTTP
redirect chain for any URL it couldn't parse directly (covers pin.it short
links and any other Pinterest URL shape that redirects to a canonical
/pin/<id>/ page) and re-extracts the ID from the resolved URL.
The per-pin loop in main() no longer lets a bad/unparseable URL bring down the
run: it's logged as a warning, added to failed_pins, and the loop moves on to
the next URL.
Actor.exit(exit_code=1) on the two "no URLs" early-exit paths was not followed
by a return, so execution continued past the actor teardown (__aexit__) and
could go on to call further Actor SDK methods (proxy setup, push_data, logging)
against an already-exited actor context. Added the missing return after both
await Actor.exit(...) calls.