Compare commits
2 Commits
1cee931913
...
db74e20571
| Author | SHA1 | Date | |
|---|---|---|---|
| db74e20571 | |||
| 70f50eec2a |
16
src/App.tsx
16
src/App.tsx
@@ -20,7 +20,8 @@ import { useMultimediaKeys } from "@/hooks/useMultimediaKeys";
|
||||
import { FeedVisibility } from "@/types/feed";
|
||||
import { useAppKeyboard } from "@/hooks/useAppKeyboard";
|
||||
import { Clipboard } from "@/utils/clipboard";
|
||||
import { emit } from "@/utils/event-bus";
|
||||
import { useToast } from "@/ui/toast";
|
||||
import { useRenderer } from "@opentui/solid";
|
||||
import type { TabId } from "@/components/Tab";
|
||||
import type { AuthScreen } from "@/types/auth";
|
||||
import type { Episode } from "@/types/episode";
|
||||
@@ -35,6 +36,8 @@ export function App() {
|
||||
const feedStore = useFeedStore();
|
||||
const appStore = useAppStore();
|
||||
const audio = useAudio();
|
||||
const toast = useToast();
|
||||
const renderer = useRenderer();
|
||||
|
||||
// Global multimedia key handling — active when Player tab is NOT
|
||||
// focused (Player.tsx handles its own keys when focused).
|
||||
@@ -105,13 +108,12 @@ export function App() {
|
||||
|
||||
Clipboard.copy(text)
|
||||
.then(() => {
|
||||
emit("toast.show", {
|
||||
message: "Copied to clipboard",
|
||||
variant: "info",
|
||||
duration: 1500,
|
||||
});
|
||||
toast.show({ message: "Copied to Clipboard!", variant: "info" });
|
||||
})
|
||||
.catch(() => {});
|
||||
.catch(toast.error)
|
||||
.finally(() => {
|
||||
renderer.clearSelection();
|
||||
});
|
||||
});
|
||||
|
||||
const getPanels = createMemo(() => {
|
||||
|
||||
@@ -25,10 +25,10 @@ const decodeEntities = (value: string) =>
|
||||
.replace(/'/g, "'")
|
||||
|
||||
/**
|
||||
* Clean a description field: detect HTML vs plain text, and convert
|
||||
* Clean a field (description or title): detect HTML vs plain text, and convert
|
||||
* HTML to readable plain text. Plain text just gets entity decoding.
|
||||
*/
|
||||
const cleanDescription = (raw: string): string => {
|
||||
const cleanField = (raw: string): string => {
|
||||
if (!raw) return ""
|
||||
const decoded = decodeEntities(raw)
|
||||
const type = detectContentType(decoded)
|
||||
@@ -76,15 +76,15 @@ const parseEpisodeType = (raw: string): EpisodeType | undefined => {
|
||||
|
||||
export const parseRSSFeed = (xml: string, feedUrl: string): Podcast & { episodes: Episode[] } => {
|
||||
const channel = xml.match(/<channel[\s\S]*?<\/channel>/i)?.[0] ?? xml
|
||||
const title = decodeEntities(getTagValue(channel, "title")) || "Untitled Podcast"
|
||||
const description = cleanDescription(getTagValue(channel, "description"))
|
||||
const title = cleanField(getTagValue(channel, "title")) || "Untitled Podcast"
|
||||
const description = cleanField(getTagValue(channel, "description"))
|
||||
const author = decodeEntities(getTagValue(channel, "itunes:author"))
|
||||
const lastUpdated = new Date()
|
||||
|
||||
const items = channel.match(/<item[\s\S]*?<\/item>/gi) ?? []
|
||||
const episodes = items.map((item, index) => {
|
||||
const epTitle = decodeEntities(getTagValue(item, "title")) || `Episode ${index + 1}`
|
||||
const epDescription = cleanDescription(getTagValue(item, "description"))
|
||||
const epTitle = cleanField(getTagValue(item, "title")) || `Episode ${index + 1}`
|
||||
const epDescription = cleanField(getTagValue(item, "description"))
|
||||
const pubDate = new Date(getTagValue(item, "pubDate") || Date.now())
|
||||
|
||||
// Audio URL + file size + MIME type from <enclosure>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import type { Feed, FeedVisibility } from "@/types/feed";
|
||||
import { format } from "date-fns";
|
||||
import { htmlToText } from "@/utils/html-to-text";
|
||||
import { useTheme } from "@/context/ThemeContext";
|
||||
|
||||
interface FeedItemProps {
|
||||
@@ -55,7 +54,7 @@ export function FeedItem(props: FeedItemProps) {
|
||||
</text>
|
||||
<text fg={visibilityColor()}>{visibilityIcon()}</text>
|
||||
<text fg={props.isSelected ? "white" : theme.accent}>
|
||||
{htmlToText(props.feed.customName || props.feed.podcast.title)}
|
||||
{props.feed.customName || props.feed.podcast.title}
|
||||
</text>
|
||||
{props.showEpisodeCount && <text fg="gray">({episodeCount()})</text>}
|
||||
</box>
|
||||
@@ -81,7 +80,7 @@ export function FeedItem(props: FeedItemProps) {
|
||||
<text fg="yellow">{pinnedIndicator()}</text>
|
||||
<text fg={props.isSelected ? "white" : theme.text}>
|
||||
<strong>
|
||||
{htmlToText(props.feed.customName || props.feed.podcast.title)}
|
||||
{props.feed.customName || props.feed.podcast.title}
|
||||
</strong>
|
||||
</text>
|
||||
</box>
|
||||
|
||||
@@ -10,7 +10,6 @@ import { format } from "date-fns";
|
||||
import type { Episode } from "@/types/episode";
|
||||
import type { Feed } from "@/types/feed";
|
||||
import { useTheme } from "@/context/ThemeContext";
|
||||
import { htmlToText } from "@/utils/html-to-text";
|
||||
|
||||
type FeedPageProps = {
|
||||
focused: boolean;
|
||||
|
||||
Reference in New Issue
Block a user