diff --git a/deno.lock b/deno.lock new file mode 100644 index 0000000..90c3000 --- /dev/null +++ b/deno.lock @@ -0,0 +1,9 @@ +{ + "version": "2", + "remote": { + "https://deno.land/std@0.152.0/fmt/colors.ts": "6f9340b7fb8cc25a993a99e5efc56fe81bb5af284ff412129dd06df06f53c0b4", + "https://deno.land/std@0.152.0/testing/_diff.ts": "029a00560b0d534bc0046f1bce4bd36b3b41ada3f2a3178c85686eb2ff5f1413", + "https://deno.land/std@0.152.0/testing/_format.ts": "0d8dc79eab15b67cdc532826213bbe05bccfd276ca473a50a3fc7bbfb7260642", + "https://deno.land/std@0.152.0/testing/asserts.ts": "093735c88f52bbead7f60a1f7a97a2ce4df3c2d5fab00a46956f20b4a5793ccd" + } +} diff --git a/src/graph_query_ids.ts b/src/graph_query_ids.ts index b64c319..59fe641 100644 --- a/src/graph_query_ids.ts +++ b/src/graph_query_ids.ts @@ -1,64 +1,64 @@ -import { TwitterURL } from "./mod.ts"; +import { TwitterURL } from "./mod.ts" +import { UserAgent } from "./static.ts" interface GraphQueryIdResponse { - queryId: string; - operationName: string; - operationType: "mutations" | "queries"; + queryId: string + operationName: string + operationType: "mutations" | "queries" } -export type GraphQueryIds = Map; +export type GraphQueryIds = Map export class GraphQuery { - /** - * Get graphql endpoint random ids - * @returns Promise - */ - static getIds = async (): Promise => { - const html = await fetch(TwitterURL.WebClient.value); + /** + * Get graphql endpoint random ids + * @returns Promise + */ + static getIds = async (): Promise => { + const html = await fetch(TwitterURL.WebClient.value, { + headers: { + "User-Agent": UserAgent.Firefox, + }, + }) - const htmlText = await html.text(); + const htmlText = await html.text() + // console.log(htmlText) - // get main.js from html - // const links = htmlText.match(/https:\/\/abs\.twimg\.com\/responsive-web\/client-web([^\/]+|)\/main\.[^.]+\.js/g) - const links = htmlText.match( - /https:\/\/abs\.twimg\.com\/responsive-web\/client-web([^\/]+|)\/main\.[^.]+\.js/g, - ); + // get api.*..js from html + // the format is `api:"9eacf99",` + const apiJsId = htmlText.match(/api:"([^"]+)",/) + if (apiJsId === null) { + throw new Error("Cannot get api.*.js id") + } + // console.log(apiJsId) - // if mainJsURLs is null, return empty array - if (links === null) { - return new Map(); - } + const link = `https://abs.twimg.com/responsive-web/client-web/api.${apiJsId[1]}a.js` + // console.log(link) - // get main.js from mainJsURLs[0] - const link = links[0]; - const mainJs = await fetch(link); + const mainJs = await fetch(link) - // get all query ids from main.js - const mainJsText = await mainJs.text(); - const queryIds = mainJsText.match( - /{queryId:"([^"]+)",operationName:"([^"]+)",operationType:"([^"]+)"/g, - ) || []; - const patchedQueryArray = queryIds.map((query) => query + "}"); + // get all query ids from main.js + const mainJsText = await mainJs.text() + // console.log(mainJsText) + const queryIds = mainJsText.match(/{queryId:"([^"]+)",operationName:"([^"]+)",operationType:"([^"]+)"/g) || [] + const patchedQueryArray = queryIds.map((query) => query + "}") - const queries = patchedQueryArray.map((query) => { - const correctQuery = query.replace( - /(['"])?([a-z0-9A-Z_]+)(['"])?:/g, - '"$2": ', - ); - const queryJson = JSON.parse(correctQuery); - const queryData: GraphQueryIdResponse = { - queryId: queryJson.queryId, - operationName: queryJson.operationName, - operationType: queryJson.operationType, - }; - return queryData; - }); + const queries = patchedQueryArray.map((query) => { + const correctQuery = query.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ') + const queryJson = JSON.parse(correctQuery) + const queryData: GraphQueryIdResponse = { + queryId: queryJson.queryId, + operationName: queryJson.operationName, + operationType: queryJson.operationType, + } + return queryData + }) - const queryIdsMap = new Map(); - for (const query of queries) { - queryIdsMap.set(query.operationName, query.queryId); - } + const queryIdsMap = new Map() + for (const query of queries) { + queryIdsMap.set(query.operationName, query.queryId) + } - return queryIdsMap; - }; + return queryIdsMap + } } diff --git a/src/static.ts b/src/static.ts index ade532a..1a77432 100644 --- a/src/static.ts +++ b/src/static.ts @@ -1,93 +1,91 @@ export class Authorization { - type: "Bearer" | "OAuth"; - token: string; + type: "Bearer" | "OAuth" + token: string - constructor(type: "Bearer" | "OAuth", token: string) { - this.type = type; - this.token = token; - } + constructor(type: "Bearer" | "OAuth", token: string) { + this.type = type + this.token = token + } } /** * Class of bearer token. */ export class Bearer extends Authorization { - private constructor(token: string) { - super("Bearer", token); - } + private constructor(token: string) { + super("Bearer", token) + } - /** - * The official web client bearer token. (Recommended) - */ - static Web: Bearer = new Bearer( - "AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA", - ); + /** + * The official web client bearer token. (Recommended) + */ + static Web: Bearer = new Bearer( + "AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA" + ) - /** - * Use your own bearer token if you want to use. - * @param token - * @returns - */ - static Own(token: string): Bearer { - return new Bearer(token); - } + /** + * Use your own bearer token if you want to use. + * @param token + * @returns + */ + static Own(token: string): Bearer { + return new Bearer(token) + } } /** * Class of bearer token. */ export class OAuth extends Authorization { - private constructor(token: string) { - super("OAuth", token); - } + private constructor(token: string) { + super("OAuth", token) + } - /** - * Use your own oauth token if you want to use. - * @param token - * @returns - */ - static Own(token: string): Bearer { - return new OAuth(token); - } + /** + * Use your own oauth token if you want to use. + * @param token + * @returns + */ + static Own(token: string): Bearer { + return new OAuth(token) + } } -export type APIURLType = - | "gql" - | "api" - | "api/1.1" - | "i/api/1.1" - | "i/api/2" - | "i/api/i"; +export type APIURLType = "gql" | "api" | "api/1.1" | "i/api/1.1" | "i/api/2" | "i/api/i" export class TwitterURL { - value: string; + value: string - private constructor(link: string) { - this.value = link; - } + private constructor(link: string) { + this.value = link + } - static WebClient = new TwitterURL("https://twitter.com"); + static WebClient = new TwitterURL("https://twitter.com") - static API(urlType: APIURLType): TwitterURL { - switch (urlType) { - case "gql": { - return new TwitterURL("https://api.twitter.com/graphql"); - } - case "api": { - return new TwitterURL("https://api.twitter.com"); - } - case "api/1.1": { - return new TwitterURL("https://api.twitter.com/1.1"); - } - case "i/api/1.1": { - return new TwitterURL("https://twitter.com/i/api/1.1"); - } - case "i/api/2": { - return new TwitterURL("https://twitter.com/i/api/2"); - } - case "i/api/i": { - return new TwitterURL("https://twitter.com/i/api/i"); - } + static API(urlType: APIURLType): TwitterURL { + switch (urlType) { + case "gql": { + return new TwitterURL("https://api.twitter.com/graphql") + } + case "api": { + return new TwitterURL("https://api.twitter.com") + } + case "api/1.1": { + return new TwitterURL("https://api.twitter.com/1.1") + } + case "i/api/1.1": { + return new TwitterURL("https://twitter.com/i/api/1.1") + } + case "i/api/2": { + return new TwitterURL("https://twitter.com/i/api/2") + } + case "i/api/i": { + return new TwitterURL("https://twitter.com/i/api/i") + } + } } - } +} + +export enum UserAgent { + Firefox = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/110.0", } diff --git a/test/graph_query_ids.test.ts b/test/graph_query_ids.test.ts index 1d0f0d4..7e6ee24 100644 --- a/test/graph_query_ids.test.ts +++ b/test/graph_query_ids.test.ts @@ -1,8 +1,10 @@ -import { assertExists } from "../deps.ts"; -import { GraphQuery } from "../src/mod.ts"; +import { assertExists } from "../deps.ts" +import { GraphQuery } from "../src/mod.ts" Deno.test("Get graph query ids", async () => { - const graphQueryIds = await GraphQuery.getIds(); + const graphQueryIds = await GraphQuery.getIds() - assertExists(graphQueryIds.get("UserByScreenName")); -}); + console.log(graphQueryIds) + + assertExists(graphQueryIds.get("UserByScreenName")) +})