Update for static file serving
This commit is contained in:
47
server.ts
47
server.ts
@ -129,15 +129,33 @@ app.get("/podcast.xml", async (c) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Category-specific RSS feeds
|
// Category-specific RSS feeds - try static file first, then generate dynamically
|
||||||
app.get("/podcast/category/:category.xml", async (c) => {
|
app.get("/podcast/category/:category.xml", async (c) => {
|
||||||
try {
|
try {
|
||||||
const category = decodeURIComponent(c.req.param("category") || "");
|
const category = decodeURIComponent(c.req.param("category") || "");
|
||||||
if (!category) {
|
if (!category) {
|
||||||
return c.notFound();
|
return c.notFound();
|
||||||
}
|
}
|
||||||
const { generateCategoryRSS } = await import("./services/podcast.js");
|
|
||||||
|
|
||||||
|
// Try to serve static file first
|
||||||
|
const safeCategory = encodeURIComponent(category);
|
||||||
|
const staticFilePath = path.join(
|
||||||
|
config.paths.publicDir,
|
||||||
|
`podcast_category_${safeCategory}.xml`,
|
||||||
|
);
|
||||||
|
const staticFile = Bun.file(staticFilePath);
|
||||||
|
|
||||||
|
if (await staticFile.exists()) {
|
||||||
|
const blob = await staticFile.arrayBuffer();
|
||||||
|
return c.body(blob, 200, {
|
||||||
|
"Content-Type": "application/xml; charset=utf-8",
|
||||||
|
"Cache-Control": "public, max-age=3600", // Cache for 1 hour
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to dynamic generation
|
||||||
|
console.log(`📄 Static category RSS not found for "${category}", generating dynamically...`);
|
||||||
|
const { generateCategoryRSS } = await import("./services/podcast.js");
|
||||||
const rssXml = await generateCategoryRSS(category);
|
const rssXml = await generateCategoryRSS(category);
|
||||||
|
|
||||||
return c.body(rssXml, 200, {
|
return c.body(rssXml, 200, {
|
||||||
@ -146,22 +164,39 @@ app.get("/podcast/category/:category.xml", async (c) => {
|
|||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
console.error(
|
||||||
`Error generating category RSS for "${c.req.param("category")}":`,
|
`Error serving category RSS for "${c.req.param("category")}":`,
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
return c.notFound();
|
return c.notFound();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Feed-specific RSS feeds
|
// Feed-specific RSS feeds - try static file first, then generate dynamically
|
||||||
app.get("/podcast/feed/:feedId.xml", async (c) => {
|
app.get("/podcast/feed/:feedId.xml", async (c) => {
|
||||||
try {
|
try {
|
||||||
const feedId = c.req.param("feedId");
|
const feedId = c.req.param("feedId");
|
||||||
if (!feedId) {
|
if (!feedId) {
|
||||||
return c.notFound();
|
return c.notFound();
|
||||||
}
|
}
|
||||||
const { generateFeedRSS } = await import("./services/podcast.js");
|
|
||||||
|
|
||||||
|
// Try to serve static file first
|
||||||
|
const staticFilePath = path.join(
|
||||||
|
config.paths.publicDir,
|
||||||
|
`podcast_feed_${feedId}.xml`,
|
||||||
|
);
|
||||||
|
const staticFile = Bun.file(staticFilePath);
|
||||||
|
|
||||||
|
if (await staticFile.exists()) {
|
||||||
|
const blob = await staticFile.arrayBuffer();
|
||||||
|
return c.body(blob, 200, {
|
||||||
|
"Content-Type": "application/xml; charset=utf-8",
|
||||||
|
"Cache-Control": "public, max-age=3600", // Cache for 1 hour
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to dynamic generation
|
||||||
|
console.log(`📄 Static feed RSS not found for "${feedId}", generating dynamically...`);
|
||||||
|
const { generateFeedRSS } = await import("./services/podcast.js");
|
||||||
const rssXml = await generateFeedRSS(feedId);
|
const rssXml = await generateFeedRSS(feedId);
|
||||||
|
|
||||||
return c.body(rssXml, 200, {
|
return c.body(rssXml, 200, {
|
||||||
@ -170,7 +205,7 @@ app.get("/podcast/feed/:feedId.xml", async (c) => {
|
|||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
console.error(
|
||||||
`Error generating feed RSS for "${c.req.param("feedId")}":`,
|
`Error serving feed RSS for "${c.req.param("feedId")}":`,
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
return c.notFound();
|
return c.notFound();
|
||||||
|
@ -139,20 +139,118 @@ export async function updatePodcastRSS(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate all category RSS files as static files
|
||||||
|
*/
|
||||||
|
export async function generateAllCategoryRSSFiles(): Promise<void> {
|
||||||
|
try {
|
||||||
|
const { getAllEpisodeCategories } = await import("./database.js");
|
||||||
|
const categories = await getAllEpisodeCategories();
|
||||||
|
|
||||||
|
console.log(`🔄 Generating ${categories.length} category RSS files...`);
|
||||||
|
|
||||||
|
for (const category of categories) {
|
||||||
|
try {
|
||||||
|
await saveCategoryRSSFile(category);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`❌ Failed to generate RSS for category "${category}":`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`✅ Generated category RSS files for ${categories.length} categories`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("❌ Error generating category RSS files:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate all feed RSS files as static files
|
||||||
|
*/
|
||||||
|
export async function generateAllFeedRSSFiles(): Promise<void> {
|
||||||
|
try {
|
||||||
|
const { fetchActiveFeeds } = await import("./database.js");
|
||||||
|
const feeds = await fetchActiveFeeds();
|
||||||
|
|
||||||
|
console.log(`🔄 Generating ${feeds.length} feed RSS files...`);
|
||||||
|
|
||||||
|
for (const feed of feeds) {
|
||||||
|
try {
|
||||||
|
await saveFeedRSSFile(feed.id);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`❌ Failed to generate RSS for feed "${feed.id}":`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`✅ Generated feed RSS files for ${feeds.length} feeds`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("❌ Error generating feed RSS files:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save category RSS as static file with URL-safe filename
|
||||||
|
*/
|
||||||
|
export async function saveCategoryRSSFile(category: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
const rssXml = await generateCategoryRSS(category);
|
||||||
|
const safeCategory = encodeURIComponent(category);
|
||||||
|
const outputPath = path.join(
|
||||||
|
config.paths.publicDir,
|
||||||
|
`podcast_category_${safeCategory}.xml`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure directory exists
|
||||||
|
await fs.mkdir(dirname(outputPath), { recursive: true });
|
||||||
|
await fs.writeFile(outputPath, rssXml);
|
||||||
|
|
||||||
|
console.log(`📄 Category RSS saved: podcast_category_${safeCategory}.xml`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`❌ Error saving category RSS for "${category}":`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save feed RSS as static file
|
||||||
|
*/
|
||||||
|
export async function saveFeedRSSFile(feedId: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
const rssXml = await generateFeedRSS(feedId);
|
||||||
|
const outputPath = path.join(
|
||||||
|
config.paths.publicDir,
|
||||||
|
`podcast_feed_${feedId}.xml`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure directory exists
|
||||||
|
await fs.mkdir(dirname(outputPath), { recursive: true });
|
||||||
|
await fs.writeFile(outputPath, rssXml);
|
||||||
|
|
||||||
|
console.log(`📄 Feed RSS saved: podcast_feed_${feedId}.xml`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`❌ Error saving feed RSS for "${feedId}":`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regenerate all static files on startup
|
* Regenerate all static files on startup
|
||||||
* This ensures that podcast.xml and other generated files are up-to-date
|
* This ensures that podcast.xml and other generated files are up-to-date
|
||||||
*/
|
*/
|
||||||
export async function regenerateStartupFiles(): Promise<void> {
|
export async function regenerateStartupFiles(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
console.log("🔄 Regenerating static files on startup...");
|
console.log("🔄 Regenerating all static files on startup...");
|
||||||
|
|
||||||
// Regenerate main podcast.xml
|
// Regenerate main podcast.xml
|
||||||
await updatePodcastRSS();
|
await updatePodcastRSS();
|
||||||
console.log("✅ podcast.xml regenerated successfully");
|
console.log("✅ podcast.xml regenerated successfully");
|
||||||
|
|
||||||
// Note: Category and feed-specific RSS files are generated dynamically on request
|
// Generate all category RSS files
|
||||||
// This is more efficient and ensures they're always up-to-date with current data
|
await generateAllCategoryRSSFiles();
|
||||||
|
|
||||||
|
// Generate all feed RSS files
|
||||||
|
await generateAllFeedRSSFiles();
|
||||||
|
|
||||||
console.log("✅ All startup files regenerated successfully");
|
console.log("✅ All startup files regenerated successfully");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
Reference in New Issue
Block a user