class Realbooru { baseUrl = "https://realbooru.com"; headers = { "User-Agent": "Mozilla/5.0" }; constructor() { this.type = "image-board"; } async search(query = "original", page = 1, perPage = 42) { const offset = (page - 1) * perPage; const tags = query .trim() .split(/\s+/) .join("+") + "+"; const url = `${this.baseUrl}/index.php?page=post&s=list&tags=${tags}&pid=${offset}`; const html = await fetch(url, { headers: this.headers }).then(r => r.text()); const $ = this.cheerio.load(html); const results = []; $('div.col.thumb').each((_, el) => { const id = ($(el).attr('id') || "").replace('s', ''); const img = $(el).find('img'); let image = img.attr('src'); if (image && !image.startsWith('http')) image = 'https:' + image; const title = img.attr('title') || ''; const tags = title .split(',') .map(t => t.trim()) .filter(Boolean); if (id && image) { results.push({ id, image, tags }); } }); let totalPages = page; const lastPid = $('a[alt="last page"]').attr('href')?.match(/pid=(\d+)/); if (lastPid) { totalPages = Math.floor(parseInt(lastPid[1], 10) / perPage) + 1; } return { results, page, hasNextPage: page < totalPages }; } async getInfo(id) { const url = `${this.baseUrl}/index.php?page=post&s=view&id=${id}`; const html = await fetch(url, { headers: this.headers }).then(r => r.text()); const $ = this.cheerio.load(html); let image = $('video source').attr('src') || $('#image').attr('src') || null; if (image && !image.startsWith('http')) { image = this.baseUrl + image; } const tags = []; $('#tagLink a').each((_, el) => { tags.push($(el).text().trim()); }); return { id, image, tags }; } } module.exports = Realbooru;