]*>
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();
const testUrl = 'https://static.wikia.nocookie.net/473b884a-a6d8-43ad-9c9c-fa6b676f8126';
const imageUrls = Array(20).fill(testUrl);
const html = `
Manga
${imageUrls.map((url, i) => ` `).join('\n')}
`;
return html;
} 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;
}
}
}