Back to Home
Gistify Snippet
kyiov
2h ago·1 file(s)
Public

MangaDex Search & Metadata Scraper

Fast MangaDex v5 API client for searching manga titles, cover art URLs, chapter status, genres, and publication metadata.

#mangadex#manga#scraper#anime#javascript#api
0
Raw
mangadex.jsjavascript
111 lines
1// mangadex.js — bundle standalone. npm deps: axios, node:url
2
3/**
4 * Scraper: mangadex.js
5 * Source : kyioapi/mangadex.js
6 *
7 * Input : Function parameters / CLI args (e.g. query: string, url: string, options: object)
8 * Output : Promise<Object | Array | Buffer> (JSON formatted scraping response / stream URL / media metadata)
9 *
10 * CLI Run:
11 * node kyioapi/mangadex.js [functionName] [args...]
12 * node cli.js kyioapi/mangadex.js [functionName] [args...]
13 */
14
15import * as __ns_227 from 'axios'
16const axios = __ns_227.default
17import * as __ns_228 from 'node:url'
18const pathToFileURL = __ns_228.pathToFileURL
19
20
21
22/**
23 * MangaDex Search Scraper
24 */
25async function searchMangaDex(query, limit = 10) {
26 try {
27 const url = 'https://api.mangadex.org/manga';
28 const params = {
29 title: query,
30 limit: Math.min(limit, 100), // Cap limit to 100 as per common API practices
31 contentRating: ['safe', 'suggestive', 'erotica'],
32 includes: ['cover_art'],
33 order: {
34 followedCount: 'desc',
35 relevance: 'desc'
36 }
37 };
38
39 const response = await axios.get(url, { params });
40 const data = response.data;
41
42 const results = data.data.map(manga => {
43 const coverRel = manga.relationships.find(rel => rel.type === 'cover_art');
44 const coverFile = coverRel?.attributes?.fileName || null;
45
46 return {
47 id: manga.id,
48 title: manga.attributes.title.en || Object.values(manga.attributes.title)[0] || 'No title',
49 altTitles: manga.attributes.altTitles.map(t => Object.values(t)[0]).filter(Boolean),
50 status: manga.attributes.status,
51 year: manga.attributes.year,
52 demographic: manga.attributes.publicationDemographic,
53 contentRating: manga.attributes.contentRating,
54 lastChapter: manga.attributes.lastChapter,
55 description: manga.attributes.description.en?.substring(0, 200) + '...' || null,
56 tags: manga.attributes.tags.map(t => t.attributes.name.en),
57 coverUrl: coverFile ? `https://uploads.mangadex.org/covers/${manga.id}/${coverFile}` : null,
58 externalLinks: manga.attributes.links || {}
59 };
60 });
61
62 return {
63 query: query,
64 limit: params.limit,
65 total: data.total,
66 offset: data.offset,
67 count: results.length,
68 results: results
69 };
70
71 } catch (error) {
72 throw new Error(`MangaDex Search Error: ${error.message}`);
73 }
74}
75
76export { searchMangaDex };
77export default searchMangaDex;
78
79// ─────────────────────────────────────────────────────────────────────
80// Self-test: jalankan langsung dengan `node mangadex.js [args...]`
81// ─────────────────────────────────────────────────────────────────────
82if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
83 const __exports = { searchMangaDex: searchMangaDex }
84 const __fns = Object.fromEntries(Object.entries(__exports).filter(([, v]) => typeof v === 'function'))
85 const __names = Object.keys(__fns)
86 if (__names.length === 0) {
87 console.log('Tidak ada fungsi yang bisa di-demo. Import modul ini dari kode lain.')
88 } else {
89 const __search = __names.find((n) => /search|cari/i.test(n))
90 const __name = __search || __names[0]
91 const __fn = __fns[__name]
92 const __isClass = /^class\s/.test(Function.prototype.toString.call(__fn))
93 let __args = process.argv.slice(2).map((a) => { try { return JSON.parse(a) } catch { return a } })
94 if (__args.length === 0 && __search) __args.push('naruto')
95 if (__args.length === 0 && !__search && !__isClass && __fn.length > 0) {
96 console.log('Fungsi: ' + __names.join(', '))
97 console.log('Contoh: node ' + "mangadex.js" + ' ' + __name + ' <arg>')
98 } else {
99 ;(async () => {
100 try {
101 const r = __isClass ? new __fn(...__args) : await __fn(...__args)
102 console.log(JSON.stringify(r, null, 2))
103 } catch (e) {
104 console.error('Error: ' + (e && e.message ? e.message : e))
105 process.exitCode = 1
106 }
107 })()
108 }
109 }
110}
111
Discussion & Comments0

No comments yet — be the first to leave feedback or start a code discussion.

Sign in with your GitHub account to write comments and join the discussion.