` WITHOUT the `is-shown` class — that class is added
+ # by SubscribeStar's infinite-scroll JS when a post scrolls into view, so it's
+ # present in a browser-SAVED page but absent from the feed we actually fetch.
+ # The delimiter must match the generic `
'
+ '
May 01, 2026 12:00 pm
'
+ '
'
+ )
+ page = (
+ '
'
+ f'{raw_post}
'
+ )
+ monkeypatch.setattr(client, "_feed_html", lambda url: page)
+ out = list(client.iter_posts("https://subscribestar.adult/x"))
+ assert [p["id"] for p, _inc, _cur in out] == ["555"]
+
+
+def test_redirect_to_age_wall_is_auth_error():
+ # gallery-dl parity: SubscribeStar redirects an unauthenticated / age-
+ # unconfirmed request to /age_confirmation_warning (or /verify_subscriber).
+ # That's auth, not drift — rotate cookies / set the age cookie.
+ client = SubscribeStarClient(None)
+
+ class _Resp:
+ status_code = 200
+ url = "https://subscribestar.adult/age_confirmation_warning"
+ history = [object()]
+ text = ""
+ headers: dict = {}
+
+ class _Session:
+ def get(self, url, timeout=None, headers=None):
+ return _Resp()
+
+ client._session = _Session()
+ try:
+ client._get("https://subscribestar.adult/x")
+ except SubscribeStarAuthError:
+ return
+ raise AssertionError("expected SubscribeStarAuthError")
+
+
def test_iter_posts_drift_when_no_container(monkeypatch):
client = SubscribeStarClient(None)
monkeypatch.setattr(client, "_feed_html", lambda url: "nothing")