Skip to content

Commit

Permalink
Merge pull request #8 from Butterstroke/1.2.3
Browse files Browse the repository at this point in the history
Version 1.2.3
  • Loading branch information
AurelicButter authored Jan 27, 2020
2 parents e016231 + f9def35 commit 2ae688b
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 46 deletions.
9 changes: 8 additions & 1 deletion documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ Upon using a function, the data it returns is given in an object. So within the
- `media.updatedAt` | Timestamp of when the page was last updated
- `media.siteUrl` | The media's Anilist page
- `media.modNotes` | Mod notes for the media
- `media.recommendations` | An array of recommendations
- `media.recommendations.id` | The ID of the show recommended.
- `media.recommendations.title` | An object of the show's titles. Four values: romanji, english, native, and userPreferred.

## Anime Unique
- `anime.episodes` | Number of episodes
Expand All @@ -57,13 +60,14 @@ Upon using a function, the data it returns is given in an object. So within the

## Manga Unique
- `manga.volumes` | Number of volumes
- `manga.chapters` | Number of chapters

# People

## Functions
Names must be strings and ids must be numbers.
`Anilist.people.staff(name|id)` | Staff function. Fetches a staff member by their id or name.<br/>
`Anilist.people.character(id)` | Character function. Fetches a character by their id.<br/>
`Anilist.people.character(name|id)` | Character function. Fetches a character by their id or name.<br/>

## General
- `people.id` | Person's id
Expand All @@ -72,6 +76,7 @@ Names must be strings and ids must be numbers.
- `people.descriptions` | Person's description
- `people.isFavourite` | [Requires login] Check if person is favourited
- `people.siteUrl` | Person's AniList page
- `people.favourites` | Number of users that have favourited the person.

## Character Unique
- `character.media` | All media that the character is in (Returns id, idMal, title (All four options), and format)
Expand Down Expand Up @@ -119,6 +124,8 @@ Usernames must be strings and ids must be numbers!<br/>
- `profile.donatorTier` | Check if the user is a donator
- `profile.moderatorStatus` | Check if the user is a moderator
- `profile.updatedAt` | Timestamp of the last update of the user
- `profile.isFollower` | [Requires login] Checks if the searched user is following the logged in user.
- `profile.isBlocked` | [Requires login] Checks if the logged in user has blocked the searched user.

## Stats Unique
- `stats.watchedTime` | Total amount of watch time on the user's anime list
Expand Down
40 changes: 30 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,53 @@ module.exports = class AniList {
this.people = people;
};

/**
* Grabs data on a studio
* @param {Number} id - The studio ID on AniList.
* @returns { Object } Returns a customized data object.
*/
studio(id) {
if (!id) { throw new Error("Studio id is not provided."); }
if (typeof id !== "number") { throw new Error("Term provided is not a number!"); }

return Fetch.send(`query($id: Int) { Studio(id: $id) { id name media { edges { id } } siteUrl isFavourite } }`, { id: id });
};

