Files
AniKotoAPI/src/extractors/azList.extractor.js
T
Shinei Nouzen a8f1917ce7 feat: v2.2.0 — Modularize codebase, unify mirror fallback, harden security
Major Changes:
- Add shared parseListItem.helper.js for unified list parsing (DRY)
- Migrate all 22 extractors to use fetchWithMirror() for consistent mirror fallback
- Remove unused cors dependency (custom CORS middleware handles it)
- Fix middleware ordering: timeout now registered before routes
- Fix CORS to allow POST for /api/mirrors/reset endpoint
- Remove redundant cache check in homeInfo extractor

New Features:
- Request ID tracking (X-Request-Id header) for debugging
- Graceful shutdown handling (SIGTERM/SIGINT) with 10s timeout
- CSP and HSTS security headers
- Rate limiter cleanup interval (every 5 min) to prevent memory leak
- Request body size limits (10kb) via express.json()

Security:
- Content-Security-Policy header for XSS protection
- Strict-Transport-Security for HTTPS enforcement
- X-Permitted-Cross-Domain-Policies: none
- Body size limits to prevent large payload attacks

Code Quality:
- All files follow strict documentation style (box headers, section separators,
  feature markers, JSDoc params/returns, inline notes, module footers)
- Eliminated ~200 lines of duplicated code across 8+ extractors
- Updated CHANGELOG.md with comprehensive change history
2026-07-28 19:28:21 +05:30

69 lines
3.0 KiB
JavaScript

/*
* ======= • ======= • ======= • ======= • =======• =======
* AniKotoAPI — azList.extractor.js
* Repository: https://github.com/Shineii86/AniKotoAPI
*
* @description
* Extracts anime from A-Z listing pages with pagination.
* Supports filtering by letter (a-z) or "all" for complete list.
*
* @exports
* extractAzList
*
* @author Shinei Nouzen
* @license MIT
* ======= • ======= • ======= • ======= • =======• =======
*/
import { URLS } from "../configs/dataUrl.js";
import { extractPages } from "../helper/extractPages.helper.js";
import { countPages } from "../helper/countPages.helper.js";
import { parseListItems } from "../helper/parseListItem.helper.js";
// ══════════════════════════════════════════════════════════════
// A-Z LIST EXTRACTION
// ══════════════════════════════════════════════════════════════
// ---- FEATURE: Extract anime from A-Z listing with pagination ----
/**
* Fetches and parses anime from the A-Z listing page.
* Supports filtering by letter (a-z) or "all" for complete list.
*
* @param {string} letter - Letter to filter by (a-z) or "all" (default: "all")
* @param {number} page - Page number to fetch (default: 1)
* @returns {Promise<Object>} Object containing totalPages, letter, and data array
* @returns {number} return.totalPages - Total number of pages available
* @returns {string} return.letter - The letter filter used
* @returns {Array<Object>} return.data - Array of anime objects
* @returns {string} return.data[].slug - URL slug for the anime
* @returns {string} return.data[].poster - Poster image URL
* @returns {string} return.data[].title - English title
* @returns {string} return.data[].japaneseTitle - Japanese title
* @returns {number} return.data[].sub - Subbed episode count
* @returns {number} return.data[].dub - Dubbed episode count
* @returns {number} return.data[].total - Total episode count
* @returns {string} return.data[].type - Anime type (TV, Movie, etc.)
* @returns {string} return.data[].rating - Anime rating
*
* @example
* const azList = await extractAzList("a", 1);
* console.log(azList.letter); // "a"
* console.log(azList.data[0].title); // First anime starting with "a"
*/
const extractAzList = async (letter = "all", page = 1) => {
try {
const url = URLS.azList(letter);
const $ = await extractPages(url, page);
const totalPages = countPages($);
const results = parseListItems($);
return { totalPages, letter, data: results };
} catch (error) {
throw error;
}
};
export { extractAzList };
// ══════════════════════════════════════════════════════════════ END: azList.extractor.js