async function searchResults(keyword) { try { const encodedKeyword = encodeURIComponent(keyword); const url = `https://readnovelfull.com/novel-list/search?keyword=${encodedKeyword}`; const response = await soraFetch(url); const html = await response.text(); const results = []; const rowRegex = /
([\s\S]*?)<\/div>\s*<\/div>\s*<\/div>/g; let rowMatch; while ((rowMatch = rowRegex.exec(html)) !== null) { const rowHtml = rowMatch[1]; const imgMatch = rowHtml.match(/]*class="cover"/); const linkMatch = rowHtml.match(/

\s*]*itemprop="description"[^>]*>([\s\S]*?)<\/div>/i); let description = descMatch ? descMatch[1] .replace(/]*>/gi, '') .replace(/<\/p>/gi, '') .replace(/\s+/g, ' ') .trim() : "No description available"; const aliases = 'N/A'; const airdate = 'N/A'; const transformedResults = [{ description, aliases, airdate }]; console.log(JSON.stringify(transformedResults)); return JSON.stringify(transformedResults); } catch (error) { console.log('Details error:' + error); return JSON.stringify([{ description: 'Error loading description', aliases: 'N/A', airdate: 'N/A' }]); } } async function extractChapters(url) { try { const response = await soraFetch(url); const htmlText = await response.text(); const novelIdMatch = htmlText.match(/
]*data-novel-id="([^"]+)"[^>]*>/i); if (!novelIdMatch) { throw new Error("Novel ID not found"); } const novelId = novelIdMatch[1]; const chaptersResponse = await soraFetch(`https://readnovelfull.com/ajax/chapter-archive?novelId=${novelId}`); const chaptersHtml = await chaptersResponse.text(); const chapters = []; const chapterRegex = /]*>[\s\S]*?]*class="[^"]*\bnchr-text\b[^"]*"[^>]*>([\s\S]*?)<\/span>/gi; let match; while ((match = chapterRegex.exec(chaptersHtml)) !== null) { const href = "https://readnovelfull.com" + match[1]; const titleFromAttr = match[2].trim(); const titleFromSpan = match[3].replace(/\s+/g, ' ').trim(); const title = titleFromAttr || titleFromSpan; chapters.push({ title, href }); } chapters.sort((a, b) => { const numA = parseFloat(a.title.match(/Chapter\s+(\d+)/i)?.[1]) || 0; const numB = parseFloat(b.title.match(/Chapter\s+(\d+)/i)?.[1]) || 0; return numA - numB; }); chapters.forEach((chapter, index) => { chapter.number = index + 1; }); console.log(JSON.stringify(chapters)); return JSON.stringify(chapters); } catch (error) { console.error('Fetch error in extractChapters:', error); return JSON.stringify([{ href: url, title: "Error fetching chapters", number: 0 }]); } } async function extractText(url) { try { const response = await soraFetch(url); let htmlText = await response.text(); console.log(htmlText); const startPattern = /
]*>[\s\S]*?<\/div>/; const endPattern = /
/; const startMatch = htmlText.search(startPattern); const endMatch = htmlText.search(endPattern); if (startMatch === -1 || endMatch === -1) { const contentStartPattern = /
]*>/; const contentEndPattern = /
/; const contentStartMatch = htmlText.search(contentStartPattern); const contentEndMatch = htmlText.search(contentEndPattern); if (contentStartMatch === -1 || contentEndMatch === -1) { throw new Error("Content markers not found"); } const contentStartIndex = htmlText.match(contentStartPattern)[0].length + contentStartMatch; let content = htmlText.substring(contentStartIndex, contentEndMatch).trim(); content = content.replace(/
]*>[\s\S]*?<\/div>/gi, ''); content = content.replace(//gi, ''); content = content.replace(/<[^>]+>/g, ''); content = content.replace(/\s+/g, ' ').trim(); if (!content) { throw new Error("No content found between markers"); } console.log(content); return content; } const startIndex = htmlText.match(startPattern)[0].length + startMatch; let content = htmlText.substring(startIndex, endMatch).trim(); content = content.replace(/
]*>[\s\S]*?<\/div>/gi, ''); content = content.replace(//gi, ''); content = content.replace(/
]*>[\s\S]*?<\/div>/gi, ''); content = content.replace(/\s+/g, ' ').trim(); if (!content) { throw new Error("No content found between markers"); } console.log(content); return content; } catch (error) { console.log("Fetch error in extractText: " + error); return '

Error extracting text

'; } } async function soraFetch(url, options = { headers: {}, method: 'GET', body: null }) { try { return await fetchv2(url, options.headers ?? {}, options.method ?? 'GET', options.body ?? null); } catch (e) { try { return await fetch(url, options); } catch (error) { return null; } } } function decodeHtmlEntities(text) { const entities = { '—': '—', '–': '–', '&': '&', '<': '<', '>': '>', '"': '"', ''': "'", '/': '/', '`': '`', '=': '=', ' ': ' ' }; return text.replace(/&#x[\dA-Fa-f]+;|&\w+;/g, (match) => { return entities[match] || match; }); }