Add searching feature

This commit is contained in:
2025-06-08 21:53:45 +09:00
parent cd0e4065fc
commit b7f3ca6a27
16 changed files with 564 additions and 194 deletions

View File

@ -218,7 +218,9 @@ function initializeDatabase(): Database {
// Ensure the category column exists in episodes
const episodeInfos = db.prepare("PRAGMA table_info(episodes);").all();
const hasEpisodeCategory = episodeInfos.some((col: any) => col.name === "category");
const hasEpisodeCategory = episodeInfos.some(
(col: any) => col.name === "category",
);
if (!hasEpisodeCategory) {
db.exec("ALTER TABLE episodes ADD COLUMN category TEXT DEFAULT NULL;");
@ -581,6 +583,88 @@ export async function fetchEpisodeWithSourceInfo(
}
}
// Search episodes with feed information
export async function searchEpisodesWithFeedInfo(
query: string,
category?: string,
): Promise<EpisodeWithFeedInfo[]> {
try {
let whereClause = `
WHERE f.active = 1
AND (
e.title LIKE ?
OR e.description LIKE ?
OR a.title LIKE ?
OR a.description LIKE ?
OR a.content LIKE ?
)
`;
const searchPattern = `%${query}%`;
const params = [
searchPattern,
searchPattern,
searchPattern,
searchPattern,
searchPattern,
];
if (category) {
whereClause += " AND f.category = ?";
params.push(category);
}
const stmt = db.prepare(`
SELECT
e.id,
e.title,
e.description,
e.audio_path as audioPath,
e.duration,
e.file_size as fileSize,
e.category,
e.created_at as createdAt,
e.article_id as articleId,
a.title as articleTitle,
a.link as articleLink,
a.pub_date as articlePubDate,
f.id as feedId,
f.title as feedTitle,
f.url as feedUrl,
f.category as feedCategory
FROM episodes e
JOIN articles a ON e.article_id = a.id
JOIN feeds f ON a.feed_id = f.id
${whereClause}
ORDER BY e.created_at DESC
`);
const rows = stmt.all(...params) as any[];
return rows.map((row) => ({
id: row.id,
title: row.title,
description: row.description,
audioPath: row.audioPath,
duration: row.duration,
fileSize: row.fileSize,
category: row.category,
createdAt: row.createdAt,
articleId: row.articleId,
articleTitle: row.articleTitle,
articleLink: row.articleLink,
articlePubDate: row.articlePubDate,
feedId: row.feedId,
feedTitle: row.feedTitle,
feedUrl: row.feedUrl,
feedCategory: row.feedCategory,
}));
} catch (error) {
console.error("Error searching episodes with feed info:", error);
throw error;
}
}
export async function getAllFeedsIncludingInactive(): Promise<Feed[]> {
try {
const stmt = db.prepare("SELECT * FROM feeds ORDER BY created_at DESC");
@ -1309,7 +1393,9 @@ export async function deleteEpisode(episodeId: string): Promise<boolean> {
}
// Episode category management functions
export async function getEpisodesByCategory(category?: string): Promise<EpisodeWithFeedInfo[]> {
export async function getEpisodesByCategory(
category?: string,
): Promise<EpisodeWithFeedInfo[]> {
try {
let stmt;
let rows;
@ -1458,7 +1544,10 @@ export async function getEpisodeCategoryStats(): Promise<{
}
}
export async function updateEpisodeCategory(episodeId: string, category: string): Promise<boolean> {
export async function updateEpisodeCategory(
episodeId: string,
category: string,
): Promise<boolean> {
try {
const stmt = db.prepare("UPDATE episodes SET category = ? WHERE id = ?");
const result = stmt.run(category, episodeId);
@ -1519,10 +1608,7 @@ export async function migrateEpisodesWithCategories(): Promise<void> {
// Add a small delay to avoid rate limiting
await new Promise((resolve) => setTimeout(resolve, 1000));
} catch (error) {
console.error(
`❌ Failed to classify episode ${episode.title}:`,
error,
);
console.error(`❌ Failed to classify episode ${episode.title}:`, error);
errorCount++;
// Set a default category for failed classifications