diff --git a/surfsense_backend/app/capabilities/instagram/__init__.py b/surfsense_backend/app/capabilities/instagram/__init__.py index 4004f86c7..17866e4b5 100644 --- a/surfsense_backend/app/capabilities/instagram/__init__.py +++ b/surfsense_backend/app/capabilities/instagram/__init__.py @@ -2,6 +2,5 @@ from __future__ import annotations -from app.capabilities.instagram.comments import definition as _comments # noqa: F401 from app.capabilities.instagram.details import definition as _details # noqa: F401 from app.capabilities.instagram.scrape import definition as _scrape # noqa: F401 diff --git a/surfsense_backend/app/capabilities/instagram/comments/__init__.py b/surfsense_backend/app/capabilities/instagram/comments/__init__.py deleted file mode 100644 index 84899d758..000000000 --- a/surfsense_backend/app/capabilities/instagram/comments/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -"""``instagram.comments`` verb: post/reel URLs → comments (and replies).""" - -from __future__ import annotations diff --git a/surfsense_backend/app/capabilities/instagram/comments/definition.py b/surfsense_backend/app/capabilities/instagram/comments/definition.py deleted file mode 100644 index 7794228ac..000000000 --- a/surfsense_backend/app/capabilities/instagram/comments/definition.py +++ /dev/null @@ -1,22 +0,0 @@ -"""``instagram.comments`` capability registration (billed per comment; see config -``INSTAGRAM_SCRAPE_MICROS_PER_COMMENT``).""" - -from __future__ import annotations - -from app.capabilities.core import BillingUnit, Capability, register_capability -from app.capabilities.instagram.comments.executor import build_comments_executor -from app.capabilities.instagram.comments.schemas import CommentsInput, CommentsOutput - -INSTAGRAM_COMMENTS = Capability( - name="instagram.comments", - description=( - "Fetch comments (and optionally replies) for Instagram post or reel URLs." - ), - input_schema=CommentsInput, - output_schema=CommentsOutput, - executor=build_comments_executor(), - billing_unit=BillingUnit.INSTAGRAM_COMMENT, - docs_url="/docs/connectors/native/instagram", -) - -register_capability(INSTAGRAM_COMMENTS) diff --git a/surfsense_backend/app/capabilities/instagram/comments/executor.py b/surfsense_backend/app/capabilities/instagram/comments/executor.py deleted file mode 100644 index 260ee06c9..000000000 --- a/surfsense_backend/app/capabilities/instagram/comments/executor.py +++ /dev/null @@ -1,53 +0,0 @@ -"""``instagram.comments`` executor: verb input → scraper → comment items.""" - -from __future__ import annotations - -from collections.abc import Awaitable, Callable - -from app.capabilities.core import Executor -from app.capabilities.core.progress import emit_progress -from app.capabilities.instagram.comments.schemas import CommentsInput, CommentsOutput -from app.exceptions import ForbiddenError -from app.proprietary.platforms.instagram import ( - InstagramAccessBlockedError, - InstagramScrapeInput, - scrape_instagram, -) - -ScrapeFn = Callable[..., Awaitable[list[dict]]] - - -def build_comments_executor(scrape_fn: ScrapeFn | None = None) -> Executor: - """Bind the executor to a scraper fn (defaults to the proprietary actor).""" - scrape_fn = scrape_fn or scrape_instagram - - async def execute(payload: CommentsInput) -> CommentsOutput: - actor_input = InstagramScrapeInput( - resultsType="comments", - directUrls=payload.urls, - resultsLimit=payload.max_comments_per_post, - isNewestComments=payload.newest_first, - includeNestedComments=payload.include_replies, - ) - emit_progress( - "starting", - "Fetching Instagram comments", - total=payload.max_items, - unit="comment", - ) - try: - items = await scrape_fn(actor_input, limit=payload.max_items) - except InstagramAccessBlockedError as exc: - raise ForbiddenError( - f"Instagram refused anonymous access: {exc}", - code="INSTAGRAM_ACCESS_BLOCKED", - ) from exc - emit_progress( - "done", - f"Scraped {len(items)} comment(s)", - current=len(items), - unit="comment", - ) - return CommentsOutput(items=items) - - return execute diff --git a/surfsense_backend/app/capabilities/instagram/comments/schemas.py b/surfsense_backend/app/capabilities/instagram/comments/schemas.py deleted file mode 100644 index fadb83215..000000000 --- a/surfsense_backend/app/capabilities/instagram/comments/schemas.py +++ /dev/null @@ -1,61 +0,0 @@ -"""``instagram.comments`` I/O contracts. - -A lean surface over ``InstagramScrapeInput`` (``resultsType="comments"``). The -scraper's ``InstagramComment`` is reused verbatim as the output element. -""" - -from __future__ import annotations - -from pydantic import BaseModel, Field - -from app.capabilities.instagram.scrape.schemas import ( - MAX_INSTAGRAM_ITEMS, - MAX_INSTAGRAM_SOURCES, -) -from app.proprietary.platforms.instagram import InstagramComment - -MAX_COMMENTS_PER_POST = 50 -"""Anonymous web media pages surface at most ~50 comments per post.""" - - -class CommentsInput(BaseModel): - urls: list[str] = Field( - min_length=1, - max_length=MAX_INSTAGRAM_SOURCES, - description="Post or reel URLs to fetch comments for (shortCode or numeric-ID forms).", - ) - newest_first: bool = Field( - default=False, - description="Return newest comments first.", - ) - include_replies: bool = Field( - default=False, - description="Include nested replies; each reply is a separate billable item.", - ) - max_comments_per_post: int = Field( - default=10, - ge=1, - le=MAX_COMMENTS_PER_POST, - description="Max comments per post (Instagram caps at 50).", - ) - max_items: int = Field( - default=10, - ge=1, - le=MAX_INSTAGRAM_ITEMS, - description="Max total comments to return across all posts.", - ) - - @property - def estimated_units(self) -> int: - return self.max_items - - -class CommentsOutput(BaseModel): - items: list[InstagramComment] = Field( - default_factory=list, - description="One item per comment (or reply), in emission order.", - ) - - @property - def billable_units(self) -> int: - return len(self.items)