diff --git a/package-lock.json b/package-lock.json index 9b39710..ced729e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,6 @@ "@vercel/analytics": "^1.4.1", "@vercel/kv": "^1.0.1", "astro": "^5.1.6", - "feed": "^4.2.2", "ioredis": "^5.4.2", "tailwindcss": "^3.4.1" } @@ -2971,17 +2970,6 @@ "reusify": "^1.0.4" } }, - "node_modules/feed": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", - "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", - "dependencies": { - "xml-js": "^1.6.11" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -5570,11 +5558,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" - }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -7055,17 +7038,6 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, - "node_modules/xml-js": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", - "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", - "dependencies": { - "sax": "^1.2.4" - }, - "bin": { - "xml-js": "bin/cli.js" - } - }, "node_modules/xxhash-wasm": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", diff --git a/package.json b/package.json index cc44e93..5e529dc 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "@vercel/analytics": "^1.4.1", "@vercel/kv": "^1.0.1", "astro": "^5.1.6", - "feed": "^4.2.2", "ioredis": "^5.4.2", "tailwindcss": "^3.4.1" } diff --git a/src/components/ComicCard.astro b/src/components/ComicCard.astro index f7923b0..37687b2 100644 --- a/src/components/ComicCard.astro +++ b/src/components/ComicCard.astro @@ -20,8 +20,6 @@ const isNSFW = comic.md_comics.content_rating === 'erotica';
@@ -52,7 +50,7 @@ const isNSFW = comic.md_comics.content_rating === 'erotica';
-

+

{comic.md_comics.title}

