Installations needed
Basic Info
This wiki is all about the use of Jikan
package for interacting with the MAL(My Anime List) API and getting the manga, character info from it.
This gives the information as per the result type specified in the custom function and you can make it into an embed like the normal AOI uses. This code is for those who are fans of manga and wanna make such a system but, getting it hard to code. Use this function as I say or you can also edit this if you have experience in DJS and API interacts.
Index config
Before heading to the custom funcs code, we need to config our index.js
a little so that instead of cluttering the index with random custom funcs, we do that in a seperate directory(folder). Here, we use a directory named customFunctions
.
Here is the thing that you must add in your index, probably towards the end of it.
const funcsdir = " ./customFunctions/ " ;
const fs = require ( ' fs ' );
files = fs . readdirSync ( funcsdir );
files . forEach ( ( file ) => {
let func = require ( funcsdir + file );
// Replace "bot" with "client" if necessary.
Custom Function Code
This is split into two parts, anime and manga . We here discuss the manga part only whereas, I have also made the anime part and posted it here . Also, the basic custom function which both of em needs and that is, the $getID
which gets Manga ID from its name.
So, let’s head to the important part AKA the code!
$getID
This function deals with the fetching of anime/manga ID from its name. This also simplifies the code as we don’t need to fetch ID every time to get it’s info. Instead, we use this function alongside the other to fetch ID as other funcs has manga ID parameter NOT manga name.
const Jikan = require ( ' jikan4.js ' );
const JIKAN_CLIENT = new Jikan . Client ();
// Edit the "bot" as per your config in index.js
// Replace it with "client" if necessary.
module . exports = ( bot ) => {
bot . functionManager . createFunction ({
const data = d . util . aoiFunc ( d );
if ( data . err ) return d . error ( data . err );
const [ name , type = ' Anime ' ] = data . inside . splits ;
return d . aoiError . fnError ( d , " custom " , {}, " Anime/Manga name not specified " );
if ( ! type ) return d . aoiError . fnError ( d , " custom " , {}, " Type not specified. " )
const ty = type . toLowerCase () . trim ();
if ( ty != ' anime ' && ty != ' manga ' ) {
return d . aoiError . fnError ( d , " custom " , {}, " Invalid type specified. Either Manga / Anime only " );
searchResults = await JIKAN_CLIENT . anime . search ( n );
searchResults = await JIKAN_CLIENT . manga . search ( n );
const quarterLength = Math . ceil ( searchResults . length / 4 );
for ( let i = 0 ; i < quarterLength ; i ++ ) {
const result = searchResults [ i ] . title . default . toLowerCase ();
foundID = searchResults [ i ] . id ;
foundID = searchResults [ 0 ] . id ;
code: d . util . setCode ( data ),
$mangaInfo
This function deals with getting info of the manga from the ID passed and returns the output as per the parameter passed. It has 2 parameters.
const Jikan = require ( ' jikan4.js ' );
const JIKAN_CLIENT = new Jikan . Client ();
// Replace "bot" with "client" if necessary (as per your index.js config
module . exports = ( bot ) => {
bot . functionManager . createFunction ({
const data = d . util . aoiFunc ( d );
if ( data . err ) return d . error ( data . err );
const [ mangaID , res ] = data . inside . splits ;
if ( ! mangaID ) return d . aoiError . fnError ( d , " custom " , {}, " Anime ID not provided! " )
if ( ! res ) return d . aoiError . fnError ( d , " custom " , {}, " No result type specified. " )
const mID = mangaID . trim ()
const resu = res . trim () . toLowerCase ()
const type = [ ' title ' , ' synopsis ' , ' background ' , ' image ' , ' ratings ' , ' genre ' , ' url ' , ' volumes ' , ' serializations ' , ' year ' , ' author ' , ' popularity ' ];
if ( ! type . includes ( resu )) return d . aoiError . fnError ( d , " custom " , {}, " Invalid result type. " );
const manga = await JIKAN_CLIENT . manga . get ( mID );
if ( ! manga ) return d . aoiError . fnError ( d , " custom " , {}, " Invalid manga ID. " );
const stats = await JIKAN_CLIENT . manga . getStatistics ( mID );
let genres = manga . genres . map ( genre => genre . name ) . join ( ' , ' );
if ( ! genres || genres . trim () === '' ) {
genres = ' No genre information. ' ;
for ( const obj of stats . scores ) {
totalScore += obj . score * obj . votes ;
const averageScore = totalScore / totalVotes ;
ratings = ` Average score based off ${ totalVotes . toLocaleString () } votes: ${ averageScore . toFixed ( 2 ) + ' / 10 ' } ` ;
ratings = ' Rating information not found. ' ;
//SYNOPSIS, URL, EPISODES, GENRES, RATINGS, ETC.
const SYNOPSIS = manga . synopsis ?? " Synopsis not found! " ;
const BACKGROUND = manga . background ?? " Background not found! " ;
const URL = manga . url ?? ' URL not found. ' ;
const TITLE = manga . title . default ;
const IMAGE = manga . image . webp . default ;
const YEAR = manga . publishInfo ?. publishedFrom ?. getFullYear () ?? ' Year information not found. ' ;
const AUTHOR = manga . authors [ 0 ] . name ?? " Author information unavailable! " ;
const VOLUMES = manga . volumes ?. toLocaleString () ?? " Volume information not found! " ;
const POPULARITY = manga . popularity ?. toLocaleString () ?? " Popularity information not found! " ;
const SERIALIZATIONS = manga . serializations [ 0 ] ?. name ?? " Serialization info not found! " ;
code: d . util . setCode ( data ),
$mangaCharInfo
This function deals with getting the character info of the character and anime(which includes the character) passed. The output will be dependent on the parameter you pass. It has 3 parameters.
const Jikan = require ( ' jikan4.js ' );
const JIKAN_CLIENT = new Jikan . Client ();
function getFirstName ( characterName , databaseNames ) {
const nameParts = databaseNames . split ( ' , ' ) . map ( part => part . trim () . toLowerCase ());
if ( nameParts . includes ( characterName . toLowerCase ())) {
function getDescription ( characterDescription ) {
if ( ! characterDescription ) {
return description = ' Description not found. ' ;
if ( characterDescription . length > 1024 ) {
const midPoint = characterDescription . lastIndexOf ( ' . ' , 1024 );
const descriptionFirstPart = characterDescription . substring ( 0 , midPoint + 1 );
description = descriptionFirstPart ;
description = characterDescription
// Replace "bot" with "client" if necessary (as per your index.js config
module . exports = ( bot ) => {
bot . functionManager . createFunction ({
const data = d . util . aoiFunc ( d );
if ( data . err ) return d . error ( data . err );
const [ mangaID , character , res ] = data . inside . splits ;
if ( ! mangaID ) return d . aoiError . fnError ( d , " custom " , {}, " Anime ID not provided. " );
if ( ! character ) return d . aoiError . fnError ( d , " custom " , {}, " Character not provided. " );
if ( ! res ) return d . aoiError . fnError ( d , " custom " , {}, " Enter the result type. " )
const mID = mangaID . trim ();
const characterName = character . trim () . toLowerCase ();
const resu = res . trim () . toLowerCase ();
const type = [ " name " , " url " , , " image " , " nicknames " , " role " , " description " , " manga " ];
if ( ! type . includes ( resu )) return d . aoiError . fnError ( d , " custom " , {}, " Invalid result type entered. " )
const manga = await JIKAN_CLIENT . manga . get ( mID );
if ( ! manga ) return d . aoiError . fnError ( d , " custom " , {}, " Manga not found. " );
const ch = await JIKAN_CLIENT . manga . getCharacters ( mID );
let characterFound = false ;
for ( let i = 0 ; i < ch . length ; i ++ ) {
if ( getFirstName ( characterName , ( ch [ i ] . character . name ) . toLowerCase ())) {
characterArr . push ( ch [ i ]);
characterObj = await JIKAN_CLIENT . characters . getFull ( characterArr [ i ] . character . id );
description = getDescription ( characterObj . about );
description = ' Description not found. ' ;
if ( characterObj . nicknames [ 0 ] === undefined ) {
nicknames = characterObj . nicknames . map ( item => item ) . join ( ' , ' );
const CHARACTER = characterArr [ i ] . character . name ;
const URL = characterArr [ i ] . character . url ;
const MANGA = manga . title . default ;
const ROLE = characterArr [ i ] ?. role ?? ' Role information not found. ' ;
const DESCRIPTION = description ;
const IMAGE = characterArr [ i ] . character . image . webp . default ;
const NICKNAMES = nicknames ;
code: d . util . setCode ( data ),
And these are the codes you must add in your /customFunctions/
or whatever you call it directory.
Syntax & Tables
Now, let’s know the syntax and other thing on how to use the above functions.
Syntax Table
The syntax is:
Option Type Optional Example Name String false Any anime/manga name as per type
Type String true Specify anime
(default) or manga
Use like: $getID[$message/manga_name;manga(else anime)]
The syntax is:
$mangaInfo [ mangaID ; result ]
Option Type Optional Example Manga ID Number false The ID of manga as in MAL Result String false Result to return. Refer the table (Manga) below
The syntax is:
$mangaCharInfo [ mangaID ; character ; result ]
Option Type Optional Example Manga ID Number false The ID of anime as in MAL Character String false Name of the character you are searching for (must be in the specified manga) Result String false Result to return. Refer the table (Character) below
Use like: $mangaCharInfo[$getID[$message/anime_name];$message/character_name;result_type]
Result Type Table
Now, let’s head towards the table for the result. Or rather, what you must put in the result
parameter in both cases.
Option Output title Returns the name of manga synopsis Returns the synopsis of manga background Returns the background of manga url Returns the URL of manga in MAL website genre Returns the genre of manga image Returns image of manga ratings Returns the rating of manga popularity Returns popularity of manga year Returns release year of manga author Returns author of manga serializations Returns the serializations of manga volumes Returns volume count of manga
Option Output name Returns the name of character url Returns the URL of character in MAL website image Returns image of character nicknames Returns the nicknames of the character manga Returns the manga of which character is part of description Returns a short description about the character role Returns role of character, either main
or supporting
Result Type
The result and other parameters aren’t case sensitive. What I mean is, if you accidentally add a uppercase or blank spaces(in ends), you don’t have to worry about them. I have coded them as such to catch such errors.
Error Table
There are two errors which will be most common when making a command out of it and that should be caught. They are Not Found (Anime/Manga)
and Manga Character Not Found
. I have made error catching for this which can be caught using $onlyIf
which makes sure that you won’t see unnecessary AOIErrors while making embeds.
Error Catch Function Not Found (Anime/Manga)
NFError
$getID
Manga Character Not Found
MCNFError
$mangaCharInfo
Usage:
$onlyIf[$getID[manga_name;manga]!=NFError;]
$onlyIf[$mangaCharInfo[$getID[manga_name];character;type]!=MCNFError;]
Important reference
Note
Though I said that this interacts with MAL API, the package used actually interacts with the JIKAN API which inturn reacts with the MAL. As such, you should read the links that I will post below to know how much you can use them without getting API ratelimit.
Credits
Reproduction of this code
This code DOES NOT fully belong to me. I have handled the work on converting it into aoi custom function and some small edits for it to work as it deemed to be. The owner of this code that is, @Ares owns the original code which is built with DJS v14.
As such, if you are reproducing or in the case of mass distribution of this code or anything related to it, don’t forget to thank and give credits to him.
Gallery
Manga Info Click here to see the manga info command images!