shadowmanga-scraper
v0.1.2
Published
TypeScript client for consuming the shademanga.com REST APIs
Maintainers
Readme
shadowmanga-scraper
A TypeScript client for consuming the shademanga.com REST APIs. Search manga, browse tags, and fetch series details with full type safety.
Installation
npm install shadowmanga-scraperRequires Node.js 18+ (uses native fetch).
Usage
import { ShadeMangaClient } from 'shadowmanga-scraper';
const client = new ShadeMangaClient();
// Get all available tags
const tags = await client.getTags();
console.log(tags); // ['Acción', 'Adventure', 'Comedy', ...]
// Search for manga
const results = await client.search({ query: 'frieren' });
console.log(results[0].titulo); // 'Sousou no Frieren'
// Get series detail with chapters
const series = await client.getSeries('zUIH4L');
console.log(series.titulo); // 'Sousou no Frieren'
console.log(series.capitulos.length); // 100+API Reference
new ShadeMangaClient(options?)
Creates a new client instance.
| Option | Type | Default | Description |
|----------|----------|--------------------------|--------------------------|
| baseUrl | string | https://shademanga.com | API base URL |
| timeout | number | 10000 | Request timeout in ms |
client.getTags(): Promise<string[]>
Returns all available manga tags/genres.
Endpoint: GET /api/series-locales/tags
client.search(options): Promise<MangaSearchResult[]>
Search manga by title.
| Option | Type | Default | Description |
|-------------------|-----------|---------|------------------------------------|
| query | string | — | Required. Search query |
| tags | string | — | Filter by tag/genre (e.g. Fantasía) |
| includeAdult | boolean | false | Include adult content |
| showSinPortada | boolean | false | Show results without cover |
| take | number | 120 | Max results to return |
Endpoint: GET /api/series-locales/search-candidates?q={query}&...
client.getSeries(idOrPublicId): Promise<SeriesDetail>
Get full series detail including chapters.
| Parameter | Type | Description |
|------------------|--------------------|----------------------------------|
| idOrPublicId | string \| number | Series numeric ID or public ID |
Endpoint: GET /api/series-locales/{idOrPublicId}
client.getChapterPages(serieId, capituloId): Promise<ChapterPages>
Get all page URLs for a specific chapter.
| Parameter | Type | Description |
|-------------|--------------------|------------------------------------|
| serieId | string \| number | Series numeric ID or public ID |
| capituloId | string \| number | Chapter numeric ID or public ID |
Endpoint: GET /api/series-locales/{serieId}/capitulos/{capituloId}/paginas
Returns: ChapterPages with paginas (array of image URLs), totalPaginas, and IDs.
client.getPopular(options?): Promise<PopularMangaResponse>
Get paginated list of popular manga.
| Option | Type | Default | Description |
|----------|----------|---------|--------------------------|
| pageSize | number | 24 | Items per page |
| page | number | 1 | Page number |
Endpoint: GET /api/series-locales/populares?pageSize={pageSize}&page={page}
Returns: PopularMangaResponse with items, pagination info (page, pageSize, total, totalPages), and pageTokens for cursor-based navigation.
Types / Interfaces
All types are fully exported:
import type {
Chapter,
ChapterPages,
MangaSearchResult,
SeriesDetail,
SearchOptions,
ShadeMangaClientOptions,
PopularMangaResponse,
PopularMangaResult,
PageTokens,
PopularOptions,
} from 'shadowmanga-scraper';MangaSearchResult
interface MangaSearchResult {
id: number;
publicId: string;
titulo: string;
autor: string | null;
generos: string;
titulosAlternativos: string | null;
estado: string;
esMayorDeEdad: boolean;
esDestacada: boolean;
puntuacion: number | null;
fechaActualizacion: string;
portadaUrl: string;
sinPortada: boolean;
grupoScanNombre: string | null;
grupoScanSlug: string | null;
}SeriesDetail
interface SeriesDetail {
id: number;
publicId: string;
titulo: string;
descripcion: string | null;
autor: string | null;
tags: string | null;
tagsDescripcion: string | null;
portadaUrl: string;
portadaFocalPoint: string | null;
generos: string;
titulosAlternativos: string | null;
esMayorDeEdad: boolean;
estaEnEmision: boolean;
esDestacada: boolean;
esRevisado: boolean;
visible: boolean;
puntuacion: number | null;
estado: string;
tipo: string | null;
fechaCreacion: string;
fechaActualizacion: string;
grupoScanId: number | null;
grupoScanNombre: string | null;
grupoScanSlug: string | null;
capitulos: Chapter[];
}ChapterPages
interface ChapterPages {
paginas: string[];
totalPaginas: number;
capituloId: number;
publicCapituloId: string;
serieId: number;
publicSerieId: string;
}Chapter
interface Chapter {
id: number;
publicId: string;
numeroCapitulo: number;
titulo: string | null;
archivoNombre: string;
archivoTamano: number;
totalPaginas: number;
fechaSubida: string;
orden: number;
visible: boolean;
tomoId: number | null;
}PopularMangaResult
interface PopularMangaResult {
id: number;
publicId: string;
titulo: string;
autor: string | null;
generos: string;
portadaUrl: string;
esMayorDeEdad: boolean;
esDestacada: boolean;
fechaActualizacion: string;
fechaCreacion: string;
puntuacion: number | null;
estado: string;
totalCapitulos: number;
}PopularMangaResponse
interface PopularMangaResponse {
items: PopularMangaResult[];
page: number;
pageSize: number;
total: number;
totalPages: number;
pageTokens: PageTokens;
}PageTokens
interface PageTokens {
current: string;
prev: string | null;
next: string | null;
first: string;
last: string;
}Error Handling
All methods throw on failure:
- HTTP errors:
ShadeManga API error: {status} {statusText} - Timeouts:
ShadeManga API request timed out after {timeout}ms - Network errors: Native
fetcherrors are re-thrown
try {
const series = await client.getSeries('invalid-id');
} catch (error) {
if (error instanceof Error) {
console.error(error.message);
}
}License
MIT
