├── .gitignore ├── .env.example ├── src ├── models │ ├── index.ts │ └── anime.ts ├── types │ └── global.d.ts ├── helpers │ ├── index.ts │ ├── connect-db.ts │ ├── get-collection.ts │ └── parser.ts ├── utils │ └── utils.ts ├── resolvers │ ├── validate-db.ts │ └── validate-gogoanime.ts ├── refresh.ts └── main.ts ├── package.json ├── README.md ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | yarn-error.log -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # database name where you want to store your collection data 2 | DB_NAME= 3 | # mongodb uri 4 | MONGO_URI= -------------------------------------------------------------------------------- /src/models/index.ts: -------------------------------------------------------------------------------- 1 | import { GogoEpisode, Gogoanime, GogoanimeRecent, SubOrDub, Types } from "./anime"; 2 | 3 | export { GogoEpisode, Gogoanime, GogoanimeRecent, SubOrDub, Types }; 4 | -------------------------------------------------------------------------------- /src/types/global.d.ts: -------------------------------------------------------------------------------- 1 | import { MongoClient } from "mongodb"; 2 | 3 | declare global { 4 | var config: { 5 | animesAdded: number; 6 | animesUpdated: number; 7 | }; 8 | } 9 | 10 | export default global; 11 | -------------------------------------------------------------------------------- /src/helpers/index.ts: -------------------------------------------------------------------------------- 1 | import { scrapeAnimeDetails, BASE_URL, scrapeRecentRelease, recent_release_url } from "./parser"; 2 | import { connectToDB } from "./connect-db"; 3 | import { getCollection } from "./get-collection"; 4 | 5 | export { scrapeAnimeDetails, connectToDB, getCollection, BASE_URL, scrapeRecentRelease, recent_release_url }; 6 | -------------------------------------------------------------------------------- /src/helpers/connect-db.ts: -------------------------------------------------------------------------------- 1 | import { MongoClient } from "mongodb"; 2 | 3 | import { colors, logger } from "../utils/utils"; 4 | 5 | /** 6 | * @param {MongoClient} client - MongoClient object 7 | * @returns Promise - resolves when database is connected 8 | */ 9 | export const connectToDB = async (client: MongoClient): Promise => { 10 | logger.info("\nConnecting to database...", colors.blue); 11 | try { 12 | await client.connect(); 13 | logger.info("Database connected.", colors.green); 14 | } catch (err) { 15 | throw new Error("Could not connect to database."); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gogoanimev2", 3 | "version": "1.0.0", 4 | "description": "Crawler for gogoanime. Populate your database using gogoanime", 5 | "main": "src/main.ts", 6 | "scripts": { 7 | "populate": "ts-node src/main.ts", 8 | "refresh": "ts-node src/refresh.ts", 9 | "crawl": "npm run populate && npm run refresh" 10 | }, 11 | "keywords": ["crawler", "gogoanime", "gogoanime crawler"], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "@types/node": "^17.0.36", 16 | "axios": "^0.27.2", 17 | "cheerio": "^1.0.0-rc.11", 18 | "mongodb": "^4.6.0" 19 | }, 20 | "devDependencies": { 21 | "dotenv": "^16.0.1" 22 | } 23 | } -------------------------------------------------------------------------------- /src/helpers/get-collection.ts: -------------------------------------------------------------------------------- 1 | import { MongoClient, Collection, Document } from "mongodb"; 2 | 3 | /** 4 | * 5 | * @description Gets a collection from the database and returns it. 6 | * @param {MongoClient} client MongoDB client 7 | * @param {String} dbName Database name 8 | * @param {String} collectionName Collection name 9 | * @returns {Document} MongoDB collection 10 | * @throws {Error} If database doesn't exist 11 | */ 12 | export const getCollection = ( 13 | client: MongoClient, 14 | dbName: string, 15 | collectionName: string 16 | ): Collection | undefined => { 17 | try { 18 | return client.db(dbName).collection(collectionName); 19 | } catch (err) { 20 | throw new Error((err as Error).message); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /src/models/anime.ts: -------------------------------------------------------------------------------- 1 | export interface GogoEpisode { 2 | id: string; 3 | number: number; 4 | url?: string; 5 | } 6 | 7 | export interface Gogoanime { 8 | id: string; 9 | title: string; 10 | url: string; 11 | type?: string; 12 | subOrDub?: SubOrDub; 13 | image?: string; 14 | status?: string; 15 | releasedDate?: number; 16 | genres?: string[]; 17 | otherNames?: string[] | string; 18 | description?: string; 19 | totalEpisodes?: number; 20 | episodes?: GogoEpisode[]; 21 | [x: string]: unknown; 22 | } 23 | 24 | export interface GogoanimeRecent { 25 | episodeId?: string; 26 | animeTitle?: string; 27 | episodeNum?: number | string; 28 | subOrDub?: string; 29 | animeImg?: string; 30 | episodeUrl?: string; 31 | } 32 | 33 | export enum SubOrDub { 34 | SUB = "sub", 35 | DUB = "dub", 36 | } 37 | 38 | export enum Types { 39 | SUB = 1, 40 | DUB = 2, 41 | CHINESE = 3, 42 | } 43 | -------------------------------------------------------------------------------- /src/utils/utils.ts: -------------------------------------------------------------------------------- 1 | export const colors = { 2 | reset: "\x1b[0m", 3 | 4 | //text color 5 | 6 | black: "\x1b[30m", 7 | red: "\x1b[31m", 8 | green: "\x1b[32m", 9 | yellow: "\x1b[33m", 10 | blue: "\x1b[34m", 11 | magenta: "\x1b[35m", 12 | cyan: "\x1b[36m", 13 | white: "\x1b[37m", 14 | 15 | //background color 16 | 17 | blackBg: "\x1b[40m", 18 | redBg: "\x1b[41m", 19 | greenBg: "\x1b[42m", 20 | yellowBg: "\x1b[43m", 21 | blueBg: "\x1b[44m", 22 | magentaBg: "\x1b[45m", 23 | cyanBg: "\x1b[46m", 24 | whiteBg: "\x1b[47m", 25 | }; 26 | 27 | export const logger = { 28 | info: (message: any, color: string = colors.white) => { 29 | console.log(`${color}${message}${colors.reset}`); 30 | }, 31 | 32 | warn: (message: any) => { 33 | console.log(`${colors.yellow}Warning: ${message}${colors.reset}`); 34 | }, 35 | 36 | error: (message: any) => { 37 | console.log(`${colors.red}Error: ${message}${colors.reset}`); 38 | }, 39 | }; 40 | 41 | export const animelistSuffixes = [".html"]; 42 | -------------------------------------------------------------------------------- /src/resolvers/validate-db.ts: -------------------------------------------------------------------------------- 1 | import { MongoClient, CreateCollectionOptions } from "mongodb"; 2 | 3 | import { logger, colors } from "../utils/utils"; 4 | 5 | /** 6 | * @description checks if collection exists in database and creates it if it doesn't exist. 7 | * @param client - MongoClient 8 | * @param db - database name 9 | * @param options - collection options (optional) 10 | * @returns Promise - resolves when collection is created or exists 11 | */ 12 | export const validateDB = async ( 13 | client: MongoClient, 14 | db: string, 15 | options?: CreateCollectionOptions | undefined 16 | ): Promise => { 17 | logger.info("\nValidating database collections...", colors.blue); 18 | 19 | try { 20 | const collections = await client.db(db).listCollections().toArray(); 21 | 22 | for (const coll of ["gogoanime"]) { 23 | if (!collections.find((collection) => collection.name === coll)) { 24 | logger.warn(`Collection ${coll} doesn't exist.`); 25 | await client.db(db).createCollection(coll, options); 26 | logger.info(`Collection ${coll} created.\n`, colors.green); 27 | } 28 | } 29 | logger.info("Database collections validated.", colors.green); 30 | } catch (err) { 31 | throw new Error(`${(err as Error).message}`); 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/resolvers/validate-gogoanime.ts: -------------------------------------------------------------------------------- 1 | import { Collection } from "mongodb"; 2 | 3 | import { Gogoanime } from "../models"; 4 | import { logger } from "../utils/utils"; 5 | import { scrapeAnimeDetails } from "../helpers/parser"; 6 | 7 | export const validateGogoanime = async ( 8 | animeId: string, 9 | gogoanimeColl: Collection 10 | ): Promise => { 11 | try { 12 | const animeDetails = await scrapeAnimeDetails(animeId); 13 | 14 | if (!animeDetails) return false; 15 | 16 | const anime = await gogoanimeColl.findOne({ id: animeId }, { projection: { _id: 1 } }); 17 | let gogoanimeDbId = null; 18 | 19 | if (anime) { 20 | logger.info(`Updating [${animeDetails.title} - ${animeDetails.subOrDub}]...`); 21 | gogoanimeDbId = anime._id; 22 | await gogoanimeColl.updateOne({ _id: gogoanimeDbId }, { $set: { ...animeDetails } }); 23 | global.config.animesUpdated++; 24 | } else { 25 | logger.info(`Inserting [${animeDetails.title} - ${animeDetails.subOrDub}]...`); 26 | gogoanimeDbId = (await gogoanimeColl.insertOne({ ...animeDetails })).insertedId; 27 | global.config.animesAdded++; 28 | } 29 | return true; 30 | } catch (err) { 31 | throw new Error((err as Error).message); 32 | } 33 | }; 34 | 35 | export const validateGogoanimeV2 = async ( 36 | gogoanime: Gogoanime, 37 | gogoanimeColl: Collection 38 | ): Promise => { 39 | try { 40 | if (!gogoanime) return false; 41 | 42 | const anime = await gogoanimeColl.findOne({ id: gogoanime.id }, { projection: { _id: 1 } }); 43 | let gogoanimeDbId = null; 44 | 45 | if (anime) { 46 | logger.info(`Updating [${gogoanime.title} - ${gogoanime.subOrDub}]...`); 47 | gogoanimeDbId = anime._id; 48 | await gogoanimeColl.updateOne({ _id: gogoanimeDbId }, { $set: { ...gogoanime } }); 49 | global.config.animesUpdated++; 50 | } else { 51 | logger.info(`Inserting [${gogoanime.title} - ${gogoanime.subOrDub}]...`); 52 | gogoanimeDbId = (await gogoanimeColl.insertOne({ ...gogoanime })).insertedId; 53 | global.config.animesAdded++; 54 | } 55 | 56 | return true; 57 | } catch (err) { 58 | throw new Error((err as Error).message); 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Anime Crawler 2 | 3 | ##### [Anime Crawler](#anime-crawler) can help you populate your anime *mongodb database* using [gogoanime](https://gogoanime.gg/) data in just few hours. It can also help you to keep your anime database up-to-date with new releases. 4 | 5 | ## Guide 6 | - [Getting Started](#getting-started) 7 | - [How to use](#how-to-use) 8 | - [Populate and Refresh](#populate-and-refresh) 9 | - [Populate *Only*](#populate-only) 10 | - [Refresh *Only*](#refresh-only) 11 | - [Notes](#notes) 12 | 13 | ### Getting Started 14 | 15 | ```bash 16 | git clone https://github.com/riimuru/gogoanime-crawler.git 17 | cd gogoanime-crawler 18 | yarn install # or npm install 19 | ``` 20 | 21 | Create a `.env` file in the root directory of the project. 22 | ``` 23 | DB_NAME= # Mongodb Database name 24 | MONGO_URI= # Mongodb URI 25 | ``` 26 | Check out [How to create a new mongodb cluster](https://www.mongodb.com/docs/atlas/tutorial/create-new-cluster/) to get the mongodb URI and the database name. 27 | 28 | install ts-node and typescript in your machine: 29 | ```bash 30 | yarn global add ts-node # or npm install -g ts-node 31 | yarn global add typescript # or npm install -g typescript 32 | ``` 33 | 34 | ### How to use 35 | 36 | - [Populate and Refresh](#populate-and-refresh) 37 | - [Populate *Only*](#populate-only) 38 | - [Refresh *Only*](#refresh-only) 39 | 40 | #### Populate and Refresh 41 | 42 | If you want to populate your anime database, and keep it up-to-date with new releases, you can use the following command: 43 | 44 | ```bash 45 | yarn crawl # or npm run crawl 46 | ``` 47 | 48 | #### Populate Only 49 | If you want to populate your anime database, but don't want to keep it up-to-date with new releases, you can use the following command: 50 | 51 | ```bash 52 | yarn populate # or npm run populate 53 | ``` 54 | #### Refresh Only 55 | if you want to add new releases, but don't want to populate your anime database, you can use the following command: 56 | ```bash 57 | yarn refresh # or npm run refresh 58 | ``` 59 | 60 | ### Notes 61 | The crawler will validate the environment variables and the database connection. If everything is fine, it will start crawling. 62 | 63 | if everything is fine, your terminal will show the following: 64 | 65 | ``` 66 | Checking enviroment variables... 67 | Enviroment variables checked. 68 | 69 | Connecting to database... 70 | Database connected. 71 | 72 | Validating database collections... 73 | Database collections validated. 74 | 75 | Starting crawler... 76 | 77 | Scraping anime-list.html page = 1... 78 | Updating [.Hack//G.U. Returner - sub]... 79 | Updating [.hack//G.U. Trilogy - sub]... 80 | ... 81 | ``` 82 | 83 | **I recommend you to use the `yarn crawl` or `npm run crawl` even if you already have your database populated.** 84 | 85 | **if you want to stop the crawler, you can use `ctrl + c` on the terminal.** 86 | 87 | **NOTE: if you stop the crawler and want to start it again, it will start from the first page again, But it will not re-add the anime that already exist in the database.** 88 | 89 | The crawler will stop when it reaches the last page of the anime-list.html page. it will take approximately 2 hours to crawl all of gogoanime. Then it will start the refresh process to the database up-to-date. 90 | 91 | -------------------------------------------------------------------------------- /src/refresh.ts: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | 3 | import { load } from "cheerio"; 4 | import axios from "axios"; 5 | import { Collection, MongoClient, MongoClientOptions } from "mongodb"; 6 | 7 | import { logger, colors } from "./utils/utils"; 8 | import { scrapeRecentRelease, recent_release_url, getCollection, connectToDB } from "./helpers"; 9 | import { Types, Gogoanime } from "./models"; 10 | import { validateGogoanimeV2 } from "./resolvers/validate-gogoanime"; 11 | 12 | let mongoClient: MongoClient; 13 | let gogoanimeColl: Collection; 14 | 15 | let startTime: number, endTime: number; 16 | global.config = { 17 | animesAdded: 0, 18 | animesUpdated: 0, 19 | }; 20 | 21 | const startRefresh = async () => { 22 | logger.info(`\nStarting refreshing crawler... PID:${process.pid}`, colors.blue); 23 | 24 | gogoanimeColl = getCollection(mongoClient, process.env.DB_NAME!, "gogoanime")!; 25 | 26 | try { 27 | for (const type of [Types.SUB, Types.DUB, Types.CHINESE]) { 28 | let page = 1; 29 | 30 | await handlePages(type, page); 31 | 32 | logger.info(`\nFinished scraping type ${type}...`, colors.green); 33 | } 34 | 35 | logger.info( 36 | `\nFinished refreshing process. PID:${process.pid}, will start refreshing again right now.`, 37 | colors.green 38 | ); 39 | } catch (err) { 40 | throw new Error((err as Error).message); 41 | } 42 | }; 43 | 44 | const handlePages = async (type: number, page: number) => { 45 | const url = `${recent_release_url}?page=${page}&type=${type}`; 46 | 47 | logger.info(`\nScraping type ${type}, page ${page}...`, colors.blue); 48 | 49 | const html = await axios.get(url); 50 | const $ = load(html.data); 51 | 52 | const hasNextPage = page < 10; 53 | 54 | const animeList = (await scrapeRecentRelease($))!; 55 | 56 | for (const anime of animeList) { 57 | if (!(await validateGogoanimeV2(anime, gogoanimeColl))) { 58 | logger.error(`\nCould not validate animeId = ${anime.id}\n`); 59 | } 60 | } 61 | endTime = performance.now(); 62 | logger.info( 63 | `type ${type} page = ${page} refreshed. ${global.config.animesAdded} anime(s) added, ${ 64 | global.config.animesUpdated 65 | } anime(s) updated. ${((endTime - startTime) / 1000 / 60).toFixed(3)} minutes elapsed.`, 66 | colors.green 67 | ); 68 | 69 | if (hasNextPage) { 70 | await handlePages(type, page + 1); 71 | } 72 | }; 73 | 74 | const validateEnviromentVariables = () => { 75 | logger.info("Checking enviroment variables...", colors.blue); 76 | if (!process.env.MONGO_URI || !process.env.DB_NAME) { 77 | throw new Error( 78 | `${colors.red}Missing environment variables. Please check the README.md file for more information.${colors.reset}` 79 | ); 80 | } 81 | 82 | const mongoOptions: MongoClientOptions = { 83 | keepAlive: true, 84 | }; 85 | 86 | mongoClient = new MongoClient(process.env.MONGO_URI!, mongoOptions); 87 | 88 | logger.info("Enviroment variables checked.", colors.green); 89 | }; 90 | 91 | (async () => { 92 | logger.info(`\nStarting refreshing process...`, colors.blue); 93 | 94 | validateEnviromentVariables(); 95 | startTime = performance.now(); 96 | 97 | await connectToDB(mongoClient!); 98 | while (true) { 99 | await startRefresh(); 100 | } 101 | })(); 102 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | 3 | import { Collection, MongoClient, MongoClientOptions } from "mongodb"; 4 | import axios from "axios"; 5 | import { load } from "cheerio"; 6 | 7 | import { logger, colors, animelistSuffixes } from "./utils/utils"; 8 | import { BASE_URL, connectToDB, getCollection } from "./helpers/"; 9 | import { validateDB } from "./resolvers/validate-db"; 10 | import { validateGogoanime } from "./resolvers/validate-gogoanime"; 11 | import { Gogoanime } from "./models"; 12 | 13 | let mongoClient: MongoClient; 14 | 15 | // for testing purposes 16 | let startTime: number, endTime: number; 17 | global.config = { 18 | animesAdded: 0, 19 | animesUpdated: 0, 20 | }; 21 | 22 | const validateEnviromentVariables = () => { 23 | logger.info("Checking enviroment variables...", colors.blue); 24 | 25 | if (!process.env.MONGO_URI || !process.env.DB_NAME) { 26 | throw new Error( 27 | `${colors.red}Missing environment variables. Please check the README.md file for more information.${colors.reset}` 28 | ); 29 | } 30 | 31 | const mongoOptions: MongoClientOptions = { 32 | keepAlive: true, 33 | }; 34 | 35 | mongoClient = new MongoClient(process.env.MONGO_URI!, mongoOptions); 36 | 37 | logger.info("Enviroment variables checked.", colors.green); 38 | }; 39 | 40 | const startCrawler = async () => { 41 | logger.info(`\nStarting crawler... PID: ${process.pid}`, colors.blue); 42 | 43 | const gogoanimeColl = getCollection(mongoClient, process.env.DB_NAME!, "gogoanime")!; 44 | 45 | try { 46 | for (const suffix of animelistSuffixes) { 47 | // should be 1 always. unless you know what you're doing. 48 | let page = 1; 49 | 50 | await handlePages(suffix, page, gogoanimeColl); 51 | 52 | logger.info(`\nFinished scraping anime-list${suffix}...`, colors.green); 53 | } 54 | 55 | logger.info("\nFinished crawling.", colors.green); 56 | await mongoClient.close(); 57 | process.exit(0); 58 | } catch (err) { 59 | throw new Error(`${(err as Error).message}`); 60 | } 61 | }; 62 | 63 | const handlePages = async (suffix: string, page: number, gogoanimeColl: Collection): Promise => { 64 | const url = `${BASE_URL}anime-list${suffix}?page=${page}`; 65 | 66 | logger.info(`\nScraping anime-list${suffix} page = ${page}...`, colors.blue); 67 | 68 | const html = await axios.get(url); 69 | const $ = load(html.data); 70 | 71 | const hasNextPage = $("div.anime_name.anime_list > div > div > ul > li.selected").next().length > 0; 72 | 73 | const animeList = $("section.content_left > div > div.anime_list_body > ul").children(); 74 | 75 | for (const anime of animeList) { 76 | const animeId = $(anime).find("a").attr("href")?.split("/")[2]; 77 | 78 | if (animeId) { 79 | if (!(await validateGogoanime(animeId, gogoanimeColl))) { 80 | logger.error(`Could not validate animeId = ${animeId}`); 81 | } 82 | } 83 | } 84 | 85 | endTime = performance.now(); 86 | logger.info( 87 | `Anime-list page = ${page} scraped. ${global.config.animesAdded} anime(s) added, ${ 88 | global.config.animesUpdated 89 | } anime(s) updated. ${((endTime - startTime) / 1000 / 60).toFixed(3)} minutes elapsed.`, 90 | colors.green 91 | ); 92 | 93 | if (hasNextPage) { 94 | await handlePages(suffix, page + 1, gogoanimeColl); 95 | } 96 | }; 97 | 98 | (async () => { 99 | validateEnviromentVariables(); 100 | 101 | await connectToDB(mongoClient!); 102 | await validateDB(mongoClient!, process.env.DB_NAME!); 103 | 104 | startTime = performance.now(); 105 | await startCrawler(); 106 | })(); 107 | -------------------------------------------------------------------------------- /src/helpers/parser.ts: -------------------------------------------------------------------------------- 1 | import { load, CheerioAPI } from "cheerio"; 2 | import axios from "axios"; 3 | 4 | import { Gogoanime, GogoEpisode, SubOrDub } from "../models"; 5 | 6 | export const BASE_URL = "https://gogoanime.gg/"; 7 | const ajax_url = "https://ajax.gogo-load.com/"; 8 | const list_episodes_url = `${ajax_url}ajax/load-list-episode`; 9 | export const recent_release_url = `${ajax_url}ajax/page-recent-release.html`; 10 | 11 | /** 12 | * @param {string} id anime id. 13 | * @returns Resolves when the scraping is complete. 14 | * @example 15 | * scrapeGoGoAnimeInfo({id: "naruto"}) 16 | * .then((res) => console.log(res)) // => The anime information is returned in an Object. 17 | * .catch((err) => console.log(err)) 18 | * 19 | */ 20 | export const scrapeAnimeDetails = async (id: string): Promise => { 21 | try { 22 | const genres: string[] = []; 23 | const epList: GogoEpisode[] = []; 24 | 25 | const animePageTest = await axios.get(`${BASE_URL}category/${id}`); 26 | 27 | const $ = load(animePageTest.data); 28 | 29 | const animeTitle = $("div.anime_info_body_bg > h1").text().trim(); 30 | const animeImage = $("div.anime_info_body_bg > img").attr("src"); 31 | const type = $("div.anime_info_body_bg > p:nth-child(4) > a").text().trim(); 32 | const desc = $("div.anime_info_body_bg > p:nth-child(5)").text().replace("Plot Summary: ", "").trim(); 33 | const releasedDate = parseInt( 34 | $("div.anime_info_body_bg > p:nth-child(7)").text().replace("Released: ", "").trim() 35 | ); 36 | const status = $("div.anime_info_body_bg > p:nth-child(8) > a").text().trim(); 37 | const otherName = $("div.anime_info_body_bg > p:nth-child(9)") 38 | .text() 39 | .replace("Other name: ", "") 40 | .replace(/;/g, ",") 41 | .split(",") 42 | .map((name) => name.trim()); 43 | 44 | $("div.anime_info_body_bg > p:nth-child(6) > a").each((i, elem) => { 45 | genres.push($(elem).attr("title")!.trim()); 46 | }); 47 | 48 | let subOrDub: SubOrDub = SubOrDub.SUB; 49 | 50 | if (animeTitle.toLowerCase().includes("(dub)")) { 51 | subOrDub = SubOrDub.DUB; 52 | } 53 | 54 | const ep_start = $("#episode_page > li").first().find("a").attr("ep_start"); 55 | const ep_end = parseInt($("#episode_page > li").last().find("a").attr("ep_end") ?? "0"); 56 | const movie_id = $("#movie_id").attr("value"); 57 | const alias = $("#alias_anime").attr("value"); 58 | 59 | const html = await axios.get( 60 | `${list_episodes_url}?ep_start=${ep_start}&ep_end=${ep_end}&id=${movie_id}&default_ep=${0}&alias=${alias}` 61 | ); 62 | const $$ = load(html.data); 63 | 64 | $$("#episode_related > li").each((i, el) => { 65 | epList.push({ 66 | id: $(el).find("a").attr("href")?.split("/")[1]!, 67 | number: parseInt($(el).find(`div.name`).text().replace("EP ", "")), 68 | url: `${BASE_URL}${$(el).find(`a`).attr("href")?.trim()}`, 69 | }); 70 | }); 71 | 72 | return { 73 | id: id, 74 | url: `${BASE_URL}category/${id}`, 75 | title: animeTitle, 76 | subOrDub: subOrDub, 77 | type: type, 78 | genres: genres, 79 | releasedDate: releasedDate, 80 | status: status, 81 | otherNames: otherName, 82 | description: desc, 83 | image: animeImage, 84 | totalEpisodes: ep_end, 85 | episodes: epList, 86 | }; 87 | } catch (err) { 88 | throw (err as Error).message; 89 | } 90 | }; 91 | 92 | export const scrapeRecentRelease = async ($: CheerioAPI): Promise => { 93 | const list: Gogoanime[] = []; 94 | try { 95 | const items = $("div.last_episodes.loaddub > ul").children(); 96 | for (const anime of items) { 97 | let id = $(anime).find("a").attr("href")?.split("/")[1].split("-episode")[0]!; 98 | if (id == "tate-no-yuusha-no-nariagari-season-2") { 99 | id = "tate-no-yuusha-no-nariagari-2nd-season"; 100 | } 101 | const animeDetails = await scrapeAnimeDetails(id); 102 | 103 | if (animeDetails) { 104 | list.push(animeDetails); 105 | } 106 | } 107 | 108 | return list; 109 | } catch (err) { 110 | console.log(err); 111 | return []; 112 | } 113 | }; 114 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ 22 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | 26 | /* Modules */ 27 | "module": "commonjs" /* Specify what module code is generated. */, 28 | // "rootDir": "./", /* Specify the root folder within your source files. */ 29 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 30 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 31 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 32 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 33 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ 34 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 35 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 36 | // "resolveJsonModule": true, /* Enable importing .json files */ 37 | // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ 38 | 39 | /* JavaScript Support */ 40 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ 41 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 42 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ 43 | 44 | /* Emit */ 45 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 46 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 47 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 48 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 49 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ 50 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 51 | // "removeComments": true, /* Disable emitting comments. */ 52 | // "noEmit": true, /* Disable emitting files from a compilation. */ 53 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 54 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ 55 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 56 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 59 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 60 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 61 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 62 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ 63 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ 64 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 65 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ 66 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 67 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 68 | 69 | /* Interop Constraints */ 70 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 71 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 72 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, 73 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 74 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 75 | 76 | /* Type Checking */ 77 | "strict": true /* Enable all strict type-checking options. */, 78 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ 79 | // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ 80 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 81 | // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ 82 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 83 | // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ 84 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ 85 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 86 | // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ 87 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ 88 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 89 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 90 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 91 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 92 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 93 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ 94 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 95 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 96 | 97 | /* Completeness */ 98 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 99 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 100 | }, 101 | "ts-node": { 102 | "files": true 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/node@*", "@types/node@^17.0.36": 6 | version "17.0.36" 7 | resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.36.tgz#c0d5f2fe76b47b63e0e0efc3d2049a9970d68794" 8 | integrity sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA== 9 | 10 | "@types/webidl-conversions@*": 11 | version "6.1.1" 12 | resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz#e33bc8ea812a01f63f90481c666334844b12a09e" 13 | integrity sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q== 14 | 15 | "@types/whatwg-url@^8.2.1": 16 | version "8.2.1" 17 | resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-8.2.1.tgz#f1aac222dab7c59e011663a0cb0a3117b2ef05d4" 18 | integrity sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ== 19 | dependencies: 20 | "@types/node" "*" 21 | "@types/webidl-conversions" "*" 22 | 23 | asynckit@^0.4.0: 24 | version "0.4.0" 25 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 26 | integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== 27 | 28 | axios@^0.27.2: 29 | version "0.27.2" 30 | resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" 31 | integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== 32 | dependencies: 33 | follow-redirects "^1.14.9" 34 | form-data "^4.0.0" 35 | 36 | base64-js@^1.3.1: 37 | version "1.5.1" 38 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" 39 | integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== 40 | 41 | boolbase@^1.0.0: 42 | version "1.0.0" 43 | resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" 44 | integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== 45 | 46 | bson@^4.6.3: 47 | version "4.6.4" 48 | resolved "https://registry.yarnpkg.com/bson/-/bson-4.6.4.tgz#e66d4a334f1ab230dfcfb9ec4ea9091476dd372e" 49 | integrity sha512-TdQ3FzguAu5HKPPlr0kYQCyrYUYh8tFM+CMTpxjNzVzxeiJY00Rtuj3LXLHSgiGvmaWlZ8PE+4KyM2thqE38pQ== 50 | dependencies: 51 | buffer "^5.6.0" 52 | 53 | buffer@^5.6.0: 54 | version "5.7.1" 55 | resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" 56 | integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== 57 | dependencies: 58 | base64-js "^1.3.1" 59 | ieee754 "^1.1.13" 60 | 61 | cheerio-select@^2.1.0: 62 | version "2.1.0" 63 | resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-2.1.0.tgz#4d8673286b8126ca2a8e42740d5e3c4884ae21b4" 64 | integrity sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g== 65 | dependencies: 66 | boolbase "^1.0.0" 67 | css-select "^5.1.0" 68 | css-what "^6.1.0" 69 | domelementtype "^2.3.0" 70 | domhandler "^5.0.3" 71 | domutils "^3.0.1" 72 | 73 | cheerio@^1.0.0-rc.11: 74 | version "1.0.0-rc.11" 75 | resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.11.tgz#1be84be1a126958366bcc57a11648cd9b30a60c2" 76 | integrity sha512-bQwNaDIBKID5ts/DsdhxrjqFXYfLw4ste+wMKqWA8DyKcS4qwsPP4Bk8ZNaTJjvpiX/qW3BT4sU7d6Bh5i+dag== 77 | dependencies: 78 | cheerio-select "^2.1.0" 79 | dom-serializer "^2.0.0" 80 | domhandler "^5.0.3" 81 | domutils "^3.0.1" 82 | htmlparser2 "^8.0.1" 83 | parse5 "^7.0.0" 84 | parse5-htmlparser2-tree-adapter "^7.0.0" 85 | tslib "^2.4.0" 86 | 87 | combined-stream@^1.0.8: 88 | version "1.0.8" 89 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" 90 | integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== 91 | dependencies: 92 | delayed-stream "~1.0.0" 93 | 94 | css-select@^5.1.0: 95 | version "5.1.0" 96 | resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6" 97 | integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg== 98 | dependencies: 99 | boolbase "^1.0.0" 100 | css-what "^6.1.0" 101 | domhandler "^5.0.2" 102 | domutils "^3.0.1" 103 | nth-check "^2.0.1" 104 | 105 | css-what@^6.1.0: 106 | version "6.1.0" 107 | resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" 108 | integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== 109 | 110 | delayed-stream@~1.0.0: 111 | version "1.0.0" 112 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 113 | integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== 114 | 115 | denque@^2.0.1: 116 | version "2.0.1" 117 | resolved "https://registry.yarnpkg.com/denque/-/denque-2.0.1.tgz#bcef4c1b80dc32efe97515744f21a4229ab8934a" 118 | integrity sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ== 119 | 120 | dom-serializer@^2.0.0: 121 | version "2.0.0" 122 | resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" 123 | integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== 124 | dependencies: 125 | domelementtype "^2.3.0" 126 | domhandler "^5.0.2" 127 | entities "^4.2.0" 128 | 129 | domelementtype@^2.3.0: 130 | version "2.3.0" 131 | resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" 132 | integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== 133 | 134 | domhandler@^5.0.1, domhandler@^5.0.2, domhandler@^5.0.3: 135 | version "5.0.3" 136 | resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" 137 | integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== 138 | dependencies: 139 | domelementtype "^2.3.0" 140 | 141 | domutils@^3.0.1: 142 | version "3.0.1" 143 | resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.0.1.tgz#696b3875238338cb186b6c0612bd4901c89a4f1c" 144 | integrity sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q== 145 | dependencies: 146 | dom-serializer "^2.0.0" 147 | domelementtype "^2.3.0" 148 | domhandler "^5.0.1" 149 | 150 | dotenv@^16.0.1: 151 | version "16.0.1" 152 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d" 153 | integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ== 154 | 155 | entities@^4.2.0, entities@^4.3.0: 156 | version "4.3.0" 157 | resolved "https://registry.yarnpkg.com/entities/-/entities-4.3.0.tgz#62915f08d67353bb4eb67e3d62641a4059aec656" 158 | integrity sha512-/iP1rZrSEJ0DTlPiX+jbzlA3eVkY/e8L8SozroF395fIqE3TYF/Nz7YOMAawta+vLmyJ/hkGNNPcSbMADCCXbg== 159 | 160 | follow-redirects@^1.14.9: 161 | version "1.15.1" 162 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" 163 | integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== 164 | 165 | form-data@^4.0.0: 166 | version "4.0.0" 167 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" 168 | integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== 169 | dependencies: 170 | asynckit "^0.4.0" 171 | combined-stream "^1.0.8" 172 | mime-types "^2.1.12" 173 | 174 | htmlparser2@^8.0.1: 175 | version "8.0.1" 176 | resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.1.tgz#abaa985474fcefe269bc761a779b544d7196d010" 177 | integrity sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA== 178 | dependencies: 179 | domelementtype "^2.3.0" 180 | domhandler "^5.0.2" 181 | domutils "^3.0.1" 182 | entities "^4.3.0" 183 | 184 | ieee754@^1.1.13: 185 | version "1.2.1" 186 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" 187 | integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== 188 | 189 | ip@^1.1.5: 190 | version "1.1.8" 191 | resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.8.tgz#ae05948f6b075435ed3307acce04629da8cdbf48" 192 | integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg== 193 | 194 | memory-pager@^1.0.2: 195 | version "1.5.0" 196 | resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" 197 | integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== 198 | 199 | mime-db@1.52.0: 200 | version "1.52.0" 201 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" 202 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== 203 | 204 | mime-types@^2.1.12: 205 | version "2.1.35" 206 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" 207 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== 208 | dependencies: 209 | mime-db "1.52.0" 210 | 211 | mongodb-connection-string-url@^2.5.2: 212 | version "2.5.2" 213 | resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz#f075c8d529e8d3916386018b8a396aed4f16e5ed" 214 | integrity sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA== 215 | dependencies: 216 | "@types/whatwg-url" "^8.2.1" 217 | whatwg-url "^11.0.0" 218 | 219 | mongodb@^4.6.0: 220 | version "4.6.0" 221 | resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.6.0.tgz#a69216da61f4cb1498d68cb396c52313fa39cef6" 222 | integrity sha512-1gsxVXmjFTPJ+CkMG9olE4bcVsyY8lBJN9m5B5vj+LZ7wkBqq3PO8RVmNX9GwCBOBz1KV0zM00vPviUearSv7A== 223 | dependencies: 224 | bson "^4.6.3" 225 | denque "^2.0.1" 226 | mongodb-connection-string-url "^2.5.2" 227 | socks "^2.6.2" 228 | optionalDependencies: 229 | saslprep "^1.0.3" 230 | 231 | nth-check@^2.0.1: 232 | version "2.1.1" 233 | resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" 234 | integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== 235 | dependencies: 236 | boolbase "^1.0.0" 237 | 238 | parse5-htmlparser2-tree-adapter@^7.0.0: 239 | version "7.0.0" 240 | resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz#23c2cc233bcf09bb7beba8b8a69d46b08c62c2f1" 241 | integrity sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g== 242 | dependencies: 243 | domhandler "^5.0.2" 244 | parse5 "^7.0.0" 245 | 246 | parse5@^7.0.0: 247 | version "7.0.0" 248 | resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.0.0.tgz#51f74a5257f5fcc536389e8c2d0b3802e1bfa91a" 249 | integrity sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g== 250 | dependencies: 251 | entities "^4.3.0" 252 | 253 | punycode@^2.1.1: 254 | version "2.1.1" 255 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 256 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== 257 | 258 | saslprep@^1.0.3: 259 | version "1.0.3" 260 | resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" 261 | integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== 262 | dependencies: 263 | sparse-bitfield "^3.0.3" 264 | 265 | smart-buffer@^4.2.0: 266 | version "4.2.0" 267 | resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" 268 | integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== 269 | 270 | socks@^2.6.2: 271 | version "2.6.2" 272 | resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.2.tgz#ec042d7960073d40d94268ff3bb727dc685f111a" 273 | integrity sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA== 274 | dependencies: 275 | ip "^1.1.5" 276 | smart-buffer "^4.2.0" 277 | 278 | sparse-bitfield@^3.0.3: 279 | version "3.0.3" 280 | resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" 281 | integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE= 282 | dependencies: 283 | memory-pager "^1.0.2" 284 | 285 | tr46@^3.0.0: 286 | version "3.0.0" 287 | resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" 288 | integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== 289 | dependencies: 290 | punycode "^2.1.1" 291 | 292 | tslib@^2.4.0: 293 | version "2.4.0" 294 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" 295 | integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== 296 | 297 | webidl-conversions@^7.0.0: 298 | version "7.0.0" 299 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" 300 | integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== 301 | 302 | whatwg-url@^11.0.0: 303 | version "11.0.0" 304 | resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" 305 | integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== 306 | dependencies: 307 | tr46 "^3.0.0" 308 | webidl-conversions "^7.0.0" 309 | --------------------------------------------------------------------------------