Fix Fountain.fm episode cards: use Tauri HTTP plugin for CORS bypass

- Import fetch from @tauri-apps/plugin-http (browser fetch was CORS-blocked)
- Add fountain.fm to Tauri HTTP capability scope
- Extract og:audio meta tag for reliable audio URL resolution
- Parse OG title into show name + episode title
This commit is contained in:
Jure
2026-04-03 15:01:06 +02:00
parent ba3ef9e2c8
commit aa57ff4cd8
3 changed files with 16 additions and 6 deletions
+1 -1
View File
@@ -5318,7 +5318,7 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "vega"
version = "0.10.1"
version = "0.11.0"
dependencies = [
"futures-util",
"hex",
+2 -1
View File
@@ -14,7 +14,8 @@
{ "url": "https://nostr.build/**" },
{ "url": "https://void.cat/**" },
{ "url": "https://nostrimg.com/**" },
{ "url": "https://relay.vertexlab.io/**" }
{ "url": "https://relay.vertexlab.io/**" },
{ "url": "https://fountain.fm/**" }
]
},
"dialog:default",
+13 -4
View File
@@ -1,3 +1,4 @@
import { fetch } from "@tauri-apps/plugin-http";
import type { PodcastEpisode } from "../../types/podcast";
export const FOUNTAIN_REGEX = /fountain\.fm\/(episode|show)\/([a-zA-Z0-9-]+)/;
@@ -39,22 +40,30 @@ export async function resolveFountainEpisode(url: string): Promise<PodcastEpisod
const description = getMetaContent("og:description");
const artwork = getMetaContent("og:image");
// Look for an audio URL in the page (meta or direct link)
const audioMatch = html.match(/<meta[^>]+content=["'](https?:\/\/[^"']+\.(mp3|m4a|ogg|opus)[^"']*?)["']/i)
// Prefer og:audio meta tag (Fountain.fm provides this), then fall back to any audio URL
const ogAudioMatch = html.match(/<meta[^>]+property=["']og:audio["'][^>]+content=["']([^"']+)["']/i)
|| html.match(/<meta[^>]+content=["']([^"']+)["'][^>]+property=["']og:audio["']/i);
const audioMatch = ogAudioMatch
|| html.match(/<meta[^>]+content=["'](https?:\/\/[^"']+\.(mp3|m4a|ogg|opus)[^"']*?)["']/i)
|| html.match(/["'](https?:\/\/[^"'\s]+\.(mp3|m4a|ogg|opus)[^"'\s]*?)["']/i);
const enclosureUrl = audioMatch?.[1] ?? "";
if (!title) return null;
// OG title format: "Show • Episode • Listen on Fountain" — extract parts
const titleParts = title.split(" • ").filter((p) => p !== "Listen on Fountain");
const showTitle = titleParts.length > 1 ? titleParts[0] : "";
const episodeTitle = titleParts.length > 1 ? titleParts.slice(1).join(" • ") : title;
const episode: PodcastEpisode = {
guid: `fountain:${url}`,
title,
title: episodeTitle,
enclosureUrl,
pubDate: 0,
duration: 0,
description,
artworkUrl: artwork || undefined,
showTitle: "",
showTitle,
showArtworkUrl: artwork,
};