const axios = require('axios'); const cheerio = require('cheerio'); async function getSeriesDetail(url) { try { const baseUrl = 'https://xbato.com'; const response = await axios.get(url); const $ = cheerio.load(response.data); const container = $('.container-max-width-xl'); const title = container.find('.title-set h3.item-title a').text().trim(); const aliases = container.find('.alias-set').text().trim() .split('/').map(a => a.trim()).filter(Boolean); const thumbnail = container.find('.attr-cover img').attr('src'); const authors = []; container.find('.attr-item b:contains("Authors:")').next().find('a').each((i, el) => { authors.push($(el).text().trim()); }); const artists = []; container.find('.attr-item b:contains("Artists:")').next().find('a').each((i, el) => { artists.push($(el).text().trim()); }); const genres = []; container.find('.attr-item b:contains("Genres:")').next().children().each((i, el) => { genres.push($(el).text().trim()); }); const language = container.find('.attr-item b:contains("Original language:")').next().text().trim(); const translated = container.find('.attr-item b:contains("Translated language:")').next().text().trim(); const status = container.find('.attr-item b:contains("Original work:")').next().text().trim(); const uploadStatus = container.find('.attr-item b:contains("Upload status:")').next().text().trim(); const year = container.find('.attr-item b:contains("Year of Release:")').next().text().trim(); const summary = container.find('.limit-html').text().trim(); const chapters = []; $('.item').each((i, el) => { const chapterEl = $(el); const chapterPath = chapterEl.find('a.visited.chapt').attr('href'); const chapterUrl = baseUrl + chapterPath; const chapterTitle = chapterEl.find('a.visited.chapt b').text().trim(); const uploaderEl = chapterEl.find('.extra a.ps-3'); const uploaderName = uploaderEl.find('span').text().trim(); const uploaderPath = uploaderEl.attr('href'); const uploaderUrl = baseUrl + uploaderPath; const uploaderAvatar = uploaderEl.find('img').attr('src'); const viewsRaw = chapterEl.find('.extra span.ps-3 i').map((i, el) => $(el).text().trim()).get(); const views = viewsRaw.join(' '); const uploadDate = chapterEl.find('.extra i.ps-3').text().trim(); chapters.push({ title: chapterTitle, url: chapterUrl, views, uploadDate }); }); return { title, aliases, thumbnail, authors, artists, genres, language, translated, status, uploadStatus, year, summary, chapters }; } catch (err) { console.error('Error saat mengambil detail seri:', err.message); return null; } } async function getChapterImages(url) { try { const response = await axios.get(url); const $ = cheerio.load(response.data); const scriptContent = $('script') .map((_, el) => $(el).html()) .get() .find(text => text.includes('const imgHttps')); const imgRegex = /const imgHttps\s*=\s*(\[[^\]]+\])/; const match = imgRegex.exec(scriptContent); if (!match) throw new Error('imgHttps not found'); const imageArray = eval(match[1]); return imageArray; } catch (err) { console.error('Gagal scrape:', err.message); return []; } } // contoh getSeriesDetail detail getSeriesDetail("https://xbato.com/series/99300/can-we-become-family-official") // contoh penggunaan getChapterImages getChapterImages("https://xbato.com/chapter/3259300")