async function searchContent(keyword, page=0) { const results = []; try { const offset = page * 100; const response = await fetch(`https://api.mangadex.org/manga?title=${encodeURIComponent(keyword)}&limit=100&offset=${offset}&contentRating[]=safe&contentRating[]=suggestive&contentRating[]=erotica&includes[]=cover_art&order[followedCount]=desc&order[relevance]=desc`); const data = await response.json(); if (data.result === 'ok' && data.data) { for (const manga of data.data) { const id = manga.id; const attributes = manga.attributes; let title = attributes.title.en || attributes.title['en']; if (!title) { const altTitles = attributes.altTitles || []; for (const alt of altTitles) { if (alt.en) { title = alt.en; break; } } } if (!title) { title = Object.values(attributes.title)[0] || 'Unknown Title'; } let imageURL = ''; const relationships = manga.relationships || []; const coverArt = relationships.find(rel => rel.type === 'cover_art'); if (coverArt && coverArt.attributes && coverArt.attributes.fileName) { imageURL = `https://mangadex.org/covers/${id}/${coverArt.attributes.fileName}`; } results.push({ id: id, imageURL: imageURL, title: title }); } } return results; } catch (err) { console.error(err); return []; } } async function getContentData(ID) { try { const response = await fetch(`https://api.mangadex.org/manga/${ID}?includes[]=artist&includes[]=author&includes[]=cover_art`); const data = await response.json(); if (data.result === 'ok' && data.data) { const attributes = data.data.attributes; const description = attributes.description?.en || attributes.description?.['en'] || Object.values(attributes.description || {})[0] || ''; const tags = (attributes.tags || []).map(tag => tag.attributes?.name?.en || tag.attributes?.name?.['en'] || Object.values(tag.attributes?.name || {})[0] || '').filter(Boolean); return { description: description, tags: tags }; } return { description: "", tags: [] }; } catch (err) { console.error(err); return { description: "Error", tags: [] }; } } async function getChapters(url) { const results = []; try { const limit = 100; let offset = 0; let total = 0; const allChapters = []; do { const response = await fetch(`https://api.mangadex.org/manga/${url}/feed?limit=${limit}&offset=${offset}&includes[]=scanlation_group&includes[]=user&contentRating[]=safe&contentRating[]=suggestive&contentRating[]=erotica&contentRating[]=pornographic&excludeExternalUrl=blinktoon.com&order[chapter]=asc&includeUnavailable=0`); const data = await response.json(); if (data.result === 'ok' && data.data) { allChapters.push(...data.data); total = data.total; offset += limit; } else { break; } } while (offset < total && allChapters.length < total); const chapters = {}; for (const ch of allChapters) { const lang = ch.attributes.translatedLanguage; if (!chapters[lang]) { chapters[lang] = []; } const chapterNum = ch.attributes.chapter; const chapterFloat = parseFloat(chapterNum) || 0; const scanlationGroupRel = ch.relationships.find(rel => rel.type === 'scanlation_group'); const scanlationGroup = scanlationGroupRel ? scanlationGroupRel.attributes.name : ''; const title = ch.attributes.title || `Chapter ${chapterNum}`; chapters[lang].push({ id: ch.id, title: title + ` - Language: ${lang}`, chapter: chapterFloat, scanlation_group: scanlationGroup, language: lang }); } for (const lang in chapters) { chapters[lang].sort((a, b) => a.chapter - b.chapter); } const results = {}; for (const lang in chapters) { results[lang] = chapters[lang].map(ch => [ ch.chapter.toString(), [{ id: ch.id, title: ch.title, chapter: ch.chapter, scanlation_group: ch.scanlation_group }] ]); } return results; } catch (err) { console.error(err); return { en: [] }; } } async function getChapterImages(chapterId) { try { const apiEndpoint = `https://api.mangadex.org/at-home/server/${chapterId}`; const apiResponse = await fetch(apiEndpoint); const serverData = await apiResponse.json(); const { baseUrl: imageBaseUrl, chapter: { hash: chapterHash, data: imageFiles } } = serverData; console.log(serverData); return imageFiles.map(fileName => `${imageBaseUrl}/data/${chapterHash}/${fileName}`); } catch (error) { console.log(error.message); return []; } }