]*>
Description<\/div>\s*([\s\S]*?)<\/p>/);
+
+ let description = 'No description available';
+ if (descMatch && descMatch[1]) {
+ description = descMatch[1]
+ .replace(/<[^>]+>/g, '')
+ .replace(/\s+/g, ' ')
+ .trim();
+ }
+
+ const transformedResults = [{
+ description,
+ aliases: 'N/A',
+ airdate: 'N/A'
+ }];
+
+ console.log(`Details for "${url}":`, 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 chapterRegex = /
[\s\S]*?([\s\S]*?)<\/a>[\s\S]*?<\/tr>/g;
+ const chapters = [];
+
+ let match;
+ while ((match = chapterRegex.exec(htmlText)) !== null) {
+ const href = match[1].trim();
+ const titleMatch = /Chapter \d+[:\s]?.*/i.exec(match[2]);
+ const title = titleMatch ? decodeHtmlEntities(titleMatch[0].trim()) : "Unknown Chapter";
+ const numberMatch = /Chapter (\d+)/i.exec(title);
+ const number = numberMatch ? parseInt(numberMatch[1]) : NaN;
+
+ chapters.push({
+ number: number === 0 ? 1 : number,
+ href: href.startsWith("http") ? href : "https://mangakatana.com" + href,
+ title: title
+ });
+ }
+
+ chapters.reverse();
+
+ console.log(JSON.stringify(chapters));
+ return chapters;
+ } catch (error) {
+ console.error('Fetch error in extractChapters:', error);
+ return [];
+ }
+}
+
+async function extractText(url) {
+ try {
+ const response = await soraFetch(url);
+ const htmlText = await response.text();
+
+ } catch (error) {
+ console.error("❌ Error in extractImages:", error);
+ return {
+ error: `Error loading chapter images: ${error.message}`
+ };
+ }
+}
+
+function decodeHtmlEntities(str) {
+ const named = {
+ amp: '&',
+ lt: '<',
+ gt: '>',
+ quot: '"',
+ apos: "'",
+ nbsp: ' ',
+ hellip: '…',
+ rsquo: '’',
+ lsquo: '‘',
+ ndash: '–',
+ mdash: '—'
+ };
+
+ return str
+ .replace(/&([a-z]+);/gi, (match, name) => named[name] || match)
+ .replace(/(\d+);/g, (_, code) => String.fromCharCode(code));
+}
+
+
+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;
+ }
+ }
+}