commit 99f66230cd73aeb238a90ca95c72322e169a3cf3 Author: ldez Date: Sat Jan 18 15:35:19 2025 -0700 Add worker.js diff --git a/worker.js b/worker.js new file mode 100644 index 0000000..dd21bdf --- /dev/null +++ b/worker.js @@ -0,0 +1,162 @@ +const languages = new Set(["en", "fr", "es", "it", "pl", "tr", "ja", "zh", "sv"]); +const contentTypes = new Set(["sfw", "nsfw"]); +const urlBase = "https://api.comick.fun/chapter/"; +const genreBase = "https://api.comick.io/genre/"; +const cache = new Map(); +const genreCache = new Map(); + +export default { + async fetch(request) { + const url = new URL(request.url); + const path = url.pathname; + + if (path === "/info") { + return getInfoResponse(); + } + + try { + const language = findLanguage(url); + const contentType = findContentType(url); + const cacheKey = `${language}-${contentType}`; + + let data; + if (cache.has(cacheKey)) { + data = cache.get(cacheKey); + } else { + const apiUrl = `${urlBase}?lang=${language}&page=1&order=new&accept_erotic_content=${contentType === 'nsfw'}`; + data = await fetchData(apiUrl); + cache.set(cacheKey, data); // Cache the response + } + + // Fetch genres if not already cached + if (!genreCache.size) { + const genres = await fetchData(genreBase); + const genreMap = genres.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + genreCache.set('allGenres', genreMap); + } + + const rssData = generateRSS(data, language, contentType, url); + return new Response(rssData, { + headers: { + "Content-Type": "application/rss+xml", + }, + }); + } catch (error) { + console.error("Error processing request:", error); + return new Response("Internal Server Error", { + status: 500, + headers: { + "Content-Type": "text/plain", + }, + }); + } + }, +}; + +function getInfoResponse() { + return new Response(` + + + Worker Info + + +

Welcome to Manga-RSS!

+

Unfortunately, the GitHub repo was taken down and the python script stopped working, but after rewriting the project in JavaScript, I was able to bring it back. To use this new version with even more supported languages, you just append /[language] to the base url and either /sfw or /nsfw for the content rating.

+ + `, { + headers: { + "Content-Type": "text/html", + }, + }); +} + +async function fetchData(apiUrl) { + const init = { + headers: { + "content-type": "application/json;charset=UTF-8", + "User-Agent": "Mozilla/5.0", + }, + }; + + try { + const responseFromApi = await fetch(apiUrl, init); + if (!responseFromApi.ok) { + throw new Error(`Failed to fetch data from API (${responseFromApi.status} ${responseFromApi.statusText})`); + } + + const contentType = (responseFromApi.headers.get("content-type") || "").toLowerCase(); + return contentType.includes("application/json") ? responseFromApi.json() : responseFromApi.text(); + } catch (error) { + console.error("Error fetching data:", error); + throw new Error("Failed to fetch data from the API"); + } +} + +function findLanguage(url) { + for (const lang of languages) { + if (url.pathname.includes(`/${lang}`)) { + return lang; + } + } + return "en"; +} + +function findContentType(url) { + for (const type of contentTypes) { + if (url.pathname.includes(`/${type}`)) { + return type; + } + } + return "sfw"; +} + +function encodeHTML(text) { + return text.replace(//g, ''); +} + +function getGenreNames(genreIds) { + const allGenres = genreCache.get('allGenres'); + return genreIds.map(id => `
  • ${encodeHTML(allGenres[id] || 'Unknown Genre')}
  • `).join(''); +} + +function generateRSS(data, language, contentType, url) { + const rssHeader = ` + + + ComicK - ${language} ${contentType.toUpperCase()} RSS Feed + https://github.com/ld3z/manga-rss + A simple RSS feed for ComicK! + `; + + const rssItems = data.map(comicData => { + const comic = comicData.md_comics; + + const title = ``; + + // Embed the image in the description as an tag + const coverImageURL = comic.md_covers[0] ? `https://meo.comick.pictures/${comic.md_covers[0].b2key}` : ''; + const description = coverImageURL ? `Genres:
      ${getGenreNames(comic.genres)}

    Cover Image]]>` : + `Genres:
      ${getGenreNames(comic.genres)}
    ]]>`; + + // Extract and format the 'updated_at' field from the API response + const pubDate = comicData.updated_at ? new Date(comicData.updated_at).toUTCString() : new Date().toUTCString(); + + return ` + + https://comick.io/comic/${comic.slug} + ${title} + https://comick.io/comic/${comic.slug} + ${description} + ${pubDate} + `; + }).join(''); + + const rssFooter = ` +
    +
    `; + + return `${rssHeader}${rssItems}${rssFooter}`; +}