diff --git a/server.ts b/server.ts index 14102c7..f75da21 100644 --- a/server.ts +++ b/server.ts @@ -266,6 +266,25 @@ app.get("/api/feeds/:feedId/episodes", async (c) => { } }); +app.get("/api/episode-with-source/:episodeId", async (c) => { + try { + const episodeId = c.req.param("episodeId"); + const { fetchEpisodeWithSourceInfo } = await import( + "./services/database.js" + ); + const episode = await fetchEpisodeWithSourceInfo(episodeId); + + if (!episode) { + return c.json({ error: "Episode not found" }, 404); + } + + return c.json({ episode }); + } catch (error) { + console.error("Error fetching episode with source info:", error); + return c.json({ error: "Failed to fetch episode with source info" }, 500); + } +}); + app.get("/api/episodes-with-feed-info", async (c) => { try { const { fetchEpisodesWithFeedInfo } = await import( diff --git a/services/podcast.ts b/services/podcast.ts index 1c4cacc..61628cb 100644 --- a/services/podcast.ts +++ b/services/podcast.ts @@ -1,10 +1,6 @@ import { promises as fs } from "fs"; import { dirname } from "path"; -import { - Episode, - fetchAllEpisodes, - performDatabaseIntegrityFixes, -} from "./database.js"; +import { fetchEpisodesWithFeedInfo } from "./database.js"; import path from "node:path"; import fsSync from "node:fs"; import { config } from "./config.js"; @@ -18,7 +14,7 @@ function escapeXml(text: string): string { .replace(/'/g, "'"); } -function createItemXml(episode: Episode): string { +function createItemXml(episode: any): string { const fileUrl = `${config.podcast.baseUrl}/podcast_audio/${path.basename(episode.audioPath)}`; const pubDate = new Date(episode.createdAt).toUTCString(); @@ -35,10 +31,28 @@ function createItemXml(episode: Episode): string { console.warn(`Could not get file size for ${episode.audioPath}:`, error); } + // Build enhanced description with feed and article info + let description = episode.title; + if (episode.feedTitle || episode.articleTitle || episode.articleLink) { + description += "\n\n"; + if (episode.feedTitle) { + description += `フィード: ${episode.feedTitle}\n`; + } + if (episode.articleTitle && episode.articleTitle !== episode.title) { + description += `元記事: ${episode.articleTitle}\n`; + } + if (episode.articlePubDate) { + description += `記事公開日: ${new Date(episode.articlePubDate).toLocaleString("ja-JP")}\n`; + } + if (episode.articleLink) { + description += `元記事URL: ${episode.articleLink}`; + } + } + return ` <![CDATA[${escapeXml(episode.title)}]]> - + ${escapeXml(config.podcast.author)} ${escapeXml(config.podcast.categories)} ${config.podcast.language} @@ -46,15 +60,17 @@ function createItemXml(episode: Episode): string { ${escapeXml(fileUrl)} ${pubDate} + ${episode.articleLink ? `${escapeXml(episode.articleLink)}` : ""} `; } export async function updatePodcastRSS(): Promise { try { - const episodes: Episode[] = await fetchAllEpisodes(); + // Use episodes with feed info for enhanced descriptions + const episodesWithFeedInfo = await fetchEpisodesWithFeedInfo(); // Filter episodes to only include those with valid audio files - const validEpisodes = episodes.filter((episode) => { + const validEpisodes = episodesWithFeedInfo.filter((episode) => { try { const audioPath = path.join( config.paths.podcastAudioDir, @@ -68,7 +84,7 @@ export async function updatePodcastRSS(): Promise { }); console.log( - `Found ${episodes.length} episodes, ${validEpisodes.length} with valid audio files`, + `Found ${episodesWithFeedInfo.length} episodes, ${validEpisodes.length} with valid audio files`, ); const lastBuildDate = new Date().toUTCString();