From 5ea22b4362e0cf6ee3318825286cb30b7e3d262a Mon Sep 17 00:00:00 2001 From: torikushiii Date: Sun, 23 Jul 2023 20:31:36 +0800 Subject: [PATCH] reworked entire codebase --- .gitignore | 2 +- @types/classes/character.d.ts | 79 - @types/classes/drop.d.ts | 46 - @types/classes/equipment.d.ts | 52 - @types/classes/skill.d.ts | 46 - @types/classes/stage.d.ts | 68 - @types/classes/template.d.ts | 14 - @types/index.d.ts | 31 - @types/singletons/query.d.ts | 22 - @types/singletons/template.d.ts | 7 - @types/singletons/utils.d.ts | 74 - LICENSE | 833 ++++++++--- README.md | 6 +- app.js | 49 - core/classes/character.js | 341 +++++ core/classes/skill.js | 65 + {modules => core}/classes/template.js | 2 - {modules => core}/example.config.js | 3 +- {modules => core}/index.js | 27 +- core/singletons/logger.js | 53 + .../singleton => core/singletons}/query.js | 16 +- core/singletons/template.js | 13 + core/singletons/utils.js | 270 ++++ docs/equpiment.md | 67 - docs/query.md | 1284 ++++++++++++++--- images/icon/ch0188.png | Bin 22586 -> 0 bytes images/lobby/ch0188.png | Bin 15695 -> 0 bytes images/portrait/ch0188.png | Bin 84896 -> 0 bytes index.js | 52 + lib/fastify.js | 4 +- lib/logger.js | 12 - modules/classes/character.js | 314 ---- modules/classes/drop.js | 81 -- modules/classes/equipment.js | 137 -- modules/classes/skill.js | 66 - modules/classes/stage.js | 121 -- modules/singleton/template.js | 26 - modules/singleton/utils.js | 253 ---- package.json | 25 +- routes/banner.js | 13 +- routes/character.js | 87 +- routes/equipment.js | 60 - routes/raid.js | 53 +- routes/stage.js | 44 - 44 files changed, 2674 insertions(+), 2144 deletions(-) delete mode 100644 @types/classes/character.d.ts delete mode 100644 @types/classes/drop.d.ts delete mode 100644 @types/classes/equipment.d.ts delete mode 100644 @types/classes/skill.d.ts delete mode 100644 @types/classes/stage.d.ts delete mode 100644 @types/classes/template.d.ts delete mode 100644 @types/index.d.ts delete mode 100644 @types/singletons/query.d.ts delete mode 100644 @types/singletons/template.d.ts delete mode 100644 @types/singletons/utils.d.ts delete mode 100644 app.js create mode 100644 core/classes/character.js create mode 100644 core/classes/skill.js rename {modules => core}/classes/template.js (83%) rename {modules => core}/example.config.js (61%) rename {modules => core}/index.js (73%) create mode 100644 core/singletons/logger.js rename {modules/singleton => core/singletons}/query.js (78%) create mode 100644 core/singletons/template.js create mode 100644 core/singletons/utils.js delete mode 100644 docs/equpiment.md delete mode 100644 images/icon/ch0188.png delete mode 100644 images/lobby/ch0188.png delete mode 100644 images/portrait/ch0188.png create mode 100644 index.js delete mode 100644 lib/logger.js delete mode 100644 modules/classes/character.js delete mode 100644 modules/classes/drop.js delete mode 100644 modules/classes/equipment.js delete mode 100644 modules/classes/skill.js delete mode 100644 modules/classes/stage.js delete mode 100644 modules/singleton/template.js delete mode 100644 modules/singleton/utils.js delete mode 100644 routes/equipment.js delete mode 100644 routes/stage.js diff --git a/.gitignore b/.gitignore index b639849..90cdd74 100644 --- a/.gitignore +++ b/.gitignore @@ -79,6 +79,6 @@ typings/ bun.lockb assets/ -modules/config.js +core/config.js types.js db-access.js \ No newline at end of file diff --git a/@types/classes/character.d.ts b/@types/classes/character.d.ts deleted file mode 100644 index 78e9791..0000000 --- a/@types/classes/character.d.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { BlueArchiveTemplate } from "./template"; - -export declare class Character extends BlueArchiveTemplate { - static data: Map; - - id: number; - localizeEtcId: string; - name: string; - released: boolean; - playable: boolean; - baseStar: number; - rarity: number; - armorType: string; - bulletType: string; - position: string; - role: string; - squadType: string; - weaponType: string; - club: string; - school: string; - imageIdentifier: string; - equipmentType: string; - tags: string[]; - region: string; - - constructor (data: { - id: number, - localizeEtcId: string, - name: string, - released: boolean, - playable: boolean, - baseStar: number, - rarity: number, - armorType: string, - bulletType: string, - position: string, - role: string, - squadType: string, - weaponType: string, - club: string, - school: string, - imageIdentifier: string, - equipmentType: string, - tags: string[], - region: string - }); - - /** - * Fixes the given armor type by converting it to lowercase and replacing spaces with underscores. - * @param armorType The armor type to fix. - * @returns The fixed armor type. - */ - private fixArmorType (armorType: string): string; - - /** - * Fixes the given role type by converting it to lowercase and replacing spaces with underscores. - * @param roleType The role type to fix. - * @returns The fixed role type. - */ - private fixRoleType (roleType: string): string; - - /** - * Returns the character data that matches the given identifier. - * @param identifier The identifier of the character data to retrieve. - * @returns The character data that matches the given identifier. - */ - static get (identifier: Character | number): Character | null; - - /** - * Loads the character data from the database. - * @returns A promise that resolves when the character data has been loaded. - */ - static loadData (): Promise; - - /** - * Clears the character data. - */ - static destroy (): void; -} diff --git a/@types/classes/drop.d.ts b/@types/classes/drop.d.ts deleted file mode 100644 index 62296dd..0000000 --- a/@types/classes/drop.d.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { BlueArchiveTemplate } from "./template"; - -export declare class Drops extends BlueArchiveTemplate { - static dataGlobal: Map; - static dataJapan: Map; - - id: number; - tag: string; - stageRewardId: number; - dropAmount: number; - dropChance: number; - - constructor (data: { - id: number, - tag: string, - stageRewardId: number, - dropAmount: number, - dropChance: number - }); - - /** - * Returns the drop data that matches the identifier and region. - * @param identifier The identifier of the drop data to retrieve. - * @param region The region to retrieve the drop data from. - * @returns The drop data that matches the identifier and region. - */ - static get (identifier: Drops | number, region: "global" | "japan"): Drops[] | Drops; - - /** - * Returns the drop data that matches the identifier. - * @param identifier The identifier of the drop data to retrieve. - * @returns The drop data that matches the identifier. - */ - static getDropbyStage (identifier: Drops | number): Drops[] | Drops; - - /** - * Loads the drop data from the database for both the global and Japan regions. - * @returns A promise that resolves when the drop data has been loaded. - */ - static loadData (): Promise; - - /** - * Clears the drop data. - */ - static destroy (): void; -} \ No newline at end of file diff --git a/@types/classes/equipment.d.ts b/@types/classes/equipment.d.ts deleted file mode 100644 index 4317b9a..0000000 --- a/@types/classes/equipment.d.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { BlueArchiveTemplate } from "./template"; - -export declare class Equipment extends BlueArchiveTemplate { - static dataGlobal: Map; - static dataJapan: Map; - - id: number; - localizeId: string; - recipeId: number; - category: string; - rarity: number; - maxLevel: number; - tier: number; - tags: string[]; - - constructor (data: { - id: number, - localizeId: string, - recipeId: number, - category: string, - rarity: number, - maxLevel: number, - tier: number, - tags: string[] - }); - - /** - * Returns the equipment data that matches the identifier and region. - * @param identifier The identifier of the equipment data to retrieve. - * @param region The region to retrieve the equipment data from. - * @returns The equipment data that matches the identifier and region. - */ - static get (identifier: Equipment | number, region: "global" | "japan"): Equipment | null; - - /** - * Returns the equipment data that matches the identifier. - * @param identifier The identifier of the equipment data to retrieve. - * @returns The equipment data that matches the identifier. - */ - static getDatabyTier (identifier: Equipment | number): Equipment[]; - - /** - * Loads the equipment data from the database for both the global and Japan regions. - * @returns A promise that resolves when the equipment data has been loaded. - */ - static loadData (): Promise; - - /** - * Clears the equipment data. - */ - static destroy (): void; -} \ No newline at end of file diff --git a/@types/classes/skill.d.ts b/@types/classes/skill.d.ts deleted file mode 100644 index b45cf5a..0000000 --- a/@types/classes/skill.d.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { BlueArchiveTemplate } from "./template"; - -export declare class Skill extends BlueArchiveTemplate { - static dataGlobal: Map; - static dataJapan: Map; - - id: number; - skillEx: string; - normal: string; - passive: string; - sub: string; - - constructor (data: { - id: number, - skillEx: string, - normal: string, - passive: string, - sub: string - }); - - /** - * Returns the skill data that matches the identifier and region. - * @param identifier The identifier of the skill data to retrieve. - * @param region The region to retrieve the skill data from. - * @returns The skill data that matches the identifier and region. - */ - static get (identifier: Skill | number, region: "global" | "japan"): Skill | null; - - /** - * Loads the skill data from the database for both the global and Japan regions. - * @returns A promise that resolves when the skill data has been loaded. - */ - static loadData (): Promise; - - /** - * Clears the skill data. - */ - static destroy (): void; - - /** - * Normalizes the given name by converting it to lowercase. - * @param name The name to normalize. - * @returns The normalized name. - */ - static normalizeName (name: string): string; -} \ No newline at end of file diff --git a/@types/classes/stage.d.ts b/@types/classes/stage.d.ts deleted file mode 100644 index 6890156..0000000 --- a/@types/classes/stage.d.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { BlueArchiveTemplate } from "./template"; - -declare type ObjectiveType = { - type: string; - value: number; -}; - -declare type StageInfoType = { - title: string; - description: string; -}; - -declare type StageDataType = { - chara: number; - enemy: number[]; - count: number[]; - wave: number; - boss: number; -}; - -declare type RaidType = { - seasonId: number; - bossName: string; - startAt: Date; - settleAt: Date; - endAt: Date; -}; - -declare type StageDataTypeMain = { - id: number; - minRank: number; - staminaCost: number; - battleDuration: number; - maxTurn: number; - stageInfo: StageInfoType; - objective?: ObjectiveType[]; - stageData?: StageDataType; -}; - -declare type StageDataMapType = Map; - -export declare class Stage extends BlueArchiveTemplate { - static dataGlobal: StageDataMapType; - static dataJapan: StageDataMapType; - - id: number; - minRank: number; - staminaCost: number; - battleDuration: number; - maxTurn: number; - stageInfo: StageInfoType; - objective: ObjectiveType[]; - stageData: StageDataType; - - constructor (data: StageDataTypeMain); - - static get (identifier: number | Stage, region: string): Stage | undefined; - - static getStagebyId (identifier: number | Stage): Stage | undefined; - - static raid (region: string): Promise<{ current: RaidType[]; upcoming: RaidType[]; ended: RaidType[] }>; - - static loadData (): Promise; - - static destroy (): void; - - static normalizeName (name: string): string; -} diff --git a/@types/classes/template.d.ts b/@types/classes/template.d.ts deleted file mode 100644 index a07998c..0000000 --- a/@types/classes/template.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -export declare class BlueArchiveTemplate { - static data: Map; - static dataGlobal: Map; - static dataJapan: Map; - - static initialize (): Promise; - static loadData (): Promise; - - /** - * Cleans up module - * @abstract - */ - destroy (): void; -} diff --git a/@types/index.d.ts b/@types/index.d.ts deleted file mode 100644 index 0ab2c5a..0000000 --- a/@types/index.d.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Character } from "./classes/character"; -import { Drops } from "./classes/drop"; -import { Equipment } from "./classes/equipment"; -import { Skill } from "./classes/skill"; - -import { QuerySingleton } from "./singletons/query"; -import { Utils } from "./singletons/utils"; - -export declare type GlobalBaObject = { - Character: typeof Character; - Drops: typeof Drops; - Equipment: typeof Equipment; - Skill: typeof Skill; - - Query: InstanceType; - Utils: InstanceType; -}; - -declare type ModuleFilePath = "classes/character" - | "classes/drop" - | "classes/equipment" - | "classes/skill" - | "singletons/query" - | "singletons/utils"; - -declare type OptionsObject = { - whitelist?: ModuleFilePath[]; - skip?: ModuleFilePath[]; -}; - -export declare function initialize (options?: OptionsObject): Promise; diff --git a/@types/singletons/query.d.ts b/@types/singletons/query.d.ts deleted file mode 100644 index 338a769..0000000 --- a/@types/singletons/query.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MongoClient } from "mongodb"; -import { SingletonTemplate } from "./template"; - -declare type QuerySingletonConstructor = { - singleton (): QuerySingleton; - module: QuerySingleton | null; -}; - -export declare class QuerySingleton extends SingletonTemplate { - #pool: MongoClient | null; - - constructor (); - - connect (): Promise; - - initListeners (): void; - - destroy (): void; - - get client (): MongoClient; - get modulePath (): string; -} diff --git a/@types/singletons/template.d.ts b/@types/singletons/template.d.ts deleted file mode 100644 index bd757bd..0000000 --- a/@types/singletons/template.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -export declare abstract class SingletonTemplate { - static module: SingletonTemplate; - static singleton (): void | Promise; - - abstract destroy (): void; - abstract get modulePath (): string; -} diff --git a/@types/singletons/utils.d.ts b/@types/singletons/utils.d.ts deleted file mode 100644 index eaa815c..0000000 --- a/@types/singletons/utils.d.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { SingletonTemplate } from "./template"; - -declare type TerrainType = { - SS: { - DamageDealt: string; - ShieldBlockRate: string; - }; - S: { - DamageDealt: string; - ShieldBlockRate: string; - }; - A: { - DamageDealt: string; - ShieldBlockRate: string; - }; - B: { - DamageDealt: string; - ShieldBlockRate: string; - }; - C: { - DamageDealt: string; - ShieldBlockRate: string; - }; - D: { - DamageDealt: string; - ShieldBlockRate: string; - }; -}; - -declare type Equipment = { - id: string; - name: string; - description: string; -}; - -declare type CharacterData = { - info: any; - stat: any; - topology: { - urban: TerrainType; - outdoor: TerrainType; - indoor: TerrainType; - }; -}; - -declare type SkillInfo = { - skillDesc: string; - effectDesc: string; - animation: string; -}; - -export declare class Utils implements SingletonTemplate { - static terrainTypes: { - Urban: Record; - Desert: Record; - Indoor: Record; - }; - - static singleton (): Utils; - - isValidRegion (region: "global" | "japan"): boolean; - - getEquipmentData (id: string): Promise; - - getCharacterName (id: string, region: string): Promise; - - getCharacterData (id: string, region: string): Promise; - - getSkillInfo (id: string, region: string): Promise; - - destroy (): void; - - get modulePath (): string; -} diff --git a/LICENSE b/LICENSE index e8efbde..29ebfa5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,172 +1,661 @@ -Open Software License ("OSL") v. 3.0 - -This Open Software License (the "License") applies to any original work of -authorship (the "Original Work") whose owner (the "Licensor") has placed the -following licensing notice adjacent to the copyright notice for the Original -Work: - -Licensed under the Open Software License version 3.0 - -1) Grant of Copyright License. Licensor grants You a worldwide, royalty-free, -non-exclusive, sublicensable license, for the duration of the copyright, to do -the following: - - a) to reproduce the Original Work in copies, either alone or as part of a - collective work; - - b) to translate, adapt, alter, transform, modify, or arrange the Original - Work, thereby creating derivative works ("Derivative Works") based upon the - Original Work; - - c) to distribute or communicate copies of the Original Work and Derivative - Works to the public, with the proviso that copies of Original Work or - Derivative Works that You distribute or communicate shall be licensed under - this Open Software License; - - d) to perform the Original Work publicly; and - - e) to display the Original Work publicly. - -2) Grant of Patent License. Licensor grants You a worldwide, royalty-free, -non-exclusive, sublicensable license, under patent claims owned or controlled -by the Licensor that are embodied in the Original Work as furnished by the -Licensor, for the duration of the patents, to make, use, sell, offer for sale, -have made, and import the Original Work and Derivative Works. - -3) Grant of Source Code License. The term "Source Code" means the preferred -form of the Original Work for making modifications to it and all available -documentation describing how to modify the Original Work. Licensor agrees to -provide a machine-readable copy of the Source Code of the Original Work along -with each copy of the Original Work that Licensor distributes. Licensor -reserves the right to satisfy this obligation by placing a machine-readable -copy of the Source Code in an information repository reasonably calculated to -permit inexpensive and convenient access by You for as long as Licensor -continues to distribute the Original Work. - -4) Exclusions From License Grant. Neither the names of Licensor, nor the names -of any contributors to the Original Work, nor any of their trademarks or -service marks, may be used to endorse or promote products derived from this -Original Work without express prior permission of the Licensor. Except as -expressly stated herein, nothing in this License grants any license to -Licensor's trademarks, copyrights, patents, trade secrets or any other -intellectual property. No patent license is granted to make, use, sell, offer -for sale, have made, or import embodiments of any patent claims other than the -licensed claims defined in Section 2. No license is granted to the trademarks -of Licensor even if such marks are included in the Original Work. Nothing in -this License shall be interpreted to prohibit Licensor from licensing under -terms different from this License any Original Work that Licensor otherwise -would have a right to license. - -5) External Deployment. The term "External Deployment" means the use, -distribution, or communication of the Original Work or Derivative Works in any -way such that the Original Work or Derivative Works may be used by anyone -other than You, whether those works are distributed or communicated to those -persons or made available as an application intended for use over a network. -As an express condition for the grants of license hereunder, You must treat -any External Deployment by You of the Original Work or a Derivative Work as a -distribution under section 1(c). - -6) Attribution Rights. You must retain, in the Source Code of any Derivative -Works that You create, all copyright, patent, or trademark notices from the -Source Code of the Original Work, as well as any notices of licensing and any -descriptive text identified therein as an "Attribution Notice." You must cause -the Source Code for any Derivative Works that You create to carry a prominent -Attribution Notice reasonably calculated to inform recipients that You have -modified the Original Work. - -7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that -the copyright in and to the Original Work and the patent rights granted herein -by Licensor are owned by the Licensor or are sublicensed to You under the -terms of this License with the permission of the contributor(s) of those -copyrights and patent rights. Except as expressly stated in the immediately -preceding sentence, the Original Work is provided under this License on an "AS -IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without -limitation, the warranties of non-infringement, merchantability or fitness for -a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK -IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this -License. No license to the Original Work is granted by this License except -under this disclaimer. - -8) Limitation of Liability. Under no circumstances and under no legal theory, -whether in tort (including negligence), contract, or otherwise, shall the -Licensor be liable to anyone for any indirect, special, incidental, or -consequential damages of any character arising as a result of this License or -the use of the Original Work including, without limitation, damages for loss -of goodwill, work stoppage, computer failure or malfunction, or any and all -other commercial damages or losses. This limitation of liability shall not -apply to the extent applicable law prohibits such limitation. - -9) Acceptance and Termination. If, at any time, You expressly assented to this -License, that assent indicates your clear and irrevocable acceptance of this -License and all of its terms and conditions. If You distribute or communicate -copies of the Original Work or a Derivative Work, You must make a reasonable -effort under the circumstances to obtain the express assent of recipients to -the terms of this License. This License conditions your rights to undertake -the activities listed in Section 1, including your right to create Derivative -Works based upon the Original Work, and doing so without honoring these terms -and conditions is prohibited by copyright law and international treaty. -Nothing in this License is intended to affect copyright exceptions and -limitations (including "fair use" or "fair dealing"). This License shall -terminate immediately and You may no longer exercise any of the rights granted -to You by this License upon your failure to honor the conditions in Section -1(c). - -10) Termination for Patent Action. This License shall terminate automatically -and You may no longer exercise any of the rights granted to You by this -License as of the date You commence an action, including a cross-claim or -counterclaim, against Licensor or any licensee alleging that the Original Work -infringes a patent. This termination provision shall not apply for an action -alleging patent infringement by combinations of the Original Work with other -software or hardware. - -11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this -License may be brought only in the courts of a jurisdiction wherein the -Licensor resides or in which Licensor conducts its primary business, and under -the laws of that jurisdiction excluding its conflict-of-law provisions. The -application of the United Nations Convention on Contracts for the -International Sale of Goods is expressly excluded. Any use of the Original -Work outside the scope of this License or after its termination shall be -subject to the requirements and penalties of copyright or patent law in the -appropriate jurisdiction. This section shall survive the termination of this -License. - -12) Attorneys' Fees. In any action to enforce the terms of this License or -seeking damages relating thereto, the prevailing party shall be entitled to -recover its costs and expenses, including, without limitation, reasonable -attorneys' fees and costs incurred in connection with such action, including -any appeal of such action. This section shall survive the termination of this -License. - -13) Miscellaneous. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent necessary -to make it enforceable. - -14) Definition of "You" in This License. "You" throughout this License, -whether in upper or lower case, means an individual or a legal entity -exercising rights under, and complying with all of the terms of, this License. -For legal entities, "You" includes any entity that controls, is controlled by, -or is under common control with you. For purposes of this definition, -"control" means (i) the power, direct or indirect, to cause the direction or -management of such entity, whether by contract or otherwise, or (ii) ownership -of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial -ownership of such entity. - -15) Right to Use. You may use the Original Work in all ways not otherwise -restricted or conditioned by this License or by law, and Licensor promises not -to interfere with or be responsible for such uses by You. - -16) Modification of This License. This License is Copyright © 2005 Lawrence -Rosen. Permission is granted to copy, distribute, or communicate this License -without modification. Nothing in this License permits You to modify this -License as applied to the Original Work or to Derivative Works. However, You -may modify the text of this License and copy, distribute or communicate your -modified version (the "Modified License") and apply it to other original works -of authorship subject to the following conditions: (i) You may not indicate in -any way that your Modified License is the "Open Software License" or "OSL" and -you may not use those names in the name of your Modified License; (ii) You -must replace the notice specified in the first paragraph above with the notice -"Licensed under " or with a notice of your own -that is not confusingly similar to the notice in this License; and (iii) You -may not claim that your original works are open source software unless your -Modified License has been approved by Open Source Initiative (OSI) and You -comply with its license review and certification process. \ No newline at end of file + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. \ No newline at end of file diff --git a/README.md b/README.md index b8cb77d..0bd7fe6 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,4 @@ If you want to have the API running on a different port, change the port on `con # REST API - DOCUMENTATION -Moved to [docs](https://github.com/torikushiii/BlueArchiveAPI/tree/main/docs) folder - -### License - -Licensed under Open Software License v3.0 +Moved to [docs](https://github.com/torikushiii/BlueArchiveAPI/tree/main/docs) folder. diff --git a/app.js b/app.js deleted file mode 100644 index 79d44d3..0000000 --- a/app.js +++ /dev/null @@ -1,49 +0,0 @@ -const fastify = require("./lib/fastify"); -const logger = require("./lib/logger"); - -(async function () { - require("./db-access"); - globalThis.ba = await require("./modules/index")(); - const subroutes = [ - "character", - "equipment", - "stage", - "raid", - "banner", - "image" - ]; - - const config = ba.Config; - if (!config.host || !config.port) { - logger.error("Config file is missing host or port"); - process.exit(1); - } - - fastify.get("/robots.txt", (req, res) => { - res.type("text/plain"); - res.send("User-agent: *\nDisallow: /"); - }); - - fastify.get("/buruaka/", async (req, res) => { - res.send({ - status: 200, - version: config.version, - uptime: Math.round(Date.now() - process.uptime() * 1000), - endpoints: subroutes.filter((route) => route !== "image" && route !== "stage") - }); - }); - - for (const route of subroutes) { - fastify.register(require(`./routes/${route}`), { prefix: `buruaka/${route}` }); - } - - fastify.get("*", (req, res) => { - res.notFound("That endpoint does not exist"); - }); - - fastify.get("/buruaka", (req, res) => { - res.redirect(302, "/buruaka/"); - }); - - fastify.listen({ port: config.port, host: config.host }); -})(); diff --git a/core/classes/character.js b/core/classes/character.js new file mode 100644 index 0000000..f6b0229 --- /dev/null +++ b/core/classes/character.js @@ -0,0 +1,341 @@ +module.exports = class Character extends require("./template.js") { + static data = new Map(); + + constructor (data) { + super(); + + this.id = data.id; + + this.name = data.name; + + this.localizeEtcId = data.localizeEtcId; + + this.released = data.released; + + this.playable = data.playable; + + this.baseStar = data.baseStar; + + this.rarity = data.rarity; + + this.armorType = this.fixArmor(data.armorType); + + this.bulletType = this.fixBulletType(data.bulletType); + + this.position = data.position; + + this.role = this.fixRoleType(data.role); + + this.squadType = data.squadType; + + this.weaponType = data.weaponType; + + this.club = data.club; + + this.school = data.school; + + this.imageIdentifier = data.imageIdentifier; + + this.equipmentType = data.equipmentType; + + this.tags = data.tags; + + this.region = data.region; + } + + static async get (identifier, options = {}) { + if (identifier instanceof Character) { + return identifier; + } + else if (typeof identifier === "number") { + const region = options.region ?? "global"; + + const character = Character.data.get(`${region}.${identifier}`); + if (!character) { + return null; + } + + return character; + } + else if (typeof identifier === "string") { + const region = options.region ?? "global"; + + const values = [...Character.data.values()]; + const character = values.find( + i => i.name.toLowerCase() === identifier.toLowerCase() + && i.region === region + ); + + if (!character) { + return null; + } + + return character; + } + else { + if (options.getAll) { + const region = options.region ?? "global"; + + const characters = [...Character.data.values()] + .filter(i => i.region === region) + .filter(i => i.released === true); + + if (characters.length === 0) { + return null; + } + + const data = []; + for (const character of characters) { + const parsedCharacter = await this.buildCharacterObject(character, options); + if (!parsedCharacter) { + ba.Logger.warn(`Failed to parse character ${character.id}`, character); + continue; + } + + data.push(parsedCharacter); + } + + return data; + } + + ba.Logger.error("Invalid identifier provided. Must be a number or string.", { identifier, options }); + } + } + + static async getCharacterByQuery (query, options = {}) { + const region = options.region ?? "global"; + + const { + armor, + attack, + weapon, + position, + role, + school, + type + } = query; + + const characters = [...Character.data.values()] + .filter(i => i.region === region) + .filter(i => i.released === true); + + const filteredCharacters = characters.filter(i => { + if (armor && i.armorType.toLowerCase() !== armor) { + return false; + } + + if (attack && i.bulletType.toLowerCase() !== attack) { + return false; + } + + if (weapon && i.weaponType.toLowerCase() !== weapon) { + return false; + } + + if (position && i.position.toLowerCase() !== position) { + return false; + } + + if (role && i.role.toLowerCase() !== role) { + return false; + } + + if (school && i.school.toLowerCase() !== school) { + return false; + } + + if (type && i.squadType.toLowerCase() !== type) { + return false; + } + + return true; + }); + + if (filteredCharacters.length === 0) { + return null; + } + + return filteredCharacters.map(i => ({ + id: i.id, + name: i.name + })); + } + + static async loadData () { + const regions = [ + "global", + "japan" + ]; + + for (const region of regions) { + const characterData = await ba.Query.collection(`${region}.CharacterData`).find({}).toArray(); + if (characterData.length === 0) { + ba.Logger.error(`No character data found for ${region}`); + } + + for (const character of characterData) { + if (character.playable === false) { + continue; + } + + const char = await ba.Utils.getCharacterName(character.localizeEtcId, region); + if (!char || char.name === "LocalizeError") { + continue; + } + + const object = new Character({ ...character, name: char.name, region }); + Character.data.set(`${region}.${character.id}`, object); + } + } + } + + static async buildCharacterObject (character, options = {}) { + const region = options.region ?? "global"; + + if (options.getAll) { + const charData = await ba.Utils.getCharacterData(character, region); + if (!charData) { + return null; + } + + return { + id: character.id, + name: charData.name, + profile: charData.info.introduction, + rarity: character.rarity, + baseStar: character.baseStar, + position: character.position, + role: character.role, + armorType: character.armorType, + bulletType: character.bulletType, + weaponType: character.weaponType, + squadType: character.squadType, + school: character.school, + terrain: charData.topology + }; + } + + const skills = { + ex: [], + normal: [], + passive: [], + sub: [] + }; + + const skillData = ba.Skill.get(character.id, { region }); + if (skillData) { + if (skillData.skillEx) { + const exSkill = await ba.Utils.getSkillData(skillData.skillEx, region); + if (exSkill) { + skills.ex.push(exSkill); + } + } + + if (skillData.normal) { + const normalSkill = await ba.Utils.getSkillData(skillData.normal, region); + if (normalSkill) { + skills.normal.push(normalSkill); + } + } + + if (skillData.passive) { + const passiveSkill = await ba.Utils.getSkillData(skillData.passive, region); + if (passiveSkill) { + skills.passive.push(passiveSkill); + } + } + + if (skillData.sub) { + const subSkill = await ba.Utils.getSkillData(skillData.sub, region); + if (subSkill) { + skills.sub.push(subSkill); + } + } + } + + const charData = await ba.Utils.getCharacterData(character, region); + if (!charData) { + return null; + } + + delete charData.stat._id; + + let image = {}; + if (ba.Config.domain && ba.Config.domain !== null) { + image = this.getImage(character.imageIdentifier, ba.Config.domain); + } + + return { + id: character.id, + isReleased: character.released, + isPlayable: character.playable, + character: { + name: character.name, + baseStar: character.baseStar, + rarity: character.rarity, + armorType: character.armorType, + bulletType: character.bulletType, + position: character.position, + role: character.role, + squadType: character.squadType, + weaponType: character.weaponType, + profile: charData.info.introduction + }, + info: { + age: charData.info.age, + birthDate: charData.info.birthDate, + height: charData.info.height, + artist: charData.info.artistName, + club: character.club, + school: character.school, + schoolYear: charData.info.schoolYear, + voiceActor: charData.info.voiceActor + }, + image, + stat: charData.stat, + terrain: charData.topology, + skills + }; + } + + fixRoleType (roleType) { + const types = { + DamageDealer: "Dealer", + Tanker: "Tank", + Healer: "Healer", + Supporter: "Support", + Vehicle: "T.S." + }; + + return types[roleType] ?? "???"; + } + + fixBulletType (bulletType) { + const types = { + Explosion: "Explosive", + Mystic: "Mystic", + Penetration: "Piercing" + }; + + return types[bulletType] ?? bulletType; + } + + fixArmor (armor) { + const types = { + Unarmed: "Special", + HeavyArmor: "Heavy", + LightArmor: "Light", + ElasticArmor: "Elastic" + }; + + return types[armor] ?? armor; + } + + static getImage (identifier, domain) { + return { + icon: `${domain}/image/icon/${identifier}`, + lobby: `${domain}/image/lobby/${identifier}`, + portrait: `${domain}/image/portrait/${identifier}` + }; + } +}; diff --git a/core/classes/skill.js b/core/classes/skill.js new file mode 100644 index 0000000..2e2daa8 --- /dev/null +++ b/core/classes/skill.js @@ -0,0 +1,65 @@ +module.exports = class Skill extends require("./template.js") { + static data = new Map(); + + constructor (data) { + super(); + + this.id = data.id; + + this.skillEx = data.skillEx; + + this.normal = data.normal; + + this.passive = data.passive; + + this.sub = data.sub; + } + + static get (identifier, options = {}) { + if (identifier instanceof Skill) { + return identifier; + } + else if (typeof identifier === "number") { + const region = options.region ?? "global"; + + const skill = Skill.data.get(`${region}.${identifier}`); + if (!skill) { + return null; + } + + const values = [...Skill.data.values()]; + const index = values.findIndex(i => i.id === skill.id); + if (index === -1) { + return null; + } + + return values[index]; + } + else { + ba.Logger.error("Invalid identifier type passed to Skill.get()", { + identifier, + type: typeof identifier, + options + }); + } + } + + static async loadData () { + const regions = [ + "global", + "japan" + ]; + + for (const region of regions) { + const skillData = await ba.Query.collection(`${region}.SkillListData`).find({}).toArray(); + if (skillData.length === 0) { + ba.Logger.error(`No skill data found for ${region}`); + } + + for (const skill of skillData) { + const skillObj = new Skill(skill); + Skill.data.set(`${region}.${skillObj.id}`, skillObj); + } + } + } +}; diff --git a/modules/classes/template.js b/core/classes/template.js similarity index 83% rename from modules/classes/template.js rename to core/classes/template.js index 221c744..017fe9b 100644 --- a/modules/classes/template.js +++ b/core/classes/template.js @@ -1,7 +1,5 @@ module.exports = class BlueArchiveTemplate { static data = new Map(); - static dataGlobal = new Map(); - static dataJapan = new Map(); static async initialize () { await this.loadData(); diff --git a/modules/example.config.js b/core/example.config.js similarity index 61% rename from modules/example.config.js rename to core/example.config.js index 48271bc..4e0350f 100644 --- a/modules/example.config.js +++ b/core/example.config.js @@ -3,6 +3,5 @@ module.exports = { host: "0.0.0.0", port: 80, domain: null, - hostname: "example.com", - redis_configuration: {} + hostname: "example.com" }; diff --git a/modules/index.js b/core/index.js similarity index 73% rename from modules/index.js rename to core/index.js index 63d32f0..7f46c79 100644 --- a/modules/index.js +++ b/core/index.js @@ -1,20 +1,14 @@ module.exports = (async function (options = {}) { - /** - * Global namespace - * @namespace - * @type {Object} - */ globalThis.ba = {}; const files = [ + "singleton/logger", + "singleton/query", "singleton/utils", "classes/character", - "classes/drop", - "classes/equipment", - "classes/skill", - "classes/stage" + "classes/skill" ]; const { @@ -38,21 +32,20 @@ module.exports = (async function (options = {}) { if (type === "singleton") { switch (moduleName) { case "query": { - const Component = require("./singleton/query"); + const Component = require("./singletons/query"); ba.Query = Component.singleton().client; - await new Promise(resolve => setTimeout(resolve, 500)); break; } - case "cache": { - const Component = require("./singleton/cache"); - ba.Cache = Component.singleton(); + case "utils": { + const Component = require("./singletons/utils"); + ba.Utils = Component.singleton(); break; } - case "utils": { - const Component = require("./singleton/utils"); - ba.Utils = Component.singleton(); + case "logger": { + const Component = require("./singletons/logger"); + ba.Logger = Component.singleton(); break; } } diff --git a/core/singletons/logger.js b/core/singletons/logger.js new file mode 100644 index 0000000..4cf8cd9 --- /dev/null +++ b/core/singletons/logger.js @@ -0,0 +1,53 @@ +const Debug = require("debug"); + +module.exports = class LoggerSingleton extends require("./template.js") { + /** + * @returns {LoggerSingleton} + */ + static singleton () { + if (!LoggerSingleton.module) { + LoggerSingleton.module = new LoggerSingleton(); + } + + return LoggerSingleton.module; + } + + /** + * @hideconstructor + */ + constructor () { + super(); + + const logger = Debug("buruaka"); + + const log = logger.extend("[ LOG ]:"); + log.log = console.log.bind(console); + log.enabled = true; + this.log = log; + + const info = logger.extend("[ INFO ]:"); + info.log = console.info.bind(console); + info.color = log.color; + info.enabled = true; + this.info = info; + + const warn = logger.extend("[ WARN ]:"); + warn.log = console.warn.bind(console); + warn.color = "9"; + warn.enabled = true; + this.warn = warn; + + const error = logger.extend("[ ERROR ]:"); + error.log = console.error.bind(console); + error.color = "196"; + error.enabled = true; + this.error = error; + } + + log (message) { this.log(message); } + info (message) { this.info(message); } + warn (message) { this.warn(message); } + error (message) { this.error(message); } + + get modulePath () { return "logger"; } +}; diff --git a/modules/singleton/query.js b/core/singletons/query.js similarity index 78% rename from modules/singleton/query.js rename to core/singletons/query.js index d0987e7..694b58c 100644 --- a/modules/singleton/query.js +++ b/core/singletons/query.js @@ -1,7 +1,7 @@ const { MongoClient } = require("mongodb"); const url = `mongodb://${process.env.MONGO_IP}:${process.env.MONGO_PORT}`; -module.exports = class QuerySingleton extends require("./template") { +module.exports = class QuerySingleton extends require("./template.js") { /** @type {MongoClient} */ #pool = null; @@ -21,13 +21,12 @@ module.exports = class QuerySingleton extends require("./template") { super(); if (!process.env.MONGO_IP || !process.env.MONGO_PORT) { - throw new Error("Missing MongoDB credentials"); + throw new Error("MONGO_IP and MONGO_PORT environment variables must be set."); } else { this.#pool = new MongoClient(url, { useUnifiedTopology: true, - useNewUrlParser: true, - keepAlive: true + useNewUrlParser: true }); } @@ -36,8 +35,7 @@ module.exports = class QuerySingleton extends require("./template") { async connect () { await this.#pool.connect() - .then(() => console.log("Connected to MongoDB")) - .catch(e => console.error(e)); + .catch(e => ba.Logger.error(e)); this.initListeners(); } @@ -46,15 +44,15 @@ module.exports = class QuerySingleton extends require("./template") { const pool = this.#pool; pool.on("serverHeartbeatFailed", () => { - console.log("Server heartbeat failed"); + ba.Logger.error("MongoDB server heartbeat failed."); }); pool.on("topologyOpening", () => { - console.log("Topology opening"); + ba.Logger.info("MongoDB topology opening."); }); pool.on("topologyClosed", () => { - console.log("Topology closed"); + ba.Logger.info("MongoDB topology closed."); }); } diff --git a/core/singletons/template.js b/core/singletons/template.js new file mode 100644 index 0000000..680881d --- /dev/null +++ b/core/singletons/template.js @@ -0,0 +1,13 @@ +module.exports = class SingletonTemplate { + destroy () { + throw new Error("Module.destroy is not implemented"); + } + + static singleton () { + throw new Error("Module.singleton is not implemented"); + } + + get modulePath () { + throw new Error("Module.modulePath is not implemented"); + } +}; diff --git a/core/singletons/utils.js b/core/singletons/utils.js new file mode 100644 index 0000000..2b36222 --- /dev/null +++ b/core/singletons/utils.js @@ -0,0 +1,270 @@ +module.exports = class UtilsSingleton extends require("./template.js") { + static terrainTypes = { + Urban: { + SS: { + DamageDealt: "130%(1.3x)", + ShieldBlockRate: "75%" + }, + S: { + DamageDealt: "120%(1.2x)", + ShieldBlockRate: "60%" + }, + A: { + DamageDealt: "110%(1.1x)", + ShieldBlockRate: "45%" + }, + B: { + DamageDealt: "100%(1x)", + ShieldBlockRate: "30%" + }, + C: { + DamageDealt: "90%(0.9x)", + ShieldBlockRate: "15%" + }, + D: { + DamageDealt: "80%(0.8x)", + ShieldBlockRate: "0%" + } + }, + Desert: { + SS: { + DamageDealt: "130%(1.3x)", + ShieldBlockRate: "75%" + }, + S: { + DamageDealt: "120%(1.2x)", + ShieldBlockRate: "60%" + }, + A: { + DamageDealt: "110%(1.1x)", + ShieldBlockRate: "45%" + }, + B: { + DamageDealt: "100%(1x)", + ShieldBlockRate: "30%" + }, + C: { + DamageDealt: "90%(0.9x)", + ShieldBlockRate: "15%" + }, + D: { + DamageDealt: "80%(0.8x)", + ShieldBlockRate: "0%" + } + }, + Indoor: { + SS: { + DamageDealt: "130%(1.3x)", + ShieldBlockRate: "75%" + }, + S: { + DamageDealt: "120%(1.2x)", + ShieldBlockRate: "60%" + }, + A: { + DamageDealt: "110%(1.1x)", + ShieldBlockRate: "45%" + }, + B: { + DamageDealt: "100%(1x)", + ShieldBlockRate: "30%" + }, + C: { + DamageDealt: "90%(0.9x)", + ShieldBlockRate: "15%" + }, + D: { + DamageDealt: "80%(0.8x)", + ShieldBlockRate: "0%" + } + } + }; + + static data = new Map(); + + /** + * @inheritdoc + */ + static singleton () { + if (!UtilsSingleton.module) { + UtilsSingleton.module = new UtilsSingleton(); + } + + return UtilsSingleton.module; + } + + async getCharacterName (identifier, region) { + if (!UtilsSingleton.data.has(`${region}.LocalizeEtc`)) { + const characterNames = await ba.Query.collection(`${region}.LocalizeEtc`).find({}).toArray(); + if (!characterNames) { + throw new Error(`No character names found for ${region}`); + } + + UtilsSingleton.data.set(`${region}.LocalizeEtc`, characterNames); + } + + const characterMap = UtilsSingleton.data.get(`${region}.LocalizeEtc`); + const characterData = characterMap.find(i => i.key === identifier); + if (!characterData) { + return null; + } + + return characterData; + } + + async getCharacterData (character, region) { + if (!UtilsSingleton.data.has(`${region}.CharacterLocalize`)) { + const characterLocalize = await ba.Query.collection(`${region}.CharacterLocalize`).find({}).toArray(); + if (!characterLocalize) { + throw new Error(`No character localize data found for ${region}`); + } + + UtilsSingleton.data.set(`${region}.CharacterLocalize`, characterLocalize); + } + + if (!UtilsSingleton.data.has(`${region}.CharacterStat`)) { + const characterStat = await ba.Query.collection(`${region}.CharacterStat`).find({}).toArray(); + if (!characterStat) { + throw new Error(`No character stat data found for ${region}`); + } + + UtilsSingleton.data.set(`${region}.CharacterStat`, characterStat); + } + + const info = UtilsSingleton.data.get(`${region}.CharacterLocalize`).find(i => i.id === character.id); + const statData = UtilsSingleton.data.get(`${region}.CharacterStat`).find(i => i.id === character.id); + if (!info || !statData) { + return null; + } + + const charName = await this.getCharacterName(character.localizeEtcId, region); + if (!charName) { + return null; + } + + return { + info, + name: charName.name, + stat: statData, + topology: { + urban: UtilsSingleton.terrainTypes.Urban[statData.streetMood], + outdoor: UtilsSingleton.terrainTypes.Desert[statData.outdoorMood], + indoor: UtilsSingleton.terrainTypes.Indoor[statData.indoorMood] + } + }; + } + + async getSkillInfo (identifier, region) { + if (!UtilsSingleton.data.has(`${region}.SkillLocalize`)) { + const skillLocalize = await ba.Query.collection(`${region}.SkillLocalize`).find({}).toArray(); + if (!skillLocalize) { + throw new Error(`No skill localize data found for ${region}`); + } + + UtilsSingleton.data.set(`${region}.SkillLocalize`, skillLocalize); + } + + const skillLocalize = UtilsSingleton.data.get(`${region}.SkillLocalize`); + const skillData = skillLocalize.find(i => i.id === identifier); + if (!skillData) { + return null; + } + + return { + id: skillData.id, + name: skillData.name, + description: skillData.description + }; + } + + async getSkillData (identifier, region) { + if (!UtilsSingleton.data.has(`${region}.SkillListTable`)) { + const skillListTable = await ba.Query.collection(`${region}.SkillListTable`).find({}).toArray(); + if (!skillListTable) { + throw new Error(`No skill list table data found for ${region}`); + } + + UtilsSingleton.data.set(`${region}.SkillListTable`, skillListTable); + } + + const stuff = []; + const skillListTable = UtilsSingleton.data.get(`${region}.SkillListTable`); + const skillData = skillListTable.filter(i => i.groupId === identifier); + if (skillData.length !== 0) { + for (const skill of skillData) { + const skillInfo = await this.getSkillInfo(skill.localizeSkillId, region); + if (skillInfo) { + stuff.push(skillInfo); + } + } + } + + return stuff; + } + + async getBannerData (region) { + if (!UtilsSingleton.data.has(`${region}.GachaData`)) { + const bannerData = await ba.Query.collection(`${region}.GachaData`).find({}).toArray(); + if (!bannerData) { + throw new Error(`No banner data found for ${region}`); + } + + UtilsSingleton.data.set(`${region}.GachaData`, bannerData); + } + + const current = []; + const upcoming = []; + const ended = []; + + const bannerData = UtilsSingleton.data.get(`${region}.GachaData`); + for (const banner of bannerData) { + const now = Date.now(); + const start = banner.startAt; + const end = banner.endAt; + + const bannerInfo = await this.parseBannerData(banner, region); + + if (now >= start && now <= end) { + current.push(bannerInfo); + } + else if (now < start) { + upcoming.push(bannerInfo); + } + else if (now > end) { + ended.push(bannerInfo); + } + } + + return { + current, + upcoming, + ended + }; + } + + async parseBannerData (data, region) { + const rateups = []; + for (const rateup of data.rateup) { + const charData = await ba.Character.get(rateup, { region }); + if (!charData) { + ba.Logger.error(`Character rate-up ${rateup} not found`); + continue; + } + + const characterData = await this.getCharacterName(charData.localizeEtcId, region); + if (!characterData) { + ba.Logger.error(`Character name rate-up ${rateup} not found`); + continue; + } + + rateups.push(characterData.name); + } + + return { + gachaType: data.type, + startAt: data.startAt, + endAt: data.endAt, + rateups + }; + } +}; diff --git a/docs/equpiment.md b/docs/equpiment.md deleted file mode 100644 index da2979a..0000000 --- a/docs/equpiment.md +++ /dev/null @@ -1,67 +0,0 @@ -# Equipment API - -**BASE URL:** `https://api.ennead.cc/buruaka/` - -### Get Equipment -Get Equipment by Tier or ID - -> [https://api.ennead.cc/buruaka/equipment/](https://api.ennead.cc/buruaka/equipment) - -> GET `equipment/:equipment` | `equipment/t1%20hairpin` | `equipment/Tennis%20Headband` - -> GET `equipment/6000?id=true` You need to pass `?id=true` to get equipment by ID - -> Returns: `Equipment Object` -
-View Payload Example - -```json -{ - "data": { - "id": 6000, - "localizeId": 1494732916, - "recipeId": 600, - "category": "Hairpin", - "rarity": "N", - "maxLevel": 10, - "tier": 1, - "tags": [ - "Equipment", - "Hairpin" - ] - }, - "drops": [ - { - "stageName": "CHAPTER01_Normal_Main_Stage04", - "dropAmount": 1, - "dropChance": 30 - }, - { - "stageName": "CHAPTER01_Hard_Main_Stage03", - "dropAmount": 1, - "dropChance": 60 - }, - { - "stageName": "CHAPTER02_Normal_Main_Stage01", - "dropAmount": 1, - "dropChance": 40 - }, - { - "stageName": "CHAPTER02_Normal_Main_Stage02", - "dropAmount": 1, - "dropChance": 40 - }, - { - "stageName": "CHAPTER02_Normal_Main_Stage03", - "dropAmount": 1, - "dropChance": 30 - }, - { - "stageName": "CHAPTER02_Hard_Main_Stage03", - "dropAmount": 1, - "dropChance": 80 - } - ] -} -``` -
\ No newline at end of file diff --git a/docs/query.md b/docs/query.md index db8e1fa..a07344a 100644 --- a/docs/query.md +++ b/docs/query.md @@ -4,68 +4,283 @@ ## Character Query list example -### Get characters by role +### Get characters by their role -> https://api.ennead.cc/buruaka/character/query?role=attacker +> https://api.ennead.cc/buruaka/character/query?role=dealer Role list: - - Attacker + - Tank + - Dealer - Healer - - Supporter - - Tanker + - Support + - T.S.
View Payload Example ```json -{ - [ - "Akari", - "Aris", - "Aru", - "Asuna", - "Azusa", - "Azusa (Swimsuit)", - "Cherino", - "Chise", - "Haruna", - "Hasumi", - "Hibiki", - "Hina", - "Hina (Swimsuit)", - "Iori", - "Iori (Swimsuit)", - "Izumi", - "Izuna", - "Junko", - "Karin", - "Maki", - "Mashiro", - "Mashiro (Swimsuit)", - "Midori", - "Momoi", - "Mutsuki", - "Neru", - "Nonomi", - "Pina", - "Saya", - "Serika", - "Shiroko", - "Shiroko (Cycling)", - "Shun", - "Shun (Small)", - "Sumire", - "Tsurugi", - "Tsurugi (Swimsuit)", - "Utaha", - "Yoshimi", - "Yuzu" - ] -} +[ + { + "id": 10000, + "name": "Aru" + }, + { + "id": 10002, + "name": "Haruna" + }, + { + "id": 10004, + "name": "Hina" + }, + { + "id": 10006, + "name": "Iori" + }, + { + "id": 10007, + "name": "Maki" + }, + { + "id": 10008, + "name": "Neru" + }, + { + "id": 10009, + "name": "Izumi" + }, + { + "id": 10010, + "name": "Shiroko" + }, + { + "id": 10011, + "name": "Shun" + }, + { + "id": 10012, + "name": "Sumire" + }, + { + "id": 10013, + "name": "Tsurugi" + }, + { + "id": 10014, + "name": "Izuna" + }, + { + "id": 10015, + "name": "Aris" + }, + { + "id": 10016, + "name": "Midori" + }, + { + "id": 10017, + "name": "Cherino" + }, + { + "id": 10018, + "name": "Yuzu" + }, + { + "id": 10019, + "name": "Azusa" + }, + { + "id": 10021, + "name": "Azusa (Swimsuit)" + }, + { + "id": 10022, + "name": "Hina (Swimsuit)" + }, + { + "id": 10023, + "name": "Iori (Swimsuit)" + }, + { + "id": 10024, + "name": "Shiroko (Cycling)" + }, + { + "id": 10025, + "name": "Shun (Small)" + }, + { + "id": 10027, + "name": "Karin (Bunny)" + }, + { + "id": 10031, + "name": "Aru (New Year)" + }, + { + "id": 10032, + "name": "Mutsuki (New Year)" + }, + { + "id": 10033, + "name": "Wakamo" + }, + { + "id": 10036, + "name": "Hinata" + }, + { + "id": 10041, + "name": "Misaki" + }, + { + "id": 10043, + "name": "Wakamo (Swimsuit)" + }, + { + "id": 10044, + "name": "Nonomi (Swimsuit)" + }, + { + "id": 10046, + "name": "Izuna (Swimsuit)" + }, + { + "id": 10048, + "name": "Saori" + }, + { + "id": 10049, + "name": "Kazusa" + }, + { + "id": 10051, + "name": "Utaha (Cheer Squad)" + }, + { + "id": 10055, + "name": "Shigure" + }, + { + "id": 10057, + "name": "Haruna (New Year)" + }, + { + "id": 13001, + "name": "Chise" + }, + { + "id": 13002, + "name": "Akari" + }, + { + "id": 13003, + "name": "Hasumi" + }, + { + "id": 13004, + "name": "Nonomi" + }, + { + "id": 13006, + "name": "Mutsuki" + }, + { + "id": 13007, + "name": "Junko" + }, + { + "id": 13008, + "name": "Serika" + }, + { + "id": 13011, + "name": "Momoi" + }, + { + "id": 16001, + "name": "Asuna" + }, + { + "id": 16004, + "name": "Pina" + }, + { + "id": 16005, + "name": "Tsurugi (Swimsuit)" + }, + { + "id": 16008, + "name": "Fubuki" + }, + { + "id": 16009, + "name": "Michiru" + }, + { + "id": 16010, + "name": "Hibiki (Cheer Squad)" + }, + { + "id": 16011, + "name": "Hasumi (Track)" + }, + { + "id": 16012, + "name": "Junko (New Year)" + }, + { + "id": 20000, + "name": "Hibiki" + }, + { + "id": 20001, + "name": "Karin" + }, + { + "id": 20002, + "name": "Saya" + }, + { + "id": 20003, + "name": "Mashiro" + }, + { + "id": 20004, + "name": "Mashiro (Swimsuit)" + }, + { + "id": 20006, + "name": "Saya (Casual)" + }, + { + "id": 20013, + "name": "Chihiro" + }, + { + "id": 20014, + "name": "Saki" + }, + { + "id": 20018, + "name": "Moe" + }, + { + "id": 20019, + "name": "Akane (Bunny)" + }, + { + "id": 23004, + "name": "Utaha" + }, + { + "id": 26005, + "name": "Yoshimi" + } +] ```
-### Get characters by type +### Get characters by their type > https://api.ennead.cc/buruaka/character/query?type=special Type list: @@ -76,66 +291,240 @@ View Payload Example ```json -{ - [ - "Airi", - "Ayane", - "Chinatsu", - "Fuuka", - "Hanae", - "Hanako", - "Hare", - "Hibiki", - "Hifumi (Swimsuit)", - "Juri", - "Karin", - "Kotama", - "Mashiro", - "Mashiro (Swimsuit)", - "Nodoka", - "Saya", - "Saya (Casual)", - "Serina", - "Shimiko", - "Shizuko", - "Utaha", - "Yoshimi" - ] -} - +[ + { + "id": 20000, + "name": "Hibiki" + }, + { + "id": 20001, + "name": "Karin" + }, + { + "id": 20002, + "name": "Saya" + }, + { + "id": 20003, + "name": "Mashiro" + }, + { + "id": 20004, + "name": "Mashiro (Swimsuit)" + }, + { + "id": 20005, + "name": "Hifumi (Swimsuit)" + }, + { + "id": 20006, + "name": "Saya (Casual)" + }, + { + "id": 20007, + "name": "Hatsune Miku" + }, + { + "id": 20008, + "name": "Ako" + }, + { + "id": 20009, + "name": "Cherino (Hot Spring)" + }, + { + "id": 20010, + "name": "Nodoka (Hot Spring)" + }, + { + "id": 20011, + "name": "Serika (New Year)" + }, + { + "id": 20012, + "name": "Sena" + }, + { + "id": 20013, + "name": "Chihiro" + }, + { + "id": 20014, + "name": "Saki" + }, + { + "id": 20015, + "name": "Kaede" + }, + { + "id": 20016, + "name": "Iroha" + }, + { + "id": 20017, + "name": "Hiyori" + }, + { + "id": 20018, + "name": "Moe" + }, + { + "id": 20019, + "name": "Akane (Bunny)" + }, + { + "id": 20020, + "name": "Himari" + }, + { + "id": 20021, + "name": "Hanae (Christmas)" + }, + { + "id": 20022, + "name": "Fuuka (New Year)" + }, + { + "id": 23000, + "name": "Airi" + }, + { + "id": 23001, + "name": "Fuuka" + }, + { + "id": 23002, + "name": "Hanae" + }, + { + "id": 23003, + "name": "Hare" + }, + { + "id": 23004, + "name": "Utaha" + }, + { + "id": 23005, + "name": "Ayane" + }, + { + "id": 23006, + "name": "Shizuko" + }, + { + "id": 23007, + "name": "Hanako" + }, + { + "id": 23008, + "name": "Mari" + }, + { + "id": 26000, + "name": "Chinatsu" + }, + { + "id": 26001, + "name": "Kotama" + }, + { + "id": 26002, + "name": "Juri" + }, + { + "id": 26003, + "name": "Serina" + }, + { + "id": 26004, + "name": "Shimiko" + }, + { + "id": 26005, + "name": "Yoshimi" + }, + { + "id": 26006, + "name": "Nodoka" + }, + { + "id": 26007, + "name": "Ayane (Swimsuit)" + }, + { + "id": 26008, + "name": "Shizuko (Swimsuit)" + } +] ``` -### Get chracters by school +### Get chracters by their school > https://api.ennead.cc/buruaka/character/query?school=abydos School list: - Abydos + - Arius - Gehenna - Hyakkiyako - Millennium + - Red Winter - Shanhaijing + - SRT - Trinity + - Valkyrie
View Payload Example ```json -{ - [ - "Ayane", - "Hoshino", - "Nonomi", - "Serika", - "Shiroko", - "Shiroko (Cycling)" - ] -} - +[ + { + "id": 10005, + "name": "Hoshino" + }, + { + "id": 10010, + "name": "Shiroko" + }, + { + "id": 10024, + "name": "Shiroko (Cycling)" + }, + { + "id": 10044, + "name": "Nonomi (Swimsuit)" + }, + { + "id": 10045, + "name": "Hoshino (Swimsuit)" + }, + { + "id": 13004, + "name": "Nonomi" + }, + { + "id": 13008, + "name": "Serika" + }, + { + "id": 20011, + "name": "Serika (New Year)" + }, + { + "id": 23005, + "name": "Ayane" + }, + { + "id": 26007, + "name": "Ayane (Swimsuit)" + } +] ```
-### Get characters by position +### Get characters by their position > https://api.ennead.cc/buruaka/character/query?position=front Position list: @@ -147,28 +536,102 @@ View Payload Example ```json -{ - [ - "Eimi", - "Haruka", - "Hoshino", - "Izuna", - "Neru", - "Sumire", - "Tsubaki", - "Tsurugi", - "Tsurugi (Swimsuit)", - "Yuuka" - ] -} - +[ + { + "id": 10001, + "name": "Eimi" + }, + { + "id": 10005, + "name": "Hoshino" + }, + { + "id": 10008, + "name": "Neru" + }, + { + "id": 10012, + "name": "Sumire" + }, + { + "id": 10013, + "name": "Tsurugi" + }, + { + "id": 10014, + "name": "Izuna" + }, + { + "id": 10026, + "name": "Neru (Bunny)" + }, + { + "id": 10029, + "name": "Natsu" + }, + { + "id": 10037, + "name": "Marina" + }, + { + "id": 10038, + "name": "Miyako" + }, + { + "id": 10040, + "name": "Tsukuyo" + }, + { + "id": 10042, + "name": "Atsuko" + }, + { + "id": 10045, + "name": "Hoshino (Swimsuit)" + }, + { + "id": 10046, + "name": "Izuna (Swimsuit)" + }, + { + "id": 10051, + "name": "Utaha (Cheer Squad)" + }, + { + "id": 10053, + "name": "Yuuka (Track)" + }, + { + "id": 10058, + "name": "Mine" + }, + { + "id": 13009, + "name": "Tsubaki" + }, + { + "id": 13010, + "name": "Yuuka" + }, + { + "id": 16000, + "name": "Haruka" + }, + { + "id": 16005, + "name": "Tsurugi (Swimsuit)" + }, + { + "id": 16009, + "name": "Michiru" + } +] ``` -### Get characters by weapon +### Get characters by their weapon type > https://api.ennead.cc/buruaka/character/query?weapon=ar - Weapon list: - AR - GL @@ -181,141 +644,550 @@ - SG - SMG - SR + - FT
View Payload Example ```json -{ - [ - "Akari", - "Asuna", - "Azusa", - "Azusa (Swimsuit)", - "Hanae", - "Hanako", - "Hare", - "Hifumi", - "Hifumi (Swimsuit)", - "Junko", - "Momoi", - "Serika", - "Serina", - "Shimiko", - "Shiroko", - "Shiroko (Cycling)", - "Suzumi", - "Yoshimi" - ] -} - +[ + { + "id": 10003, + "name": "Hifumi" + }, + { + "id": 10010, + "name": "Shiroko" + }, + { + "id": 10019, + "name": "Azusa" + }, + { + "id": 10021, + "name": "Azusa (Swimsuit)" + }, + { + "id": 10024, + "name": "Shiroko (Cycling)" + }, + { + "id": 10028, + "name": "Asuna (Bunny)" + }, + { + "id": 10048, + "name": "Saori" + }, + { + "id": 10050, + "name": "Kokona" + }, + { + "id": 10056, + "name": "Serina (Christmas)" + }, + { + "id": 13002, + "name": "Akari" + }, + { + "id": 13007, + "name": "Junko" + }, + { + "id": 13008, + "name": "Serika" + }, + { + "id": 13011, + "name": "Momoi" + }, + { + "id": 16001, + "name": "Asuna" + }, + { + "id": 16003, + "name": "Suzumi" + }, + { + "id": 16012, + "name": "Junko (New Year)" + }, + { + "id": 20005, + "name": "Hifumi (Swimsuit)" + }, + { + "id": 20011, + "name": "Serika (New Year)" + }, + { + "id": 20013, + "name": "Chihiro" + }, + { + "id": 20021, + "name": "Hanae (Christmas)" + }, + { + "id": 23002, + "name": "Hanae" + }, + { + "id": 23003, + "name": "Hare" + }, + { + "id": 23007, + "name": "Hanako" + }, + { + "id": 26003, + "name": "Serina" + }, + { + "id": 26004, + "name": "Shimiko" + }, + { + "id": 26005, + "name": "Yoshimi" + } +] ```
-### Get characters by damage -> https://api.ennead.cc/buruaka/character/query?damage=explosion +### Get characters by their attack type +> https://api.ennead.cc/buruaka/character/query?damage=explosive Damage list: - - Explosion + - Explosive - Mystic - - Penetration + - Piercing
View Payload Example ```json -{ - [ - "Airi", - "Akari", - "Aru", - "Azusa", - "Eimi", - "Fuuka", - "Hanae", - "Hare", - "Haruka", - "Hibiki", - "Hina", - "Hina (Swimsuit)", - "Iori (Swimsuit)", - "Izumi", - "Izumi (Swimsuit)", - "Juri", - "Kayoko", - "Kirino", - "Koharu", - "Kotama", - "Mashiro", - "Mutsuki", - "Nodoka", - "Saya", - "Serika", - "Shimiko", - "Shiroko", - "Shun", - "Shun (Small)", - "Suzumi", - "Yuuka" - ] -} - +[ + { + "id": 10000, + "name": "Aru" + }, + { + "id": 10001, + "name": "Eimi" + }, + { + "id": 10004, + "name": "Hina" + }, + { + "id": 10009, + "name": "Izumi" + }, + { + "id": 10010, + "name": "Shiroko" + }, + { + "id": 10011, + "name": "Shun" + }, + { + "id": 10019, + "name": "Azusa" + }, + { + "id": 10020, + "name": "Koharu" + }, + { + "id": 10022, + "name": "Hina (Swimsuit)" + }, + { + "id": 10023, + "name": "Iori (Swimsuit)" + }, + { + "id": 10025, + "name": "Shun (Small)" + }, + { + "id": 10026, + "name": "Neru (Bunny)" + }, + { + "id": 10035, + "name": "Ui" + }, + { + "id": 10041, + "name": "Misaki" + }, + { + "id": 10042, + "name": "Atsuko" + }, + { + "id": 10044, + "name": "Nonomi (Swimsuit)" + }, + { + "id": 10045, + "name": "Hoshino (Swimsuit)" + }, + { + "id": 10048, + "name": "Saori" + }, + { + "id": 10055, + "name": "Shigure" + }, + { + "id": 10057, + "name": "Haruna (New Year)" + }, + { + "id": 10058, + "name": "Mine" + }, + { + "id": 13002, + "name": "Akari" + }, + { + "id": 13005, + "name": "Kayoko" + }, + { + "id": 13006, + "name": "Mutsuki" + }, + { + "id": 13008, + "name": "Serika" + }, + { + "id": 13010, + "name": "Yuuka" + }, + { + "id": 13012, + "name": "Kirino" + }, + { + "id": 16000, + "name": "Haruka" + }, + { + "id": 16003, + "name": "Suzumi" + }, + { + "id": 16006, + "name": "Izumi (Swimsuit)" + }, + { + "id": 16010, + "name": "Hibiki (Cheer Squad)" + }, + { + "id": 20000, + "name": "Hibiki" + }, + { + "id": 20002, + "name": "Saya" + }, + { + "id": 20003, + "name": "Mashiro" + }, + { + "id": 20007, + "name": "Hatsune Miku" + }, + { + "id": 20009, + "name": "Cherino (Hot Spring)" + }, + { + "id": 20010, + "name": "Nodoka (Hot Spring)" + }, + { + "id": 20015, + "name": "Kaede" + }, + { + "id": 20017, + "name": "Hiyori" + }, + { + "id": 23000, + "name": "Airi" + }, + { + "id": 23001, + "name": "Fuuka" + }, + { + "id": 23002, + "name": "Hanae" + }, + { + "id": 23003, + "name": "Hare" + }, + { + "id": 26001, + "name": "Kotama" + }, + { + "id": 26002, + "name": "Juri" + }, + { + "id": 26004, + "name": "Shimiko" + }, + { + "id": 26006, + "name": "Nodoka" + } +] ```
-### Get characters by armor -> https://api.ennead.cc/buruaka/character/query?armor=heavy%20armor +### Get characters by their armor type +> https://api.ennead.cc/buruaka/character/query?armor=heavy Armor list: - - Heavy Armor - - Light Armor - - Special Armor + - Heavy + - Light + - Special + - Elastic
View Payload Example ```json -{ - [ - "Akari", - "Azusa", - "Chise", - "Fuuka", - "Hanae", - "Haruna", - "Hasumi", - "Hibiki", - "Hifumi (Swimsuit)", - "Hina", - "Hina (Swimsuit)", - "Hoshino", - "Iori", - "Karin", - "Kayoko", - "Koharu", - "Mashiro", - "Nodoka", - "Shiroko (Cycling)", - "Suzumi", - "Tsurugi", - "Utaha", - "Yoshimi", - "Yuuka" - ] -} - +[ + { + "id": 10002, + "name": "Haruna" + }, + { + "id": 10004, + "name": "Hina" + }, + { + "id": 10005, + "name": "Hoshino" + }, + { + "id": 10006, + "name": "Iori" + }, + { + "id": 10013, + "name": "Tsurugi" + }, + { + "id": 10019, + "name": "Azusa" + }, + { + "id": 10020, + "name": "Koharu" + }, + { + "id": 10022, + "name": "Hina (Swimsuit)" + }, + { + "id": 10024, + "name": "Shiroko (Cycling)" + }, + { + "id": 10026, + "name": "Neru (Bunny)" + }, + { + "id": 10027, + "name": "Karin (Bunny)" + }, + { + "id": 10029, + "name": "Natsu" + }, + { + "id": 10032, + "name": "Mutsuki (New Year)" + }, + { + "id": 10036, + "name": "Hinata" + }, + { + "id": 10038, + "name": "Miyako" + }, + { + "id": 10043, + "name": "Wakamo (Swimsuit)" + }, + { + "id": 10049, + "name": "Kazusa" + }, + { + "id": 10055, + "name": "Shigure" + }, + { + "id": 13001, + "name": "Chise" + }, + { + "id": 13002, + "name": "Akari" + }, + { + "id": 13003, + "name": "Hasumi" + }, + { + "id": 13005, + "name": "Kayoko" + }, + { + "id": 13010, + "name": "Yuuka" + }, + { + "id": 16003, + "name": "Suzumi" + }, + { + "id": 16008, + "name": "Fubuki" + }, + { + "id": 16012, + "name": "Junko (New Year)" + }, + { + "id": 20000, + "name": "Hibiki" + }, + { + "id": 20001, + "name": "Karin" + }, + { + "id": 20003, + "name": "Mashiro" + }, + { + "id": 20005, + "name": "Hifumi (Swimsuit)" + }, + { + "id": 20008, + "name": "Ako" + }, + { + "id": 20009, + "name": "Cherino (Hot Spring)" + }, + { + "id": 20013, + "name": "Chihiro" + }, + { + "id": 20016, + "name": "Iroha" + }, + { + "id": 20019, + "name": "Akane (Bunny)" + }, + { + "id": 23001, + "name": "Fuuka" + }, + { + "id": 23002, + "name": "Hanae" + }, + { + "id": 23004, + "name": "Utaha" + }, + { + "id": 26005, + "name": "Yoshimi" + }, + { + "id": 26006, + "name": "Nodoka" + }, + { + "id": 26008, + "name": "Shizuko (Swimsuit)" + } +] ```
## Get character with multiple queries Support multiple queries -> https://api.ennead.cc/buruaka/character/query?armor=special%20armor&position=front&damage=penetration +> https://api.ennead.cc/buruaka/character/query?armor=special&position=front&damage=penetration
View Payload Example ```json -{ ["Sumire", "Tsubaki"] } +[ + { + "id": 10012, + "name": "Sumire" + }, + { + "id": 10042, + "name": "Atsuko" + }, + { + "id": 10045, + "name": "Hoshino (Swimsuit)" + }, + { + "id": 10046, + "name": "Izuna (Swimsuit)" + }, + { + "id": 10051, + "name": "Utaha (Cheer Squad)" + }, + { + "id": 10053, + "name": "Yuuka (Track)" + }, + { + "id": 13009, + "name": "Tsubaki" + }, + { + "id": 16005, + "name": "Tsurugi (Swimsuit)" + } +] ```
\ No newline at end of file diff --git a/images/icon/ch0188.png b/images/icon/ch0188.png deleted file mode 100644 index a291bc178217bbffbb2d17fddc27d8328e780475..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22586 zcmV($K;yqsNk&F8SO5T5MM6+kP&il$0000G0002{007GX06|PpNG%iq009gKZ5s(v z%^&u!rZe{hB4Ps4%Ax6wXPyq`U+XK2`B;CK!s;w{e{Q!*J-dfOv&jq!DUqS9jxHhC zAx}RxKCQ5a|Nku|(FdIhaYXPo^fZ;1aTg19OxoyTQR1^`+OmebRBG%>#fldwTJJh7 zg(%)H4*O8VKK%Tj_7e>m|O9!%uqdl1oK5W*;@!H0A}-{q+*b%e*{9a4%4sS0VQ7z5k`m ziJpQ(rZ$-A&1A7yEau0bc*6X!IKFM9yr-w|Fh(1<0gN0udBLuq&Y!R6_3ED;-)&lu zHmpyu_9i)~uq*)Jqp$oYao={)kUI7N^6O_xziDlbv-)h*rh1!n-DRx8urC$8<@l4|Q8nYpDWZc=SULZ^W6 z6|!xF&J3e<;^HF@!yhx}e|eyqKD@ov5(vU3*JTwlNH&07nG<`qX${jeqjLA|J?o)w zFK$L44Eu#SfqYgZcfI4g7iVs|(A?ZipI5#hIcbJ%rXaxKDcN8ogay zbid|vQHokwzROz`DdE3=c`f~SiRga!_xw9+YWnNfyWca>HMDd6CV4$BhyL6{XyM`E z;V=))&$K^c!)nD>`D-mdS*qD*S2KRo<)UmxmP20AQgoGHo zM0B@AjTn(MD<{9-S5S~>qJ}nY%3m^O8=d&4__!DT(0|~w&p!A3i!rYZ9r@O{ zDrRLhfX9$B$)_2ra)oIcx2fAFegtywgIGx9aMuTvx7KxkA~-x}Ohzku`Hldis=^ zWm!I-lt&3P-E+Vze@>p9H9!B$?fcH2JzHH@=f2={p8m0X|F)u4i!)^>emH$jc5Ydg zA0W@}+UoY`laWskcdXAZwBuUubE3ZG^_-%C?sss;F|huQuLlZkE*7IIAiS zm2Ka=ZsljwCyyLCa^&DX5@bT0xzQ0Ci^@z*&zzYxcY*8_*_oN?DalER!{Y}%+pkZb z9>IXgWJ2a%c^v*GHa1#QU819`(J?Q@4wHRJHaaTO(%t-+sdML!?ICM2A#*Q9>Mqa} z07J0R7#1uG*)XFq*Z{SedS!RC)?}5be-g;d+)F)rVm$(4JawjX&cT(K5fG!w^oItj zm;f<>`olR!K|lz$I`v59z!Gx+=$=RYp&bKcNdT}?hcMXbf`UMBOoz-n*Ds1TZG*%& zk~(xmX8r2$LW%*eFH_VE~zyIigI02 z87PwI)mi~Wj);vF9RiHCkYEU@*g)_Q@X!J|Yazghz^RFW06<8E7sw!TOcVx&&^>{Xs3X27u}M0x=?Ri!A_*)iI_2kHt2309d6z&_;{+j_Q!mHdTDo9dQu5 z@SJ)>`ZFNL2PA3vKWsSwso}wb3JMAe(k%$FWvWqNK|!WR4(OYb2%%XzEz>tuX2DtX z4K0F_=DR$e>})+U=yG8VbGcj|kB2(8xtYaXMAh#Vr*Bt~Y*Q1cX&AniSVytK3g*}7c3k|d_bk0D>Dlbj$LQ>X!kFCbyNjkJp<)Mzkt(MMIO4pxN= zrgLYbaZa^}nuh1GDN;1uI){Bh84ph-69g05rE3T3w~$Pa?lE(NJrhg>BTOIq^2U9OM`)KJ6Nlmesy{&mP9d2 zO9^}lK-6LC=i_!SxpFowIDQ=F?P^>)` zKn|s>aW4^-a&LB*oI3{%N4Qe~?9@#b_o8u5=34)7;NkGbe`^V}0TGvUQw>)bev|pR zYdfI*6ZgN;Tq<=lMF)(RWxhAG0Xh%3KV3^!cOFoxp8^-aQX#Vp0G=3i|4&+i-Hur5 zXrGQ4%1)9D%(>r7Qwz_S7y3(~E(If915lSgj5n@Y{konG0c(h^k_Z zmH*7kev%xKS{nGuj7X5#{g5QO=>u({`~r)1`w3vR$?XeVc|fw{{xX9krKz9Bj$gYx zZmr({cx#(;8+v;JRthjx(v)J9?5={w&+v$Oo>XMk$9pvxi2mol{s)0mTtz#RWW?*P?gLF6ftmp+k1 zb2+qarQ2!2c>kzWhM9rMZ9$xiqyy6BjMi8oOXp6-DF2`e>kid3WoB&P)vNHR}S!bFX|Mw-p#&)_-$)1A|z3>!qoNp%k%)SFC2q{lN2fQ7rE z@l5XN-1+Nti3{B|*;K$4h{D<(kn{ym;*QhWMo#V6VOrt9CU}Dk4;fV~3OIaFKNjan zj}t)O=Izk>IS%L&Y~F9X2eY0-(@QGMivrAp|2?Sh*6%jySpwj&D^hEdXh%c{7Lzc` zp(|HO6KyJB4lw__$9hDO^b7~y@yvzRS8)`~p?F5dbhX>!q*D!Cfu*IH^~jU}@OYs4 zQbO8~erboDj8(HuSU#?v0sNU9&6%;7dl6Cp%S zkcr>tA0+_Dqdk>j6R(Ra#v!shWV6Fkl1nWRVuCwTW)%IWoR^2Fx-YCaREG`+IgI3n z=evr*<_Pw?#pEP4Hz_bG&z49>;1MyD7n)@j`bmWa7)@?hks-88%7zU)NNE{F>6{wj zSF{3A4XjoXeqUG*9#mXcCOvqN94d}@$d>z2_YzXgb%B+sI5=z=4^ki_jze|`y%PC| z*g;lUFtW&4WmqOG)@`F=H;~AkBx6PK!B)AkiUPW<4DRqy7MZTXCMtdFfBCz$%FY2LWTmwtQxvO5%WY9q$4(}MbnMtfyNcdI zaPIQK-(SBiQg#BUAZNm!D~e@<Qu1kKT{RI*4f6KI)59Sf z6yNe)t%}2|t0&)9K^Lt6_8k&Msf;1FwdkHVtkK&F%phOZnj!#bJeS=cUV{=^mN-=u z6&?M6Dhpi=-2v=AA{2wMtkv#bi%e|xQiBQP2xX6H0HCEmZ-;k;!l1b+5F^IWuIFcV^r9UyPKjV-yIUgn0)}O z4Na|5Q%g(ByT-zsza5s7YUA1u>lVM(FC0EL%x*G&qwIZaOHUO=<}0o+$&tN6S#{&K zlB+(Njv`mho@Q@*U=CGu!#~!Hc^s{2_{<%)UfJ*$X_}n%!h)WNs> z@BTM%R85UIG%s|mr9xMX zOI`CjD``cF66wv#Y_nvYKU{*>AX#5vxf4!hV?TBqzEJk&nwBmSvnyQ~aG4jn#woIV z>zk@lmIfonTiLQTM;AQ{uYNJ!53*cVm$J0Q=hTcle$*(5Y#1$&g$t(+R%Be{8_yLc z0b&1@%dX#7->gH1=ivuQ&5mXz zwP}azO4RJV`m{`XLl=R>kd>E}B*Nt*hZR7!Z%*X!xj)2H`N;t%`MCnze$DsHZ<~UtJhrQg&_86+U0tXb4xpF1tB3Zrv(JU2KU$GSE=Yt`+ z6h+rMWg889xB~lB43?`X5Xt8K?PC<>0Zw0W@L(?+lzd8IJoKxw&kgxpfgQ@+CYjKN zRFP!thuK^8HM)TmpV5{lH%-Ahilb|tvU!H_T!C+tZ|^yBL}?Di5vBM!Lv zJ+c)YgKSvCzXkJQc)r}XlCyXyyo4DU3P=?;bkiQOM7VsgM8ytopNS>yWOy8TnPe_- zfqV|3pbas$id!;w*D?BcGqBQoY^zYQUaoh;8)Cu9@!=kCQ^}cV3mXBLUYoq1ymJSe zLb8I;=m*r+Vxpo2a%l~n1oPpgr>iK<1%{mEzBT|zz+?anrc3-UUhi(E55DK4gB4}V zZ9ELYhUb)(dF#1^dRaE8vr0IIWZC2DbR_nWcT7krsP#1r^x0|^s&q@ zUqi$hGMgmWa56az01~l?LVc@sD!in~jReMjZ+2W!GC?xr)(9ctvgEs760CK{he3K? zEPN}ZHBNhpl^Y8T|G9IPQ^|V(+8_D_VqPTSSQ*&d$&&39?NW=ycQtC#fWDr-C{QvM zz@S?*1l3b!g;P~uuvme*v=cw6tjbDD6u6)8|B6i?cP0bARu!mkC`x5 zkX$3l1d^2P^g!S>B9my20(=kv;(muF9C?P z1K8|s)To+4ngRe;P&gpoLjVA+_vIhz2g8>r_f7FErgm4@-e+9%{^#zu=Lh^hR$tlu zLBCgj#(ryd!T#;&6ZP}`xA`A;Kl=Z$-s-=^`hb5#{{{b}+Q-!|`;YxUV87+x=6yJS zalR9OxBtBV*Z!B_ANlw9ANhX3ANu`3I9UIt{x^Q8e6jG;?LUp5xgM_mEAs!@Kem3v ze{TQD{@>w0`mYas?fx_SN9{kmAI84H{h#|s_}}w?-hXd?H2*>VANMQIAB%s{{%C)S z`33xM`G@zF%=Ve?ALxJKdV>35^pEnN-oMQMs{bGRf9!AlAND`mFLpmS z{@MOt^E3PJ*az{?<)7ZavwqkAdH?zJSNi|r{)2xZ{&)T-`;|Vy+gBd%En=(Z?e3LrJ1E#zoesvh+q`jc?Bg!vynt5pck|LHy z_1WP||LQ&V<0{nsZTNCUn6?Rad7PK1Q36ob<|j+H#n)gMEi4Vq;x+0V{Cgi9>{U)& zgot;=HxM(%pcs!3gx2r*EBS%xXs~n8$@iAeDHU%7;k}Ytz3%V2KUax z3zh7Al=UpxL79g#zykNU%oCB~fY+e80Fyag{UON?lfrXhgvXpv8)mdvtB6QO)D^M} zYklF)F^CvXC=cK@KSpf!$Q)8H-FCbq&+QrpncIwciTuGJKZl4;i*v54x7#t%2ad!2 zi2H&3>hDdkL9r|R?!N{`RgZ1$1nktq8r%>BJ*{0aj**-pNli1&{^$qtn#|P=d;6Ul zAmn5`-B?BP{P0>gL@>dTTqWlxW8s6MN(iToFTmD}?w98u8AyW5aZGb)lM=~Q#){Zy zZ8}qm9KQxgvW@_%#jJUK#cLA4h`sH8OV4?HsK8#FUL&0n54Hltv0?A+Q3@$YBh>MJ zsKmwVN_mXD-j1KTW)KR5V^ey_2ESM-yfv0;xupV2eiPv{WU)!@S{;mL$d%h;fn=b6 zJ~vyLmW5WgXl}26282944ckLb+f2#`!Xs_p5)L@ zDK+*24q;ya3%j|0FRUds0iE^trn_!Zci?`7yc>9>NzzDlX5npfElk}C5zu32*$4B| z&>m)EaTq-E6Y(f>)-VcPxxaPv9g?gha%j_*=Fry;Z~4qB;7;I z(witOVNJA-d50;EtKfV^+czFxWy1$G18K<-kBuriW5!6s;xW+=^mqT1!%IhVTej3R z;4-ra+slqSv-M8+I0~{IYk%Exl!2h@jIQia`#Dp#)Yj=MrJ!#ucL{oit!QV>sSH0W zsC`#dIa~6#ClHcy0092&qW{WD zraI=JdE_nejPdxlbB}K7*cIY5@W{C(3y1ERx3TzE{>HF`2#%%7Ku0Q}#_+oQ+=8tq zJM~e&l{lXZ;&AvsVdwhoXQoiq zavl0heO^o_muvM17KQ(p^c`?@t%r!MET3`q%rh*o(LcX56JGZBm6QySv7b?(Lr_;8 zf)Of*KFfUjG74bVvVgSnM0Mtpbk4JoJquoMwYbwa<|%NpB-tJ6+PemO&`%#9Sqss; zd%OhQhJ^Aw!Zbfp19wUH<*(G?un%&A{U!fv)HoXGhpgZ0!Z`jaEWTrTW6dw%8b%c{ z027M&$8n(r3@yQ}-sH@9W^Wh5{*t^D+P~M#89z8gR^zL>Y`VTXI!%(FZ7VNCtcq!X z^Li0=vNrrIgsl#Ob*R)pSZpALiI1z)VdK0Hepn&$w*{o6yO6LZj?04I+Az>9J+d{V z6Y`gZfc;GA>2`}*MKkuBOlQ;;k$c)H^hIa*(dB|3J)d&mXWQ9N2iM8X(V7CggfpBL zVq0R`xJ@@N*o-N=qPuDq-BA=bFD$`Gwl`m>S^QirCS@=k^mVWv^n(aX?$UfDw6HXL z-clYBDB+7ZJ$L+&AY0SU)zbPyQEzR$VMJ#Sq`?ekTfySU(Mscs-HrAKJk#l!?Vs$y zg4Z)MdrmUsze@{?1I}=ZddKj56nl$%7_@uNa>QPGet(D=)-lbenB4xIFQ$vgpRv13 z7rlw!VXLHDf5Q5Dn&hWD@-zIT>1%=P)FSpG-vI2!M1g6cY=CqXyO8l*t-z%=F<+9ib1h|FxY?=O z-rW5{V=m1crFs=5RpLUK6-@cD`pvTOt$K`Gd8thbp;RVCC9KFS1#Zbexv+i4N3;;^ z{RMEEarDo5W;ddRyzqSV3O)~6Fp<5nH>gUawWxA)o3wFRF}}%OTCz9Y2OrIF0ui2o za2G&jmtHNsxaTRN_9Iy|k#t+X!=BVje;rK!0z)Muf_U*;ef)>N4ht-cYci$=?$|uc zNm*Oi*nBy!{Gcb4goreE>QbAWc zAj5kcR4Y@9y{>yn_m0%FBUP{UlI+s&>t>3rCCUSv1nK68uUHpn#!Z#|w(+WTFJ&Y^ zmoDrKXulZ$W(~oYF2_ob@DBX?>+zn4o{~)lETbk&eDRuOL(dZhFb+a>hci;^Ja~E#;zrQH6xvkfcRT?|%}}I^+o*8~lITIoeBwRvH40~QI{A_iUb{&S>VM&W$o@(i+Bv&l@~m}|P;4lR^?&2W zW#k175iHFY{H;BkY0^G`Jv;gkWT<$2ja8C6QMqZeSn(2J)SIB3;aXBXRi$zP&7Y2C z!-ZDZRs7c3w3q%Up~8MG6b8I146GS5%3&CNcC-`AAjwK#wxu;uok@W_~Y2 zVUS?aQ&Ab{Ai;hwdfB5wO{!sYj#Al}=HXz4fBGT<`V=yy$1%nHV2@FUtt zg*nKl!(+cI~kSI=#`fi<>tLM)_?5z36X14Gl z*I0)`drXmel=(eCOE!&>g?ID3w?y;KjKkp_!xT6>&sqT$ZV#TH;}>*w{ecLOli(JI zh-t6ahQ;LxF_hZuN#n0C`YaR8Av|sd78w2RmojuI}^Z zgoPMzTA0$AQ;6^fM6sYzuLn(&OpsZ}U!Q^3A^Qp$MY@kT?iDL%Ng#!~W2R|H!XQ9{ zpG1dMmaVe4dyF-8;1Z_RFM(99TsM`@Whx$43b;Wd6WOPCfaj^C1218A{PYkM)^c z>%3#8S3cz%wBSan$W+7$dKT7<6ZanpJYebq+}Df|_Ml99fots3Ml&{34&q^>oSQ-3 zcv3aZ)2jILdHRyax)7(!TYt-ihSditIj+&g47J)K=kt1F4CpufYAmI&9|2+FnH7^M z(-?_p4W9Y<>y++@toBA5O{<-TeKSWFy-WfRqm@*QSaMK8zyWv$2i^_5JrQSHBQ57I z8O_l}Y(~6^6Y?di;@^0fQen@Hoy)ouEsIS4b5{yx853$xjQKLWGHsp%JmOIHKq3n8 zB3|#fNNYwGXM31Fbl~NLtWV?UaHWk%N3QBEjZj4(xFpTPUoW28*wiz^zlEYIb*pho z!=U$%-m}Dx2;q|a{kXju=LTd2I@aYVaPIAJX1#R}Dg-&QpsfJ)czxLz4oTio$w+~o z(UeYn`*WrK47^@n2rXdM0z}AaveOQP%<=7xLsezhqb&~LK9h@=zyNWq5S81&UtJr7 z>Q_-g{~m}59+LOXwFq-Ah{y%Lt>!eJ2+#snJA$;+2Gmn=DKwB{)p7!=$aDDRO<$2; z5sxf2q*)=hI-BjA>m3M7*A!RcJQbOG3*31l&_!p2M^Hwv&a6?j>d z(vN^Pwf$SnIeFIVX#RRjlo~gpW$;aJN8t*G;;|bJHVkd#k|wZv;RMSUV@~m^8<+?r z=K*xQp#yoY&BHJvVSXcVwqWZ_A${M`K$K*CfleH0MtoVTf~W~J?RNYir0gjPSbQc{ zM=qK;d6bL+nX^zN4d^ot45(|^G&H5@mO$ot>4){tU29b|;RU#V zEw;|rN|Nt+sDxKGT;=m{yW7#EqfYdG~S|vGBNz?$9+VP);3VST6mf`STILenl`Ql3~M#o#yPhN=eUZ$&kI&W`FpB}Jgvp5DUHc3>Ll2~SU?AOTpY21`m?O@xdDgOVEZ!C=Ak1P%3jZCYYU0AI5o6W z9uMs}30TkZ&6RF$7hzvyjIBZT3~_xt(R?U`xQp)fjSG$}EvPu{ielT%c@b1pw*0%g zXyjzy4SL6Z65nCTgC9y3{D)T(SsI_QTuM<}Cwb^sdb#+>db&C5+zXPuzPS+jkOTN1 z?WYf|0eUWanMg>(DC*mq6E$hEH^1wsNFZk#+lojc<1*E#aq{0iAfg88(POJoD@haK zVQ%*EUZ#`u7zA=MoUXyMd4;EPujn??_@CanI-qB3O(Z&SIjia6b{ioS!rxN~DNDU0 z86}-ZQ?3!f$*6NKuBPsC3ptYZaciUaSx+r2F8qn0d`9|9-A&@ZJ}D;7(%g?&Gf~-k z!_kDb*OHysP!TwNM1K1xQy&)xy&wDSlVSEo$ZB|j+4E5+LRW|1VH2VJMkID1NZY3Bfs~?0s(_#!ap6Q$%6I8CIG$SIUMSNx2@oGYBa%yN6U%p9 zVFbQ&eW}|VFTev`fDbx6Jix&ja$ZmIfb|A$j5`j2?M)vl!2YDKVs{*5gB*c3OiEH3 z8f!Z9l+Ro(@Bzh6z(3+Q&)1~FbC0CqZ&pX@-O=iBB&GS^g2%cGbUhwP*Szo%@3hLx zccBE)&dt1S77_87A|IkfkSoQnIV8n)C;ELust!RuJY3$@bU&}W2tAz>AP}WFTu##z zU&%I{YdzqPIIU0-ciw#;rumHB5vXL6i^}glq$i5@`5o?}8aA-XRBHcbYfaWZM;vA^ z4yM!icxD{If-pk(seo{I+2vpzcK(3yX`G@;1QY_gQoy=e$h1L+>*n-{J_T0yHQ-xf zlb|dhft+y5Vz0>qGG85hoItjEZ8K7OD4|>ABeWE=6g%^DgJ14}&ba;r5dB18LX&b+ zjvj!*(&osq!pjyCQ|RC*TF(NosKEeZ?W`%!sF~Q`6dQh1hvEOHlUUE`dGAPahgINo z>a{Pslk=Zr<*c_chHa1GbxtZBMA{*bKV`#KQUDeA_fX%)h3Q?~plm#`U%ioVc9VtK zQnO*X^Mf+hUS&gpmb}`8VRp1eqnKtLYmQV-Bjl?=y4Zk0 zZ_|UW%W)geS>ggPp}nM>wDZ<##V*m3BZzgSiFE5qsCkl)`2I9=l%cH=3Fa3l6>o{96pSWlF3x z)?eIbMJh4a4&QrHF7iMY-OY>waqIp&e`mVULHscStY=HP&0^bZ0spT!_D;D{fWjV< z)r@W~m^l_w0}N5KUFx3=6>}_l(JoO~r}^&&mFeW*x)q!buqK%@L16IcL)N_5wCB7V>S79&lux_|eV_F&D!oZdg37L2-M9Uh zw=^+nf@A%QSw6Fw_!(Az6v0gA*z}1O&c}~eJz}ik_Ffcp$^Az*5VH~QEg#aaOBN&e zJ)O9EC+^{v`N1GxyDE0SKJubv{f}@qKiFOsez&pP#z^*%Prr^yfoL%#A^ANW15Zx+ z&W#~^bLx6s7MrkhNIhf0tI;*H#eP?%T8{-K9vea{t+1CuH|&*)Jj-dcd`KP#fmFF} z1%076Z~cH7ZD7-!NI_C*w_^O|z^T}V%GtC<)Yb>$f+K9Wk5)#cMa3xKt?aob()h|@ z6zDlM+%Ab$iKv!TBIw7K8QVt1v?Ap49l>g|*YY(9k6+DYA&6ExFo0fXvomM!lmxec zJ(re$@y`b64#V=wxHqFop}GBThl`X>B({p+_DIl!CgTnOS;TDGnl)j^^a5`PSt`!v z!>oHu6-ABk50fOjy26miEM*#no}L1;b^Uh;0UApfWoZw(cp3a+T6W1*`hb=~so~Lg zgEJnw3nkBd%PA<2XNeZ0-c7|OpdR`#QTCvKr2>iI^FRE5Uj~GyIJIIdcm}%2z=3_@93}}8=vckCHU7C zxicI}JUbPS95skluEI1RYl$C#?A`GZ2q*jZ_MS@cUt{QOIc=KSVha+ajJXx1Iygygb?H-U- z8cKBEYI&PISO1Xv4U$yxewIb1D0+Vu=29=Q56`q1f~j!4d!3sSsNYvW z`X$+e?-4tfa1SW#Y%*wT@HXqEu&_T6e)oER1iFx(n?DMc20VdbJQ*O1GVrW|vlAvS{*vB4m34R%z#ZokfcaeEdlOdsW5SlpZb_mN?Rw)t%>6<=yz?jfP;^)Jk zCc@^Oe@KtwLh)QGQSnww;_6} zP8gkGeYtfO%r!9F`tsvaT?hifa8)YA8vVM66L|2?+tx*yfHo|+NLcez=!AjeD!bG3 zp1m{f!SDXKurhYWGV#(Hb*;-@Dl8P_3wx;7FvCZ?4jn=>YfHkUodKHbxZLdT`At0A zU@ap4Yov6hgbX-YsuS9uXE>eSTTIjmAw?$u zHrJ=f8~`D)!eLx$v%?uI32qjQ{}Zl9mJSzOlH2y>xb3TWZ&*`O)N%nEZo=DU=p3Xu zx$qhuKs1O5?l@oRmx$Xw#Uw6(ibJQ@%{PP9A_R-Hh&PPS<;uXawb};#F5`;d z3e4B6L9l9~98~+@1=SD=C{8v*xMsTy@bfKci4BqH5z9`Z(i(|kUIC_)dqiEx<=m@h zuZ#^Y6j=a0Ae${+{S@K}k+YnU&?&B|@toTx40k7F|KV|M1IuO`e@QUk3TEBN( z+|ZxhQ&U<`ON^av_*3~7h|F8Q1j})V%h%L-6%?cQMiEc}XlXwHFS&hU-QY4>3p7D?w`9fIE%?oujL|^mO>TE0{pQeyjmx@0U(; zOYuIHkqp8Qc@RRxwp6U~|8X0$8Lbfmc1UtKBEQ~$8&tvD$z)G9wV?49Ht1-|rCFII ze3q27)(A!1obQlu-1?%vy{+o<=&cDi*z)hrRzu}?38dk6x?cq0U zP~{uRCb#;X&E2JfqyqL+PbjF1+-TA?xbydpxW??Q4@?mRfUn9}Ht?1AvIV6clNgvh0%&$xa|UX}Q!(hNL(U(N}a`F(sDdkkiP z4W87@mMOg+$isHnM_h7gfN=7Tu=!>TaF1d!mc@zSmu~#D5YglG^cZ7UYO)Nzu~1kI z0F(U+7NhjQ_2YaMC|^R@&WAIKwalt+Qb2 zk2E^IaBf;qi074(dhS}7TG<jRpqx`SPD$kC@v z#?PPlDt6X@lCiv1rUV+g>FqOi*d9s8smZU1nd>c+FUOx9zcmJC$aOw*pDk@*8~~wQ z3v#)9HeteH?B4&XYstMsdpk7#+G|eFlfuXc5^fp*&kG;C2`H$ik&{b*rR>7iu-xE$ zdH(phSa>|ad9)l@ss+p?7*|)02Dy5%rOgIRyR`e4Ublkf6q{Pwg7|t&c^s3T8Y3#A z#(h4{_5f1)Wt~Cff5}W{107W@ zc3%B(P@Ihp$q^*eVdbx1;Qyip%RwY;7{|nsm2$8o_a>L*m8I@OX$0+P3K#;wpxM)# zymT1WM^a!+17RK__bUWbnPoagp-VC5hlv9@AoUf0=2Zvnx0C#-+pCmH+Na8{9b6dn z4<#;;Z>WnLpsJG2$nfbDF!JiQ*be&pz)OUJO`7_w*sW{;tjQ)AM0UuSqAkQjI(CeY zgF;A`%2Jjh<{c6XrAF{FHwjl(K|-}jd<)_k&EES&TWMfH@a!5~{i@}F;#7^hl(Gzt zjjr<$_rkBk-lx&siM!Uc#pyEk(15<}VFzIk}ISoOp>To$4e?2Phju^ux#OZ!vYcj9?s z4<1Bve0#Bo1y~NekaS)dWdd~BGg-`}2yx}>rxt+Gz55r+%4$U|rA$=ygm+~B5g2P~ zPHCqR0-TT{Bm7)%W$%lU^Mbw6{mLHL2fmYXa{sIXRaS4O_nc}PF^0Xrsx4+lxRk_z z?P38*E?uMY0tZ*&9VUn3;zWOq-+0|r-QkP}Id zN`f%cHKe?HxZt26YQGp^>cg#?nX)}6c6q7QOt8S)O(@e{R&AiW<7YPM>DV%o`X3O) zQU2xf%Z{7rpW5mH%_E;I%!=!Y%O?W^uA!}R*x(2dib@6fCFgIW^C|7A00EDl-9t;* zT@3%*@5yniyL~Aor24869)ux^D1o?k{OOcrn=A7A=u6G7mtYCv>9XKleLmS;-ynU^ z<-=V>UVQspFlX$?G-M_!e2+56!59c#{GW8AC^0^GRB^;3&c#3V+xhp4Z-Mda~ zl(ts>RlOuRNuQdb>Lez+l0nuMl>}sSQP}|7GLtB#CRl#NzgFo1EiZ$}x+V4R0Dvu! zYB&EnH|xUZsd}us7zf&m>BXpP0r7SUS5;`eGvVVivHPs#;cT6LW|(9iZf>m9oBm=_ zcV|Q(Gt4J}rJr2c-g3QH^w@=aR7V{TcwIP8>3>t=Jd&+e=6Au`Dz~H>iYEW(`N&fQ zl`$qNpfq>ms;l*9Bhj~jmv-)p6$Kt8nBgo!Kpl!q3jjMJ*R%S1x+PqRsz&jtl@|Cn zwrf3Wtcx_3VGwv@1NDc?_6pykrT9PA`x|&|J4r*TH57dSjclfS_mDd5ngWf*lYv0K zw`4H&g;ei!(__|v&2lkv59u6{Vj(_~?a%_Qt9`ru+U2NV45{_Bdm$6RufVFs9(?Gc zZ}3kZsZ7n}-FWEBAME9gPqnuOnY!<{_rd~#@BT$*VwP>B3Z@O9IP_J)-)JW_^7@@p zUz15{|BkKE8P#K>916Xe9(M*GIk-C*PqMvB7Lb}`3ErL6} z5pwEKnV!mg?zAr;N7LQWr+=C_t`D8EEMK4@D<~AdwcAZ*%mVUQJTy!q0YevvMt6FN zE{KOjhDkgM0|;9in|sb+gn&|qCY}r;5kidt!*3dntdZLk;ffqsLXf#1d z>p1_!)C9bRd9+!%93xcslSFPK(Fm-gh~30uD~n--49EV}u~U}t68$F{F$o=U&4s$- zicv3M98<+GzL~a2Qa>sf=ik7x0YV>CO%kK_pRH{*%ovRJeMHXy;J%>Fhk65l^)rlOs&XY@IeN}+#*Ro4Gs zynRB;t)S=o@@;SLtK-Nt*m~baww4C{SUarD7I)H?Bi&@uGn zZm1hJ?ES%(*bd!h+7WY4kf@d}o`=aOB-R$i%omKn3ha=*x>)bAZ6z_#brxz_fhKu< ze@VITA#C(my>DAjeYXgA@CzEJ<$e+C^(S$q`d3xJaK_`QmF^Q3G(JCW^>aD>2$5{@L%avZX5;*uh4mJ=!3caIYec-Dr zu|)H#bK&Rx-^CR4WoS=ppe1?LrB3Fkv3K63IobGw*1`8)u}Y$U%>GE%2W-n&eS-B- zrVvGwvCLGCha5P#TI&pQFi&(>6M z2u3b+1DDTD_QnHpbuW)5jii9kF7@-Pbfc!0t$X9jK-pNcXfCdKc9PaX%QNSz)2ymW zhFN?-DBiu@xJ?$-^dCzQ8j|Kmgx&vp4zy*WR8x!yR+pW%)931UH#|(#4w4En@qzY( ze0c>$PM=k(TCWq`QRU}y6Rm6PtE3`K%qh9nxBZLC)@8q2aq`c)kx(W!Ja4>;_1{np zA@0Y}r!`0q30p~VUR6(IY1M)0bXXkLjLQV4<^*ZkW5&j8RD9Thufk>(Y)#?Qx=I>M zV|CYlYcpYIwH5w-Dx{YO?H{c8dvEXVc8^5=!IJ#pqGUSPGVP-$1VE-5kQj+hjrWnp z7c2%N0BM?mPLca^k|f>)6De{c1~N)Z_reEPd50*aM0)d>;S+9!OaP zII_I{{k%Dy4%`?4M6PE)6xA5~^Ft(n%!pU%WVJ!2G}xnU4(COMZa}zgS+7`W+?s{6A-JGvaAjK)-fKRIJl~9hk7&( zT^nb)8vCMEx*nkk=6&1{Nn(JdxtQJw=H8|ei}qGxf?2dJpj>&PPMe}?aC?%4!G;aVLF<@yOLh$8Xk*M0zhl@m_kpi{N*E`Sq6 zc;@W826T!iRlJ0X9GYL-^^}%!y)o$6-Q>CKq2dPA_+p6^SXTG}9vI>0l37CE@`Ikm zDOlF|;}o_e@KE7aFvgl^?G{q*9KM0&hc1l(z3C8i34ilCh~$t(eX|!yLT1lyN2abP z)cCD(o}dNH3W!|k!LEJk))_H-P|CU{4dOYLZR}WfKBq@Iyyj8z>lD+GZtmljR%^oA zQOQQ_@l~APxcG+->rF?4m@dGKTq?E2Y$I%IlF73bBf3zSJMOQhuHuLbXzJg*DgTgE z(xb9;j{1zUs8CPv3n1eM8=I4tG*gy8&+@#_0liy%2va%~5t#qxe}nAUMg7jkN;BSE znX|&E9=IOREqD?mH&8ULjw`KaavaUKZUT2eNAerrve8}sy|&e8jaI-86!Q#88V{kG zEZ>{JT41}65I(Mm>e-&R7rf!7thzP<`oZ~S+7FT2WQX+~MEH&hiDaME*g9JSTDj*E zS%p}$1N4?V&IB@-{m|Kvy-mI93y)nAsht3f^;GF&*rGAXN!tc@n~8?NKmZOgH-#Q2 zwCe~PqT#JST`!mEFmIgEkK9NDW&ToLf3cEi!=WlkC~i<_=Z7EvkZ-32Nz(~-kXG;4 z6bOkC!u!jEzWDAZh2nk2o01teb=ZzieVnOcY3c5l*Nk-{sL1kJ`YM*~oW`bgZx(Dm z=$_w*G$>>sTYU!~2Dr%AV=H2ifZ0G4Bxx%&=*|v~KkA$hBVBO=$!g=>-~@ILwoy3B z-X&~xTI{{KpE~zGON2Gh>IW$QS`WZZdTb~UQCA!;P?i#Foi@Ru;PCT(LzN-fy0TH!e-Cpy;mO4U(RAVBkLHv{VZqJ%HU ziaCuYCBoTFh>Wm`&A*z-_H^H?SPPv8wu+gIFOfXZd~~nE&CdYp^ujO$?b-Q17F4uo z9wc=rNRLy@149_S+*xyvh;{JZ(r4E^hZETPQpLzo5;g`oDeazXH@?W2)YYE$8z`aB z-3)#yE!>jvdSu5AMA7S;Z-b0ryFOT4S-HJ zh)ExE&WgHQdh?K#tvVU)Er45dR#}G8XnTCDb+>ItsBD(1B?r?v&=Fg|B28Kf;G?@! zy>b+Ql4DR_$=l+C3{zgb5Gj*|#RO0OlJFUTo-F(m$kVXNf+cN=brR?+fCE!$oaV6; z1ssY+#v<(P?Ha?$s6yiFI#jq8zqdLxpm5*)H=EKMVar1@F1;eyK9I8q@HG>WHv*b) zB)P-|oA^sXwU8%zY`}5yytaP}qk&?U zz*{oBD<>yxY0O@?wXp|I(Kt;*0kAP^&cAvR?ms(A&zzez0tbpq+T+lJ8NCV46<&Ws zm4cr_$t;r?{#~}^wJ*HMd%0+K#U>zDoN>>?iYDqu{UCP-+mE^jJPgMpAiQ@&35-GlxW$raJm{c{n7|ojU13DqK|Xak4Mvg4;mjIH0#Z32Asr}2 zvE-`Sl}tS4kw}L-xFizV<`!~*0WZyxTRzkQry=ez%@L$|1%_=$j;i3XW%zTCt39uB zeUo{Nd`oVH283rlG43&Wn>2B5-b-ydgPRUYznNMd@=}M>r4)+Gc9+rW!gkDM1n}+y z$4;`~)BtBv6}D7d;D$l3)sxFzact4!G(x-^%-nP`Y4$zvE1&7@P`z+n>RV>5Zv8pk z#J4g9yt(XD^n`C?oBQKz{n%X2;hS6T``{lw9a3!Ncag5UEw7bO?57AA^PI=x9`HUO z_#Xmd5$6`FLnES8#nV?Xhx}zD@FZ6h=51$e*0)eQphDwezPEU2wjbLHz*<+f4Sj)6 z-OTJT%-j})E3AV`8?(KCFkVhh-lknxIK&p?^aT&_rgpO{SGM8lwB+o`yN=q+f6UZu z_F^kg4rFr&tXn}A2%fil?8sxFyffRP4ifvPlu1x$ z(7-`ylZW;7vBq6-Wx!d7Y>FpsACc+V?`XFxjw5>DC9UhiscB9<>9~M?zmWVhoF^;o0TBp^BK4c^C^)BDEDC9nIsm`XKAag9z zV57Z>FtL^k?Zubfds$36Nt@xmQkQ@g+tHaK`O&F@G$_+4 zXG{%Z=ay2ao4;V+-M-r$E>*Sq7unm7%C>8Of*6L5cuN+Y;4pOfU+)piLr0gsZgTPr zm>5XBlAl#nL`W_(I3j3)39tqv<7MW=p(z8S<%^*F`Ma-yC{iEumc_13+8U~~Jw*L+ zn^$9GJ?xrF>;6x~_qO)@OETTs}K)DvvM; z8%CClSyP@$-W&4BTTZtL7AjN@8%vxD{dJyiF>8xj>I*sxFLLXHf#*)2UJXU>IJIFd zA+(a4g4$^SG+NFbdV||wV8&W(D$wZ|(TGq4&j^3*7?*ue zCBENh2YpV3y?_e%WO63Rgx0%KdT}{B9@pT)Yo-BHq)#(~hoShrl#XA8xW&jPlzqp8 z_IA1A@-X>=E+4*;>5_`X#jj{XL?JuG$(oI^3u2&3VY1Zcsa(ojqaFmeC^lKM1@!~K zF7WOsFE*VImh~@Lhb4iT+O{l9qDzmO|4Pz$G+B2==;Qp^{?w0*LUC$B1@?XCybFiN z=dJA+aRIZzk`!^D!gu-d6ApR2rm(1n2RvLP%`@_JDhcK9gWV6|YhG@=pBxP>1w%=J z0~|4M%E$~u%UQ-vY^VdtP%%jF;+b>mG^|N|miW7ILBM3QXGSfn z)_({Oc+nIC@pn`xCi3aPA{-XWxhS#nOV1}PSbxR7TZ&rvHo{+WLL3jm<2A{%9rAU8 z&wWKp9kJ@NLpt8rmW-fezjk{04AF6`wu1V|X%dY$_j)P`{Tl9e(^S`jUz>s{3{}p1 zLq%G$Fn`Of`WwM{B_JC^c@bjNC!y!ACZLUh|nOX@6tp}d-e|$Z%HGI3s)lV zIipYqD$4A9{|wen2de{vDp2EdB}c;A#vMRI9jirPk^NnwuJAVj2;M$ESqUK6e8}>CARfL=lM^ zLt-vT6UZ%=?x)wWia}WsY>gG$Oz%J|(cm~>5KseLWwrr}T`VVZdQ1kHf{n|-8D~9B z>LHnJ!GG>@>x!p3z;ZS*;37_~c9d8%g{c9woG=8AU5W9@XSXzIi79Pjsip0=x*ao6 zoof%L)SNG9qdBe@@Z$)&z&f^az|*UVDcd-Ey+20^{sK8h_Z5Bg#44ANhOvz&6%5L|Q%FTiQ1P_*FpeY?ENp;RmNT8NB zwkH05f3FV$RsyHSV*+sL`(et+GLt7jhll68e}Q@p$Wgs+S6)G*AsA543h%KdF4D;! z#6x;&5y8xP@GRc9+8@Cc2Xr=Do_ua&`M87wXhov@oN44iiL>%AZ<*hk;Zs$jKu7#= zFDtl}=wEG~oNbQ4P8)NxT^B}#Ys=q+L!sIT#>GI}CZ`e4gX)eFbko4^kT~^m?TnkJ zaMH51HIfx+#j5;-@)aDK4b@e7K#K4N<9vw%b`6upl3813Z5G2V5!SYDa$ZPHc;Nl( zxJDeskdkVMIff|gmOapN-lLI0BV`8zYV(NdkRi^E$=UFp-lM8$IvBaYO0*f)pGpq8 zStZI;pfbX}u4n7Fw}V&E6+&fCXW@CY0{egqCH$|nhIeZTYGvybecSYfkKGBZLl>|c zII!?I8f~xx@=FoRWkscI22oZ|tDm}b(w^a&TomU2($&VTSeu6AFn-w1Aqd3pJQkbR zCbsd5GY4BD=}A!u0bAOa&74}QIS8^cs@^dV>n;C=(JJp627dWz$Nt(T`rtjqX*KGq z-twB2?FNIiTfdNXC|t$nD9}Fbrf}^*7_m9{tHk1<*}!<@7B!rFFJwK&FSZ^R8fcCH zbF}(lHR3akiO-MDj$`iGc@#$!dIJ34(>+wGBWNB~)Jhl(F#Gatlpr;slhD1(t&<)U zrNdlgIfas^Za<8dkiTdIK{ten7)M_MBGnV?VU0>|l@=fNB}MMM*V-yeTnkwm{4g2J zMl?-uxDQWu;-%6N>HBtvT$7<{`GYC=aj#uuTH0G_ZX6}Apjtc2T;XhM^gsHyt;9h( zWJUZbl>oxbKYJ6bpbaX@Qh{-YC9j9%sEuHE<`t9IPdOZciCi;dDxuAVvpP~UtFrU|7aXTY^^3b0CvP91=#Nwn z%UR+`9~!Ab#CuZaUrbK_-egJ;q??fdz2p#uQx9IG896si@t!BvJgfG487(P-r3Kqo zR-1llh|T8ft{;{qaq)S$MGF82X9}{o=)(HTED7J~lNggde6=Ui6jgkLh&Be$ye%zN=4ZaQ zn`BV*&PFV)rag|xL10Tj(}Go5ATD4#c5j<@T04tcp@{+wNO@REamg&pzW&3mi6}0-EZPQq4h&sf z6+e-?bx`HX!5KN}^f5T?hHEx};$0QYf(Fr*IFkxk*p@Wec5A_P3VEMy;K|iFV?i{q z9WH!)U7ocohvbM~HxN8HI}&=(PD`^?$~h*QBRB~5$zW*T{O;YAP?2TNiD)2)aF zk?31cDpv)@Kqb5l&LM~#NX)?q-bk=31R8MgjmH!p{2*4c1E2A%IRaq4Wm41cnRv4C zp&{%gB%cO;3;UL-h)7N$Yz+OcH6Epwm)k5s?g#tEquDOrG$MJ#q`-Dn<7W#$Zi12s zI_R@oE_U>Ix6}aiRceA)kt&MEzK*|nAOuRqV<4hL#O;7~fFBgBcu3Wsavem+E4>|{ z_((6(;o1CP;DeUA)@bs7i9Cn7?)u-f2n_Zlb8>o&oU>tj`?G}OWaCdw6TWF6ot}Cf zcvF~L7icPTzY=ghuYw;1sG71hlj1#ROM|mtd_>!HLr=EMcY>_~Y#gk}D>M%JZy-hm zpSa)Td<)PABAO*zAO5!D^N%`T9nObPT;`-BKk4Wf1ix$7bHrVUajo{$)v@K#a&6oq zX13k5g``buujv76 zPk{U5e?dD2R}-k%dEdN;arP*>nIl4CbdkU(ZC?ToP%&pPj+ik|Ac%)K>2%58Q+cXS zR0ACBA0RHN$Z|*tzP2**FI~{1OOw=LjL3R#S_(&*dI52(%hC5I76nDn_x~DCGbEBd)XqQc&Rhpq|03waR*{@kF>=0;{e}j_celFaWNx^7dLW{2Hkn| zxy$Db z-ph+41m>Uq<1T4t#1j)r0p%quj8~Es{>v0ZVdU&4sqRv(Q>z`_U<5{2D=H|18lcYN zg&+#GHFtIK>+vHml);o(!c-Dlp{I(}l4^7H;ISf|7G92YVih1+4tJ4!y&>SW*~Or2 zQ>yzB#D+W&NVasE#64i2?5FeiM|&mbTPG zt>D@iGlHEq=I+aFx?3}$qy_uBd5REB6V-iIc|U2Jry83w_Sd=pOi!($VJ`_j3E_Vw z8r8Mb3D9}0HRmFlr5KZU$(Zaln86~Jd4bHXJkN;?CH>E>EpWH2#L5DK*jcvsA9!D1 zDmLeTB?9IC^&7VNP_&_wL337c^JIrl@oCvn8oyeW^p^Qg^NRz`xsM&Aqyr;hTbV$) z@YH_+M(+iJik;&Bl-I4L(c@?=$lzAU=1oG=<&w+K`2b;-ae0LvZ@y^lND7K~DHxTQ~!`q;VXEu)yIvndsoj}{E{(`9cw8WPnvrWAp za^aKkOBq$ECk@nZh1^`a;8i%zGo2DN>uTU_Fx%KX(T)+FGVSH3jo6jiDDw7`y0Rm> z<$}?LK3Sx6J55o@yqHA}^Dt)@Z6-7hG8>jVJ^e3%_XVY$v>1*%J*yr^<6l~i4-9dc zZ9il09Ul3G;1bEGa1~nCzZw%WfEErgn*hg=Qo(E?r7A&Hi1$!EH|uVn)_Ja3m=jU1 zu_d2}o)s*P3(x?|)t=o5___gCqE#i%N&5?VL zIJGC3n2UCSmazi>nFWHvV^PXMvUVNF%Eyf9A2M9Kc6C~VSW6IW!>dc`3gf4ZZ5m zLY=B7oCu1eLb=UaplBP60fDLQ8ViRAg7ii^cV}HnX`PpFM|_0sj62gDHQ19#!vIC3 zDI;hQyL6x9-p|S6&|=Z`#AfcthmNQDf&Q+4L(>LutqucDJ_<3XOcxeW9K*P5vL*|X zO14BV^F^QQ4C-X`qBJe1b=Wdj@|u%S-Aq-Hc2wP7720Md65R0ZpvXj9@-rF56e`09 zh8IA`jy^B8*!VpXc-E&SS@3%R`M7z^BlS-}uh9KpQFaHgB(PsC@H{mr@@eV!}c$ h>}(4i(T5vm&*_@%004PV^?d*U diff --git a/images/lobby/ch0188.png b/images/lobby/ch0188.png deleted file mode 100644 index 8d650292012dfcc102b964e2a8cc5a0fb5538355..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15695 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%0Aixd&>kA1t>RzXsPNawnF1P75#9Nq6OyP?QxLW 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 K1+{ { + res.type("text/plain"); + res.send("User-agent: *\nDisallow: /"); + }); + + fastify.get("/buruaka/", (req, res) => { + // eslint-disable-next-line max-nested-callbacks + const endpoints = subroutes.filter((route) => route[1]).map((route) => route[0]); + + res.send({ + status: 200, + uptime: Math.round(Date.now() - process.uptime() * 1000), + endpoints + }); + }); + + for (const route of subroutes) { + const routeName = route[0]; + fastify.register(require(`./routes/${routeName}.js`), { prefix: `buruaka/${routeName}` }); + } + + fastify.get("*", (req, res) => { + res.notFound(); + }); + + fastify.get("/buruaka", (req, res) => { + res.redirect(301, "/buruaka/"); + }); + + fastify.listen({ port: config.port, host: config.host }); +})(); diff --git a/lib/fastify.js b/lib/fastify.js index 0f39c30..ab277cb 100644 --- a/lib/fastify.js +++ b/lib/fastify.js @@ -1,5 +1,3 @@ -const logger = require("./logger"); - /** * @type {import('fastify').FastifyInstance} */ @@ -48,7 +46,7 @@ fastify.setErrorHandler(async (error, request, reply) => { }); } catch (e) { - logger.error("Error while trying to log error", e); + ba.Logger.error("Error while trying to log error", e); } fastify.log.error(error); diff --git a/lib/logger.js b/lib/logger.js deleted file mode 100644 index 9b2c7db..0000000 --- a/lib/logger.js +++ /dev/null @@ -1,12 +0,0 @@ -const Logger = require("pino")({ - level: "info", - transport: { - target: "pino-pretty", - options: { - translateTime: "HH:MM:ss", - ignore: "pid,hostname" - } - } -}); - -module.exports = Logger; diff --git a/modules/classes/character.js b/modules/classes/character.js deleted file mode 100644 index 371156b..0000000 --- a/modules/classes/character.js +++ /dev/null @@ -1,314 +0,0 @@ -const chalk = require("chalk"); -const { domain } = require("../config.js"); - -module.exports = class Character extends require("./template") { - static data = new Map(); - - constructor (data) { - super(); - - this.id = data.id; - - this.localizeEtcId = data.localizeEtcId; - - this.name = data.name; - - this.released = data.released; - - this.playable = data.playable; - - this.baseStar = data.baseStar; - - this.rarity = data.rarity; - - this.armorType = this.fixArmorType(data.armorType); - - this.bulletType = data.bulletType; - - this.position = data.position; - - this.role = this.fixRoleType(data.role); - - this.squadType = data.squadType; - - this.weaponType = data.weaponType; - - this.club = data.club; - - this.school = data.school; - - this.imageIdentifier = data.imageIdentifier; - - this.equipmentType = data.equipmentType; - - this.tags = data.tags; - - this.region = data.region; - } - - static get (identifier, region = "global") { - if (identifier instanceof Character) { - return identifier; - } - else if (typeof identifier === "number") { - return Character.data.get(`${region}-${identifier}`); - } - else if (typeof identifier === "string") { - const normalized = Character.normalizeName(identifier); - for (const character of Character.data.values()) { - if (Character.normalizeName(character.name) === normalized) { - return character; - } - } - - return null; - } - else { - console.error(chalk `{red Invalid identifier for Character.get(). Expected number!}`, { - identifier, - type: typeof identifier - }); - } - } - - static getCharacterbyQuery (identifier, region = "global") { - if (identifier instanceof Character) { - return identifier; - } - else if (typeof identifier === "object") { - const { type, armor, damage, school, role, position, weapon } = identifier; - if (type === undefined - && armor === undefined - && damage === undefined - && school === undefined - && role === undefined - && position === undefined - && weapon === undefined) { - return null; - } - - const values = [...Character.data.values()]; - const data = values.filter(value => ((type) ? Character.normalizeName(value.squadType) === Character.normalizeName(type) : true) - && ((armor) ? Character.normalizeName(value.armorType) === Character.normalizeName(armor) : true) - && ((damage) ? Character.normalizeName(value.bulletType) === Character.normalizeName(damage) : true) - && ((school) ? Character.normalizeName(value.school) === Character.normalizeName(school) : true) - && ((role) ? Character.normalizeName(value.role) === Character.normalizeName(role) : true) - && ((position) ? Character.normalizeName(value.position) === Character.normalizeName(position) : true) - && ((weapon) ? Character.normalizeName(value.weaponType) === Character.normalizeName(weapon) : true) - && value.playable - && value.name !== "???" - && value.name !== "LocalizeError" - && value.region === region - ); - - if (data.length === 0) { - return null; - } - - return data.map(i => i.name).sort(); - } - else { - console.error(chalk `{red Invalid identifier for Character.get(). Expected object!}`, { - identifier, - type: typeof identifier - }); - } - } - - static async getAll (region = "global") { - const data = []; - - const values = [...Character.data.values()]; - const character = values.filter(i => i.playable - && i.name !== "???" - && i.name !== "LocalizeError" - && i.region === region - ); - - for (const char of character) { - const charData = await this.parseCharacterData(char, { allChars: true, region }); - if (!charData) { - continue; - } - - data.push(charData); - } - - return data; - } - - static async loadData () { - const regions = ["global", "japan"]; - - for (const region of regions) { - const data = await ba.Query.collection(`${region}.CharacterData`).find({}).toArray(); - if (data.length === 0) { - throw new Error(`No character data found for region ${region}!`); - } - - for (const character of data) { - const charData = await ba.Utils.getCharacterName(character.localizeEtcId, region); - if (!charData) { - continue; - } - - const characterData = new Character({ ...character, name: charData.name, region }); - Character.data.set(`${region}-${characterData.id}`, characterData); - } - } - } - - static destroy () { - Character.data.clear(); - } - - fixArmorType (armorType) { - const types = { - Unarmed: "Special Armor", - HeavyArmor: "Heavy Armor", - LightArmor: "Light Armor", - ElasticArmor: "Elastic Armor" - }; - - return types[armorType] ?? "???"; - } - - fixRoleType (roleType) { - const types = { - DamageDealer: "Attacker", - Tanker: "Tanker", - Healer: "Healer", - Supporter: "Supporter", - Vehicle: "Tactical" - }; - - return types[roleType] ?? "???"; - } - - static async parseCharacterData (data, options = {}) { - const skills = { - ex: [], - normal: [], - passive: [], - sub: [] - }; - - if (options.allChars) { - const charData = await ba.Utils.getCharacterData(data.id, options.region); - if (!charData) { - return null; - } - - return { - id: data.id, - baseStar: data.baseStar, - rarity: data.rarity, - name: data.name, - profile: charData.info.introduction, - armorType: data.armorType, - bulletType: data.bulletType, - position: data.position, - role: data.role, - squadType: data.squadType, - weaponType: data.weaponType, - terrain: charData.topology, - school: data.school - }; - } - - const region = options.region ?? "global"; - const skillData = ba.Skill.get(data.id, { region }); - if (skillData) { - for (const [type, name] of Object.entries(skillData)) { - if (type === "id") { - continue; - } - - switch (type) { - case "skillEx": { - const exInfo = await ba.Utils.getSkillData(name, region); - skills.ex.push(...exInfo); - break; - } - - case "normal": { - const normalInfo = await ba.Utils.getSkillData(name, region); - skills.normal.push(...normalInfo); - break; - } - - case "passive": { - const passiveInfo = await ba.Utils.getSkillData(name, region); - skills.passive.push(...passiveInfo); - break; - } - - case "sub": { - const subInfo = await ba.Utils.getSkillData(name, region); - skills.sub.push(...subInfo); - break; - } - - default: - return null; - } - } - } - - const charData = await ba.Utils.getCharacterData(data.id, region); - if (!charData) { - return null; - } - - let image = {}; - if (domain && domain !== null) { - image = this.getImage(data.imageIdentifier, domain); - } - - return { - id: data.id, - isReleased: data.released, - isPlayable: data.playable, - character: { - armorType: data.armorType, - baseStar: data.baseStar, - bulletType: data.bulletType, - name: data.name, - position: data.position, - profile: charData.info.introduction, - rarity: data.rarity, - role: data.role, - squadType: data.squadType, - weaponType: data.weaponType - }, - info: { - age: charData.info.age, - height: charData.info.height, - artist: charData.info.artistName, - birthDate: charData.info.birthDate, - club: data.club, - school: data.school, - schoolYear: charData.info.schoolYear, - voiceActor: charData.info.voiceActor - }, - image, - stat: charData.stat, - terrain: charData.topology, - skills - }; - } - - static getImage (identifier, domain) { - return { - icon: `${domain}/image/icon/${identifier}`, - lobby: `${domain}/image/lobby/${identifier}`, - portrait: `${domain}/image/portrait/${identifier}` - }; - } - - static normalizeName (name) { - return name - .toLowerCase() - .replace(/\s+/g, "_"); - } -}; diff --git a/modules/classes/drop.js b/modules/classes/drop.js deleted file mode 100644 index 65930fd..0000000 --- a/modules/classes/drop.js +++ /dev/null @@ -1,81 +0,0 @@ -const chalk = require("chalk"); - -module.exports = class Drops extends require("./template") { - static dataGlobal = new Map(); - static dataJapan = new Map(); - - constructor (data) { - super(); - - this.id = data.id; - - this.tag = data.tag; - - this.stageRewardId = data.stageRewardId; - - this.dropAmount = data.dropAmount; - - this.dropChance = data.dropChance; - } - - static get (identifier, region) { - if (identifier instanceof Drops) { - return identifier; - } - else if (typeof identifier === "number") { - const data = region === "global" ? Drops.dataGlobal : Drops.dataJapan; - const values = [...data.values()]; - const dropData = values.filter(i => i.stageRewardId === identifier); - return dropData; - } - else { - console.error(chalk `{red Invalid identifier for Drops.get(). Expected number!}`, { - identifier, - type: typeof identifier - }); - } - } - - static getDropbyStage (identifier) { - if (identifier instanceof Drops) { - return identifier; - } - else if (typeof identifier === "number") { - const values = [...Drops.data.values()]; - const dropData = values.filter(i => i.id === identifier); - return dropData; - } - else { - console.error(chalk `{red Invalid identifier for Drops.getDropbyStage(). Expected number!}`, { - identifier, - type: typeof identifier - }); - } - } - - static async loadData () { - const regions = ["global", "japan"]; - - for (const region of regions) { - const data = await ba.Query.collection(`${region}.DropDataMain`).find({}).toArray(); - if (data.length === 0) { - throw new Error(`No drop data found for region ${region}!`); - } - - for (const drop of data) { - const dropData = new Drops(drop); - if (region === "global") { - Drops.dataGlobal.set(Symbol(dropData.id), dropData); - } - else if (region === "japan") { - Drops.dataJapan.set(Symbol(dropData.id), dropData); - } - } - } - } - - - static destroy () { - Drops.data.clear(); - } -}; diff --git a/modules/classes/equipment.js b/modules/classes/equipment.js deleted file mode 100644 index 3dacc0a..0000000 --- a/modules/classes/equipment.js +++ /dev/null @@ -1,137 +0,0 @@ -const chalk = require("chalk"); - -module.exports = class Equipment extends require("./template") { - static dataGlobal = new Map(); - static dataJapan = new Map(); - - constructor (data) { - super(); - - this.id = data.id; - - this.localizeId = data.localizeId; - - this.recipeId = data.recipeId; - - this.category = data.category; - - this.rarity = data.rarity; - - this.maxLevel = data.maxLevel; - - this.tier = data.tier; - - this.tags = data.tags; - } - - static get (identifier, region) { - if (identifier instanceof Equipment) { - return identifier; - } - else if (typeof identifier === "number") { - const data = region === "global" ? Equipment.dataGlobal : Equipment.dataJapan; - const values = [...data.values()]; - const equipmentData = values.filter(i => i.id === identifier); - if (equipmentData.length === 0) { - return null; - } - - return equipmentData[0]; - } - else { - console.error(chalk `{red Invalid identifier for Equipment.get(). Expected number!}`, { - identifier, - type: typeof identifier - }); - } - } - - static getDatabyTier (identifier) { - if (identifier instanceof Equipment) { - return identifier; - } - else if (typeof identifier === "string") { - const tierTypes = { - t1: 1, - t2: 2, - t3: 3, - t4: 4, - t5: 5, - t6: 6, - t7: 7, - t8: 8, - t9: 9 - }; - - const [tier, name] = identifier.split(" "); - const values = [...Equipment.dataGlobal.values()]; - if (tierTypes[tier] === 1) { - return this.parseEquipmentData(values.find(i => i.tier === tierTypes[tier] - && Equipment.normalizeName(i.category) === Equipment.normalizeName(name)) - ); - } - else { - const tierData = values.find(i => i.tier === tierTypes[tier] - && Equipment.normalizeName(i.category) === Equipment.normalizeName(name) - ); - - if (typeof tierData === "undefined") { - return null; - } - - const recipeId = Number(`10${tierData.id}`); - return values.find(i => i.id === recipeId); - } - } - else { - console.error(chalk `{red Invalid identifier for Equipment.get(). Expected string!}`, { - identifier, - type: typeof identifier - }); - } - } - - static async loadData () { - const regions = ["global", "japan"]; - - for (const region of regions) { - const data = await ba.Query.collection(`${region}.EquipmentData`).find({}).toArray(); - if (data.length === 0) { - throw new Error(`No equipment data found for region ${region}`); - } - - for (const equipment of data) { - const equipmentData = new Equipment(equipment); - if (region === "global") { - Equipment.dataGlobal.set(Symbol(equipmentData.id), equipmentData); - } - else if (region === "japan") { - Equipment.dataJapan.set(Symbol(equipmentData.id), equipmentData); - } - } - } - } - - static async parseEquipmentData (data) { - const equipData = await ba.Utils.getEquipmentData(data.id); - return { - id: data.id, - name: equipData.name, - description: equipData.description, - category: data.category, - rarity: data.rarity, - maxLevel: data.maxLevel, - recipeId: data.recipeId, - tier: data.tier, - tags: data.tags - }; - } - - static destroy () { - Equipment.data.clear(); - } - - static normalizeName (name) { - return name.toLowerCase(); - } -}; diff --git a/modules/classes/skill.js b/modules/classes/skill.js deleted file mode 100644 index 165d7ab..0000000 --- a/modules/classes/skill.js +++ /dev/null @@ -1,66 +0,0 @@ -const chalk = require("chalk"); - -module.exports = class Skill extends require("./template") { - static dataGlobal = new Map(); - static dataJapan = new Map(); - - constructor (data) { - super(); - - this.id = data.id; - - this.skillEx = data.skillEx; - - this.normal = data.normal; - - this.passive = data.passive; - - this.sub = data.sub; - } - - static get (identifier, region) { - if (identifier instanceof Skill) { - return identifier; - } - else if (typeof identifier === "number") { - const data = region === "global" ? Skill.dataGlobal : Skill.dataJapan; - const values = [...data.values()]; - return values.find(i => i.id === identifier); - } - else { - console.error(chalk `{red Invalid identifier for Skill.get(). Expected number!}`, { - identifier, - type: typeof identifier - }); - } - } - - static async loadData () { - const regions = ["global", "japan"]; - - for (const region of regions) { - const data = await ba.Query.collection(`${region}.SkillListData`).find({}).toArray(); - if (data.length === 0) { - throw new Error(`No skill data found for region ${region}!`); - } - - for (const skill of data) { - const skillData = new Skill(skill); - if (region === "global") { - Skill.dataGlobal.set(Symbol(skillData.id), skillData); - } - else if (region === "japan") { - Skill.dataJapan.set(Symbol(skillData.id), skillData); - } - } - } - } - - static destroy () { - Skill.data.clear(); - } - - static normalizeName (name) { - return name.toLowerCase(); - } -}; diff --git a/modules/classes/stage.js b/modules/classes/stage.js deleted file mode 100644 index efa4758..0000000 --- a/modules/classes/stage.js +++ /dev/null @@ -1,121 +0,0 @@ -const chalk = require("chalk"); - -module.exports = class Stage extends require("./template") { - static dataGlobal = new Map(); - static dataJapan = new Map(); - - constructor (data) { - super(); - - this.id = data.id; - - this.minRank = data.minRank; - - this.staminaCost = data.staminaCost; - - this.battleDuration = data.battleDuration; - - this.maxTurn = data.maxTurn; - - this.stageInfo = data.stageInfo; - - this.objective = data.objective ?? []; - - this.stageData = data.stageData ?? {}; - } - - static get (identifier, region) { - if (identifier instanceof Stage) { - return identifier; - } - else if (typeof identifier === "number") { - return Stage.data.get(`${region}-${identifier}`); - } - else { - console.error(chalk `{red Invalid identifier for Stage.get(). Expected number!}`, { - identifier, - type: typeof identifier - }); - } - } - - static getStagebyId (identifier, region = "global") { - if (identifier instanceof Stage) { - return identifier; - } - else if (typeof identifier === "number") { - return Stage.data.get(`${region}-${identifier}`); - } - else { - console.error(chalk `{red Invalid identifier for Stage.getStagebyId(). Expected number!}`, { - identifier, - type: typeof identifier - }); - } - } - - static async raid (region) { - const stages = { - current: [], - upcoming: [], - ended: [] - }; - - const raidData = await ba.Query.collection(`${region}.RaidData`).find({}).toArray(); - for (const raid of raidData) { - const startAt = raid.startAt; - const endAt = raid.endAt; - const now = new Date(); - - if (now > startAt && now < endAt) { - stages.current.push({ - seasonId: raid.id, - bossName: raid.boss, - startAt: raid.startAt, - settleAt: raid.settleAt, - endAt: raid.endAt - }); - } - else if (now < startAt) { - stages.upcoming.push({ - seasonId: raid.id, - bossName: raid.boss, - startAt: raid.startAt, - settleAt: raid.settleAt, - endAt: raid.endAt - }); - } - else if (now > endAt) { - stages.ended.push({ - seasonId: raid.id, - bossName: raid.boss, - startAt: raid.startAt, - settleAt: raid.settleAt, - endAt: raid.endAt - }); - } - } - - return stages; - } - - static async loadData () { - const regions = ["global", "japan"]; - - for (const region of regions) { - const data = await ba.Query.collection(`${region}.StageDataMain`).find({}).toArray(); - if (data.length === 0) { - throw new Error(`No stage data found for region ${region}!`); - } - - for (const stage of data) { - const stageData = new Stage(stage); - Stage.data.set(`${region}-${stageData.id}`, stageData); - } - } - } - - static destroy () { - Stage.data.clear(); - } -}; diff --git a/modules/singleton/template.js b/modules/singleton/template.js deleted file mode 100644 index ceae460..0000000 --- a/modules/singleton/template.js +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = class SingletonTemplate { - /** - * Cleans up the module. - * All submodules must implement this method. - * @abstract - */ - destroy () { - throw new Error("SingletonTemplate::destroy() is not implemented"); - } - - /** - * Construct the singleton instance. - * @return {Promise} - */ - static singleton () { - throw new Error("SingletonTemplate::singleton() is not implemented"); - } - - /** - * File name of the module. - * All submodules must implement this method. - */ - get modulePath () { - throw new Error("SingletonTemplate::modulePath() is not implemented"); - } -}; diff --git a/modules/singleton/utils.js b/modules/singleton/utils.js deleted file mode 100644 index 1e32b62..0000000 --- a/modules/singleton/utils.js +++ /dev/null @@ -1,253 +0,0 @@ -module.exports = class Utils extends require("./template") { - #localizeEtc = {}; - #statData = {}; - #characterLocalize = {}; - #skillLocalize = {}; - #skillList = {}; - #bannerData = {}; - - static terrainTypes = { - Urban: { - SS: { - DamageDealt: "130%(1.3x)", - ShieldBlockRate: "75%" - }, - S: { - DamageDealt: "120%(1.2x)", - ShieldBlockRate: "60%" - }, - A: { - DamageDealt: "110%(1.1x)", - ShieldBlockRate: "45%" - }, - B: { - DamageDealt: "100%(1x)", - ShieldBlockRate: "30%" - }, - C: { - DamageDealt: "90%(0.9x)", - ShieldBlockRate: "15%" - }, - D: { - DamageDealt: "80%(0.8x)", - ShieldBlockRate: "0%" - } - }, - Desert: { - SS: { - DamageDealt: "130%(1.3x)", - ShieldBlockRate: "75%" - }, - S: { - DamageDealt: "120%(1.2x)", - ShieldBlockRate: "60%" - }, - A: { - DamageDealt: "110%(1.1x)", - ShieldBlockRate: "45%" - }, - B: { - DamageDealt: "100%(1x)", - ShieldBlockRate: "30%" - }, - C: { - DamageDealt: "90%(0.9x)", - ShieldBlockRate: "15%" - }, - D: { - DamageDealt: "80%(0.8x)", - ShieldBlockRate: "0%" - } - }, - Indoor: { - SS: { - DamageDealt: "130%(1.3x)", - ShieldBlockRate: "75%" - }, - S: { - DamageDealt: "120%(1.2x)", - ShieldBlockRate: "60%" - }, - A: { - DamageDealt: "110%(1.1x)", - ShieldBlockRate: "45%" - }, - B: { - DamageDealt: "100%(1x)", - ShieldBlockRate: "30%" - }, - C: { - DamageDealt: "90%(0.9x)", - ShieldBlockRate: "15%" - }, - D: { - DamageDealt: "80%(0.8x)", - ShieldBlockRate: "0%" - } - } - }; - - /** - * @inheritdoc - * @returns {Utils} - */ - static singleton () { - if (!Utils.module) { - Utils.module = new Utils(); - } - - return Utils.module; - } - - isValidRegion (region) { - return ["global", "japan"].includes(region); - } - - async getEquipmentData (id, region = "global") { - if (!this.#localizeEtc[region]) { - this.#localizeEtc[region] = await ba.Query.collection(`${region}.LocalizeEtc`).find({}).toArray(); - } - - const equipmentData = ba.Equipment.get(id); - if (!equipmentData) { - return null; - } - - const equipmentLoc = this.#localizeEtc[region].find(i => i.key === equipmentData.localizeId); - const equipment = { - id: equipmentData.id, - name: equipmentLoc.name, - description: equipmentLoc.description - }; - - return equipment; - } - - async getCharacterName (id, region) { - if (!this.#localizeEtc[region]) { - this.#localizeEtc[region] = await ba.Query.collection(`${region}.LocalizeEtc`).find({}).toArray(); - } - - return this.#localizeEtc[region].find(i => i.key === id); - } - - async getCharacterData (id, region) { - if (!this.#characterLocalize[region]) { - this.#characterLocalize[region] = await ba.Query.collection(`${region}.CharacterLocalize`).find({}).toArray(); - } - - if (!this.#statData[region]) { - this.#statData[region] = await ba.Query.collection(`${region}.CharacterStat`).find({}).toArray(); - } - - const info = this.#characterLocalize[region].find(i => i.id === id); - const statData = this.#statData[region].find(i => i.id === id); - - if (!info || !statData) { - return null; - } - - if (statData) { - delete statData._id; // not sorry for this xd - } - - return { - info, - stat: statData, - topology: { - urban: Utils.terrainTypes.Urban[statData.streetMood], - outdoor: Utils.terrainTypes.Desert[statData.outdoorMood], - indoor: Utils.terrainTypes.Indoor[statData.indoorMood] - } - }; - } - - async getSkillInfo (id, region) { - if (!this.#skillLocalize[region]) { - this.#skillLocalize[region] = await ba.Query.collection(`${region}.SkillLocalize`).find({}).toArray(); - } - - const skill = this.#skillLocalize[region].find(i => i.id === id); - if (!skill) { - return null; - } - - return { - id: skill.id, - name: skill.name, - description: skill.description - }; - } - - async getSkillData (name, region) { - if (!this.#skillList[region]) { - this.#skillList[region] = await ba.Query.collection(`${region}.SkillListTable`).find({}).toArray(); - } - - const stuff = []; - const skills = this.#skillList[region].filter(i => i.groupId === name); - if (skills.length !== 0) { - for (const skill of skills) { - const skillInfo = await this.getSkillInfo(skill.localizeSkillId, region); - if (skillInfo) { - stuff.push({ - level: skill.level, - name: skillInfo.name, - description: skillInfo.description, - skillCost: skill.skillCost, - bulletType: skill.bulletType - }); - } - } - } - - return stuff; - } - - async getBannerData (region) { - if (!this.#bannerData[region]) { - this.#bannerData[region] = await ba.Query.collection(`${region}.GachaData`).find({}).toArray(); - } - - const current = []; - const upcoming = []; - const ended = []; - - for (const banner of this.#bannerData[region]) { - const now = Date.now(); - const startAt = banner.startAt; - const endAt = banner.endAt; - - if (now >= startAt && now <= endAt) { - current.push(Utils.parseBannerData(banner, region)); - } - else if (now < startAt) { - upcoming.push(Utils.parseBannerData(banner, region)); - } - else if (now > endAt) { - ended.push(Utils.parseBannerData(banner, region)); - } - } - - return { - current, - upcoming, - ended - }; - } - - static parseBannerData (data, region) { - const rateups = []; - for (const rateup of data.rateup) { - const charData = ba.Character.get(rateup, region); - rateups.push(charData.name); - } - - return { - gachaType: data.type, - startAt: data.startAt, - endAt: data.endAt, - rateups - }; - } -}; diff --git a/package.json b/package.json index 0f356c1..ca756d1 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "BlueArchiveAPI", + "name": "blue-archive-api", "version": "1.3.0", "description": "API that serves data for the game Blue Archive", "main": "app.js", @@ -16,20 +16,21 @@ }, "homepage": "https://api.ennead.cc/buruaka", "author": "torikushiii", - "license": "OSL-3.0", + "license": "AGPL-3.0", "dependencies": { - "@fastify/cors": "^8.1.0", - "@fastify/sensible": "^5.1.0", - "fastify": "^4.3.0", - "mongodb": "^4.8.1", - "pino": "^8.4.0", - "pino-pretty": "^8.1.0" + "@fastify/cors": "^8.3.0", + "@fastify/sensible": "^5.2.0", + "debug": "^4.3.4", + "fastify": "^4.20.0", + "mongodb": "^5.7.0", + "pino": "^8.14.1", + "pino-pretty": "^10.1.0" }, "devDependencies": { - "@babel/core": "^7.18.10", - "@babel/eslint-parser": "^7.18.9", - "eslint": "^8.21.0", - "eslint-plugin-unicorn": "^43.0.2" + "@babel/core": "^7.22.9", + "@babel/eslint-parser": "^7.22.9", + "eslint": "^8.45.0", + "eslint-plugin-unicorn": "^48.0.0" }, "types": "./@types/index.d.ts" } \ No newline at end of file diff --git a/routes/banner.js b/routes/banner.js index a61c032..a6f3e86 100644 --- a/routes/banner.js +++ b/routes/banner.js @@ -3,16 +3,13 @@ module.exports = function (fastify, opts, done) { Router.get("/", async (req, res) => { const region = req.query.region || "global"; - if (!ba.Utils.isValidRegion(region)) { + if (!["global", "japan"].includes(region)) { return res.badRequest("Invalid region"); } - - const data = await ba.Utils.getBannerData(region); - if (data.current.length === 0 && data.ended.length === 0) { - return res.notFound("No banners found"); - } - - res.send(data); + + const bannerData = await ba.Utils.getBannerData(region); + + return res.send(bannerData); }); done(); diff --git a/routes/character.js b/routes/character.js index 08a9d8c..cbb9d11 100644 --- a/routes/character.js +++ b/routes/character.js @@ -1,64 +1,89 @@ module.exports = function (fastify, opts, done) { const Router = fastify; - + Router.get("/", async (req, res) => { const region = req.query.region || "global"; - if (!ba.Utils.isValidRegion(region)) { + if (!["global", "japan"].includes(region)) { return res.badRequest("Invalid region"); } - const data = await ba.Character.getAll(region); + const data = await ba.Character.get(null, { getAll: true, region }); if (!data) { - return res.notFound("No data found (?)"); + return res.notFound(); + } + + if (req.query.star) { + const star = Number(req.query.star); + if (isNaN(star)) { + return res.badRequest("Invalid character rarity"); + } + + const filteredData = data.filter(i => i.baseStar === star); + if (filteredData.length === 0) { + return res.notFound(); + } + + return res.send(filteredData); } - return res.send({ data }); + return res.send(data); }); Router.get("/query", async (req, res) => { - if (Object.keys(req.query).length === 0) { - res.badRequest("No query parameters are given!"); - - return; + const region = req.query.region || "global"; + if (!["global", "japan"].includes(region)) { + return res.badRequest("Invalid region"); } - - const data = ba.Character.getCharacterbyQuery(req.query); - if (data) { - res.send(data); + + for (const key in req.query) { + req.query[key] = req.query[key].toLowerCase(); } - else { - res.notFound("No character found with that matching query!"); + + const data = await ba.Character.getCharacterByQuery(req.query, { region }); + if (!data) { + return res.notFound(); } + + return res.send(data); }); - Router.get("/:id", async (req, res) => { + Router.get("/:character", async (req, res) => { const region = req.query.region || "global"; - if (!ba.Utils.isValidRegion(region)) { + if (!["global", "japan"].includes(region)) { return res.badRequest("Invalid region"); } if (req.query.id) { - const isId = Boolean(req.query.id === "true"); - if (isId) { - const data = ba.Character.get(Number(req.params.id), region); - if (data) { - return res.send(data); + const characterId = Boolean(req.query.id === "true"); + if (characterId) { + const data = await ba.Character.get(Number(req.params.character), { region }); + if (!data) { + return res.notFound(); } - } - } - else { - const data = ba.Character.get(req.params.id, region); - if (data) { - const parsedCharacter = await ba.Character.parseCharacterData(data, { region }); + + const parsedCharacter = await ba.Character.buildCharacterObject(data, { region }); if (!parsedCharacter) { - return res.notFound("No character with such ID/name was found!"); + return res.notFound("No character data found with that identifier"); } - + return res.send(parsedCharacter); } } + else { + const data = await ba.Character.get(req.params.character, { region }); + if (!data) { + return res.notFound(); + } + + const parsedCharacter = await ba.Character.buildCharacterObject(data, { region }); + if (!parsedCharacter) { + return res.notFound("No character data found with that identifier"); + } + + return res.send(parsedCharacter); + } - res.notFound("No character with such ID/name was found!"); + return res.notFound(); }); done(); diff --git a/routes/equipment.js b/routes/equipment.js deleted file mode 100644 index 953ea84..0000000 --- a/routes/equipment.js +++ /dev/null @@ -1,60 +0,0 @@ -module.exports = function (fastify, opts, done) { - const Router = fastify; - - Router.get("/", (req, res) => { - res.badRequest("No equipment found"); - }); - - Router.get("/:id", async (req, res) => { - if (req.query.id) { - const isId = Boolean(req.query.id === "true"); - if (isId) { - const data = ba.Equipment.get(Number(req.params.id)); - if (data) { - const droplist = []; - - const drops = ba.Drops.get(data.id); - for (const drop of drops) { - const stageData = ba.Stage.getStagebyId(drop.id); - droplist.push({ - stageName: stageData.stageInfo.fullName, - dropAmount: drop.dropAmount, - dropChance: drop.dropChance / 100 - }); - } - - return res.send({ data, drops: droplist }); - } - } - } - else { - const droplist = []; - const item = req.params.id.toLowerCase(); - - const tierRegex = /^t[1-9] (.*)$/; - const tierMatch = item.match(tierRegex); - if (tierMatch) { - const equipData = await ba.Equipment.getDatabyTier(item); - if (equipData) { - const drops = ba.Drops.get(equipData.id); - if (drops) { - for (const drop of drops) { - const stageData = ba.Stage.getStagebyId(drop.id); - droplist.push({ - stageName: stageData.stageInfo.fullName, - dropAmount: drop.dropAmount, - dropChance: drop.dropChance / 100 - }); - } - - return res.send({ data: equipData, drops: droplist }); - } - } - } - } - - res.notFound("No equipment exists with this ID / Name!"); - }); - - done(); -}; diff --git a/routes/raid.js b/routes/raid.js index 4a233f4..1498835 100644 --- a/routes/raid.js +++ b/routes/raid.js @@ -3,17 +3,56 @@ module.exports = function (fastify, opts, done) { Router.get("/", async (req, res) => { const region = req.query.region || "global"; - if (!ba.Utils.isValidRegion(region)) { + if (!["global", "japan"].includes(region)) { return res.badRequest("Invalid region"); } - - const data = await ba.Stage.raid(region); - if (data.upcoming.length !== 0 || data.current.length !== 0 || data.ended.length !== 0) { - res.send(data); + + const raidData = await ba.Query.collection(`${region}.RaidData`).find({}).toArray(); + if (!raidData || raidData.length === 0) { + return res.notFound(); } - else { - res.notFound("No raid data found"); + + const stages = { + current: [], + upcoming: [], + ended: [] + }; + + for (const raid of raidData) { + const startAt = raid.startAt; + const endAt = raid.endAt; + const now = new Date(); + + if (now > startAt && now < endAt) { + stages.current.push({ + seasonId: raid.id, + bossName: raid.boss, + startAt: raid.startAt, + settleAt: raid.settleAt, + endAt: raid.endAt + }); + } + else if (now < startAt) { + stages.upcoming.push({ + seasonId: raid.id, + bossName: raid.boss, + startAt: raid.startAt, + settleAt: raid.settleAt, + endAt: raid.endAt + }); + } + else if (now > endAt) { + stages.ended.push({ + seasonId: raid.id, + bossName: raid.boss, + startAt: raid.startAt, + settleAt: raid.settleAt, + endAt: raid.endAt + }); + } } + + return res.send(stages); }); done(); diff --git a/routes/stage.js b/routes/stage.js deleted file mode 100644 index 87328a9..0000000 --- a/routes/stage.js +++ /dev/null @@ -1,44 +0,0 @@ -module.exports = function (fastify, opts, done) { - const Router = fastify; - - Router.get("/", (req, res) => { - res.send({ data: "No stage ID is given!" }); - }); - - Router.get("/:id", async (req, res) => { - const isNumber = Number.isInteger(Number(req.params.id)); - if (!isNumber) { - res.badRequest("Stage ID must be an number!"); - - return; - } - - const stageId = Number(req.params.id); - const data = ba.Stage.get(stageId); - if (data) { - const drops = []; - const dropData = ba.Drops.getDropbyStage(stageId); - if (dropData.length !== 0) { - for (const drop of dropData) { - const loc = await ba.Utils.getEquipmentData(drop.stageRewardId); - if (loc) { - drops.push({ - id: drop.id, - ...loc, - droprate: drop.dropChance / 100 - }); - } - } - } - - res.send({ data, drops }); - } - else { - res.notFound("No stage found with this ID!"); - - return; - } - }); - - done(); -};