diff --git a/frontend/src/components/EpisodeList.tsx b/frontend/src/components/EpisodeList.tsx index 224e829..0049555 100644 --- a/frontend/src/components/EpisodeList.tsx +++ b/frontend/src/components/EpisodeList.tsx @@ -34,7 +34,7 @@ function EpisodeList() { const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [currentAudio, setCurrentAudio] = useState(null) - const [useDatabase, setUseDatabase] = useState(false) + const [useDatabase, setUseDatabase] = useState(true) useEffect(() => { fetchEpisodes() diff --git a/server.ts b/server.ts index 9b31614..f2e6cee 100644 --- a/server.ts +++ b/server.ts @@ -110,9 +110,9 @@ app.get("/index.html", serveIndex); // API endpoints for frontend app.get("/api/episodes", async (c) => { try { - const { fetchEpisodesWithArticles } = await import("./services/database.js"); - const episodes = await fetchEpisodesWithArticles(); - return c.json(episodes); + const { fetchEpisodesWithFeedInfo } = await import("./services/database.js"); + const episodes = await fetchEpisodesWithFeedInfo(); + return c.json({ episodes }); } catch (error) { console.error("Error fetching episodes:", error); return c.json({ error: "Failed to fetch episodes" }, 500); diff --git a/services/database.ts b/services/database.ts index 9ce4b0f..de3fe23 100644 --- a/services/database.ts +++ b/services/database.ts @@ -3,6 +3,79 @@ import fs from "fs"; import crypto from "crypto"; import { config } from "./config.js"; +// Database integrity fixes function +function performDatabaseIntegrityFixes(db: Database): void { + console.log("🔧 Performing database integrity checks..."); + + try { + // Fix 1: Set active flag to 1 for feeds where it's NULL + const nullActiveFeeds = db.prepare("UPDATE feeds SET active = 1 WHERE active IS NULL").run(); + if (nullActiveFeeds.changes > 0) { + console.log(`✅ Fixed ${nullActiveFeeds.changes} feeds with NULL active flag`); + } + + // Fix 2: Fix orphaned articles (articles referencing non-existent feeds) + const orphanedArticles = db.prepare(` + SELECT a.id, a.link, a.title + FROM articles a + LEFT JOIN feeds f ON a.feed_id = f.id + WHERE f.id IS NULL + `).all() as any[]; + + if (orphanedArticles.length > 0) { + console.log(`🔍 Found ${orphanedArticles.length} orphaned articles, attempting to fix...`); + + for (const article of orphanedArticles) { + // Try to match article to feed based on URL domain + const articleDomain = extractDomain(article.link); + if (articleDomain) { + const matchingFeed = db.prepare(` + SELECT id FROM feeds + WHERE url LIKE ? OR url LIKE ? + ORDER BY created_at DESC + LIMIT 1 + `).get(`%${articleDomain}%`, `%${articleDomain.replace('www.', '')}%`) as any; + + if (matchingFeed) { + db.prepare("UPDATE articles SET feed_id = ? WHERE id = ?") + .run(matchingFeed.id, article.id); + console.log(`✅ Fixed article "${article.title}" -> feed ${matchingFeed.id}`); + } else { + console.log(`⚠️ Could not find matching feed for article: ${article.title} (${articleDomain})`); + } + } + } + } + + // Fix 3: Ensure all episodes have valid article references + const orphanedEpisodes = db.prepare(` + SELECT e.id, e.title, e.article_id + FROM episodes e + LEFT JOIN articles a ON e.article_id = a.id + WHERE a.id IS NULL + `).all() as any[]; + + if (orphanedEpisodes.length > 0) { + console.log(`⚠️ Found ${orphanedEpisodes.length} episodes with invalid article references`); + // We could delete these or try to fix them, but for now just log + } + + console.log("✅ Database integrity checks completed"); + } catch (error) { + console.error("❌ Error during database integrity fixes:", error); + } +} + +// Helper function to extract domain from URL +function extractDomain(url: string): string | null { + try { + const urlObj = new URL(url); + return urlObj.hostname; + } catch { + return null; + } +} + // Initialize database with proper error handling function initializeDatabase(): Database { // Ensure data directory exists @@ -98,6 +171,9 @@ function initializeDatabase(): Database { CREATE INDEX IF NOT EXISTS idx_feed_requests_status ON feed_requests(status); CREATE INDEX IF NOT EXISTS idx_feed_requests_created_at ON feed_requests(created_at);`); + // Perform database integrity checks and fixes + performDatabaseIntegrityFixes(db); + return db; } @@ -181,7 +257,7 @@ export async function saveFeed( feed.description || null, feed.lastUpdated || null, createdAt, - feed.active ? 1 : 0, + feed.active !== undefined ? (feed.active ? 1 : 0) : 1, // Default to active=1 if not specified ); return id; } catch (error) {