diff --git a/src/config/backgrounds.ts b/src/config/backgrounds.ts index 4179bc8..329fce9 100644 --- a/src/config/backgrounds.ts +++ b/src/config/backgrounds.ts @@ -75,10 +75,3 @@ export function getRandomBackground(): BackgroundImage { } return backgrounds[Math.floor(Math.random() * backgrounds.length)]; } - -export function preloadBackgrounds() { - backgrounds.forEach(bg => { - const img = new Image(); - img.src = bg.url; - }); -} diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index 7ce0919..7c27522 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -147,12 +147,11 @@ const isCreditsPage = Astro.url.pathname === '/credits'; } }; - // Add theme initialization to prevent flash of wrong theme - const themeScript = ` - const theme = localStorage.getItem('theme') ?? - (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'); - document.documentElement.setAttribute('data-theme', theme); - `; + // Initialize theme + const savedTheme = localStorage.getItem('theme') as 'light' | 'dark' | null; + const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; + const initialTheme = savedTheme || (prefersDark ? 'dark' : 'light'); + updateThemeToggle(initialTheme); // Event listeners settingsButton?.addEventListener('click', () => { diff --git a/src/lib/api.ts b/src/lib/api.ts index 3d482f1..d566cbe 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -69,43 +69,30 @@ export function getGenreNames(genreIds: number[], genres: Genre[]): string[] { .filter(name => name !== ''); } -export class APIError extends Error { - constructor( - message: string, - public statusCode?: number, - public endpoint?: string - ) { - super(message); - this.name = 'APIError'; - } -} - export async function fetchComics( language: string = 'en', contentType: string = 'sfw', comicType: ComicType = 'all', page: number = 1 ): Promise { - const apiUrl = `${urlBase}?lang=${language}&page=${page}&order=new&accept_erotic_content=${contentType === 'nsfw'}${comicType === 'all' ? '' : `&type=${comicType}`}`; - try { + const typeParam = comicType === 'all' ? '' : `&type=${comicType}`; + const apiUrl = `${urlBase}?lang=${language}&page=${page}&order=new&accept_erotic_content=${contentType === 'nsfw'}${typeParam}`; + console.log('Fetching comics from:', apiUrl); const response = await fetchWithRetry(apiUrl); const data = await response.json(); if (!Array.isArray(data)) { - throw new APIError('Invalid API response format', undefined, apiUrl); + console.error('Unexpected API response format:', data); + return []; } return data; } catch (error) { - if (error instanceof APIError) throw error; - throw new APIError( - 'Failed to fetch comics', - error instanceof Response ? error.status : undefined, - apiUrl - ); + console.error('Error fetching comics:', error); + return []; } } diff --git a/src/lib/db.ts b/src/lib/db.ts index ffcc509..84a8deb 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -3,8 +3,6 @@ import type { FeedMapping } from './types'; const REDIS_URL = import.meta.env.REDIS_URL || process.env.REDIS_URL; let redis: Redis | null = null; -let redisRetryCount = 0; -const MAX_RETRIES = 3; try { console.log('Environment check:', { @@ -25,14 +23,11 @@ try { console.log(`Retry attempt ${times} with delay ${delay}ms`); return delay; }, - maxRetriesPerRequest: 2, + maxRetriesPerRequest: 3, enableReadyCheck: true, - reconnectOnError: (err) => { - const targetError = 'READONLY'; - if (err.message.includes(targetError)) { - return true; - } - return false; + reconnectOnError(err) { + console.log('Reconnect on error:', err.message); + return true; } }); @@ -60,38 +55,6 @@ try { } } -async function getRedisClient(): Promise { - if (redis?.status === 'ready') return redis; - - if (redisRetryCount >= MAX_RETRIES) { - throw new Error('Failed to connect to Redis after multiple attempts'); - } - - try { - redis = new Redis(REDIS_URL, { - retryStrategy(times) { - const delay = Math.min(times * 50, 2000); - console.log(`Retry attempt ${times} with delay ${delay}ms`); - return delay; - }, - maxRetriesPerRequest: 2, - enableReadyCheck: true, - reconnectOnError: (err) => { - const targetError = 'READONLY'; - if (err.message.includes(targetError)) { - return true; - } - return false; - } - }); - redisRetryCount = 0; - return redis; - } catch (error) { - redisRetryCount++; - throw error; - } -} - export async function storeFeedMapping(feedId: string, slugs: string[], lang: string): Promise { if (!redis) { console.error('Redis client not initialized'); diff --git a/src/lib/types.ts b/src/lib/types.ts index 2970743..69b3f03 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -6,9 +6,11 @@ export interface Comic { title: string; slug: string; genres: number[]; - md_covers: ComicCover[]; - content_rating: 'safe' | 'suggestive' | 'erotica'; - comic_type: ComicType; + md_covers: { + b2key: string; + }[]; + content_rating: string; + comic_type: string; }; } @@ -22,10 +24,4 @@ export interface FeedMapping { lang: string; } -export type ComicType = 'manga' | 'manhwa' | 'manhua' | 'all'; - -export interface ComicCover { - b2key: string; - width?: number; - height?: number; -} \ No newline at end of file +export type ComicType = 'manga' | 'manhwa' | 'manhua' | 'all'; \ No newline at end of file diff --git a/src/pages/rss/[feedId].xml.ts b/src/pages/rss/[feedId].xml.ts index 9429878..d589c17 100644 --- a/src/pages/rss/[feedId].xml.ts +++ b/src/pages/rss/[feedId].xml.ts @@ -1,9 +1,9 @@ -import { Feed } from 'feed'; +import rss from "@astrojs/rss"; import { getChaptersForSlugs, isValidLanguage } from "../../lib/api"; import { getFeedMapping } from "../../lib/db"; import type { APIRoute } from "astro"; -export const GET: APIRoute = async ({ params, request }) => { +export const GET: APIRoute = async ({ params }) => { const feedId = params.feedId?.replace('.xml', ''); if (!feedId) { @@ -28,29 +28,14 @@ export const GET: APIRoute = async ({ params, request }) => { return new Response("No chapters found for the provided comics", { status: 404 }); } - const siteUrl = new URL(request.url).origin; - const feedUrl = new URL(request.url).href; - - const feed = new Feed({ + return rss({ title: `ComicK - Custom Feed (${lang.toUpperCase()})`, description: `Custom RSS feed for selected comics: ${slugs.join(', ')}`, - id: feedUrl, - link: siteUrl, - feedLinks: { - rss2: feedUrl - }, - language: lang, - copyright: "All rights reserved", - updated: new Date(), - generator: 'ComicK RSS Generator', - }); - - chapters.forEach((chapter) => { - const chapterUrl = `https://comick.io/comic/${chapter.md_comics.slug}`; - feed.addItem({ + site: "https://github.com/ld3z/manga-rss", + items: chapters.map((chapter) => ({ title: `${chapter.md_comics.title} - Chapter ${chapter.chap}`, - id: `${chapter.md_comics.slug}-${chapter.chap}`, - link: chapterUrl, + link: `https://comick.io/comic/${chapter.md_comics.slug}`, + pubDate: new Date(chapter.updated_at), description: `
${ @@ -62,13 +47,6 @@ export const GET: APIRoute = async ({ params, request }) => {

New chapter available: Chapter ${chapter.chap}

`, - date: new Date(chapter.updated_at), - }); - }); - - return new Response(feed.rss2(), { - headers: { - 'Content-Type': 'application/xml; charset=utf-8', - }, + })), }); }; \ No newline at end of file diff --git a/src/pages/rss/custom/[slugs].xml.ts b/src/pages/rss/custom/[slugs].xml.ts index d29f95c..f5bb501 100644 --- a/src/pages/rss/custom/[slugs].xml.ts +++ b/src/pages/rss/custom/[slugs].xml.ts @@ -1,4 +1,4 @@ -import { Feed } from 'feed'; +import rss from "@astrojs/rss"; import { getChaptersForSlugs, isValidLanguage } from "../../../lib/api"; import type { APIRoute } from "astro"; @@ -22,37 +22,15 @@ export const GET: APIRoute = async ({ params, url }) => { return new Response("No chapters found for the provided comics", { status: 404 }); } - const siteUrl = new URL(url).origin; - const feedUrl = new URL(url).href; - - const feed = new Feed({ + return rss({ title: `ComicK - Custom Feed (${lang.toUpperCase()})`, description: `Custom RSS feed for selected comics: ${slugs.join(', ')}`, - id: feedUrl, - link: siteUrl, - feedLinks: { - rss2: feedUrl - }, - language: lang, - copyright: "All rights reserved", - updated: new Date(), - generator: 'ComicK RSS Generator', - }); - - chapters.forEach((chapter) => { - const chapterUrl = `https://comick.io/comic/${chapter.md_comics.slug}`; - feed.addItem({ + site: "https://github.com/ld3z/manga-rss", + items: chapters.map((chapter) => ({ title: `${chapter.md_comics.title} - Chapter ${chapter.chap}`, - id: `${chapter.md_comics.slug}-${chapter.chap}`, - link: chapterUrl, + link: `https://comick.io/comic/${chapter.md_comics.slug}`, + pubDate: new Date(chapter.updated_at), description: `New chapter available: Chapter ${chapter.chap}`, - date: new Date(chapter.updated_at), - }); - }); - - return new Response(feed.rss2(), { - headers: { - 'Content-Type': 'application/xml; charset=utf-8', - }, + })), }); }; \ No newline at end of file