diff --git a/src/routes/blog/+server.ts b/src/routes/blog/+server.ts index a52f8ee..7fcca67 100644 --- a/src/routes/blog/+server.ts +++ b/src/routes/blog/+server.ts @@ -1,13 +1,24 @@ import type { RequestHandler } from '@sveltejs/kit'; +import { + PUBLIC_ATPROTO_DID, + PUBLIC_LEAFLET_BASE_PATH, + PUBLIC_LEAFLET_BLOG_PUBLICATION, + PUBLIC_ENABLE_WHITEWIND +} from '$env/static/public'; +import { fetchLeafletPublications } from '$lib/services/atproto'; /** * Blog root redirect handler * - * This redirects /blog to a helpful page explaining the blog setup. + * Redirects /blog to the appropriate blog platform: + * - Priority 1: Leaflet blog (if PUBLIC_LEAFLET_BASE_PATH is configured) + * - Priority 2: Leaflet publication page (if PUBLIC_LEAFLET_BLOG_PUBLICATION is set) + * - Fallback: WhiteWind blog page (if PUBLIC_ENABLE_WHITEWIND is true) + * * Individual posts are handled by the [rkey] route which detects - * whether the post is from WhiteWind or Leaflet. + * whether the post is from Leaflet or WhiteWind (if enabled). */ -export const GET: RequestHandler = ({ url }) => { +export const GET: RequestHandler = async ({ url }) => { // If there's a path after /blog, let it fall through to other routes const blogPath = url.pathname.replace(/^\/blog\/?/, ''); @@ -21,19 +32,56 @@ export const GET: RequestHandler = ({ url }) => { }); } - // For /blog root, return a helpful message + // For /blog root, redirect to the blog platform if (!blogPath || blogPath === '') { - return new Response( - `Blog posts are distributed across multiple platforms: + let redirectUrl: string | null = null; -- WhiteWind: https://whtwnd.com -- Leaflet: https://leaflet.pub + // Priority 1: Use Leaflet base path if configured + if (PUBLIC_LEAFLET_BASE_PATH) { + redirectUrl = PUBLIC_LEAFLET_BASE_PATH; + } + // Priority 2: Use Leaflet publication page if configured + else if (PUBLIC_LEAFLET_BLOG_PUBLICATION) { + try { + const { publications } = await fetchLeafletPublications(); + const publication = publications.find(p => p.rkey === PUBLIC_LEAFLET_BLOG_PUBLICATION); + + if (publication?.basePath) { + // Ensure basePath is a complete URL + redirectUrl = publication.basePath.startsWith('http') + ? publication.basePath + : `https://${publication.basePath}`; + } else { + // Use Leaflet /lish format + redirectUrl = `https://leaflet.pub/lish/${PUBLIC_ATPROTO_DID}/${PUBLIC_LEAFLET_BLOG_PUBLICATION}`; + } + } catch (error) { + console.error('Error fetching Leaflet publication:', error); + // Will check WhiteWind fallback below + } + } + + // Fallback: WhiteWind blog page (if enabled) + if (!redirectUrl && PUBLIC_ENABLE_WHITEWIND === 'true') { + redirectUrl = `https://whtwnd.com/${PUBLIC_ATPROTO_DID}`; + } -Individual post URLs like /blog/{rkey} will automatically redirect to the correct platform. + // If we have a redirect URL, use it + if (redirectUrl) { + return new Response(null, { + status: 301, + headers: { + Location: redirectUrl, + 'Cache-Control': 'public, max-age=3600' + } + }); + } -For RSS feeds, visit: /blog/rss`, + // No blog configured + return new Response( + 'Blog not configured. Please set PUBLIC_LEAFLET_BASE_PATH or PUBLIC_LEAFLET_BLOG_PUBLICATION in your environment variables.', { - status: 200, + status: 404, headers: { 'Content-Type': 'text/plain; charset=utf-8' } diff --git a/src/routes/blog/[rkey]/+server.ts b/src/routes/blog/[rkey]/+server.ts index 9e8acc3..5faa490 100644 --- a/src/routes/blog/[rkey]/+server.ts +++ b/src/routes/blog/[rkey]/+server.ts @@ -3,7 +3,8 @@ import { PUBLIC_ATPROTO_DID, PUBLIC_LEAFLET_BASE_PATH, PUBLIC_LEAFLET_BLOG_PUBLICATION, - PUBLIC_BLOG_FALLBACK_URL + PUBLIC_BLOG_FALLBACK_URL, + PUBLIC_ENABLE_WHITEWIND } from '$env/static/public'; import { withFallback } from '$lib/services/atproto'; import { fetchLeafletPublications } from '$lib/services/atproto'; @@ -11,11 +12,12 @@ import { fetchLeafletPublications } from '$lib/services/atproto'; /** * Smart blog post redirect handler * - * Automatically detects whether the post is from WhiteWind or Leaflet + * Automatically detects whether the post is from Leaflet or WhiteWind (if enabled) * and redirects to the appropriate URL. * - * WhiteWind: https://whtwnd.com/{DID}/{rkey} - * Leaflet: {LEAFLET_BASE_PATH}/{rkey} or https://leaflet.pub/{DID}/{rkey} + * Priority order: + * 1. Leaflet: {LEAFLET_BASE_PATH}/{rkey} or https://leaflet.pub/{DID}/{rkey} + * 2. WhiteWind: https://whtwnd.com/{DID}/{rkey} (only if PUBLIC_ENABLE_WHITEWIND is true) * * If detection fails, falls back to PUBLIC_BLOG_FALLBACK_URL or returns 404. * @@ -28,37 +30,7 @@ async function detectPostPlatform( rkey: string ): Promise<{ platform: 'whitewind' | 'leaflet' | 'unknown'; url?: string }> { try { - // Check WhiteWind first using atproto services - const whiteWindRecord = await withFallback( - PUBLIC_ATPROTO_DID, - async (agent) => { - try { - const response = await agent.com.atproto.repo.getRecord({ - repo: PUBLIC_ATPROTO_DID, - collection: 'com.whtwnd.blog.entry', - rkey - }); - return response.data; - } catch (err) { - // Record not found - return null; - } - }, - true // Use PDS first for custom collections - ); - - if (whiteWindRecord) { - const value = whiteWindRecord.value as any; - // Skip drafts and non-public posts - if (!value?.isDraft && (!value?.visibility || value.visibility === 'public')) { - return { - platform: 'whitewind', - url: `https://whtwnd.com/${PUBLIC_ATPROTO_DID}/${rkey}` - }; - } - } - - // Check Leaflet using atproto services + // Check Leaflet FIRST (prioritized) using atproto services const leafletRecord = await withFallback( PUBLIC_ATPROTO_DID, async (agent) => { @@ -119,6 +91,38 @@ async function detectPostPlatform( }; } + // Check WhiteWind as fallback (only if enabled) + if (PUBLIC_ENABLE_WHITEWIND === 'true') { + const whiteWindRecord = await withFallback( + PUBLIC_ATPROTO_DID, + async (agent) => { + try { + const response = await agent.com.atproto.repo.getRecord({ + repo: PUBLIC_ATPROTO_DID, + collection: 'com.whtwnd.blog.entry', + rkey + }); + return response.data; + } catch (err) { + // Record not found + return null; + } + }, + true // Use PDS first for custom collections + ); + + if (whiteWindRecord) { + const value = whiteWindRecord.value as any; + // Skip drafts and non-public posts + if (!value?.isDraft && (!value?.visibility || value.visibility === 'public')) { + return { + platform: 'whitewind', + url: `https://whtwnd.com/${PUBLIC_ATPROTO_DID}/${rkey}` + }; + } + } + } + return { platform: 'unknown' }; } catch (error) { console.error('Error detecting post platform:', error); @@ -158,15 +162,17 @@ export const GET: RequestHandler = async ({ params, url }) => { const blogPublicationNote = PUBLIC_LEAFLET_BLOG_PUBLICATION ? `\n\nNote: Only checking Leaflet publication: ${PUBLIC_LEAFLET_BLOG_PUBLICATION}` : ''; + const whiteWindNote = PUBLIC_ENABLE_WHITEWIND === 'true' + ? '\n- WhiteWind: https://whtwnd.com' + : ''; return new Response( `Blog post not found: ${rkey} -This post could not be found on WhiteWind or Leaflet platforms.${blogPublicationNote} +This post could not be found on Leaflet${PUBLIC_ENABLE_WHITEWIND === 'true' ? ' or WhiteWind' : ''} platform${PUBLIC_ENABLE_WHITEWIND === 'true' ? 's' : ''}.${blogPublicationNote} Please check: -- WhiteWind: https://whtwnd.com -- Leaflet: https://leaflet.pub`, +- Leaflet: https://leaflet.pub${whiteWindNote}`, { status: 404, headers: { diff --git a/src/routes/blog/rss/+server.ts b/src/routes/blog/rss/+server.ts index 68bff82..9aee7a6 100644 --- a/src/routes/blog/rss/+server.ts +++ b/src/routes/blog/rss/+server.ts @@ -5,7 +5,8 @@ import { PUBLIC_SITE_DESCRIPTION, PUBLIC_SITE_URL, PUBLIC_LEAFLET_BASE_PATH, - PUBLIC_LEAFLET_BLOG_PUBLICATION + PUBLIC_LEAFLET_BLOG_PUBLICATION, + PUBLIC_ENABLE_WHITEWIND } from '$env/static/public'; import { fetchBlogPosts, fetchLeafletPublications } from '$lib/services/atproto'; @@ -13,9 +14,9 @@ import { fetchBlogPosts, fetchLeafletPublications } from '$lib/services/atproto' * RSS 2.0 feed for blog posts * * Strategy: - * 1. If only Leaflet posts exist and there's a single publication, redirect to its RSS feed - * 2. If WhiteWind posts exist, generate RSS with WhiteWind posts (linking to them) - * 3. If mixed content, prioritize WhiteWind and generate RSS for those + * 1. If WhiteWind is disabled or no WhiteWind posts exist, redirect to Leaflet RSS feed + * 2. If WhiteWind is enabled and WhiteWind posts exist, generate RSS with WhiteWind posts + * 3. If mixed content and WhiteWind is enabled, prioritize WhiteWind and generate RSS for those */ export const GET: RequestHandler = async () => { try { @@ -25,12 +26,12 @@ export const GET: RequestHandler = async () => { const whiteWindPosts = posts.filter((p) => p.platform === 'WhiteWind'); const leafletPosts = posts.filter((p) => p.platform === 'leaflet'); - // If we have WhiteWind posts, generate RSS for them - if (whiteWindPosts.length > 0) { + // If WhiteWind is enabled and we have WhiteWind posts, generate RSS for them + if (PUBLIC_ENABLE_WHITEWIND === 'true' && whiteWindPosts.length > 0) { return generateWhiteWindRSS(whiteWindPosts); } - // If only Leaflet posts, redirect to Leaflet RSS feed + // If WhiteWind is disabled or only Leaflet posts exist, redirect to Leaflet RSS feed if (leafletPosts.length > 0) { return await redirectToLeafletRSS(); }