asurascans.com
by RFour · Jul 26, 2026 ·javascript
Basically search stuff and uhh chapter and uhh series, this is uhh for manhwa and manga I think mangatoon, if bored and uhhh idk, use this I think to read stuff, I'm lazy to add turn the chapter into pdf cuz uhh fuck it I'm lazy as fuck.
ManhwaMangaSearchChapterSeries
asura.jsjavascript
1const https = require('https');
2
3function asura(a, t, cb) {
4 const H = { 'User-Agent': 'Mozilla/5.0', 'Accept': 'application/json, text/html' };
5
6 const u = n => {
7 if (Array.isArray(n)) {
8 if (n.length < 2) return null;
9 const g = n[0], v = n[1];
10 if (g === 1) return Array.isArray(v) ? v.map(u) : v;
11 if (v && typeof v === 'object' && !Array.isArray(v)) {
12 const o = {};
13 for (const k in v) o[k] = u(v[k]);
14 return o;
15 }
16 if (Array.isArray(v)) return u([1, v]);
17 return v;
18 }
19 if (n && typeof n === 'object') {
20 const o = {};
21 for (const k in n) o[k] = u(n[k]);
22 return o;
23 }
24 return n;
25 };
26
27 const p = (h, f) => {
28 const re = /<astro-island\b[^>]*>/g;
29 let m;
30 while ((m = re.exec(h)) !== null) {
31 const c = m[0].match(/component-url="([^"]*)"/);
32 if (!c || !c[1].includes(f)) continue;
33 const pr = m[0].match(/props="([^"]*)"/);
34 if (!pr) continue;
35 let d = pr[1]
36 .replace(/"/g, '"')
37 .replace(/'/g, "'")
38 .replace(/'/g, "'")
39 .replace(/</g, '<')
40 .replace(/>/g, '>')
41 .replace(/&/g, '&');
42 d = d.replace(/,\s*([}\]])/g, '$1').replace(/undefined/g, 'null');
43 try { return u(JSON.parse(d)); } catch (e) { return null; }
44 }
45 return null;
46 };
47
48 const f = (h, p2, c) => {
49 https.get({ host: h, path: p2, headers: H }, (r) => {
50 let b = '';
51 r.on('data', (d) => b += d);
52 r.on('end', () => c(null, r.statusCode, b));
53 }).on('error', (e) => c(e));
54 };
55
56 const ct = s => s ? s.replace(/<[^>]+>/g, '').trim() : s;
57
58 if (a === 'search') {
59 const q = new URLSearchParams({ search: t, sort: 'latest', order: 'desc', limit: '20', offset: '0' });
60 f('api.asurascans.com', `/api/series?${q}`, (e, s, b) => {
61 if (e || s !== 200) return cb('Search failed');
62 try {
63 const ls = JSON.parse(b);
64 const it = (Array.isArray(ls) ? ls : ls.data || []).map((x) => ({
65 id: x.id,
66 title: x.title,
67 slug: x.slug,
68 url: `https://asurascans.com/comics/${x.slug}`,
69 cover: x.cover,
70 rating: x.rating,
71 status: x.status,
72 chapter_count: x.chapter_count
73 }));
74 cb(null, it);
75 } catch (e) { cb('Search failed'); }
76 });
77 return;
78 }
79
80 let fu = t;
81 if (!t.startsWith('http')) {
82 fu = t.startsWith('/') ? `https://asurascans.com${t}` : `https://asurascans.com/${t}`;
83 }
84 const pa = fu.replace(/^https?:\/\/[^/]+/, '');
85
86 f('asurascans.com', pa, (e, s, html) => {
87 if (e || s !== 200) return cb('Fetch failed');
88
89 if (a === 'series') {
90 const d = p(html, 'DescriptionModal') || {};
91 const l = p(html, 'ChapterListReact') || {};
92 const ch = (l.chapters || []).map((c) => ({ id: c.id, number: c.number, title: c.title, slug: c.slug }));
93 const res = {
94 url: fu,
95 title: d.title,
96 description: ct(d.description),
97 cover: d.coverUrl,
98 rating: d.rating,
99 status: d.status,
100 type: d.type,
101 author: d.author,
102 artist: d.artist,
103 genres: (d.genres || []).map((g) => g.name),
104 total_chapters: d.chapterCount || ch.length,
105 chapters: ch
106 };
107 for (let k in res) if (res[k] === null || res[k] === undefined || (Array.isArray(res[k]) && !res[k].length)) delete res[k];
108 cb(null, res);
109 } else if (a === 'chapter') {
110 const r = p(html, 'ChapterReader');
111 if (!r) return cb('No chapter data');
112 const res = {
113 url: fu,
114 series_name: r.seriesName,
115 chapter_number: r.chapterNumber
116 };
117 if (r.chapterTitle) res.chapter_title = r.chapterTitle;
118 if (r.commentCount) res.comment_count = r.commentCount;
119 if (r.pages && r.pages.length) {
120 res.pages = r.pages;
121 res.images = r.pages.map((x) => x.url);
122 }
123 if (r.prevChapter && r.prevChapter.number) {
124 res.prev_chapter = { number: r.prevChapter.number };
125 if (r.prevChapter.slug) res.prev_chapter.slug = r.prevChapter.slug;
126 }
127 if (r.nextChapter && r.nextChapter.number) {
128 res.next_chapter = { number: r.nextChapter.number };
129 if (r.nextChapter.slug) res.next_chapter.slug = r.nextChapter.slug;
130 }
131 for (let k in res) if (res[k] === null || res[k] === undefined || (Array.isArray(res[k]) && !res[k].length)) delete res[k];
132 cb(null, res);
133 } else {
134 cb('Unknown action');
135 }
136 });
137}
138/*
139asura("search","query",(e,d)=>console.log(e||d))
140asura("series","/comics/...",(e,d)=>console.log(e||d))
141asura("chapter","/comics/.../chapter/N",(e,d)=>console.log(e||d))
142*\