diff --git a/src/components/RssFeedItem/index.tsx b/src/components/RssFeedItem/index.tsx
index b8723cf1..45196696 100644
--- a/src/components/RssFeedItem/index.tsx
+++ b/src/components/RssFeedItem/index.tsx
@@ -16,6 +16,7 @@ import MediaPlayer from '@/components/MediaPlayer'
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle } from '@/components/ui/drawer'
import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { useSmartRssArticleNavigation } from '@/PageManager'
+import { getStandardRssFeedProfile } from '@/lib/standard-rss-feed-url'
/**
* Convert HTML to plain text by extracting text content and cleaning up whitespace
@@ -401,16 +402,26 @@ export default function RssFeedItem({
setSelectedText('')
}
- // Format feed source name from URL
+ const standardFeedProfile = useMemo(
+ () => (isWebFaux ? null : getStandardRssFeedProfile(item.feedUrl)),
+ [item.feedUrl, isWebFaux]
+ )
+
+ // Format feed source name from URL (known shapes get a translated label)
const feedSourceName = useMemo(() => {
if (isWebFaux) return ''
+ if (standardFeedProfile) {
+ return t(standardFeedProfile.labelKey, {
+ defaultValue: standardFeedProfile.defaultLabel
+ })
+ }
try {
const url = new URL(item.feedUrl)
return url.hostname.replace(/^www\./, '')
} catch {
return item.feedTitle || 'RSS Feed'
}
- }, [item.feedUrl, item.feedTitle, isWebFaux])
+ }, [item.feedUrl, item.feedTitle, isWebFaux, standardFeedProfile, t])
// Clean and parse HTML description safely
// Decode HTML entities and remove any XML artifacts that might have leaked through
@@ -586,6 +597,12 @@ export default function RssFeedItem({
{isWebFaux ? t('Web page') : item.feedTitle || feedSourceName}
+ {!isWebFaux && standardFeedProfile && item.feedTitle ? (
+
+ {feedSourceName}
+ {standardFeedProfile.detail ? ` · ${standardFeedProfile.detail}` : ''}
+
+ ) : null}
{item.feedDescription && (
{item.feedDescription}
diff --git a/src/components/RssFeedList/index.tsx b/src/components/RssFeedList/index.tsx
index 0be4cc4b..8bcfe102 100644
--- a/src/components/RssFeedList/index.tsx
+++ b/src/components/RssFeedList/index.tsx
@@ -43,6 +43,11 @@ import {
import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { Check, ChevronDown } from 'lucide-react'
import { normalizeHttpArticleUrl } from '@/lib/rss-article'
+import {
+ getRssFeedUrlHostname,
+ getStandardRssFeedProfile
+} from '@/lib/standard-rss-feed-url'
+import { StandardRssFeedUrlInline } from '@/components/StandardRssFeedUrlRow'
function ManualRssUrlAddRow({
className,
@@ -436,15 +441,22 @@ export default function RssFeedList() {
// Normalize URLs to prevent duplicates (e.g., with/without trailing slash)
const availableFeeds = useMemo(() => {
const feedMap = new Map()
-
- items.forEach(item => {
+
+ items.forEach((item) => {
const normalizedUrl = normalizeFeedUrl(item.feedUrl)
if (!feedMap.has(normalizedUrl)) {
- feedMap.set(normalizedUrl, { url: normalizedUrl, title: item.feedTitle || item.feedUrl })
+ const profile = getStandardRssFeedProfile(normalizedUrl)
+ const fallback = profile
+ ? t(profile.labelKey, { defaultValue: profile.defaultLabel })
+ : getRssFeedUrlHostname(normalizedUrl)
+ feedMap.set(normalizedUrl, {
+ url: normalizedUrl,
+ title: item.feedTitle?.trim() || fallback
+ })
}
})
return Array.from(feedMap.values())
- }, [items])
+ }, [items, t])
// Helper function to truncate text
const truncateText = (text: string, maxLength: number): string => {
@@ -882,8 +894,12 @@ export default function RssFeedList() {
{isChecked && }
-