Crunchyroll wrapper using webscraping utilities. Made using Crunchyroll's beta API. Created by Eltik, Inumaki, and the Consumet Community.
Cronchy is available on NPM via the following command:
$ npm install cronchy
However, you can also clone the GitHub via git clone https://github.com/Eltik/Cronchy
. If you are cloning the repository, you can build the project using the following commands:
$ npm run install
$ npm run build
It is also important to note that Cronchy requires TypeScript and NodeJS to run, so if you have difficulties installing the library make sure to check that your machine supports both.
Cronchy requires a premium account to work properly (and no, we will/cannot support non-premium accounts). To initialize a Cronchy "instance", pass your email and password into the constructor.
// ES6
import Cronchy from "cronchy";
// commonjs
const Cronchy = require("cronchy").default;
const instance = new Cronchy("myemail@outlook.com", "password123");
There is a third argument you can pass into the constructor which is the token. As of now, Crunchyroll requires a token header for all requests that is constant. The token should work for all accounts, but in the case it doesn't, you can provide a it into the constructor in the case Crunchyroll changes how their API works. Support will not be provided on how to fetch the token, but for peace of mind the argument is there just in case.
...
const instance = new Cronchy("myemail@outlook.com", "password123", "a3ZvcGlzdXZ6Yy0teG96Y21kMXk6R21JSTExenVPVnRnTjdlSWZrSlpibzVuLTRHTlZ0cU8=");
To use all functions of the package, you need to run the login()
function beforehand. This is important because Crunchyroll requires an access_token
header for each request. Some other functions such as the querySeason()
function require other account data such as the signature
and policy
of the account. Don't worry, though; this function is completely safe and simulates a real login.
const instance = ...;
await instance.login(); // Returns Promise<AccountData>
interface AccountData {
access_token: string;
refresh_token?: string;
expires_in: number;
token_type: string;
scope: string;
country: string;
account_id: string;
signature: string;
key_pair_id: string;
bucket: string;
policy: string;
}
For convenience sake, the login()
function will store all account data in the instance object. This means that if you are running a web server, upon the server's startup you can run the login()
function to prevent having to continuously fetch the access_token
. For example:
import Fastify from "fastify";
import Cronchy from "cronchy";
const instance = new Cronchy(...);
const fastify = Fastify({
...
});
fastify.listen({ port: 3000 }, (err, address) => {
if (err) throw err;
instance.login().then((accountData) => {
console.log(`Listening to ${address}.`);
});
})
Searching using the Cronchy package is simple. Just run instance.search(query, amount?);
to search through all of Crunchyroll for a specific show. amount
is an optional parameter that by default will input 8 if not specified.
const instance = new Cronchy(...);
/**
* @param query Search query. Takes a string.
* @param amount Max amount of search results. Takes a number.
* returns Promise<SearchData>
*/
instance.search("Bocchi the Rock", 5);
interface SearchData {
total: number;
data: Array<SearchResult>;
meta: JSON;
}
interface SearchResult {
type: MediaType["top_results"] | MediaType["series"] | MediaType["movie_listing"] | MediaType["episode"];
count: number;
items: Array<SearchQuery>;
}
Fetchin episodes requires the ID of the show. In past versions of Cronchy you were required to input a SearchQuery
object. However, I realized that Crunchyroll actually fetches the show info based on the show ID so I removed that parameter. getEpisodes()
also requires the locale of the show, but most of the time it's just en-US
. If you need to confirm the locale of the show you are querying, you can run the getLocaleFromSearchQuery()
function and input a SearchQuery
object. Lastly, the mediaType
parameter is the type of the show as the name suggests. You can run the getMediaTypeFromSearchQuery()
function and input a SearchQuery
object to fetch it. If either the locale or media type return undefined
, it most likely means that the show has not been released officially on Crunchyroll (eg. it's not available yet).
const instance = new Cronchy(...);
/**
* @param id SearchQuery id. Can be obtained from the search function.
* @param locale The locale of the show. Can be obtained from the search function or via getLocaleFromSearchQuery().
* @param mediaType The type of media. Must be a valid Crunchyroll series string.
* @param fetchAll Whether or not to fetch all "seasons" (whatever Crunchyroll means by that lol). If false, only the the episodes from the "season" will be fetched.
*/
const results = await instance.search(...);
const locale = instance.getLocaleFromSearchQuery(result.data[0].items[0]);
const mediaType = instance.getMediaTypeFromSearchQuery(result.data[0].items[0]);
await instance.getEpisodes(results.data[0].items[0].id, locale, mediaType, false);
interface Show {
id: string;
title: string;
isAdult: string|boolean;
image: string;
cover: string;
description: string;
releaseDate: number;
genres: string[];
season: string;
hasDub: boolean;
hasSub: boolean;
rating: string;
recommendations: any; // This needs to be fixed, but it returns data correctly.
episodes: any; // This to. TypeScript moment :pray:
}
To elaborate on the fetchAll
parameter, fetching all episodes will take longer but also get all the episodes Crunchyroll has. Crunchyroll has "seasons", or multiple "series" of episodes. As a result, the fetchAll
option is thus required for fetching all episodes as the name suggests.
Crunchyroll stores the source of their videos as m3u8s, or streamable files. By default, this package is meant to be lightweight and doesn't contain a convertor. But considering that m3u8s are better for streaming videos rather than mp4s, it makes sense that the getSources()
function will return an m3u8 instead.
const instance = new Cronchy(...);
/**
* @param episodeId The episode ID of the show.
* @param locale The locale of the episode. For example, "en-US".
* returns Promise<Sources>
*/
await instance.getSources("G6Q4Q3V1R", "en-US");
interface Sources {
sources: Array<Source>;
subtitles: Array<Subtitle>;
}
interface Source {
url: string;
quality: string;
isM3U8: boolean;
}
interface Subtitle {
url: string;
lang: string;
format: string;
}
Contribution to this documentation would be appreciated as it is not finished.
- MalSync
- Cleanup (the whole thing is sort of messy) If anyone wishes to contribute, that would be appreciated. Feel free to create a Pull Request.
Rip Kamyroll