Merge upstream/ci_mvp: add YouTube scraper actor under app/proprietary

Resolved modify/delete conflicts on the old 'revamp phases 4-7/' plan docs
by keeping our deletion (superseded by flattened plans/backend/00-*.md).
This commit is contained in:
CREDO23 2026-07-02 20:01:11 +02:00
commit af3e70ea56
22 changed files with 4177 additions and 9 deletions

View file

@ -9,6 +9,12 @@ from fastapi import APIRouter, Depends, HTTPException, Query
from scrapling.fetchers import AsyncFetcher
from app.auth.context import AuthContext
from app.proprietary.scrapers.youtube import (
YouTubeCommentsInput,
YouTubeScrapeInput,
scrape_comments,
scrape_youtube,
)
from app.users import require_session_context
from app.utils.proxy import get_proxy_url
@ -26,6 +32,45 @@ _INNERTUBE_CLIENT = {
}
@router.post("/youtube/scrape")
async def scrape_youtube_route(
payload: YouTubeScrapeInput,
_auth: AuthContext = Depends(require_session_context),
) -> list[dict]:
"""Scrape public YouTube data (search / video / channel / playlist / shorts).
Apify YouTube Scraper-compatible input/output. The scrape runs inline and is
bounded only by the request's own ``maxResults`` / ``maxResultsShorts`` /
``maxResultStreams`` no separate per-request ceiling.
"""
try:
return await scrape_youtube(payload)
except Exception as e:
logger.error("YouTube scrape failed: %s", e)
raise HTTPException(
status_code=502, detail=f"YouTube scrape failed: {e!s}"
) from e
@router.post("/youtube/comments")
async def scrape_comments_route(
payload: YouTubeCommentsInput,
_auth: AuthContext = Depends(require_session_context),
) -> list[dict]:
"""Scrape YouTube comments (+ replies) for the given video URLs.
Apify "YouTube Comments Scraper"-compatible. Runs inline and is bounded only
by the request's own ``maxComments`` — no separate per-request ceiling.
"""
try:
return await scrape_comments(payload)
except Exception as e:
logger.error("YouTube comments scrape failed: %s", e)
raise HTTPException(
status_code=502, detail=f"YouTube comments scrape failed: {e!s}"
) from e
@router.get("/youtube/playlist-videos")
async def get_playlist_videos(
url: str = Query(..., description="YouTube playlist URL"),