search(type, term, page, amount) {
/**
* Searchs AniList based on a specific term.
* @param {String} type - Required. Either anime, manga, character, staff or studio.
* @param {String} term - Required. The term to lookup.
* @param {Number} page - Which page of the results to look at. Will default to 1 if not provided.
* @param {Number} amount - The amount of results per page. AniList will cap this at 25 and function will default to 5 if not provided.
*/
search(type, term, page=1, amount=5) {
if (!type) { throw new Error("Type of search not defined!"); }
else if (!term || !page || !amount) { throw new Error("Search term, page count, or amount per page was not provided!"); }
else if (!term) { throw new Error("Search term was not provided!"); }

//Validate all type conditions.
if (typeof type !== "string") { throw new Error("Type is not a string."); }
if (typeof term !== "string") { throw new Error("Term is not a string"); }
if (typeof page !== "number") { throw new Error("Page number is not a number"); }
if (typeof amount !== "number") { throw new Error("Amount is not a number"); }

var search = {
"anime": "media (id: $id, type: ANIME, search: $search) { id title { romaji english native userPreferred } }",
"manga": "media (id: $id, type: MANGA, search: $search) { id title { romaji english native userPreferred } }",
"char": "characters (id: $id, search: $search) { id name { first last native } }" ,
"staff": "staff (id: $id, search: $search) { id name { first last native } }",
"studio": "studios (id: $id, search: $search) { id name }"
"anime": "media (type: ANIME, search: $search) { id title { romaji english native userPreferred } }",
"manga": "media (type: MANGA, search: $search) { id title { romaji english native userPreferred } }",
"char": "characters (search: $search) { id name { first last native } }" ,
"staff": "staff (search: $search) { id name { first last native } }",
"studio": "studios (search: $search) { id name }"
}
type = type.toLowerCase(); //Correct terms for switch case.

switch (type) {
switch (type.toLowerCase()) {
case "anime": var query = search["anime"]; break;
case "manga": var query = search["manga"]; break;
case "character": var query = search["char"]; break;
case "staff": var query = search["staff"]; break;
case "studio": var query = search["studio"]; break;
default: throw new Error("Type not supported.");
}
return Fetch.send(`query ($id: Int, $page: Int, $perPage: Int, $search: String) {

return Fetch.send(`query ($page: Int, $perPage: Int, $search: String) {
Page (page: $page, perPage: $perPage) { pageInfo { total currentPage lastPage hasNextPage perPage } ${query} } }`, { search: term, page: page, perPage: amount});
};
};
36 changes: 28 additions & 8 deletions lib/fetcher.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
const fetch = require('node-fetch');
const fetch = require("node-fetch");

function edgeRemove(obj) { // Move data up levels in the object for better use
/**
* Moves data up levels in the object for better use.
* @param { Object } obj - Required. The object to edit.
* @returns { Object } Returns the edited object.
*/
function edgeRemove(obj) {
var list = [];
for (var x = 0; x < obj.length; x++) {
if (obj[x].name) {
Expand All @@ -18,12 +23,20 @@ function edgeRemove(obj) { // Move data up levels in the object for better use
return list;
}

/**
* Converts a fuzzyDate into a Javascript Date
* @param { fuzzyDate } fuzzyDate - Date provided by AniList's API.
*/
function convertFuzzyDate(fuzzyDate) {
if (Object.values(fuzzyDate).some(d => d === null)) return null;
return new Date(fuzzyDate.year, fuzzyDate.month - 1, fuzzyDate.day);
}

async function formatMedia(media) { //Formats the media data to read better.
/**
* Formats the media data to read better.
* @param { Object } media
*/
async function formatMedia(media) {
media.reviews = (media.reviews.nodes.length === 0) ? null : media.reviews.nodes;

media.externalLinks = await edgeRemove(media.externalLinks);
Expand All @@ -34,19 +47,26 @@ async function formatMedia(media) { //Formats the media data to read better.
if (media.studios) { media.studios = media.studios.nodes; }
media.relations = media.relations.nodes;
media.trends = media.trends.nodes;
media.recommendations = media.recommendations.nodes;

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 "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: media.trailer = media.trailer; break;
default: media.trailer = media.trailer; 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 || !variables) { throw new Error("Query or variables are not given!"); }
var options = {
Expand All @@ -57,7 +77,7 @@ module.exports = {
},
body: JSON.stringify({ query: query, variables: variables })
};
if (this.key) { options.headers.Authorization = 'Bearer ' + this.key; }
if (this.key) { options.headers.Authorization = `Bearer ${this.key}`; }
var response = await fetch('https://graphql.anilist.co', options);
var json = await response.json();

Expand Down Expand Up @@ -103,4 +123,4 @@ module.exports = {

return json.data; //If nothing matches, return collected data,
}
};
};
20 changes: 17 additions & 3 deletions lib/lists.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
const Fetch = require('./fetcher');
const { send } = require('./fetcher');

function variables(user, type) {
if (typeof user === 'string') { return [{ name: user, type: type }, `query ($name: String, $type: MediaType) { MediaListCollection(userName: $name, type: $type) { `]; }
else if (typeof user === 'number') { return [{ id: user, type: type }, `query ($id: Int, $type: MediaType) { MediaListCollection(userId: $id,, type: $type) { `]; }
}

module.exports = {
/**
* Fetch a user's AniList anime lists.
* @param { Number | String } user - Required. Can either be the username or the AniList ID.
* @returns { Object } Returns a customized data object.
*/
anime: function(user) {
if (!user) { throw new Error("AniList username or id is missing!"); }
if (typeof user !== "string" && typeof user !== "number") { throw new Error("Term provided is not a string or a number!"); }

var start = variables(user, 'ANIME');
var query = start[1] + `lists { name isCustomList isSplitCompletedList status entries {
media { id idMal title { romaji english native userPreferred } type episodes description format status startDate { year month day }
Expand All @@ -21,10 +28,17 @@ module.exports = {
reviews { nodes { id score summary body } } siteUrl autoCreateForumThread modNotes }
userId status score progress repeat priority private notes hiddenFromStatusLists
advancedScores startedAt { year month day } completedAt { year month day } updatedAt createdAt } } } }`;
return Fetch.send(query, start[0]);
return send(query, start[0]);
},
/**
* Fetch a user's AniList manga lists.
* @param { Number | String } user - Required. Can either be the username or the AniList ID.
* @returns { Object } Returns a customized data object.
*/
manga: function(user) {
if (!user) { throw new Error("AniList username or id is missing!"); }
if (typeof user !== "string" && typeof user !== "number") { throw new Error("Term provided is not a string or a number!"); }

var start = variables(user, 'MANGA');
var query = start[1] + `lists { name isCustomList isSplitCompletedList status entries {
media { id idMal title { romaji english native userPreferred }
Expand All @@ -36,6 +50,6 @@ module.exports = {
mediaListEntry { id } reviews { nodes { id score summary body } } }
userId status score progress progressVolumes repeat priority private notes hiddenFromStatusLists
advancedScores startedAt { year month day } completedAt { year month day } updatedAt createdAt } } } }`;
return Fetch.send(query, start[0]);
return send(query, start[0]);
}
};
28 changes: 22 additions & 6 deletions lib/media.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
const Fetch = require('./fetcher');
const { send } = require('./fetcher');

module.exports = {
/**
* Fetch an anime entry by its AniList ID.
* @param { Number } id - Required. The ID tied to the AniList entry.
* @returns { Object } Returns a customized data object.
*/
anime: function(id) {
if (!id) { throw new Error("Anime id is not provided!"); }
return Fetch.send(`query ($id: Int) { Media (id: $id, type: ANIME) { id idMal title { romaji english native userPreferred }
if (typeof id !== "number") { throw new Error("Term provided is not a number!"); }

return send(`query ($id: Int) { Media (id: $id, type: ANIME) { id idMal title { romaji english native userPreferred }
type episodes description format status startDate { year month day } endDate { year month day }
season duration countryOfOrigin isLicensed source hashtag trailer { id site }
updatedAt coverImage { large medium } bannerImage genres synonyms averageScore meanScore
Expand All @@ -12,16 +19,25 @@ module.exports = {
isFavourite isAdult nextAiringEpisode { timeUntilAiring airingAt } airingSchedule { nodes { airingAt timeUntilAiring } }
trends { nodes { date trending popularity inProgress } } externalLinks { url }
streamingEpisodes { title thumbnail url site } rankings { id } mediaListEntry { id }
reviews { nodes { id score summary body } } siteUrl autoCreateForumThread modNotes } }`, { id: id });
reviews { nodes { id score summary body } } siteUrl autoCreateForumThread modNotes
isRecommendationBlocked recommendations { nodes { mediaRecommendation { id title { romaji english native userPreferred } } } } } }`, { id: id });
},
/**
* Fetch a manga entry by its AniList ID.
* @param { Number } id - Required. The ID tied to the AniList entry.
* @returns { Object } Returns a customized data object.
*/
manga: function(id) {
if (!id) { throw new Error("Manga id is not provided!"); }
return Fetch.send(`query ($id: Int) { Media (id: $id, type: MANGA) { id idMal title { romaji english native userPreferred }
type description format status startDate { year month day } endDate { year month day } volumes countryOfOrigin isLicensed updatedAt
if (typeof id !== "number") { throw new Error("Term provided is not a number!"); }

return send(`query ($id: Int) { Media (id: $id, type: MANGA) { id idMal title { romaji english native userPreferred }
type description format status startDate { year month day } endDate { year month day } chapters volumes countryOfOrigin isLicensed updatedAt
coverImage { large medium } bannerImage genres synonyms averageScore meanScore siteUrl autoCreateForumThread modNotes
popularity trending tags { name isMediaSpoiler } relations { nodes { id idMal title { english native romaji userPreferred } type format } }
characters { nodes { id name { first last } } } staff { nodes { id name { first last native } } } isFavourite isAdult
trends { nodes { date trending popularity inProgress } } externalLinks { url } rankings { id }
mediaListEntry { id } reviews { nodes { id score summary body } } } }`, { id: id });
mediaListEntry { id } reviews { nodes { id score summary body } }
isRecommendationBlocked recommendations { nodes { mediaRecommendation { id title { romaji english native userPreferred } } } } } }`, { id: id });
}
};
36 changes: 27 additions & 9 deletions lib/people.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
const Fetch = require('./fetcher');
const { send } = require('./fetcher');

module.exports = {
/**
* Fetch a character entry by its AniList ID.
* @param { Number|String } id - Required. The ID tied to the AniList entry.
* @returns { Object } Returns a customized data object.
*/
character: function(id) {
if (!id) { throw new Error("Person id is not provided"); }
return Fetch.send(`query ($id: Int) { Character (id: $id) { id name { first last native } image { large medium }
description isFavourite siteUrl media { nodes { id idMal title { romaji english native userPreferred } format } } } }`, { id: id });
if (!id) { throw new Error("Character term is not provided!"); }

if (typeof id === 'string') { queryVars = [{ search: id }, `query ($search: String) { Character (search: $search) { `]; }
else if (typeof id === 'number') { queryVars = [{ id: id }, `query ($id: Int) { Character (id: $id,) { `]; }
else { throw new Error("Term does not match the required types!"); }

return send(queryVars[1] + `id name { first last native } image { large medium } description isFavourite favourites
siteUrl media { nodes { id idMal title { romaji english native userPreferred } format } } } }`, queryVars[0]);
},
/**
* Fetch a staff entry by its AniList ID or their name.
* @param { Number|String } id - Required. The ID can either be the AniList ID or the staff's name.
* @returns { Object } Returns a customized data object.
*/
staff: function(id) {
if (!id) { throw new Error("Person id is not provided"); }
qStart = (typeof id === "string") ? [{ search: id }, `query ($search: String) { Staff (search: $search) { `] : [{ id: id }, `query ($id: Int) { Staff (id: $id) { `];
if (!id) { throw new Error("Person term is not provided"); }

if (typeof id === 'string') { queryVars = [{ search: id }, `query ($search: String) { Staff (search: $search) { `]; }
else if (typeof id === 'number') { queryVars = [{ id: id }, `query ($id: Int) { Staff (id: $id,) { `]; }
else { throw new Error("Term does not match the required types!"); }

return Fetch.send(qStart[1] + `id name { first last native } language image { large medium }
description isFavourite siteUrl
return send(queryVars[1] + `id name { first last native } language image { large medium }
description isFavourite siteUrl favourites
staffMedia { nodes { id title { romaji english native userPreferred } } }
characters { nodes { id name { first last } } } } }`, qStart[0]);
characters { nodes { id name { first last } } } } }`, queryVars[0]);
}
};
Loading

0 comments on commit 2ae688b

Please sign in to comment.