From 54e36a8232107a89120acba4c224387f902559ac Mon Sep 17 00:00:00 2001 From: Eltik Date: Tue, 29 Aug 2023 18:53:54 -0400 Subject: [PATCH] Bug fixes and optimizations --- anify-auth/.env.example | 25 ++++ anify-auth/src/env.ts | 5 +- anify-backend/.env.example | 5 - anify-backend/README.md | 8 +- anify-backend/package-lock.json | 9 -- anify-backend/package.json | 1 - anify-backend/src/database/index.ts | 35 ++--- anify-backend/src/database/meilisearch.ts | 64 --------- anify-backend/src/env.ts | 3 - .../src/mapping/impl/anime/bilibili.ts | 55 -------- .../src/mapping/impl/anime/nineanime.ts | 24 +++- anify-backend/src/mapping/index.ts | 3 +- anify-backend/src/scripts/buildDb.ts | 35 ++--- anify-backend/src/test.ts | 86 ------------- anify-backend/yarn.lock | 7 - anify-frontend/.env.example | 5 +- anify-frontend/src/env.mjs | 6 - anify-frontend/src/pages/api/search.tsx | 121 ++++-------------- 18 files changed, 99 insertions(+), 398 deletions(-) delete mode 100644 anify-backend/src/database/meilisearch.ts delete mode 100644 anify-backend/src/mapping/impl/anime/bilibili.ts delete mode 100644 anify-backend/src/test.ts diff --git a/anify-auth/.env.example b/anify-auth/.env.example index e69de29..be71c28 100644 --- a/anify-auth/.env.example +++ b/anify-auth/.env.example @@ -0,0 +1,25 @@ +# What port to listen to +PORT="3606" +# Public URL +PUBLIC_URL="http://localhost:3606" +FRONTEND_URL="http://localhost:3000" +# Backend URL +BACKEND_URL="http://localhost:3060" +# API Key +BACKEND_KEY="" +# SQLite database URL +DATABASE_URL="file:./db.sqlite" +# Redis URL +REDIS_URL="redis://localhost:6379" +# How long to cache redis data +REDIS_CACHE_TIME="18000" + +# Provider API information +ANILIST_CLIENT_ID="" +ANILIST_CLIENT_SECRET="" + +MAL_CLIENT_ID="" +MAL_CLIENT_SECRET="" + +SIMKL_CLIENT_ID="" +SIMKL_CLIENT_SECRET="" \ No newline at end of file diff --git a/anify-auth/src/env.ts b/anify-auth/src/env.ts index 610cef6..e4c55b3 100644 --- a/anify-auth/src/env.ts +++ b/anify-auth/src/env.ts @@ -6,10 +6,7 @@ export const env = { BACKEND_KEY: process.env.BACKEND_KEY ?? "", DATABASE_URL: process.env.DATABASE_URL, REDIS_URL: process.env.REDIS_URL, - REDIS_CACHE_TIME: Number(process.env.REDIS_CACHE_TIME) || 60 * 60 * 24 * 7, - USE_API_KEYS: process.env.USE_API_KEYS || "false", - MASTER_KEY: process.env.MASTER_KEY, - API_KEY_WHITELIST: process.env.API_KEY_WHITELIST?.split(",") || [], + REDIS_CACHE_TIME: Number(process.env.REDIS_CACHE_TIME) || 60 * 60 * 24 * 7 }; export const providerEnv = { diff --git a/anify-backend/.env.example b/anify-backend/.env.example index a1a7a47..a0a1c9c 100644 --- a/anify-backend/.env.example +++ b/anify-backend/.env.example @@ -4,11 +4,6 @@ PORT="3060" DATABASE_TYPE="postgres" # PostgreSQL database URL DATABASE_URL="postgresql://postgres:password@localhost:5432/?connection_limit=100" -# Whether to use Meilisearch -USE_MEILISEARCH="true" -# Meilisearch URL + Keys -MEILISEARCH_URL="http://localhost:7700" -MEILISEARCH_KEY="keylol" # 9anime resolver URL NINEANIME_RESOLVER="https://9anime.resolver.com" # 9anime resolver API key diff --git a/anify-backend/README.md b/anify-backend/README.md index 62fcd24..9d1ece3 100644 --- a/anify-backend/README.md +++ b/anify-backend/README.md @@ -4,14 +4,13 @@ Robust JavaScript API server for scraping anime, manga, and light novel sites. # Information ## Scraping -Anify scrapes numerous Japanese media sites from Zoro, to GogoAnime, to AnimePahe, and more. The API is built on top of [AniSync](https://github.com/Eltik/AniSync) to map AniList information accurately, allowing for multiple providers in case one ever goes down. To avoid rate limits, the API stores information in a database to ensure fast and accurate results. This is meant to be a robust web server, so there are a ton of features from Redis caching, PostgreSQL support, configurable `.env` options, etc. +Anify scrapes numerous Japanese media sites from Zoro, to MangaSee, to NovelUpdates, and more. The API is built on top of [AniSync](https://github.com/Eltik/AniSync) to map AniList information accurately, allowing for multiple providers in case one ever goes down. To avoid rate limits, the API stores information in a database to ensure fast and accurate results. This is meant to be a robust web server, so there are a ton of features from Redis caching, PostgreSQL support, configurable `.env` options, etc. ## Anime The API supports the following anime sites: - [x] [Zoro](https://aniwatch.to) - [x] [GogoAnime](https://www1.gogoanime.bid/) - [x] [AnimePahe](https://animepahe.com) - [x] [9anime](https://9anime.pl) -- [x] [AnimeFlix](https://animeflix.live) ## Manga The API supports the following manga sites: @@ -54,11 +53,6 @@ You can configure the web server via a `.env` file (not included). Default value PORT="3060" # PostgreSQL database URL DATABASE_URL="postgresql://postgres:password@localhost:5432/?connection_limit=100" -# Whether to use Meilisearch -USE_MEILISEARCH="true" -# Meilisearch URL + Keys -MEILISEARCH_URL="http://localhost:7700" -MEILISEARCH_KEY="keylol" # 9anime resolver URL NINEANIME_RESOLVER="https://9anime.resolver.com" # 9anime resolver API key diff --git a/anify-backend/package-lock.json b/anify-backend/package-lock.json index fb27caa..9bef6d3 100644 --- a/anify-backend/package-lock.json +++ b/anify-backend/package-lock.json @@ -26,7 +26,6 @@ "express-rate-limit": "^6.7.0", "form-data": "^4.0.0", "ioredis": "^5.3.2", - "meilisearch": "^0.33.0", "pdfkit": "^0.13.0", "probe-image-size": "^7.2.3", "rate-limit-redis": "^3.0.2" @@ -3958,14 +3957,6 @@ "node": ">= 0.6" } }, - "node_modules/meilisearch": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.33.0.tgz", - "integrity": "sha512-bYPb9WyITnJfzf92e7QFK8Rc50DmshFWxypXCs3ILlpNh8pT15A7KSu9Xgnnk/K3G/4vb3wkxxtFS4sxNkWB8w==", - "dependencies": { - "cross-fetch": "^3.1.6" - } - }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", diff --git a/anify-backend/package.json b/anify-backend/package.json index 838b6f3..5c94c29 100644 --- a/anify-backend/package.json +++ b/anify-backend/package.json @@ -77,7 +77,6 @@ "express-rate-limit": "^6.7.0", "form-data": "^4.0.0", "ioredis": "^5.3.2", - "meilisearch": "^0.33.0", "pdfkit": "^0.13.0", "probe-image-size": "^7.2.3", "rate-limit-redis": "^3.0.2" diff --git a/anify-backend/src/database/index.ts b/anify-backend/src/database/index.ts index fbbe475..e54d77f 100644 --- a/anify-backend/src/database/index.ts +++ b/anify-backend/src/database/index.ts @@ -1,13 +1,10 @@ import { randomUUID } from "crypto"; import { Anime, Format, Genres, Manga, Type } from "../mapping"; -import { prisma, search as searchPostgres, searchAdvanced as searchAdvancedPostgres, seasonal as seasonalPostgres, info as infoPostgres, media as mediaPostgres, recent } from "./postgresql"; -import { createMeiliEntry, initializeMeilisearch } from "./meilisearch"; -import { env } from "../env"; import cluster from "cluster"; +import { info, media, prisma, recent, search, searchAdvanced, seasonal as seasonalPostgres, } from "./postgresql"; export default class Database { private static type = "postgresql"; - private static useMeilisearch = env.USE_MEILISEARCH; static async initializeDatabase() { if (this.type === "postgresql") { @@ -20,15 +17,11 @@ export default class Database { $$;`; } } - - if (this.useMeilisearch && cluster.isPrimary) { - await initializeMeilisearch(); - } } static async search(query: string, type: Type, formats: Format[], page: number, perPage: number): Promise { if (this.type === "postgresql") { - return await searchPostgres(query, type, formats, page, perPage); + return await search(query, type, formats, page, perPage); } else { return []; } @@ -36,7 +29,7 @@ export default class Database { static async searchAdvanced(query: string, type: Type, formats: Format[], page: number, perPage: number, genres: Genres[] = [], genresExcluded: Genres[] = [], year = 0, tags: string[] = [], tagsExcluded: string[] = []): Promise { if (this.type === "postgresql") { - return await searchAdvancedPostgres(query, type.toUpperCase() as Type, formats, page, 40, genres as Genres[], genresExcluded as Genres[], year, tags, tagsExcluded); + return await searchAdvanced(query, type.toUpperCase() as Type, formats, page, 40, genres as Genres[], genresExcluded as Genres[], year, tags, tagsExcluded); } else { return []; } @@ -57,7 +50,7 @@ export default class Database { static async info(id: string): Promise { if (this.type === "postgresql") { - return (await infoPostgres(id)) as Anime | Manga; + return (await info(id)) as Anime | Manga; } else { return null; } @@ -65,7 +58,7 @@ export default class Database { static async media(providerId: string, id: string): Promise { if (this.type === "postgresql") { - return (await mediaPostgres(providerId, id)) as Anime | Manga; + return (await media(providerId, id)) as Anime | Manga; } else { return null; } @@ -125,17 +118,17 @@ export default class Database { static async delete(id: string): Promise { if (this.type === "postgresql") { - const info = await infoPostgres(id); - if (info?.type === Type.ANIME) { + const data = await info(id); + if (data?.type === Type.ANIME) { await prisma.anime.delete({ where: { - id: info?.id, + id: data?.id, }, }); } else { await prisma.manga.delete({ where: { - id: info?.id, + id: data?.id, }, }); } @@ -156,10 +149,6 @@ export default class Database { }); } } - - if (this.useMeilisearch) { - await createMeiliEntry(media); - } } static async createEntrys(media: Anime[] | Manga[]): Promise { @@ -176,12 +165,6 @@ export default class Database { }); } } - - if (this.useMeilisearch) { - for (const m of media) { - await createMeiliEntry(m); - } - } } static async findSkipTimes(id: string) { diff --git a/anify-backend/src/database/meilisearch.ts b/anify-backend/src/database/meilisearch.ts deleted file mode 100644 index 75c4ae1..0000000 --- a/anify-backend/src/database/meilisearch.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { MeiliSearch } from "meilisearch"; - -import colors from "colors"; -import { Anime, Manga, Season } from "../mapping"; -import { env } from "process"; - -const host = env.MEILISEARCH_URL ?? "http://localhost:7700"; -const key = env.MEILISEARCH_KEY ?? ""; - -const client = new MeiliSearch({ host: host, apiKey: key }); - -export const createMeiliEntry = async (media: Anime | Manga) => { - const exists = await info(media.id).catch(() => null); - if (!exists) { - await client.index(media.type.toLowerCase()).addDocuments( - [ - { - id: media.id, - title: media.title, - coverImage: media.coverImage, - bannerImage: media.bannerImage, - year: media.year ?? null, - description: media.description, - genres: media.genres, - tags: media.tags, - status: media.status, - season: (media as Anime).season ?? Season.UNKNOWN, - type: media.type, - format: media.format, - rating: media.rating, - popularity: media.popularity, - synonyms: media.synonyms, - color: media.color, - mappings: media.mappings, - artwork: media.artwork, - }, - ], - { primaryKey: "id" } - ); - } -}; - -const info = async (id: string) => { - return await client.index("anime").getDocument(id); -}; - -export const initializeMeilisearch = async () => { - const anime = await client.getIndex("anime").catch(() => null); - const manga = await client.getIndex("manga").catch(() => null); - - if (!anime) { - await client.createIndex("anime", { primaryKey: "id" }); - console.log(colors.green("Created Meilisearch index for anime.")); - } - if (!manga) { - await client.createIndex("manga", { primaryKey: "id" }); - console.log(colors.green("Created Meilisearch index for manga.")); - } - - await client.index("anime").updateFilterableAttributes(["format", "genres", "tags"]); - await client.index("manga").updateFilterableAttributes(["format", "genres", "tags"]); - await client.index("anime").updateSearchableAttributes(["title", "description", "synonyms"]); - await client.index("manga").updateSearchableAttributes(["title", "description", "synonyms"]); -}; diff --git a/anify-backend/src/env.ts b/anify-backend/src/env.ts index ea15b25..4a18604 100644 --- a/anify-backend/src/env.ts +++ b/anify-backend/src/env.ts @@ -3,9 +3,6 @@ export const env = { PORT: Number(process.env.PORT) || 3000, DATABASE_TYPE: process.env.DATABASE_TYPE || "postgres", DATABASE_URL: process.env.DATABASE_URL, - USE_MEILISEARCH: process.env.USE_MEILISEARCH === "true" || false, - MEILISEARCH_URL: process.env.MEILISEARCH_URL, - MEILISEARCH_KEY: process.env.MEILISEARCH_KEY, NINEANIME_RESOLVER: process.env.NINEANIME_RESOLVER, NINEANIME_KEY: process.env.NINEANIME_KEY, REDIS_URL: process.env.REDIS_URL, diff --git a/anify-backend/src/mapping/impl/anime/bilibili.ts b/anify-backend/src/mapping/impl/anime/bilibili.ts deleted file mode 100644 index 67e2007..0000000 --- a/anify-backend/src/mapping/impl/anime/bilibili.ts +++ /dev/null @@ -1,55 +0,0 @@ -import AnimeProvider, { Episode, Source, StreamingServers, SubType } from "."; -import { Format, Formats, Result } from "../.."; -import { load } from "cheerio"; -import Extractor from "@/src/helper/extractor"; - -export default class Bilibili extends AnimeProvider { - override rateLimit = 250; - override id = "bilibili"; - override url = "https://bilibili.com"; - - private api = "https://app.biliintl.com/intl/gateway/v2"; - - override formats: Format[] = [Format.MOVIE, Format.ONA, Format.OVA, Format.SPECIAL, Format.TV, Format.TV_SHORT]; - - override get subTypes(): SubType[] { - return [SubType.SUB]; - } - - override get headers(): Record | undefined { - return { Referer: "https://kwik.cx" }; - } - - override async search(query: string, format?: Format, year?: number): Promise { - // https://app.biliintl.com/intl/gateway/v2/app/search/type?keyword=${query}&type=7 - const request = await this.request(`${this.api}/app/search/type?keyword=${encodeURIComponent(query)}&type=7`); - if (!request.ok) { - return []; - } - const data = await request.json(); - const results: Result[] = []; - - console.log(data) - - if (!data?.data) { - return []; - } - - data.data.map((item) => { - const formatString: string = item.type.toUpperCase(); - const f: Format = Formats.includes(formatString as Format) ? (formatString as Format) : Format.UNKNOWN; - - results.push({ - id: String(item.id) ?? item.session, - title: item.title, - year: item.year, - img: item.poster, - format: f, - altTitles: [], - providerId: this.id, - }); - }); - - return results; - } -} diff --git a/anify-backend/src/mapping/impl/anime/nineanime.ts b/anify-backend/src/mapping/impl/anime/nineanime.ts index 4ee1430..ec0597b 100644 --- a/anify-backend/src/mapping/impl/anime/nineanime.ts +++ b/anify-backend/src/mapping/impl/anime/nineanime.ts @@ -15,8 +15,8 @@ export default class NineAnime extends AnimeProvider { override formats: Format[] = [Format.MOVIE, Format.ONA, Format.OVA, Format.SPECIAL, Format.TV, Format.TV_SHORT]; private userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.42"; - private resolver: string = env.NINEANIME_RESOLVER || `https://9anime.resolver.com`; - private resolverKey: string = env.NINEANIME_KEY || `9anime`; + private resolver: string | undefined = env.NINEANIME_RESOLVER; + private resolverKey: string | undefined = env.NINEANIME_KEY || `9anime`; override get subTypes(): SubType[] { return [SubType.SUB, SubType.DUB]; @@ -207,18 +207,38 @@ export default class NineAnime extends AnimeProvider { } private async getVRF(query: string): Promise { + if (!this.resolver) return { + url: query, + vrfQuery: "vrf", + } + return await (await this.request(`${this.resolver}/vrf?query=${encodeURIComponent(query)}&apikey=${this.resolverKey}`, {})).json(); } public async getSearchVRF(query: string): Promise { + if (!this.resolver) return { + url: query, + vrfQuery: "vrf", + } + return await (await this.request(`${this.resolver}/9anime-search?query=${encodeURIComponent(query)}&apikey=${this.resolverKey}`, {})).json(); } private async getRawVRF(query: string): Promise { + if (!this.resolver) return { + url: query, + vrfQuery: "vrf", + } + return await (await this.request(`${this.resolver}/rawVrf?query=${encodeURIComponent(query)}&apikey=${this.resolverKey}`, {})).json(); } private async decodeURL(query: string): Promise { + if (!this.resolver) return { + url: query, + vrfQuery: "vrf", + } + return await (await this.request(`${this.resolver}/decrypt?query=${encodeURIComponent(query)}&apikey=${this.resolverKey}`, {})).json(); } diff --git a/anify-backend/src/mapping/index.ts b/anify-backend/src/mapping/index.ts index 35a9942..8e17f28 100644 --- a/anify-backend/src/mapping/index.ts +++ b/anify-backend/src/mapping/index.ts @@ -28,9 +28,8 @@ import SimklMeta from "./impl/meta/simkl"; import Simkl from "./impl/information/simkl"; import ColoredManga from "./impl/manga/coloredmanga"; import AnimeFlix from "./impl/anime/animeflix"; -import Bilibili from "./impl/anime/bilibili"; -const ANIME_PROVIDERS: AnimeProvider[] = [new NineAnime(), new GogoAnime(), new Zoro(), new AnimePahe(), new Bilibili()]; +const ANIME_PROVIDERS: AnimeProvider[] = [new NineAnime(), new GogoAnime(), new Zoro(), new AnimePahe()]; const animeProviders: Record = ANIME_PROVIDERS.reduce((acc, provider) => { acc[provider.id] = provider; return acc; diff --git a/anify-backend/src/scripts/buildDb.ts b/anify-backend/src/scripts/buildDb.ts index 35138f0..7066532 100644 --- a/anify-backend/src/scripts/buildDb.ts +++ b/anify-backend/src/scripts/buildDb.ts @@ -3,33 +3,20 @@ dotenv.config(); import colors from "colors"; import { execSync } from "child_process"; -import { env } from "../env"; import Database from "../database"; -let databaseType: "postgres" | "meilisearch" | null = "postgres"; +const scripts = ["npm run db:generate && npm run db:push && npm run db:validate"]; -if (env.DATABASE_TYPE) { - databaseType = env.DATABASE_TYPE === "postgres" ? "postgres" : env.DATABASE_TYPE === "meilisearch" ? "meilisearch" : null; - if (!databaseType) { - console.log(colors.yellow("WARNING: Invalid database type provided. Set to postgres. Please check .env.example.")); - databaseType = "postgres"; +for (const script of scripts) { + try { + console.log(`Executing script: ${script}`); + execSync(script, { stdio: "inherit" }); + } catch (error) { + console.error(colors.red(`Error executing script: ${script}`)); + console.error(error); } } -if (databaseType === "postgres") { - const scripts = ["npm run db:generate && npm run db:push && npm run db:validate"]; - - for (const script of scripts) { - try { - console.log(`Executing script: ${script}`); - execSync(script, { stdio: "inherit" }); - } catch (error) { - console.error(colors.red(`Error executing script: ${script}`)); - console.error(error); - } - } - - Database.initializeDatabase().then(() => { - console.log(colors.green("Initialized database!")); - }); -} +Database.initializeDatabase().then(() => { + console.log(colors.green("Initialized database!")); +}); diff --git a/anify-backend/src/test.ts b/anify-backend/src/test.ts deleted file mode 100644 index 6cdbbe8..0000000 --- a/anify-backend/src/test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import dotenv from "dotenv"; -dotenv.config(); - -import queues from "./worker"; -import emitter, { Events } from "@/src/helper/event"; -import { start } from "./server/server"; -import Database from "./database"; -import { MediaStatus, animeProviders } from "./mapping"; -import { fetchCorsProxies } from "./helper/proxies"; - -emitter.on(Events.COMPLETED_SEASONAL_LOAD, async (data) => { - for (let i = 0; i < data.trending.length; i++) { - if (data.trending[i].status === MediaStatus.NOT_YET_RELEASED) { - continue; - } - const existing = await Database.info(String(data.trending[i].aniListId)); - if (!existing) { - queues.mappingQueue.add({ id: data.trending[i].aniListId, type: data.trending[i].type }); - } - } - - for (let i = 0; i < data.popular.length; i++) { - if (data.popular[i].status === MediaStatus.NOT_YET_RELEASED) { - continue; - } - const existing = await Database.info(String(data.popular[i].aniListId)); - if (!existing) queues.mappingQueue.add({ id: data.popular[i].aniListId, type: data.popular[i].type }); - } - - for (let i = 0; i < data.top.length; i++) { - if (data.top[i].status === MediaStatus.NOT_YET_RELEASED) { - continue; - } - const existing = await Database.info(String(data.top[i].aniListId)); - if (!existing) queues.mappingQueue.add({ id: data.top[i].aniListId, type: data.top[i].type }); - } - - for (let i = 0; i < data.seasonal.length; i++) { - if (data.seasonal[i].status === MediaStatus.NOT_YET_RELEASED) { - continue; - } - const existing = await Database.info(String(data.seasonal[i].aniListId)); - if (!existing) queues.mappingQueue.add({ id: data.seasonal[i].aniListId, type: data.seasonal[i].type }); - } -}); - -emitter.on(Events.COMPLETED_MAPPING_LOAD, async (data) => { - for (let i = 0; i < data.length; i++) { - if (await Database.info(String(data[i].aniListId))) { - continue; - } - queues.createEntry.add({ toInsert: data[i], type: data[i].type }); - } -}); - -emitter.on(Events.COMPLETED_SEARCH_LOAD, (data) => { - if (data[0]?.aniListId) { - for (let i = 0; i < data.length; i++) { - if (data[i].status === MediaStatus.NOT_YET_RELEASED) { - continue; - } - queues.mappingQueue.add({ id: data[i].aniListId, type: data[i].type }); - } - } -}); - -// Todo: For inserting all skip times, merge the episodescrape repo so that it adds a bunch of events lol -emitter.on(Events.COMPLETED_SKIPTIMES_LOAD, (data) => { - // Do something -}); - -emitter.on(Events.COMPLETED_PAGE_UPLOAD, (data) => { - // Do something -}); - -queues.seasonQueue.start(); -queues.mappingQueue.start(); -queues.createEntry.start(); -queues.searchQueue.start(); -queues.skipTimes.start(); -queues.uploadPages.start(); - -fetchCorsProxies().then(async () => { - await Database.initializeDatabase(); - await animeProviders.bilibili.search("Mushoku Tensei").then(console.log) -}); diff --git a/anify-backend/yarn.lock b/anify-backend/yarn.lock index d0a383a..345bb83 100644 --- a/anify-backend/yarn.lock +++ b/anify-backend/yarn.lock @@ -2231,13 +2231,6 @@ media-typer@0.3.0: resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== -meilisearch@^0.33.0: - version "0.33.0" - resolved "https://registry.npmjs.org/meilisearch/-/meilisearch-0.33.0.tgz" - integrity sha512-bYPb9WyITnJfzf92e7QFK8Rc50DmshFWxypXCs3ILlpNh8pT15A7KSu9Xgnnk/K3G/4vb3wkxxtFS4sxNkWB8w== - dependencies: - cross-fetch "^3.1.6" - merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" diff --git a/anify-frontend/.env.example b/anify-frontend/.env.example index f7afea4..b789e85 100644 --- a/anify-frontend/.env.example +++ b/anify-frontend/.env.example @@ -6,7 +6,4 @@ ANILIST_ID="" ANILIST_SECRET="" ANILIST_REDIRECT_URL="http://localhost:3000/api/auth" IMAGE_PROXY="https://api.consumet.org/utils/image-proxy" -API_KEY="" -USE_MEILISEARCH="false" -MEILISEARCH_URL="https://search.meilisearch.com" -MEILISEARCH_KEY="" \ No newline at end of file +API_KEY="" \ No newline at end of file diff --git a/anify-frontend/src/env.mjs b/anify-frontend/src/env.mjs index 9e2a107..8050862 100644 --- a/anify-frontend/src/env.mjs +++ b/anify-frontend/src/env.mjs @@ -15,9 +15,6 @@ export const env = createEnv({ ANILIST_REDIRECT_URL: z.string().url(), IMAGE_PROXY: z.string().url(), API_KEY: z.string(), - USE_MEILISEARCH: z.string(), - MEILISEARCH_URL: z.string().url(), - MEILISEARCH_KEY: z.string(), NODE_ENV: z.enum(["development", "test", "production"]), }, @@ -44,9 +41,6 @@ export const env = createEnv({ ANILIST_REDIRECT_URL: process.env.ANILIST_REDIRECT_URL || "https://anilist.co/api/v2/oauth", IMAGE_PROXY: process.env.IMAGE_PROXY || "https://api.consumet.org/utils/image-proxy", API_KEY: process.env.API_KEY || "", - USE_MEILISEARCH: process.env.USE_MEILISEARCH?.toLowerCase() || "false", - MEILISEARCH_URL: process.env.MEILISEARCH_URL || "http://localhost:7700", - MEILISEARCH_KEY: process.env.MEILISEARCH_KEY || "", NODE_ENV: process.env.NODE_ENV, NEXT_PUBLIC_IMAGE_PROXY: process.env.IMAGE_PROXY || "https://api.consumet.org/utils/image-proxy" }, diff --git a/anify-frontend/src/pages/api/search.tsx b/anify-frontend/src/pages/api/search.tsx index 79ce521..c405dfe 100644 --- a/anify-frontend/src/pages/api/search.tsx +++ b/anify-frontend/src/pages/api/search.tsx @@ -27,102 +27,37 @@ export default async function handler(request: Request, response: ServerResponse const formats: string[] = request.body.formats ?? []; - let filter = formats.length > 0 ? `(format = ${formats.join(" OR format = ")})` : ""; - filter += genres.length > 0 ? ` AND (genres = ${genres.join(" OR genres = ")})` : ""; - filter += genresExcluded.length > 0 ? ` AND NOT (genres = ${genresExcluded.join(" OR genres = ")})` : ""; - filter += tags.length > 0 ? ` AND (tags = ${tags.join(" OR tags = ")})` : ""; - filter += tagsExcluded.length > 0 ? ` AND NOT (tags = ${tagsExcluded.join(" OR tags = ")})` : ""; - - if (env.USE_MEILISEARCH === "true") { - try { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const data: SearchResult = await (await fetch(`${env.MEILISEARCH_URL}/indexes/${request.body.type}/search`, { - method: "POST", - headers: { - Authorization: `Bearer ${env.MEILISEARCH_KEY}`, - "Content-Type": "application/json" - }, - body: JSON.stringify({ - q: request.body.query, - limit: perPage, - offset: page * perPage, - filter - }) - })).json(); - - if (data.hits.length === 0) throw new Error("No results found."); - - response.writeHead(200, { "Content-Type": "application/json" }); - response.write(JSON.stringify(data)); - response.end(); - } catch (e) { - const data = await (await fetch(`${env.BACKEND_URL}/search-advanced?apikey=${env.API_KEY}`, { - method: "POST", - headers: { - Authorization: `Bearer ${env.MEILISEARCH_KEY}`, - "Content-Type": "application/json" - }, - body: JSON.stringify({ - type: request.body.type === "manga" ? formats.includes("NOVEL") ? "novel" : "manga" : "anime", - query: request.body.query, - format: formats, - page, - perPage, - genres, - genresExcluded, - tags, - tagsExcluded, - year: 0, - }) - })).json() as Anime[] | Manga[]; - - const newData = { - hits: data, - query: request.body.query, - processingTimeMs: 0, - limit: perPage, - offset: page * perPage, - estimatedTotalHits: data.length, - } - - response.writeHead(200, { "Content-Type": "application/json" }); - response.write(JSON.stringify(newData)); - response.end(); - } - } else { - const data = await (await fetch(`${env.BACKEND_URL}/search-advanced?apikey=${env.API_KEY}`, { - method: "POST", - headers: { - Authorization: `Bearer ${env.MEILISEARCH_KEY}`, - "Content-Type": "application/json" - }, - body: JSON.stringify({ - type: request.body.type === "manga" ? formats.includes("NOVEL") ? "novel" : "manga" : "anime", - query: request.body.query, - format: formats, - page, - perPage, - genres, - genresExcluded, - tags, - tagsExcluded, - year: 0, - }) - })).json() as Anime[] | Manga[]; - - const newData = { - hits: data, + const data = await (await fetch(`${env.BACKEND_URL}/search-advanced?apikey=${env.API_KEY}`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + type: request.body.type === "manga" ? formats.includes("NOVEL") ? "novel" : "manga" : "anime", query: request.body.query, - processingTimeMs: 0, - limit: perPage, - offset: page * perPage, - estimatedTotalHits: data.length, - } + format: formats, + page, + perPage, + genres, + genresExcluded, + tags, + tagsExcluded, + year: 0, + }) + })).json() as Anime[] | Manga[]; - response.writeHead(200, { "Content-Type": "application/json" }); - response.write(JSON.stringify(newData)); - response.end(); + const newData = { + hits: data, + query: request.body.query, + processingTimeMs: 0, + limit: perPage, + offset: page * perPage, + estimatedTotalHits: data.length, } + + response.writeHead(200, { "Content-Type": "application/json" }); + response.write(JSON.stringify(newData)); + response.end(); } interface Request {