diff --git a/mangadex/mangadex.js b/mangadex/mangadex.js new file mode 100644 index 0000000..43ff835 --- /dev/null +++ b/mangadex/mangadex.js @@ -0,0 +1,163 @@ +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 []; + } +}