This commit is contained in:
2025-06-08 15:38:57 +09:00
parent 40e3754628
commit 2e41b3ac70
2 changed files with 45 additions and 10 deletions

View File

@ -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) => { app.get("/api/episodes-with-feed-info", async (c) => {
try { try {
const { fetchEpisodesWithFeedInfo } = await import( const { fetchEpisodesWithFeedInfo } = await import(

View File

@ -1,10 +1,6 @@
import { promises as fs } from "fs"; import { promises as fs } from "fs";
import { dirname } from "path"; import { dirname } from "path";
import { import { fetchEpisodesWithFeedInfo } from "./database.js";
Episode,
fetchAllEpisodes,
performDatabaseIntegrityFixes,
} from "./database.js";
import path from "node:path"; import path from "node:path";
import fsSync from "node:fs"; import fsSync from "node:fs";
import { config } from "./config.js"; import { config } from "./config.js";
@ -18,7 +14,7 @@ function escapeXml(text: string): string {
.replace(/'/g, "'"); .replace(/'/g, "'");
} }
function createItemXml(episode: Episode): string { function createItemXml(episode: any): string {
const fileUrl = `${config.podcast.baseUrl}/podcast_audio/${path.basename(episode.audioPath)}`; const fileUrl = `${config.podcast.baseUrl}/podcast_audio/${path.basename(episode.audioPath)}`;
const pubDate = new Date(episode.createdAt).toUTCString(); 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); 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 ` return `
<item> <item>
<title><![CDATA[${escapeXml(episode.title)}]]></title> <title><![CDATA[${escapeXml(episode.title)}]]></title>
<description><![CDATA[${escapeXml(episode.title)}]]></description> <description><![CDATA[${escapeXml(description)}]]></description>
<author>${escapeXml(config.podcast.author)}</author> <author>${escapeXml(config.podcast.author)}</author>
<category>${escapeXml(config.podcast.categories)}</category> <category>${escapeXml(config.podcast.categories)}</category>
<language>${config.podcast.language}</language> <language>${config.podcast.language}</language>
@ -46,15 +60,17 @@ function createItemXml(episode: Episode): string {
<enclosure url="${escapeXml(fileUrl)}" length="${fileSize}" type="audio/mpeg" /> <enclosure url="${escapeXml(fileUrl)}" length="${fileSize}" type="audio/mpeg" />
<guid>${escapeXml(fileUrl)}</guid> <guid>${escapeXml(fileUrl)}</guid>
<pubDate>${pubDate}</pubDate> <pubDate>${pubDate}</pubDate>
${episode.articleLink ? `<link>${escapeXml(episode.articleLink)}</link>` : ""}
</item>`; </item>`;
} }
export async function updatePodcastRSS(): Promise<void> { export async function updatePodcastRSS(): Promise<void> {
try { 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 // Filter episodes to only include those with valid audio files
const validEpisodes = episodes.filter((episode) => { const validEpisodes = episodesWithFeedInfo.filter((episode) => {
try { try {
const audioPath = path.join( const audioPath = path.join(
config.paths.podcastAudioDir, config.paths.podcastAudioDir,
@ -68,7 +84,7 @@ export async function updatePodcastRSS(): Promise<void> {
}); });
console.log( 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(); const lastBuildDate = new Date().toUTCString();