Shinigami
baca manga, manhwa manhua,
3 Juni 2026972 file
shinigami.jsjavascript · 167 baris
/** * Shinigami * base: https://g.shinigami.asia/ * Creator: ShanMolvyr * Jangan Hapus Kreator hargai rakyat kecil * Note: cek https://snippet.vyr.my.id/shanmolvyr/shinigami/README.md * Sumber: https://whatsapp.com/channel/0029VbB4Kw8EFeXfeExaXc3Q */const BASE_API = 'https://api.shngm.io';const ASSETS_BASE = 'https://assets.shngm.id';const HEADERS = { Accept: 'application/json', 'Content-Type': 'application/json', Origin: 'https://g.shinigami.asia', Referer: 'https://g.shinigami.asia/', 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',};async function api(path) { const res = await fetch(`${BASE_API}${path}`, { headers: HEADERS }); if (!res.ok) throw new Error(`HTTP ${res.status}: ${BASE_API}${path}`); return res.json();}function getMangaList(p = {}) { const q = new URLSearchParams({ page: p.page ?? 1, page_size: p.pageSize ?? 24, sort: p.sort ?? 'latest', sort_order: p.sortOrder ?? 'desc', }); if (p.format != null) q.set('format', p.format); if (p.isUpdate != null) q.set('is_update', p.isUpdate); if (p.isRecommended != null) q.set('is_recommended', p.isRecommended); if (p.type != null) q.set('type', p.type); return api(`/v1/manga/list?${q}`);}function getMangaTop(p = {}) { const q = new URLSearchParams({ filter: p.filter ?? 'daily', page: p.page ?? 1, page_size: p.pageSize ?? 10, }); return api(`/v1/manga/top?${q}`);}const getMangaDetail = (mangaId) => api(`/v1/manga/detail/${mangaId}`);const getChapterDetail = (chapterId) => api(`/v1/chapter/detail/${chapterId}`);function getChapterList(mangaId, p = {}) { const q = new URLSearchParams({ page: p.page ?? 1, page_size: p.pageSize ?? 100, sort_by: 'chapter_number', sort_order: p.sortOrder ?? 'desc', }); return api(`/v1/chapter/${mangaId}/list?${q}`);}function getImageUrls(chapterData) { const base = chapterData.base_url + chapterData.chapter.path; return chapterData.chapter.data.map(f => base + f);}function searchManga(p = {}) { const q = new URLSearchParams({ page: p.page ?? 1, page_size: p.pageSize ?? 24, sort: 'latest', sort_order: 'desc', genre_include_mode: 'or', genre_exclude_mode: 'or', q: p.q ?? '', }); if (p.format != null) q.set('format', p.format); if (p.genreInclude != null) q.set('genre_include', p.genreInclude); if (p.genreExclude != null) q.set('genre_exclude', p.genreExclude); return api(`/v1/manga/list?${q}`);}const getGenreList = () => api('/v1/genre/list');const getFormatList = () => api('/v1/format/list?page=1');const getAuthorList = (q = '') => api(`/v1/author/list?q=${encodeURIComponent(q)}`);function getMangaNotice(mangaId, p = {}) { const q = new URLSearchParams({ page: p.page ?? 1, page_size: p.pageSize ?? 3 }); return api(`/v1/notice/${mangaId}/list?${q}`);}function getAnnouncements(p = {}) { const q = new URLSearchParams({ page: p.page ?? 1, page_size: p.pageSize ?? 10 }); return api(`/v1/announcement/list?${q}`);}if (require.main === module) { const [,, cmd, ...args] = process.argv; async function run() { switch (cmd) { case 'home': console.log(JSON.stringify(await getMangaList({ pageSize: 10 }), null, 2)); break; case 'trending': console.log(JSON.stringify(await getMangaTop({ filter: args[0] || 'daily' }), null, 2)); break; case 'detail': if (!args[0]) throw new Error('Usage: node index.js detail <manga_id>'); console.log(JSON.stringify(await getMangaDetail(args[0]), null, 2)); break; case 'chapters': if (!args[0]) throw new Error('Usage: node index.js chapters <manga_id> [asc|desc]'); (await getChapterList(args[0], { sortOrder: args[1] || 'desc' })).data .forEach(ch => console.log(`Ch.${String(ch.chapter_number).padEnd(6)} | ${ch.chapter_id} | ${ch.release_date}`)); break; case 'read': { if (!args[0]) throw new Error('Usage: node index.js read <chapter_id>'); const r = await getChapterDetail(args[0]); const ch = r.data; console.log(`Chapter : ${ch.chapter_number}`); console.log(`Manga : ${ch.manga_id}`); console.log(`Prev : Ch.${ch.prev_chapter_number ?? '-'} (${ch.prev_chapter_id ?? '-'})`); console.log(`Next : Ch.${ch.next_chapter_number ?? '-'} (${ch.next_chapter_id ?? '-'})`); console.log(`Pages : ${ch.chapter.data.length}\n`); getImageUrls(ch).forEach(url => console.log(url)); break; } case 'search': if (!args[0]) throw new Error('Usage: node index.js search <query>'); console.log(JSON.stringify(await searchManga({ q: args.join(' ') }), null, 2)); break; case 'genres': console.log(JSON.stringify(await getGenreList(), null, 2)); break; case 'formats': console.log(JSON.stringify(await getFormatList(), null, 2)); break; case 'announcements': console.log(JSON.stringify(await getAnnouncements(), null, 2)); break; default: console.log(`Usage: node index.js <command> [args] home trending [daily|weekly|monthly] detail <manga_id> chapters <manga_id> [asc|desc] read <chapter_id> search <query> genres formats announcements`); } } run().catch(err => { console.error(err.message); process.exit(1); });}module.exports = { getMangaList, getMangaTop, getMangaDetail, getChapterList, getChapterDetail, getImageUrls, searchManga, getGenreList, getFormatList, getAuthorList, getMangaNotice, getAnnouncements, BASE_API, ASSETS_BASE,};README.mdmarkdown · 18 baris
Cara Pakai
node shinigami.js # lihat semua command
node shinigami.js home
node shinigami.js trending daily
node shinigami.js detail <manga_id>
node shinigami.js chapters <manga_id> asc
node shinigami.js read <chapter_id>
node shinigami.js search eleceed
node shinigami.js genres
node shinigami.js formats
node shinigami.js announcements
Komentar
Masuk untuk ikut berkomentar.
Belum ada komentar.