diff --git a/.npmignore b/.npmignore index 1ef2f33..9ec318d 100644 --- a/.npmignore +++ b/.npmignore @@ -1,2 +1,3 @@ .github -node_modules \ No newline at end of file +node_modules +src/ \ No newline at end of file diff --git a/AVAILABLE_LANGUAGES.md b/AVAILABLE_LANGUAGES.md index bd85b91..83409fc 100644 --- a/AVAILABLE_LANGUAGES.md +++ b/AVAILABLE_LANGUAGES.md @@ -1,7 +1,7 @@ # Here is available language you can use in this library - Indonesia ~ If your hosting location or application location is in Indonesia, you can enter code `id` -- United States ~ If your hosting location or application location is in America or United States (US), you can enter code `us`. +- ~~United States ~ If your hosting location or application location is in America or United States (US), you can enter code `us`.~~ Removed. - Spain ~ If your hosting location or application location is in Spain, you can enter code `es`. - Portuguese ~ If your hosting location or application location is in Portuguese, you can enter code `pt`. - Russia ~ If your hosting location or application location is in Russia, you can enter code `ru`. diff --git a/README.md b/README.md index 5e1b776..2e1fe84 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # Brainly Scraper V2 This library retrieves data from Brainly that has been designed to avoid `403 Forbidden` exception. -> To avoid such errors, you can fill in a valid country code according to the location of your hosting server. For example, heroku, heroku with the United States region. That is, you must fill in the code `us` as the country code inside the brainly parameter constructor. +> To avoid such errors, you can fill in a valid country code. You can test the 10 languages or country codes available to see if your server hosting country location or location is rejected. -You can test the 10 languages or country codes available to see if your server hosting country location or location is rejected. See https://github.com/hansputera/brainly-scraper-languages/blob/master/AVAILABLE_LANGUAGES.md +See https://github.com/hansputera/brainly-scraper-languages/blob/master/AVAILABLE_LANGUAGES.md # 💉 Installation - Using NPM : `npm install brainly-scraper-v2` @@ -52,5 +52,12 @@ brain.search("es", "Pythagoras").then(console.log).catch(console.error); # ⚙️ Issues and Bugs If you have problems using this library, you can create an issue in the [github repository](https://github.com/hansputera/brainly-scraper-languages). Remember, don't forget to read the instructions and try. +# 🔬 Hosting testing +## Replit.com +Free and paid hosting replit already tested. The country codes that pass are Indonesia, Spain, India, Portuguese, and Philipines. + + +Ever tried and tested on other hosting? Please send us your feedback in PR. That would be very helpful 😊. + # ✍️ Contributions Do you want to contribute with this library for the better? Very well, fork this [github repository](https://github.com/hansputera/brainly-scraper-languages) then install dependencies to your directory. Happy coding 😁 \ No newline at end of file diff --git a/dist/src/config.d.ts b/dist/src/config.d.ts index d9205e0..19526de 100644 --- a/dist/src/config.d.ts +++ b/dist/src/config.d.ts @@ -1,7 +1,6 @@ export declare const graphql_query = "query SearchQuery($query: String!, $first: Int!, $after: ID) {\n questionSearch(query: $query, first: $first, after: $after) {\n count\n edges {\n node {\n databaseId\n content\n points\n created\n lastActivity\n subject {\n name\n slug\n }\n grade {\n name\n slug\n }\n attachments {\n url\n }\n author {\n databaseId\n nick\n points\n gender\n description\n isDeleted\n avatar {\n url\n }\n category\n clientType\n rank {\n databaseId\n name\n }\n receivedThanks\n bestAnswersCount\n helpedUsersCount\n }\n isAuthorsFirstQuestion\n canBeAnswered\n pointsForAnswer\n pointsForBestAnswer\n answers {\n nodes {\n databaseId\n content\n points\n isBest\n created\n rating\n ratesCount\n thanksCount\n attachments {\n url\n }\n author {\n databaseId\n nick\n points\n gender\n description\n isDeleted\n avatar {\n url\n }\n category\n clientType\n rank {\n databaseId\n name\n }\n receivedThanks\n bestAnswersCount\n helpedUsersCount\n }\n }\n }\n }\n }\n }\n }"; export declare const baseURLs: { id: string; - us: string; es: string; pt: string; ru: string; diff --git a/dist/src/config.js b/dist/src/config.js index 17ccf2b..5f4775e 100644 --- a/dist/src/config.js +++ b/dist/src/config.js @@ -4,7 +4,7 @@ exports.languages = exports.baseURLs = exports.graphql_query = void 0; exports.graphql_query = "query SearchQuery($query: String!, $first: Int!, $after: ID) {\n questionSearch(query: $query, first: $first, after: $after) {\n count\n edges {\n node {\n databaseId\n content\n points\n created\n lastActivity\n subject {\n name\n slug\n }\n grade {\n name\n slug\n }\n attachments {\n url\n }\n author {\n databaseId\n nick\n points\n gender\n description\n isDeleted\n avatar {\n url\n }\n category\n clientType\n rank {\n databaseId\n name\n }\n receivedThanks\n bestAnswersCount\n helpedUsersCount\n }\n isAuthorsFirstQuestion\n canBeAnswered\n pointsForAnswer\n pointsForBestAnswer\n answers {\n nodes {\n databaseId\n content\n points\n isBest\n created\n rating\n ratesCount\n thanksCount\n attachments {\n url\n }\n author {\n databaseId\n nick\n points\n gender\n description\n isDeleted\n avatar {\n url\n }\n category\n clientType\n rank {\n databaseId\n name\n }\n receivedThanks\n bestAnswersCount\n helpedUsersCount\n }\n }\n }\n }\n }\n }\n }"; exports.baseURLs = { id: "https://brainly.co.id", - us: "https://brainly.com", + //us: "https://brainly.com", es: "https://brainly.lat", pt: "https://brainly.com.br", ru: "https://znanija.com", diff --git a/dist/src/main.d.ts b/dist/src/main.d.ts index 36eded6..4210917 100644 --- a/dist/src/main.d.ts +++ b/dist/src/main.d.ts @@ -1,12 +1,12 @@ -import type { Answer, LanguageList, Question } from "./types"; +import type { Answer, CountryList, LanguageList, Question } from "./types"; export default class Brainly { - country: LanguageList; + country: CountryList; clientRequest: (lang: LanguageList) => import("got").Got; /** * - * @param country - Here, please put your application server country code, if your server are in United States. Enter region/country code `us` to this parameter. Because what? All brainly website is protected, if you do not enter valid region/country code. It will trigger an Error Exception. + * @param country - Here, please put your application server country code. if you do not enter valid region/country code. It will trigger an Error Exception. */ - constructor(country?: LanguageList); + constructor(country?: CountryList); /** * Use this function if you want search question, it will returns question detail, question author, answer detail, attachments (if question or answer attachments is any), rating question and answer. * diff --git a/dist/src/main.js b/dist/src/main.js index 8a676b0..f936582 100644 --- a/dist/src/main.js +++ b/dist/src/main.js @@ -9,19 +9,24 @@ const error_1 = __importDefault(require("./error")); const random_useragent_1 = __importDefault(require("random-useragent")); const util_1 = __importDefault(require("./util")); class Brainly { - country; - clientRequest = (lang) => got_1.default.extend({ - prefixUrl: `${this.getBaseURL(lang)}/graphql`, - headers: { - "user-agent": this.getAgent() - } - }); /** * - * @param country - Here, please put your application server country code, if your server are in United States. Enter region/country code `us` to this parameter. Because what? All brainly website is protected, if you do not enter valid region/country code. It will trigger an Error Exception. + * @param country - Here, please put your application server country code. if you do not enter valid region/country code. It will trigger an Error Exception. */ constructor(country = "id") { this.country = country; + this.clientRequest = (lang) => got_1.default.extend({ + prefixUrl: `${this.getBaseURL(this.country)}/graphql`, + headers: { + "user-agent": this.getAgent(), + "origin": this.getBaseURL(lang), + "sec-gpc": "1", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", + "batch": "true" + } + }); if (!this.isValidLanguage(country)) throw new error_1.default("Please put valid country!"); } @@ -33,69 +38,74 @@ class Brainly { * @param length Length array from question list */ async search(language = "id", question, length = 10) { - if (!this.isValidLanguage(language)) - throw new error_1.default("Please put valid language!"); - const body = this.getRequestBody(question, length); - const response = await this.clientRequest(this.country.toLowerCase()).post(language.toLowerCase(), { - json: body - }); - const validJSON = JSON.parse(response.body)[0].data.questionSearch.edges; - const objects = validJSON.map(obj => { - const question = { - id: obj.node.databaseId, - content: util_1.default.clearContent(obj.node.content), - attachments: obj.node.attachments.map(attach => attach.url), - author: obj.node.author ? { - id: obj.node.author.databaseId, - avatar_url: obj.node.author.avatar ? obj.node.author.avatar.url : undefined, - deleted: obj.node.author.isDeleted, - url: `${this.getBaseURL(language)}/app/profile/${obj.node.author.databaseId}`, - rank: obj.node.author.rank.name, - username: obj.node.author.nick, - receivedThanks: obj.node.author.receivedThanks, - bestAnswersCount: obj.node.author.bestAnswersCount, - gender: obj.node.author.gender, - description: obj.node.author.description, - points: obj.node.author.points, - helpedUsersCount: obj.node.author.helpedUsersCount - } : undefined, - points: { - points: obj.node.points, - forBest: obj.node.pointsForBestAnswer - }, - grade: obj.node.grade.name, - education: obj.node.subject.name, - created: obj.node.created, - can_be_answered: obj.node.canBeAnswered, - url: `${this.getBaseURL(language)}/${util_1.default.resolveWorkName(language.toLowerCase())}/${obj.node.databaseId}` - }; - const answers = obj.node.answers.nodes.map(answerObj => ({ - content: util_1.default.clearContent(answerObj.content), - attachments: answerObj.attachments.map(attach => attach.url), - rates: answerObj.ratesCount, - rating: answerObj.rating, - isBest: answerObj.isBest, - created: answerObj.created, - author: answerObj.author ? { - id: answerObj.author.databaseId, - username: answerObj.author.nick, - gender: answerObj.author.gender, - avatar_url: answerObj.author.avatar ? answerObj.author.avatar.url : undefined, - deleted: answerObj.author.isDeleted, - url: `${this.getBaseURL(language.toLowerCase())}/app/profile/${answerObj.author.databaseId}`, - description: answerObj.author.description, - bestAnswersCount: answerObj.author.bestAnswersCount, - points: answerObj.author.points, - helpedUsersCount: answerObj.author.helpedUsersCount, - receivedThanks: answerObj.author.receivedThanks, - rank: answerObj.author.rank.name - } : undefined - })); - return { - question, answers - }; - }); - return objects; + try { + if (!this.isValidLanguage(language)) + throw new error_1.default("Please put valid language!"); + const body = this.getRequestBody(question, length); + const response = await this.clientRequest(this.country.toLowerCase()).post(language.toLowerCase(), { + json: body + }); + const validJSON = JSON.parse(response.body)[0].data.questionSearch.edges; + const objects = validJSON.map(obj => { + const question = { + id: obj.node.databaseId, + content: util_1.default.clearContent(obj.node.content), + attachments: obj.node.attachments.map(attach => attach.url), + author: obj.node.author ? { + id: obj.node.author.databaseId, + avatar_url: obj.node.author.avatar ? obj.node.author.avatar.url : undefined, + deleted: obj.node.author.isDeleted, + url: `${this.getBaseURL(language)}/app/profile/${obj.node.author.databaseId}`, + rank: obj.node.author.rank ? obj.node.author.rank.name : "-", + username: obj.node.author.nick, + receivedThanks: obj.node.author.receivedThanks, + bestAnswersCount: obj.node.author.bestAnswersCount, + gender: obj.node.author.gender, + description: obj.node.author.description, + points: obj.node.author.points, + helpedUsersCount: obj.node.author.helpedUsersCount + } : undefined, + points: { + points: obj.node.points, + forBest: obj.node.pointsForBestAnswer + }, + grade: obj.node.grade.name, + education: obj.node.subject.name, + created: obj.node.created, + can_be_answered: obj.node.canBeAnswered, + url: `${this.getBaseURL(language)}/${util_1.default.resolveWorkName(language.toLowerCase())}/${obj.node.databaseId}` + }; + const answers = obj.node.answers.nodes.map(answerObj => ({ + content: util_1.default.clearContent(answerObj.content), + attachments: answerObj.attachments.map(attach => attach.url), + rates: answerObj.ratesCount, + rating: answerObj.rating, + isBest: answerObj.isBest, + created: answerObj.created, + author: answerObj.author ? { + id: answerObj.author.databaseId, + username: answerObj.author.nick, + gender: answerObj.author.gender, + avatar_url: answerObj.author.avatar ? answerObj.author.avatar.url : undefined, + deleted: answerObj.author.isDeleted, + url: `${this.getBaseURL(language.toLowerCase())}/app/profile/${answerObj.author.databaseId}`, + description: answerObj.author.description, + bestAnswersCount: answerObj.author.bestAnswersCount, + points: answerObj.author.points, + helpedUsersCount: answerObj.author.helpedUsersCount, + receivedThanks: answerObj.author.receivedThanks, + rank: answerObj.author.rank ? answerObj.author.rank.name : "-" + } : undefined + })); + return { + question, answers + }; + }); + return objects; + } + catch (err) { + throw new Error(JSON.stringify(err)); + } } getRequestBody(question, length = 10) { return [{ diff --git a/dist/src/tests/index.test.js b/dist/src/tests/index.test.js index cbb9793..dc15c81 100644 --- a/dist/src/tests/index.test.js +++ b/dist/src/tests/index.test.js @@ -5,8 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) { Object.defineProperty(exports, "__esModule", { value: true }); const index_1 = __importDefault(require("../../index")); it("should return information about question and answer", (done) => { - const brain = new index_1.default("id"); - brain.search("ru", "Pythagoras").then((results) => { + const brain = new index_1.default("hi"); + brain.search("us", "Pythagoras").then((results) => { console.log(results[0].question); expect(results).toBeDefined(); done(); diff --git a/src/types.d.ts b/dist/src/types.d.ts similarity index 81% rename from src/types.d.ts rename to dist/src/types.d.ts index e75626f..06a057d 100644 --- a/src/types.d.ts +++ b/dist/src/types.d.ts @@ -1,7 +1,6 @@ -export type LanguageList = "id" | "us" | "es" | "ru" | "ro" | "pt" | "tr" | "ph" | "pl" | "hi"; -export type BaseURLObject = Record; -export type Attachments = string[]; - +export declare type CountryList = "id" | "es" | "ru" | "ro" | "pt" | "tr" | "ph" | "pl" | "hi"; +export declare type BaseURLObject = Record; +export declare type Attachments = string[]; export interface Question { id: number; content: string; @@ -12,12 +11,11 @@ export interface Question { points: { points: number; forBest: number; - } + }; grade: string; education: string; can_be_answered: boolean; } - export interface Author { id: number; url: string; @@ -32,7 +30,6 @@ export interface Author { bestAnswersCount: number; helpedUsersCount: number; } - export interface Answer { content: string; attachments: Attachments; @@ -42,11 +39,10 @@ export interface Answer { isBest: boolean; created: string; } - export interface BrainlyResponse { highlight: { contentFragments: string[]; - } + }; node: { id: string; created: string; @@ -71,16 +67,16 @@ export interface BrainlyResponse { bestAnswersCount: number; helpedUsersCount: number; gender: string; - } + }; canBeAnswered: boolean; grade: { name: string; slug: string; - } + }; subject: { name: string; slug: string; - } + }; answers: { hasVerified: boolean; nodes: { @@ -88,13 +84,18 @@ export interface BrainlyResponse { rating: number; thanksCount: number; content: string; - attachments: { url: string; }[]; + attachments: { + url: string; + }[]; author: BrainlyResponse["node"]["author"]; isBest: boolean; points: number; created: string; }[]; - } - attachments: { url: string; }[]; - } -} \ No newline at end of file + }; + attachments: { + url: string; + }[]; + }; +} +export declare type LanguageList = CountryList | "us"; diff --git a/dist/src/types.js b/dist/src/types.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/dist/src/types.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/package.json b/package.json index 31f6b54..55f8341 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "brainly-scraper-v2", - "version": "2.0.2", + "version": "2.0.3", "description": "A library that makes it easy to retrieve data from brainly sites.", "main": "dist/index.js", "scripts": { diff --git a/src/config.ts b/src/config.ts index 5684f94..37a13f6 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,7 +1,7 @@ export const graphql_query = "query SearchQuery($query: String!, $first: Int!, $after: ID) {\n questionSearch(query: $query, first: $first, after: $after) {\n count\n edges {\n node {\n databaseId\n content\n points\n created\n lastActivity\n subject {\n name\n slug\n }\n grade {\n name\n slug\n }\n attachments {\n url\n }\n author {\n databaseId\n nick\n points\n gender\n description\n isDeleted\n avatar {\n url\n }\n category\n clientType\n rank {\n databaseId\n name\n }\n receivedThanks\n bestAnswersCount\n helpedUsersCount\n }\n isAuthorsFirstQuestion\n canBeAnswered\n pointsForAnswer\n pointsForBestAnswer\n answers {\n nodes {\n databaseId\n content\n points\n isBest\n created\n rating\n ratesCount\n thanksCount\n attachments {\n url\n }\n author {\n databaseId\n nick\n points\n gender\n description\n isDeleted\n avatar {\n url\n }\n category\n clientType\n rank {\n databaseId\n name\n }\n receivedThanks\n bestAnswersCount\n helpedUsersCount\n }\n }\n }\n }\n }\n }\n }"; export const baseURLs = { id: "https://brainly.co.id", - us: "https://brainly.com", + //us: "https://brainly.com", es: "https://brainly.lat", pt: "https://brainly.com.br", ru: "https://znanija.com", diff --git a/src/main.ts b/src/main.ts index 5970e1e..1412ae5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,23 +1,31 @@ import Got from "got"; import { baseURLs, graphql_query, languages } from "./config"; import BrainlyError from "./error"; -import type { Answer, BaseURLObject, BrainlyResponse, LanguageList, Question } from "./types"; +import type { Answer, BaseURLObject, BrainlyResponse, CountryList, LanguageList, Question } from "./types"; import RandomUserAgent from "random-useragent"; import Util from "./util"; +import { version } from "../package.json"; export default class Brainly { + public version = version; public clientRequest = (lang: LanguageList) => Got.extend({ - prefixUrl: `${this.getBaseURL(lang)}/graphql`, + prefixUrl: `${this.getBaseURL(this.country)}/graphql`, headers: { - "user-agent": this.getAgent() as string + "user-agent": this.getAgent() as string, + "origin": this.getBaseURL(lang), + "sec-gpc": "1", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", + "batch": "true" } }); /** * - * @param country - Here, please put your application server country code, if your server are in United States. Enter region/country code `us` to this parameter. Because what? All brainly website is protected, if you do not enter valid region/country code. It will trigger an Error Exception. + * @param country - Here, please put your application server country code. if you do not enter valid region/country code. It will trigger an Error Exception. */ - constructor(public country: LanguageList = "id") { + constructor(public country: CountryList = "id") { if (!this.isValidLanguage(country)) throw new BrainlyError("Please put valid country!"); } @@ -29,71 +37,75 @@ export default class Brainly { * @param length Length array from question list */ public async search(language: LanguageList = "id", question: string, length = 10) { - if (!this.isValidLanguage(language)) throw new BrainlyError("Please put valid language!"); - const body = this.getRequestBody(question, length); - const response = await this.clientRequest(this.country.toLowerCase() as LanguageList).post(language.toLowerCase(), { - json: body - }); - const validJSON = JSON.parse(response.body)[0].data.questionSearch.edges as BrainlyResponse[]; - const objects = validJSON.map(obj => { - const question: Question = { - id: obj.node.databaseId, - content: Util.clearContent(obj.node.content), - attachments: obj.node.attachments.map(attach => attach.url), - author: obj.node.author ? { - id: obj.node.author.databaseId, - avatar_url: obj.node.author.avatar ? obj.node.author.avatar!.url : undefined, - deleted: obj.node.author.isDeleted, - url: `${this.getBaseURL(language)}/app/profile/${obj.node.author.databaseId}`, - rank: obj.node.author.rank.name, - username: obj.node.author.nick, - receivedThanks: obj.node.author.receivedThanks, - bestAnswersCount: obj.node.author.bestAnswersCount, - gender: obj.node.author.gender, - description: obj.node.author.description, - points: obj.node.author.points, - helpedUsersCount: obj.node.author.helpedUsersCount - } : undefined, - points: { - points: obj.node.points, - forBest: obj.node.pointsForBestAnswer - }, - grade: obj.node.grade.name, - education: obj.node.subject.name, - created: obj.node.created, - can_be_answered: obj.node.canBeAnswered, - url: `${this.getBaseURL(language)}/${Util.resolveWorkName(language.toLowerCase() as LanguageList)}/${obj.node.databaseId}` - }; + try { + if (!this.isValidLanguage(language)) throw new BrainlyError("Please put valid language!"); + const body = this.getRequestBody(question, length); + const response = await this.clientRequest(this.country.toLowerCase() as LanguageList).post(language.toLowerCase(), { + json: body + }); + const validJSON = JSON.parse(response.body)[0].data.questionSearch.edges as BrainlyResponse[]; + const objects = validJSON.map(obj => { + const question: Question = { + id: obj.node.databaseId, + content: Util.clearContent(obj.node.content), + attachments: obj.node.attachments.map(attach => attach.url), + author: obj.node.author ? { + id: obj.node.author.databaseId, + avatar_url: obj.node.author.avatar ? obj.node.author.avatar!.url : undefined, + deleted: obj.node.author.isDeleted, + url: `${this.getBaseURL(language)}/app/profile/${obj.node.author.databaseId}`, + rank: obj.node.author.rank ? obj.node.author.rank.name : "-", + username: obj.node.author.nick, + receivedThanks: obj.node.author.receivedThanks, + bestAnswersCount: obj.node.author.bestAnswersCount, + gender: obj.node.author.gender, + description: obj.node.author.description, + points: obj.node.author.points, + helpedUsersCount: obj.node.author.helpedUsersCount + } : undefined, + points: { + points: obj.node.points, + forBest: obj.node.pointsForBestAnswer + }, + grade: obj.node.grade.name, + education: obj.node.subject.name, + created: obj.node.created, + can_be_answered: obj.node.canBeAnswered, + url: `${this.getBaseURL(language)}/${Util.resolveWorkName(language.toLowerCase() as LanguageList)}/${obj.node.databaseId}` + }; - const answers: Answer[] = obj.node.answers.nodes.map(answerObj => ({ - content: Util.clearContent(answerObj.content), - attachments: answerObj.attachments.map(attach => attach.url), - rates: answerObj.ratesCount, - rating: answerObj.rating, - isBest: answerObj.isBest, - created: answerObj.created, - author: answerObj.author ? { - id: answerObj.author.databaseId, - username: answerObj.author.nick, - gender: answerObj.author.gender, - avatar_url: answerObj.author.avatar ? answerObj.author.avatar.url : undefined, - deleted: answerObj.author.isDeleted, - url: `${this.getBaseURL(language.toLowerCase() as LanguageList)}/app/profile/${answerObj.author.databaseId}`, - description: answerObj.author.description, - bestAnswersCount: answerObj.author.bestAnswersCount, - points: answerObj.author.points, - helpedUsersCount: answerObj.author.helpedUsersCount, - receivedThanks: answerObj.author.receivedThanks, - rank: answerObj.author.rank.name - } : undefined - })); + const answers: Answer[] = obj.node.answers.nodes.map(answerObj => ({ + content: Util.clearContent(answerObj.content), + attachments: answerObj.attachments.map(attach => attach.url), + rates: answerObj.ratesCount, + rating: answerObj.rating, + isBest: answerObj.isBest, + created: answerObj.created, + author: answerObj.author ? { + id: answerObj.author.databaseId, + username: answerObj.author.nick, + gender: answerObj.author.gender, + avatar_url: answerObj.author.avatar ? answerObj.author.avatar.url : undefined, + deleted: answerObj.author.isDeleted, + url: `${this.getBaseURL(language.toLowerCase() as LanguageList)}/app/profile/${answerObj.author.databaseId}`, + description: answerObj.author.description, + bestAnswersCount: answerObj.author.bestAnswersCount, + points: answerObj.author.points, + helpedUsersCount: answerObj.author.helpedUsersCount, + receivedThanks: answerObj.author.receivedThanks, + rank: answerObj.author.rank ? answerObj.author.rank.name : "-" + } : undefined + })); - return { - question, answers - } - }); + return { + question, answers + } + }); - return objects; + return objects; + } catch (err) { + throw new BrainlyError(JSON.stringify(err)); + } } private getRequestBody(question: string, length = 10) { diff --git a/src/tests/index.test.ts b/src/tests/index.test.ts index 6543c76..d2d9b58 100644 --- a/src/tests/index.test.ts +++ b/src/tests/index.test.ts @@ -1,8 +1,8 @@ import Brainly from "../../index"; it("should return information about question and answer", (done) => { - const brain = new Brainly("id"); - brain.search("ru", "Pythagoras").then((results) => { + const brain = new Brainly("hi"); + brain.search("us", "Pythagoras").then((results) => { console.log(results[0].question) expect(results).toBeDefined(); done(); diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..ea53628 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,102 @@ +export type CountryList = "id" | "es" | "ru" | "ro" | "pt" | "tr" | "ph" | "pl" | "hi"; +export type BaseURLObject = Record; +export type Attachments = string[]; + +export interface Question { + id: number; + content: string; + author?: Author; + attachments: Attachments; + url: string; + created: string; + points: { + points: number; + forBest: number; + } + grade: string; + education: string; + can_be_answered: boolean; +} + +export interface Author { + id: number; + url: string; + username: string; + avatar_url?: string; + deleted: boolean; + rank: string; + description: string; + gender: string; + points: number; + receivedThanks: number; + bestAnswersCount: number; + helpedUsersCount: number; +} + +export interface Answer { + content: string; + attachments: Attachments; + rates: number; + rating: number; + author?: Author; + isBest: boolean; + created: string; +} + +export interface BrainlyResponse { + highlight: { + contentFragments: string[]; + } + node: { + id: string; + created: string; + databaseId: number; + content: string; + points: number; + pointsForBestAnswer: number; + author: { + avatar: { + url: string; + } | null; + databaseId: number; + id: string; + isDeleted: boolean; + nick: string; + rank: { + name: string; + }; + description: string; + points: number; + receivedThanks: number; + bestAnswersCount: number; + helpedUsersCount: number; + gender: string; + } + canBeAnswered: boolean; + grade: { + name: string; + slug: string; + } + subject: { + name: string; + slug: string; + } + answers: { + hasVerified: boolean; + nodes: { + ratesCount: number; + rating: number; + thanksCount: number; + content: string; + attachments: { url: string; }[]; + author: BrainlyResponse["node"]["author"]; + isBest: boolean; + points: number; + created: string; + }[]; + } + attachments: { url: string; }[]; + } +} + +export type LanguageList = CountryList | "us"; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 70765e8..5cf76b1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,13 +3,19 @@ "allowJs": true, "strict": true, "outDir": "./dist", - "target": "ESNext", + "target": "ES2017", "module": "CommonJS", "declaration": true, "esModuleInterop": true, "pretty": true, - "skipLibCheck": true + "skipLibCheck": true, + "typeRoots": [ + "./node_modules/@types", + "./src/types" + ], + "baseUrl": "./src", + "resolveJsonModule": true }, - "exclude": ["node_modules"], - "include": ["src/**/*", "tests/**/*"] + "exclude": ["node_modules", "dist"], + "include": ["src/**/*.ts", "tests/**/*"] } \ No newline at end of file