diff --git a/backend/app/services/patreon_resolver.py b/backend/app/services/patreon_resolver.py index c8acd2c..8c8d963 100644 --- a/backend/app/services/patreon_resolver.py +++ b/backend/app/services/patreon_resolver.py @@ -30,9 +30,17 @@ _CAMPAIGNS_URL = "https://www.patreon.com/api/campaigns" # A source URL of the form `.../id:` already carries the campaign id # (no lookup needed). The vanity regex deliberately EXCLUDES the id: form so the # two paths don't overlap. +# +# Patreon serves the creator vanity under several path prefixes — bare +# (`patreon.com/Atole`), `c/` (`patreon.com/c/Atole`), and `cw/` +# (`patreon.com/cw/Atole`, its current "creator workspace" URL). The optional +# prefix group must list `cw/` BEFORE `c/` so the longer prefix wins — otherwise +# `cw/Atole` matches the bare branch and yields vanity="cw" (operator-flagged +# 2026-06-07: every `/cw/` source failed resolution on vanity="cw"). _ID_URL_RE = re.compile(r"/id:(\d+)") +_VANITY_PREFIXES = ("cw/", "c/") _VANITY_RE = re.compile( - r"^https?://(?:www\.)?patreon\.com/(?:c/)?(?!id:)([^/?#]+)", + r"^https?://(?:www\.)?patreon\.com/(?:cw/|c/)?(?!id:)([^/?#]+)", re.IGNORECASE, ) _USER_AGENT = ( @@ -141,10 +149,12 @@ def _lookup_via_page(vanity: str, cookies_path: str | None) -> str | None: Patreon redirects between. Never raises.""" jar = _load_cookie_jar(cookies_path) headers = {"User-Agent": _USER_AGENT, "Accept": "text/html"} - for page_url in ( - f"https://www.patreon.com/{vanity}", - f"https://www.patreon.com/c/{vanity}", - ): + # Try the bare vanity and every known creator-path prefix Patreon + # redirects between (c/, cw/) — the one the source used isn't known here + # (extract_vanity already stripped it). + page_urls = [f"https://www.patreon.com/{vanity}"] + page_urls += [f"https://www.patreon.com/{p}{vanity}" for p in _VANITY_PREFIXES] + for page_url in page_urls: try: resp = requests.get( page_url, diff --git a/frontend/src/components/subscriptions/SourceActions.vue b/frontend/src/components/subscriptions/SourceActions.vue new file mode 100644 index 0000000..ae4751c --- /dev/null +++ b/frontend/src/components/subscriptions/SourceActions.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/frontend/src/components/subscriptions/SourceCard.vue b/frontend/src/components/subscriptions/SourceCard.vue index 0e0617b..0ba7f86 100644 --- a/frontend/src/components/subscriptions/SourceCard.vue +++ b/frontend/src/components/subscriptions/SourceCard.vue @@ -12,10 +12,19 @@ /> - {{ source.url }} +
+ {{ source.url }} + + mdi-pencil + Edit source + +
Last {{ formatRelative(source.last_checked_at) }} @@ -23,7 +32,11 @@ {{ source.consecutive_failures }} err + >{{ source.consecutive_failures }} err + + {{ source.last_error }} + +
- - mdi-play - Check now - - - {{ source.backfill_state === 'running' ? 'mdi-stop' : 'mdi-magnify-scan' }} - - {{ source.backfill_state === 'running' - ? (source.backfill_bypass_seen ? 'Stop recovery' : 'Stop backfill') - : 'Backfill full history' }} - - - - mdi-eye-outline - - Preview — count what a backfill would download (no download) - - - - mdi-backup-restore - - Recover — re-fetch dropped near-dups & re-evaluate under the current threshold - - - - mdi-pencil - Edit - - - mdi-close - Remove - +