npm package: @notsopreety/anilist-js
Description: A Node.js module for accessing AniList manga and anime data via GraphQL API
Author: Samir Thakuri
Latest version: 1.0.3

# AniList JS

![npm](https://img.shields.io/npm/v/@notsopreety/anilist-js) ![license](https://img.shields.io/npm/l/@notsopreety/anilist-js) ![downloads](https://img.shields.io/npm/dm/@notsopreety/anilist-js)

A lightweight and modern Node.js module for interacting with the [AniList GraphQL API](https://docs.anilist.co/guide/introduction) to fetch manga and anime data. This package provides a simple, promise-based interface for querying AniList’s extensive database of manga, anime, manhwa, and Korean anime, with support for searching, retrieving by ID, and fetching top or trending content.

## Features

- **Manga and Anime Support**: Query both manga and anime with consistent APIs.
- **Pagination**: Built-in support for paginated results with customizable page size.
- **Comprehensive Data**: Retrieve detailed media information, including titles, descriptions, genres, scores, and more.
- **Lightweight**: Minimal dependencies (only `axios`) for a lean package.
- **Error Handling**: Robust error handling for API failures and invalid inputs.
- **TypeScript Ready**: Includes type definitions for TypeScript users (planned for future releases).

## Installation

Install the package via npm:

```bash
npm install @notsopreety/anilist-js
```

Ensure you have Node.js version `>=14` installed.

## Quick Start

Here’s a simple example to get you started with searching for anime:

```javascript
const { searchAnime } = require('@notsopreety/anilist-js');

async function main() {
  try {
    const result = await searchAnime('Attack on Titan', 1, 5);
    console.log('Page Info:', result.pageInfo);
    console.log('Results:', result.media);
  } catch (error) {
    console.error('Error:', error.message);
  }
}

main();
```

## Usage

The package exposes ten asynchronous functions for querying manga and anime data. All functions return promises and follow a consistent interface.

### Available Functions

#### Manga Functions
- **`searchManga(search, page = 1, perPage = 10)`**: Search manga by title.
- **`getMangaById(id)`**: Retrieve manga details by AniList ID.
- **`getTop100Manga(page = 1, perPage = 10)`**: Fetch top 100 manga, sorted by score.
- **`getTrendingManga(page = 1, perPage = 10)`**: Fetch trending manga.
- **`getTopManhwa(page = 1, perPage = 10)`**: Fetch top Korean manhwa.

#### Anime Functions
- **`searchAnime(search, page = 1, perPage = 10)`**: Search anime by title.
- **`getAnimeById(id)`**: Retrieve anime details by AniList ID.
- **`getTop100Anime(page = 1, perPage = 10)`**: Fetch top 100 anime, sorted by score.
- **`getTrendingAnime(page = 1, perPage = 10)`**: Fetch trending anime.
- **`getTopKoreanAnime(page = 1, perPage = 10)`**: Fetch top Korean anime.

### Response Structure

Most functions (except `getMangaById` and `getAnimeById`) return a `Page` object with:
- `pageInfo`: Pagination details (`total`, `currentPage`, `lastPage`, `hasNextPage`, `perPage`).
- `media`: Array of media objects containing fields like `id`, `title`, `coverImage`, `description`, etc.

The `getMangaById` and `getAnimeById` functions return a single media object directly.

### Media Fields

Each media object includes:
- `id`: Unique AniList ID.
- `title`: Object with `romaji`, `english`, and `native` titles.
- `coverImage`: Object with `large` image URL.
- `description`: Plain text description.
- `episodes`: Number of episodes (anime-specific, null for manga).
- `chapters`: Number of chapters (manga-specific, null for anime).
- `volumes`: Number of volumes (manga-specific, null for anime).
- `status`: Media status (e.g., `FINISHED`, `RELEASING`).
- `genres`: Array of genres.
- `averageScore`: Average community score (0-100).
- `siteUrl`: URL to the media’s AniList page.

### Detailed Examples

#### Searching for Manga

```javascript
const { searchManga } = require('@notsopreety/anilist-js');

async function searchExample() {
  try {
    const result = await searchManga('One Piece', 1, 10);
    console.log(`Total Results: ${result.pageInfo.total}`);
    result.media.forEach((manga, index) => {
      console.log(`${index + 1}. ${manga.title.english || manga.title.romaji}`);
    });
  } catch (error) {
    console.error('Error:', error.message);
  }
}

searchExample();
```

#### Fetching Anime by ID

```javascript
const { getAnimeById } = require('@notsopreety/anilist-js');

async function idExample() {
  try {
    const anime = await getAnimeById(21); // Naruto
    console.log('Title:', anime.title.english);
    console.log('Description:', anime.description);
    console.log('Genres:', anime.genres.join(', '));
  } catch (error) {
    console.error('Error:', error.message);
  }
}

idExample();
```

#### Getting Top 100 Manga with Pagination

```javascript
const { getTop100Manga } = require('@notsopreety/anilist-js');

async function topMangaExample() {
  try {
    const result = await getTop100Manga(2, 5); // Page 2, 5 items per page
    console.log(`Page ${result.pageInfo.currentPage} of ${result.pageInfo.lastPage}`);
    result.media.forEach(manga => {
      console.log(`${manga.title.english || manga.title.romaji} (Score: ${manga.averageScore})`);
    });
  } catch (error) {
    console.error('Error:', error.message);
  }
}

topMangaExample();
```

## Error Handling

The package throws errors for:
- Invalid input (e.g., non-numeric ID, negative page numbers).
- AniList API errors (e.g., rate limits, invalid queries).
- Network issues.

Example of handling errors:

```javascript
const { getMangaById } = require('@notsopreety/anilist-js');

async function errorExample() {
  try {
    await getMangaById('invalid'); // Invalid ID
  } catch (error) {
    console.error('Failed to fetch manga:', error.message);
  }
}

errorExample();
```

**Note**: AniList enforces rate limits (approximately 90 requests per minute). Handle `429 Too Many Requests` errors by implementing retries or backoff strategies in your application.

## Requirements

- **Node.js**: `>=14`
- **Dependencies**: `axios (^1.7.2)`

## Development

To contribute or modify the package locally:

1. Clone the repository:
   ```bash
   git clone https://github.com/notsopreety/anilist-js.git
   cd anilist-js
   ```

2. Install dependencies:
   ```bash
   npm install
   ```

3. Test changes:
   - Create a test file or use existing examples.
   - Run with `node <test-file>.js`.

4. Submit a pull request with your changes.

## Roadmap

- Add TypeScript support with type definitions.
- Implement caching options for frequent queries.
- Support additional AniList queries (e.g., characters, staff, user lists).
- Add unit tests with Jest.
- Provide configuration for custom API endpoints or headers.

## Contributing

Contributions are welcome! Please follow these steps:

1. Fork the repository.
2. Create a feature branch (`git checkout -b feature/your-feature`).
3. Commit your changes (`git commit -m 'Add your feature'`).
4. Push to the branch (`git push origin feature/your-feature`).
5. Open a pull request.


## License

This project is licensed under the [MIT License](LICENSE).

## Acknowledgments

- Built using the [AniList GraphQL API](https://docs.anilist.co/guide/introduction).
- Powered by [axios](https://github.com/axios/axios) for HTTP requests.

## Contact

For questions or support, open an issue on [GitHub](https://github.com/notsopreety/anilist-js/issues) or contact [Samir Thakuri](mailto:itssamir444@gmail.com).