Why Nostr? What is Njump?
To test the rss in a podcast app:

https://podcasts.puhcho.me/npub1u4x0m5grq47ahu42tmdtjq9pak7gsgz68uw2lagu44stn6rt2v7qnzgmhv
(this will run temporary and can be plugged in most podcast apps, change in code to your domain feed url). The add of rss feeds does not require apps login (fountain can use some npub).

In general self-host https://github.com/SnowCait/nostr-rss and it can use nostter client or you can change the code to nostrudel, nostr band, coracle etc to pull rss of notes.

If the notes have a direct media link in content or tags for certain events (for flarepub, wavlake and stemstr), that turns any pub to podcaster and will be played in the podcast apps if enclosure url is added like :
```
import 'websocket-polyfill'; import RSS from 'rss'; import { error, type RequestHandler } from '@sveltejs/kit'; import { nip19 } from 'nostr-tools'; import { type Content } from 'nostr-typedef'; import { NostrFetcher } from 'nostr-fetch'; import { defaultRelays } from '$lib/config'; import axios from 'axios'; import { setMaxListeners } from 'events'; // Set global max listeners for EventEmitters setMaxListeners(20); interface LNURLResponse { callback: string; minWithdrawable?: number; maxWithdrawable?: number; } interface Metadata { picture?: string; lud16?: string; display_name?: string; name?: string; } export const GET: RequestHandler = async ({ params }) => { const npub = params.slug; if (npub === undefined) { throw error(404, 'Not Found'); } const { type, data } = nip19.decode(npub); if (type !== 'npub' && type !== 'nprofile') { throw error(404, 'Not Found'); } const pubkey: string = type === 'npub' ? data : data.pubkey; const relays: string[] = type === 'npub' ? [] : data.relays ?? []; if (relays.length === 0) { relays.push(...defaultRelays); } const fetcher = NostrFetcher.init(); const event = await fetcher.fetchLastEvent(relays, { kinds: [0], authors: [pubkey] }); let metadata: Metadata | undefined; let pictureUrl: string | undefined; let lud16Address: string | undefined; if (event !== undefined) { try { metadata = JSON.parse(event.content) as Metadata; pictureUrl = metadata.picture; // Extract picture URL lud16Address = metadata.lud16; // Extract LUD-16 address console.log('LUD-16 Address:', lud16Address); // Debugging line } catch (error) { console.warn('[failed to parse metadata]', error, event); } } // Fetch a larger number of events to include older ones const abortController = new AbortController(); const events = await fetcher.fetchLatestEvents( relays, { kinds: [1, 34235, 32123, 1808], authors: [pubkey] }, 100, { abortSignal: abortController.signal } ); console.log('Fetched Events:', events); // Debugging line const podcastName = metadata?.display_name || metadata?.name || npub; const feed = new RSS({ title: podcastName, site_url: `https://nostter.app/${npub}`, feed_url: `https://podcasts.puhcho.me/${npub}`, custom_namespaces: { itunes: 'http://www.itunes.com/dtds/podcast-1.0.dtd';, podcast: 'https://podcastindex.org/namespace/1.0'; }, custom_elements: [ { 'itunes:image': { _attr: { href: pictureUrl || 'https://i.giphy.com/o1YuwnczQIcc3ZGlbq.webp'; } } } ] }); for (const event of events) { console.log(event); let enclosureUrl: string | null = null; let itemUrl = `https://nostter.app/${nip19.neventEncode({ id: event.id })}`; let itemTitle = podcastName; if (event.kind === 34235) { enclosureUrl = event.tags.find(tag => tag[0] === "url")?.[1] || null; if (enclosureUrl) { itemUrl = enclosureUrl; } } else if (event.kind === 32123) { try { const contentData = JSON.parse(event.content); enclosureUrl = contentData.enclosure || null; itemTitle = contentData.title || extractTitleFromContent(event.content, podcastName); itemUrl = contentData.link || itemUrl; } catch (error) { console.warn( '[failed to parse content for kind 32123]', error, event ); } } else if (event.kind === 1808) { enclosureUrl = event.tags.find(tag => tag[0] === "stream_url")?.[1] || null; itemTitle = extractTitleFromContent(event.content, podcastName); } else { const urlPattern = /(https?:\/\/[^\s"']+\.(mp3|mp4|wav|ogg|m4a|flac|aac|m3u8|webm|mov))/i; const urlMatch = event.content.match(urlPattern); enclosureUrl = urlMatch ? urlMatch[0] : null; itemTitle = extractTitleFromContent(event.content, podcastName); } // Set payment description to include LUD-16 address as a link label
const paymentDescription = lud16Address ? `<br><br>Support us with Lightning payments: <a href="lightning:${lud16Address}">${lud16Address}</a>` : "Payment method not found"; const descriptionWithLNURL= `${event.content || "No Description"}\n\n${paymentDescription}`; feed.item({ title: itemTitle, description: descriptionWithLNURL, date: new Date(event.created_at * 1000), url: itemUrl, enclosure: enclosureUrl ? { url: enclosureUrl, type: 'audio/mpeg' } : undefined, guid: `https://nostter.app/${nip19.neventEncode({ id:event.id })}`, custom_elements:[{'itunes:image':{_attr:{href: pictureUrl||'https://i.giphy.com/o1YuwnczQIcc3ZGlbq.webp';}}},] }); } return new Response(feed.xml(),{ headers:{'Content-Type':'application/xml; charset=UTF-8'} }); }; // Helper function to extract a potential title from the content avoiding URLs function extractTitleFromContent(content:string,fallbackTitle:string):string{ // Remove URLs and trim the result to use as a potential title const cleanedContent=content.replace(/https?:\/\/\S+/g,'').trim(); // Use the first sentence or fallback to the provided fallbackTitle if cleanedContent is empty return cleanedContent.split('. ')[0]||fallbackTitle; }
```
Public Key
npub1u4x0m5grq47ahu42tmdtjq9pak7gsgz68uw2lagu44stn6rt2v7qnzgmhv
NIP-05 Address
podcasts@nostriches.club
NIP-57 Address
podcasts@nostriches.club
Profile Code
nprofile1qqsw2n8a6yps2lwm7249ak4eqzs7m0ygypdr789075w26c9eap44x0qpzfmhxue69uhhqatjwpkx2urpvuhx2ucpzemhxue69uhhyetvv9ujuurjd9kkzmpwdejhghpdyes
Author Public Key
npub1u4x0m5grq47ahu42tmdtjq9pak7gsgz68uw2lagu44stn6rt2v7qnzgmhv