This commit is contained in:
2025-06-07 12:31:43 +09:00
parent 39f088641c
commit 337b60de26

View File

@ -114,15 +114,25 @@ export interface LegacyEpisode {
} }
// Feed management functions // Feed management functions
export async function saveFeed(feed: Omit<Feed, 'id' | 'createdAt'>): Promise<string> { export async function saveFeed(
feed: Omit<Feed, "id" | "createdAt">,
): Promise<string> {
const id = crypto.randomUUID(); const id = crypto.randomUUID();
const createdAt = new Date().toISOString(); const createdAt = new Date().toISOString();
try { try {
const stmt = db.prepare( const stmt = db.prepare(
"INSERT OR REPLACE INTO feeds (id, url, title, description, last_updated, created_at, active) VALUES (?, ?, ?, ?, ?, ?, ?)" "INSERT OR REPLACE INTO feeds (id, url, title, description, last_updated, created_at, active) VALUES (?, ?, ?, ?, ?, ?, ?)",
);
stmt.run(
id,
feed.url,
feed.title || null,
feed.description || null,
feed.lastUpdated || null,
createdAt,
feed.active ? 1 : 0,
); );
stmt.run(id, feed.url, feed.title || null, feed.description || null, feed.lastUpdated || null, createdAt, feed.active ? 1 : 0);
return id; return id;
} catch (error) { } catch (error) {
console.error("Error saving feed:", error); console.error("Error saving feed:", error);
@ -143,7 +153,7 @@ export async function getFeedByUrl(url: string): Promise<Feed | null> {
description: row.description, description: row.description,
lastUpdated: row.last_updated, lastUpdated: row.last_updated,
createdAt: row.created_at, createdAt: row.created_at,
active: Boolean(row.active) active: Boolean(row.active),
}; };
} catch (error) { } catch (error) {
console.error("Error getting feed by URL:", error); console.error("Error getting feed by URL:", error);
@ -153,17 +163,19 @@ export async function getFeedByUrl(url: string): Promise<Feed | null> {
export async function getAllFeeds(): Promise<Feed[]> { export async function getAllFeeds(): Promise<Feed[]> {
try { try {
const stmt = db.prepare("SELECT * FROM feeds WHERE active = 1 ORDER BY created_at DESC"); const stmt = db.prepare(
"SELECT * FROM feeds WHERE active = 1 ORDER BY created_at DESC",
);
const rows = stmt.all() as any[]; const rows = stmt.all() as any[];
return rows.map(row => ({ return rows.map((row) => ({
id: row.id, id: row.id,
url: row.url, url: row.url,
title: row.title, title: row.title,
description: row.description, description: row.description,
lastUpdated: row.last_updated, lastUpdated: row.last_updated,
createdAt: row.created_at, createdAt: row.created_at,
active: Boolean(row.active) active: Boolean(row.active),
})); }));
} catch (error) { } catch (error) {
console.error("Error getting all feeds:", error); console.error("Error getting all feeds:", error);
@ -172,19 +184,33 @@ export async function getAllFeeds(): Promise<Feed[]> {
} }
// Article management functions // Article management functions
export async function saveArticle(article: Omit<Article, 'id' | 'discoveredAt'>): Promise<string> { export async function saveArticle(
article: Omit<Article, "id" | "discoveredAt">,
): Promise<string> {
const id = crypto.randomUUID(); const id = crypto.randomUUID();
const discoveredAt = new Date().toISOString(); const discoveredAt = new Date().toISOString();
try { try {
const stmt = db.prepare( const stmt = db.prepare(
"INSERT OR IGNORE INTO articles (id, feed_id, title, link, description, content, pub_date, discovered_at, processed) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)" "INSERT OR IGNORE INTO articles (id, feed_id, title, link, description, content, pub_date, discovered_at, processed) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
);
const result = stmt.run(
id,
article.feedId,
article.title,
article.link,
article.description || null,
article.content || null,
article.pubDate,
discoveredAt,
article.processed ? 1 : 0,
); );
const result = stmt.run(id, article.feedId, article.title, article.link, article.description || null, article.content || null, article.pubDate, discoveredAt, article.processed ? 1 : 0);
// Return existing ID if article already exists // Return existing ID if article already exists
if (result.changes === 0) { if (result.changes === 0) {
const existing = db.prepare("SELECT id FROM articles WHERE link = ?").get(article.link) as any; const existing = db
.prepare("SELECT id FROM articles WHERE link = ?")
.get(article.link) as any;
return existing?.id || id; return existing?.id || id;
} }
@ -195,13 +221,22 @@ export async function saveArticle(article: Omit<Article, 'id' | 'discoveredAt'>)
} }
} }
export async function getUnprocessedArticles(limit?: number): Promise<Article[]> { export async function getUnprocessedArticles(
limit?: number,
): Promise<Article[]> {
try { try {
const sql = `SELECT * FROM articles WHERE processed = 0 ORDER BY pub_date DESC ${limit ? `LIMIT ${limit}` : ''}`; const sql = `
SELECT *
FROM articles
WHERE processed = 0
AND pub_date >= datetime('now','-2 days')
ORDER BY pub_date DESC
${limit ? `LIMIT ${limit}` : ""}
`;
const stmt = db.prepare(sql); const stmt = db.prepare(sql);
const rows = stmt.all() as any[]; const rows = stmt.all() as any[];
return rows.map(row => ({ return rows.map((row) => ({
id: row.id, id: row.id,
feedId: row.feed_id, feedId: row.feed_id,
title: row.title, title: row.title,
@ -210,7 +245,7 @@ export async function getUnprocessedArticles(limit?: number): Promise<Article[]>
content: row.content, content: row.content,
pubDate: row.pub_date, pubDate: row.pub_date,
discoveredAt: row.discovered_at, discoveredAt: row.discovered_at,
processed: Boolean(row.processed) processed: Boolean(row.processed),
})); }));
} catch (error) { } catch (error) {
console.error("Error getting unprocessed articles:", error); console.error("Error getting unprocessed articles:", error);
@ -256,7 +291,9 @@ export async function markAsProcessed(
} }
// Episode management functions // Episode management functions
export async function saveEpisode(episode: Omit<Episode, 'id' | 'createdAt'>): Promise<string> { export async function saveEpisode(
episode: Omit<Episode, "id" | "createdAt">,
): Promise<string> {
const id = crypto.randomUUID(); const id = crypto.randomUUID();
const createdAt = new Date().toISOString(); const createdAt = new Date().toISOString();
@ -268,7 +305,16 @@ export async function saveEpisode(episode: Omit<Episode, 'id' | 'createdAt'>): P
const stmt = db.prepare( const stmt = db.prepare(
"INSERT INTO episodes (id, article_id, title, description, audio_path, duration, file_size, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", "INSERT INTO episodes (id, article_id, title, description, audio_path, duration, file_size, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
); );
stmt.run(id, episode.articleId, episode.title, episode.description || null, episode.audioPath, episode.duration || null, episode.fileSize || null, createdAt); stmt.run(
id,
episode.articleId,
episode.title,
episode.description || null,
episode.audioPath,
episode.duration || null,
episode.fileSize || null,
createdAt,
);
return id; return id;
} catch (error) { } catch (error) {
console.error("Error saving episode:", error); console.error("Error saving episode:", error);
@ -285,7 +331,7 @@ export async function saveLegacyEpisode(ep: LegacyEpisode): Promise<void> {
try { try {
// For now, save to a temporary table for migration // For now, save to a temporary table for migration
const stmt = db.prepare( const stmt = db.prepare(
"CREATE TABLE IF NOT EXISTS legacy_episodes (id TEXT PRIMARY KEY, title TEXT, pubDate TEXT, audioPath TEXT, sourceLink TEXT)" "CREATE TABLE IF NOT EXISTS legacy_episodes (id TEXT PRIMARY KEY, title TEXT, pubDate TEXT, audioPath TEXT, sourceLink TEXT)",
); );
stmt.run(); stmt.run();
@ -321,7 +367,9 @@ export async function fetchAllEpisodes(): Promise<Episode[]> {
} }
} }
export async function fetchEpisodesWithArticles(): Promise<(Episode & { article: Article, feed: Feed })[]> { export async function fetchEpisodesWithArticles(): Promise<
(Episode & { article: Article; feed: Feed })[]
> {
try { try {
const stmt = db.prepare(` const stmt = db.prepare(`
SELECT SELECT
@ -357,7 +405,7 @@ export async function fetchEpisodesWithArticles(): Promise<(Episode & { article:
const rows = stmt.all() as any[]; const rows = stmt.all() as any[];
return rows.map(row => ({ return rows.map((row) => ({
id: row.id, id: row.id,
articleId: row.articleId, articleId: row.articleId,
title: row.title, title: row.title,
@ -375,7 +423,7 @@ export async function fetchEpisodesWithArticles(): Promise<(Episode & { article:
content: row.article_content, content: row.article_content,
pubDate: row.article_pubDate, pubDate: row.article_pubDate,
discoveredAt: row.article_discoveredAt, discoveredAt: row.article_discoveredAt,
processed: Boolean(row.article_processed) processed: Boolean(row.article_processed),
}, },
feed: { feed: {
id: row.feed_id, id: row.feed_id,
@ -384,8 +432,8 @@ export async function fetchEpisodesWithArticles(): Promise<(Episode & { article:
description: row.feed_description, description: row.feed_description,
lastUpdated: row.feed_lastUpdated, lastUpdated: row.feed_lastUpdated,
createdAt: row.feed_createdAt, createdAt: row.feed_createdAt,
active: Boolean(row.feed_active) active: Boolean(row.feed_active),
} },
})); }));
} catch (error) { } catch (error) {
console.error("Error fetching episodes with articles:", error); console.error("Error fetching episodes with articles:", error);