Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Fetch any URL via Chrome CDP and convert the rendered page to clean markdown with YouTube transcript support.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
scripts/lib/adapters/x/index.ts
1import type { Adapter, AdapterLoginInfo } from "../types";2import { exportCookies, restoreCookies, type CookieSidecarConfig } from "../../browser/cookie-sidecar";3import { detectInteractionGate } from "../../browser/interaction-gates";4import type { ExtractedDocument } from "../../extract/document";5import { collectMediaFromDocument } from "../../media/markdown-media";6import { extractArticleDocumentFromPayload } from "./article";7import { buildNeedsLoginResult, detectXLogin } from "./login";8import { extractStatusId, isXHost } from "./match";9import { collectXJsonPayloads, waitForInitialXPayload } from "./payloads";10import { extractSingleTweetDocumentFromPayload } from "./single";11import { extractThreadDocumentFromPayloads } from "./thread";12import { loadFullXThread } from "./thread-loader";1314const cookieConfig: CookieSidecarConfig = {15urls: ["https://x.com/", "https://twitter.com/"],16filename: "x-session-cookies.json",17requiredCookieNames: ["auth_token", "ct0"],18filterCookie: (c) => {19const d = c.domain ?? "";20return d.endsWith("x.com") || d.endsWith("twitter.com");21},22};2324function extractDocumentFromPayloads(25payloads: unknown[],26statusId: string,27pageUrl: string,28): ExtractedDocument | null {29for (const payload of payloads) {30const articleDocument = extractArticleDocumentFromPayload(payload, statusId, pageUrl, payloads);31if (articleDocument) {32return articleDocument;33}34}3536const threadDocument = extractThreadDocumentFromPayloads(payloads, statusId, pageUrl);37if (threadDocument) {38return threadDocument;39}4041for (const payload of payloads) {42const singleDocument = extractSingleTweetDocumentFromPayload(payload, statusId, pageUrl);43if (singleDocument) {44return singleDocument;45}46}4748return null;49}5051async function ensureXLoginState(context: Parameters<Adapter["process"]>[0]): Promise<AdapterLoginInfo> {52return detectXLogin(context);53}5455export const xAdapter: Adapter = {56name: "x",57match(input) {58return isXHost(input.url.hostname);59},60async checkLogin(context) {61return detectXLogin(context);62},63async exportCookies(context, profileDir) {64return exportCookies(context.browser.targetSession, cookieConfig, profileDir);65},66async restoreCookies(context, profileDir) {67return restoreCookies(context.browser.targetSession, cookieConfig, profileDir);68},69async process(context) {70const statusId = extractStatusId(context.input.url);71if (!statusId) {72return {73status: "no_document",74};75}7677context.log.info(`Loading ${context.input.url.toString()} with x adapter`);78await context.browser.goto(context.input.url.toString(), context.timeoutMs);7980const interaction = await detectInteractionGate(context.browser);81if (interaction) {82return {83status: "needs_interaction",84interaction,85};86}8788let login = await ensureXLoginState(context);89if (login.state === "logged_out") {90return buildNeedsLoginResult(login);91}9293await waitForInitialXPayload(context);94await loadFullXThread(context, statusId);9596const pageUrl = await context.browser.getURL();97const postLoadInteraction = await detectInteractionGate(context.browser);98if (postLoadInteraction) {99return {100status: "needs_interaction",101interaction: postLoadInteraction,102login,103};104}105106login = await ensureXLoginState(context).catch(() => login);107if (login.state === "logged_out") {108return buildNeedsLoginResult(login);109}110111const payloads = await collectXJsonPayloads(context);112if (payloads.length === 0) {113return {114status: "no_document",115login,116};117}118119const document = extractDocumentFromPayloads(payloads, statusId, pageUrl);120if (document) {121return {122status: "ok",123document,124media: collectMediaFromDocument(document),125login,126};127}128129return {130status: "no_document",131login,132};133},134};135