fix(subscribestar): inject the 18+ age cookie on every SubscribeStar domain
The cookie was pinned to .subscribestar.adult only; cookies are domain-scoped, so sources on subscribestar.art (Elasid, event #54116) never sent it and every poll 302d to /age_confirmation_warning. Emit one line per domain (.com/.adult/.art) with a per-domain presence check, and admit .art in the platform url_pattern. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CDgx8bQS5YrGRK76v8HUnM
This commit is contained in:
@@ -14,9 +14,11 @@
|
||||
`_personalization_id` age-confirmation cookie that the user can't
|
||||
easily refresh — SubscribeStar's frontend JS uses localStorage to
|
||||
suppress the age popup once dismissed. gallery-dl's own login flow
|
||||
sidesteps this by setting `18_plus_agreement_generic=true` on
|
||||
`.subscribestar.adult`; we mirror that for cookies captured via the
|
||||
extension.
|
||||
sidesteps this by setting `18_plus_agreement_generic=true`; we mirror
|
||||
that for cookies captured via the extension — on EVERY SubscribeStar
|
||||
domain, because cookies are domain-scoped and the wall exists on all
|
||||
of them: an .adult-only line never rides along to a .art creator page
|
||||
(Elasid, event #54116 — every poll 302'd to /age_confirmation_warning).
|
||||
"""
|
||||
|
||||
from .base import GD_DEFAULTS, PlatformInfo, str_id_value
|
||||
@@ -29,20 +31,31 @@ def derive_post_url(data: dict) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
# All domains SubscribeStar serves creators from; the age wall gates each.
|
||||
_SS_DOMAINS = (".subscribestar.com", ".subscribestar.adult", ".subscribestar.art")
|
||||
|
||||
|
||||
def augment_cookies(netscape: str) -> str:
|
||||
if "18_plus_agreement_generic" in netscape:
|
||||
return netscape
|
||||
# Far-future expiry — gallery-dl's own login flow sets this with no
|
||||
# explicit expiry; the server only checks presence/value.
|
||||
expiry = 4102444800 # 2100-01-01 UTC
|
||||
line = "\t".join([
|
||||
".subscribestar.adult", "TRUE", "/", "TRUE",
|
||||
str(expiry), "18_plus_agreement_generic", "true",
|
||||
])
|
||||
body = netscape.rstrip("\n")
|
||||
if not body:
|
||||
body = "# Netscape HTTP Cookie File"
|
||||
return body + "\n" + line + "\n"
|
||||
lines = netscape.splitlines()
|
||||
for domain in _SS_DOMAINS:
|
||||
# Per-domain presence check: captured cookies carrying the age
|
||||
# cookie for one domain must not suppress injection on the others.
|
||||
if any(
|
||||
line.startswith(domain + "\t") and "18_plus_agreement_generic" in line
|
||||
for line in lines
|
||||
):
|
||||
continue
|
||||
body += "\n" + "\t".join([
|
||||
domain, "TRUE", "/", "TRUE",
|
||||
str(expiry), "18_plus_agreement_generic", "true",
|
||||
])
|
||||
return body + "\n"
|
||||
|
||||
|
||||
INFO = PlatformInfo(
|
||||
@@ -51,10 +64,11 @@ INFO = PlatformInfo(
|
||||
description="Download posts from SubscribeStar creators",
|
||||
auth_type="cookies",
|
||||
requires_auth=True,
|
||||
url_pattern=r"^https?://(www\.)?subscribestar\.(com|adult)/",
|
||||
url_pattern=r"^https?://(www\.)?subscribestar\.(com|adult|art)/",
|
||||
url_examples=[
|
||||
"https://subscribestar.adult/example_artist",
|
||||
"https://www.subscribestar.com/example_artist",
|
||||
"https://subscribestar.art/example_artist",
|
||||
],
|
||||
default_config={**GD_DEFAULTS, "content_types": ["all"]},
|
||||
derive_post_url=derive_post_url,
|
||||
|
||||
@@ -116,8 +116,10 @@ async def test_get_cookies_path_subscribestar_injects_age_cookie(db, crypto, tmp
|
||||
cookie; the browser-stored cookie expires annually and can't be easily
|
||||
refreshed (the JS age popup is suppressed by localStorage). Mirror
|
||||
gallery-dl's own login-flow workaround by injecting
|
||||
`18_plus_agreement_generic=true` on `.subscribestar.adult` whenever
|
||||
cookies for subscribestar are materialized."""
|
||||
`18_plus_agreement_generic=true` whenever cookies for subscribestar
|
||||
are materialized — on EVERY SubscribeStar domain, since cookies are
|
||||
domain-scoped and creators live on .com/.adult/.art alike (a .adult-only
|
||||
line left .art sources stuck on the age wall — Elasid, event #54116)."""
|
||||
netscape_in = (
|
||||
"# Netscape HTTP Cookie File\n"
|
||||
".subscribestar.adult\tTRUE\t/\tTRUE\t1700000000\tsession_id\txyz\n"
|
||||
@@ -126,16 +128,18 @@ async def test_get_cookies_path_subscribestar_injects_age_cookie(db, crypto, tmp
|
||||
await svc.upsert(platform="subscribestar", credential_type="cookies", data=netscape_in)
|
||||
path = await svc.get_cookies_path("subscribestar")
|
||||
contents = path.read_text()
|
||||
assert "18_plus_agreement_generic\ttrue" in contents
|
||||
assert ".subscribestar.adult" in contents
|
||||
for domain in (".subscribestar.com", ".subscribestar.adult", ".subscribestar.art"):
|
||||
assert f"{domain}\tTRUE\t/\tTRUE\t4102444800\t18_plus_agreement_generic\ttrue" in contents
|
||||
# Original session_id cookie preserved.
|
||||
assert "session_id\txyz" in contents
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_cookies_path_subscribestar_idempotent_when_present(db, crypto, tmp_path):
|
||||
"""If the operator's captured cookies ALREADY contain the age cookie
|
||||
(e.g. a manual paste, or a re-login), don't double-inject."""
|
||||
async def test_get_cookies_path_subscribestar_idempotent_per_domain(db, crypto, tmp_path):
|
||||
"""If the operator's captured cookies ALREADY contain the age cookie for
|
||||
a domain (e.g. a manual paste, or a re-login), don't double-inject on
|
||||
THAT domain — but a .adult-only capture must still get the cookie added
|
||||
for .com and .art (per-domain check, not presence-anywhere)."""
|
||||
netscape_in = (
|
||||
"# Netscape HTTP Cookie File\n"
|
||||
".subscribestar.adult\tTRUE\t/\tTRUE\t1700000000\t18_plus_agreement_generic\ttrue\n"
|
||||
@@ -145,7 +149,15 @@ async def test_get_cookies_path_subscribestar_idempotent_when_present(db, crypto
|
||||
await svc.upsert(platform="subscribestar", credential_type="cookies", data=netscape_in)
|
||||
path = await svc.get_cookies_path("subscribestar")
|
||||
contents = path.read_text()
|
||||
assert contents.count("18_plus_agreement_generic") == 1
|
||||
assert contents.count("18_plus_agreement_generic") == 3
|
||||
adult_lines = [
|
||||
line for line in contents.splitlines()
|
||||
if line.startswith(".subscribestar.adult\t")
|
||||
and "18_plus_agreement_generic" in line
|
||||
]
|
||||
assert len(adult_lines) == 1
|
||||
assert ".subscribestar.com\t" in contents
|
||||
assert ".subscribestar.art\t" in contents
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
Reference in New Issue
Block a user