UNPKG

@yuna0x0/anilist-node

Version:

A lightweight Node.js wrapper for the AniList API

518 lines (469 loc) 19.2 kB
<!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <title>fetcher.js - AniList-Node Documentation</title> <meta name="description" content="Documentation for the AniList-Node NPM package." /> <meta property="og:title" content="AniList-Node Documentation" /> <meta property="og:type" content="website" /> <meta property="og:image" content="" /> <meta property="og:site_name" content="AniList-Node Documentation" /> <meta property="og:url" content="https://katsurin.com/docs/anilist-node/" /> <script src="scripts/prettify/prettify.js"></script> <script src="scripts/prettify/lang-css.js"></script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify.css" /> <link type="text/css" rel="stylesheet" href="styles/jsdoc.css" /> <script src="scripts/nav.js" defer></script> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> </head> <body> <input type="checkbox" id="nav-trigger" class="nav-trigger" /> <label for="nav-trigger" class="navicon-button x"> <div class="navicon"></div> </label> <label for="nav-trigger" class="overlay"></label> <nav> <input type="text" id="nav-search" placeholder="Search" /> <h2><a href="index.html">Home</a></h2> <h2> <a href="https://github.com/AurelicButter/AniList-Node" target="_blank" class="menu-item" id="website_link" >GitHub Repository</a > </h2> <h2> <a href="https://www.npmjs.com/package/anilist-node" target="_blank" class="menu-item" id="website_link" >AniList-Node on NPM</a > </h2> <h2> <a href="https://discord.gg/qKfqsjW" target="_blank" class="menu-item" id="website_link" >Support Server</a > </h2> <h3>Classes</h3> <ul> <li> <a href="AniList.html">AniList</a> <ul class="methods"> <li data-type="method"><a href="AniList.html#favouriteStudio">favouriteStudio</a></li> <li data-type="method"><a href="AniList.html#genres">genres</a></li> <li data-type="method"><a href="AniList.html#mediaTags">mediaTags</a></li> <li data-type="method"><a href="AniList.html#search">search</a></li> <li data-type="method"><a href="AniList.html#siteStatistics">siteStatistics</a></li> <li data-type="method"><a href="AniList.html#studio">studio</a></li> </ul> </li> <li> <a href="AniList.Activity.html">Activity</a> <ul class="methods"> <li data-type="method"><a href="AniList.Activity.html#delete">delete</a></li> <li data-type="method"><a href="AniList.Activity.html#get">get</a></li> <li data-type="method"><a href="AniList.Activity.html#getUserActivity">getUserActivity</a></li> <li data-type="method"><a href="AniList.Activity.html#postMessage">postMessage</a></li> <li data-type="method"><a href="AniList.Activity.html#postText">postText</a></li> </ul> </li> <li> <a href="AniList.Lists.html">Lists</a> <ul class="methods"> <li data-type="method"><a href="AniList.Lists.html#addEntry">addEntry</a></li> <li data-type="method"><a href="AniList.Lists.html#anime">anime</a></li> <li data-type="method"><a href="AniList.Lists.html#manga">manga</a></li> <li data-type="method"><a href="AniList.Lists.html#removeEntry">removeEntry</a></li> <li data-type="method"><a href="AniList.Lists.html#updateEntry">updateEntry</a></li> </ul> </li> <li> <a href="AniList.Media.html">Media</a> <ul class="methods"> <li data-type="method"><a href="AniList.Media.html#anime">anime</a></li> <li data-type="method"><a href="AniList.Media.html#favouriteAnime">favouriteAnime</a></li> <li data-type="method"><a href="AniList.Media.html#favouriteManga">favouriteManga</a></li> <li data-type="method"><a href="AniList.Media.html#manga">manga</a></li> </ul> </li> <li> <a href="AniList.People.html">People</a> <ul class="methods"> <li data-type="method"><a href="AniList.People.html#character">character</a></li> <li data-type="method"><a href="AniList.People.html#favouriteChar">favouriteChar</a></li> <li data-type="method"><a href="AniList.People.html#favouriteStaff">favouriteStaff</a></li> <li data-type="method"> <a href="AniList.People.html#getBirthdayCharacters">getBirthdayCharacters</a> </li> <li data-type="method"><a href="AniList.People.html#getBirthdayStaff">getBirthdayStaff</a></li> <li data-type="method"><a href="AniList.People.html#staff">staff</a></li> </ul> </li> <li> <a href="AniList.Recommendation.html">Recommendation</a> <ul class="methods"> <li data-type="method"><a href="AniList.Recommendation.html#get">get</a></li> <li data-type="method"><a href="AniList.Recommendation.html#getList">getList</a></li> </ul> </li> <li> <a href="AniList.Search.html">Search</a> <ul class="methods"> <li data-type="method"><a href="AniList.Search.html#activity">activity</a></li> <li data-type="method"><a href="AniList.Search.html#anime">anime</a></li> <li data-type="method"><a href="AniList.Search.html#character">character</a></li> <li data-type="method"><a href="AniList.Search.html#manga">manga</a></li> <li data-type="method"><a href="AniList.Search.html#staff">staff</a></li> <li data-type="method"><a href="AniList.Search.html#studio">studio</a></li> <li data-type="method"><a href="AniList.Search.html#user">user</a></li> </ul> </li> <li> <a href="AniList.Thread.html">Thread</a> <ul class="methods"> <li data-type="method"><a href="AniList.Thread.html#delete">delete</a></li> <li data-type="method"><a href="AniList.Thread.html#get">get</a></li> <li data-type="method"><a href="AniList.Thread.html#getComments">getComments</a></li> </ul> </li> <li> <a href="AniList.User.html">User</a> <ul class="methods"> <li data-type="method"><a href="AniList.User.html#all">all</a></li> <li data-type="method"><a href="AniList.User.html#follow">follow</a></li> <li data-type="method"><a href="AniList.User.html#getAuthorized">getAuthorized</a></li> <li data-type="method"><a href="AniList.User.html#getRecentActivity">getRecentActivity</a></li> <li data-type="method"><a href="AniList.User.html#profile">profile</a></li> <li data-type="method"><a href="AniList.User.html#stats">stats</a></li> <li data-type="method"><a href="AniList.User.html#update">update</a></li> </ul> </li> </ul> <h3>Tutorials</h3> <ul> <li><a href="tutorial-Filtering.html">Filtering</a></li> <li><a href="tutorial-Getting Started.html">Getting Started</a></li> </ul> <h3>Global</h3> <ul> <li><a href="global.html#ActivityEntry">ActivityEntry</a></li> <li><a href="global.html#ActivityFilterTypes">ActivityFilterTypes</a></li> <li><a href="global.html#ActivitySort">ActivitySort</a></li> <li><a href="global.html#ActivityType">ActivityType</a></li> <li><a href="global.html#AiringEntry">AiringEntry</a></li> <li><a href="global.html#AniListStats">AniListStats</a></li> <li><a href="global.html#AnimeEntry">AnimeEntry</a></li> <li><a href="global.html#CharacterEntry">CharacterEntry</a></li> <li><a href="global.html#CharacterName">CharacterName</a></li> <li><a href="global.html#CountryCode">CountryCode</a></li> <li><a href="global.html#EntryStatus">EntryStatus</a></li> <li><a href="global.html#FuzzyDateInt">FuzzyDateInt</a></li> <li><a href="global.html#FuzzyDateObj">FuzzyDateObj</a></li> <li><a href="global.html#InitOptions">InitOptions</a></li> <li><a href="global.html#ListActivity">ListActivity</a></li> <li><a href="global.html#ListEntry">ListEntry</a></li> <li><a href="global.html#MangaEntry">MangaEntry</a></li> <li><a href="global.html#MediaFilterTypes">MediaFilterTypes</a></li> <li><a href="global.html#MediaFormat">MediaFormat</a></li> <li><a href="global.html#MediaListOptions">MediaListOptions</a></li> <li><a href="global.html#MediaListOptionsInput">MediaListOptionsInput</a></li> <li><a href="global.html#MediaRelation">MediaRelation</a></li> <li><a href="global.html#MediaSeason">MediaSeason</a></li> <li><a href="global.html#MediaSort">MediaSort</a></li> <li><a href="global.html#MediaSource">MediaSource</a></li> <li><a href="global.html#MediaStatus">MediaStatus</a></li> <li><a href="global.html#MediaTag">MediaTag</a></li> <li><a href="global.html#MediaTitle">MediaTitle</a></li> <li><a href="global.html#MediaType">MediaType</a></li> <li><a href="global.html#MessageActivity">MessageActivity</a></li> <li><a href="global.html#ModRole">ModRole</a></li> <li><a href="global.html#NotificationOption">NotificationOption</a></li> <li><a href="global.html#NotificationType">NotificationType</a></li> <li><a href="global.html#PersonName">PersonName</a></li> <li><a href="global.html#PersonRelation">PersonRelation</a></li> <li><a href="global.html#RecommendationEntry">RecommendationEntry</a></li> <li><a href="global.html#RecommendationList">RecommendationList</a></li> <li><a href="global.html#RecommendationRating">RecommendationRating</a></li> <li><a href="global.html#ScoreFormat">ScoreFormat</a></li> <li><a href="global.html#SearchEntry">SearchEntry</a></li> <li><a href="global.html#SingleRecommendation">SingleRecommendation</a></li> <li><a href="global.html#StaffEntry">StaffEntry</a></li> <li><a href="global.html#StaffName">StaffName</a></li> <li><a href="global.html#StudioEntry">StudioEntry</a></li> <li><a href="global.html#TextActivity">TextActivity</a></li> <li><a href="global.html#ThreadComment">ThreadComment</a></li> <li><a href="global.html#ThreadEntry">ThreadEntry</a></li> <li><a href="global.html#UpdateEntryOptions">UpdateEntryOptions</a></li> <li><a href="global.html#UpdatedEntry">UpdatedEntry</a></li> <li><a href="global.html#UserList">UserList</a></li> <li><a href="global.html#UserOptions">UserOptions</a></li> <li><a href="global.html#UserOptionsInput">UserOptionsInput</a></li> <li><a href="global.html#UserProfile">UserProfile</a></li> <li><a href="global.html#UserRelation">UserRelation</a></li> <li><a href="global.html#UserStaffNameLanguage">UserStaffNameLanguage</a></li> <li><a href="global.html#UserStats">UserStats</a></li> <li><a href="global.html#UserTitleLanguage">UserTitleLanguage</a></li> <li><a href="global.html#headerBuilder">headerBuilder</a></li> </ul> </nav> <div id="main"> <h1 class="page-title">fetcher.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>const fetch = require("node-fetch"); const { AbortController } = require("abort-controller"); /** * Converts date object into null if year, month, and day are missing * @private * @param { Object } obj * @returns { Object | null } */ function convertPossibleDateNull(obj) { if (obj.year === null &amp;&amp; obj.month === null &amp;&amp; obj.day === null) { return null; } return obj; } /** * Moves data up levels in the object for better use. * @private * @param { Object } obj - Required. The object to edit. * @returns { Object } Returns the edited object. */ function edgeRemove(obj) { let list = []; for (let x = 0; x &lt; obj.length; x++) { if (obj[x].name) { obj[x].name = obj[x].name.english || obj[x].name.full; } if (obj[x].node) { list.push(obj[x].node); } else if (obj[x].id &amp;&amp; obj[x].length === 1) { list.push(obj[x].id); } else if (obj[x].url) { list.push(obj[x].url); } else { list.push(obj[x]); } } if (list.length &lt; 1) { list = null; } return list; } /** * Converts a fuzzyDate into a Javascript Date * @private * @param { fuzzyDate } fuzzyDate - Date provided by AniList's API. * @returns { Date } Returns a date object of the data provided. */ function convertFuzzyDate(fuzzyDate) { if (Object.values(fuzzyDate).some((d) => d === null)) return null; return new Date(fuzzyDate.year, fuzzyDate.month - 1, fuzzyDate.day); } /** * Formats the media data to read better. * @private * @param { Object } media */ function formatMedia(media) { media.reviews = media.reviews.nodes.length === 0 ? null : media.reviews.nodes; media.externalLinks = edgeRemove(media.externalLinks); media.characters = edgeRemove(media.characters.nodes); media.staff = edgeRemove(media.staff.nodes); if (media.airingSchedule) { media.airingSchedule = media.airingSchedule.nodes; } if (media.studios) { media.studios = media.studios.nodes; } media.recommendations = media.recommendations.nodes; media.relations = media.relations.nodes; media.trends = media.trends.nodes; if (media.synonyms.length &lt; 1) { media.synonyms = null; } if (media.trailer) { switch (media.trailer.site) { case "youtube": media.trailer = `https://www.youtube.com/watch?v=${media.trailer.id}`; break; case "dailymotion": media.trailer = `https://www.dailymotion.com/video/${media.trailer.id}`; break; case undefined: media.trailer = null; break; default: break; } } return media; } module.exports = { /** * Send a call to the AniList API with a query and variables. * @param { String } query * @param { Object } variables * @returns { Object } Returns a customized object containing all of the data fetched. */ send: async function (query, variables) { if (!query) { throw new Error("Query is not given!"); } if (query.startsWith("mutation") &amp;&amp; this.key === null) { throw new Error("Function requires authenciation but no authorization found."); } const controller = new AbortController(); const requestTimeout = setTimeout(() => { controller.abort(); }, this.options.timeout); const options = { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json" }, signal: controller.signal }; if (this.key) { options.headers.Authorization = `Bearer ${this.key}`; } if (variables) { options.body = JSON.stringify({ query: query, variables: variables }); } else { options.body = JSON.stringify({ query: query }); } const response = await fetch("https://graphql.anilist.co", options) .catch((error) => { if (error.name === "AbortError") { throw new Error(`ERROR: Request timed out after ${this.options.timeout}ms, is AniList up?`); } }) .finally(() => { clearTimeout(requestTimeout); }); if (response.status !== 200) { if (response.statusText) { throw new Error( `ERROR: AniList API returned with a ${response.status} error code. Message: ${response.statusText}` ); } throw new Error(`ERROR: AniList API returned with a ${response.status} error code.`); } const json = await response.json(); if (Object.keys(json).length &lt; 0) { throw new Error("ERROR: AniList API is down. Please refer to official channels for more information."); } if (json.errors) { return json.errors; } if (json.data.Media) { return formatMedia(json.data.Media); } if (json.data.Character) { json.data.Character.media = json.data.Character.media.nodes; json.data.Character.dateOfBirth = convertPossibleDateNull(json.data.Character.dateOfBirth); return json.data.Character; } if (json.data.Staff) { if (json.data.Staff.description.length &lt; 1) { json.data.Staff.description = null; } json.data.Staff.dateOfBirth = convertPossibleDateNull(json.data.Staff.dateOfBirth); json.data.Staff.dateOfDeath = convertPossibleDateNull(json.data.Staff.dateOfDeath); json.data.Staff.staffMedia = json.data.Staff.staffMedia.nodes; json.data.Staff.characters = json.data.Staff.characters.nodes; json.data.Staff.characterMedia = json.data.Staff.characterMedia.nodes; return json.data.Staff; } if (json.data.Page) { if (json.data.Page.activities) { // For list of recent activities with getRecentActivity. return json.data.Page.activities; } if (json.data.Recommendation) { // For recommendation lists. json.data.Recommendation.recommendations = json.data.Page.recommendations; return json.data.Recommendation; } return json.data.Page; // For general searching } if (json.data.Studio) { json.data.Studio.media = edgeRemove(json.data.Studio.media.nodes); return json.data.Studio; } if (json.data.User || json.data.Viewer) { let userObj = json.data.User || json.data.Viewer; if (userObj.statistics) { //Move all names up a level. userObj.statistics.anime.staff.forEach((e) => { e.staff.name = e.staff.name.english; }); userObj.statistics.anime.voiceActors.forEach((e) => { e.voiceActor.name = e.voiceActor.name.english; }); userObj.statistics.manga.staff.forEach((e) => { e.staff.name = e.staff.name.english; }); } if (userObj.statistics &amp;&amp; !userObj.avatar) { return userObj.statistics; } //Move all node objects up one level. userObj.favourites.anime = userObj.favourites.anime.nodes; userObj.favourites.manga = userObj.favourites.manga.nodes; userObj.favourites.characters = edgeRemove(userObj.favourites.characters.nodes); userObj.favourites.staff = edgeRemove(userObj.favourites.staff.nodes); userObj.favourites.studios = userObj.favourites.studios.nodes; return userObj; } if (json.data.MediaListCollection) { json.data.MediaListCollection.lists.forEach((list) => { list.entries.map((entry) => { //Media does not need to be formatted in a list query. entry.dates = { startedAt: convertFuzzyDate(entry.startedAt), completedAt: convertFuzzyDate(entry.completedAt), updatedAt: new Date(entry.updatedAt * 1000), createdAt: entry.createdAt === 0 ? null : new Date(entry.createdAt * 1000) }; ["startedAt", "completedAt", "updatedAt", "createdAt"].forEach((e) => delete entry[e]); }); }); return json.data.MediaListCollection.lists; } if (json.data.SiteStatistics) { for (const key in json.data.SiteStatistics) { json.data.SiteStatistics[key] = json.data.SiteStatistics[key].nodes; for (const entry in json.data.SiteStatistics[key]) { // Date is given in epoch time. x1000 with UTC seconds for date json.data.SiteStatistics[key][entry].date = new Date( json.data.SiteStatistics[key][entry].date * 1000 ); } } } return json.data; //If nothing matches, return collected data } }; </code></pre> </article> </section> </div> <br class="clear" /> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> using the <a href="https://github.com/clenemt/docdash">docdash</a> theme. </footer> <script> prettyPrint(); </script> <script src="scripts/polyfill.js"></script> <script src="scripts/linenumber.js"></script> <script src="scripts/search.js" defer></script> </body> </html>