diff --git a/src/main/ipc/services/app-service.ts b/src/main/ipc/services/app-service.ts index 8b9e258..5325737 100644 --- a/src/main/ipc/services/app-service.ts +++ b/src/main/ipc/services/app-service.ts @@ -32,6 +32,26 @@ class AppService extends IpcService { return dialog.showMessageBox(options) } + + @IpcMethod() + async getSiteIcon(_context: IpcContext, domain: string): Promise { + try { + const iconUrl = `https://unavatar.io/${domain}` + const response = await fetch(iconUrl) + if (!response.ok) { + return null + } + + const arrayBuffer = await response.arrayBuffer() + const buffer = Buffer.from(arrayBuffer) + const contentType = response.headers.get('content-type') || 'image/png' + const base64 = buffer.toString('base64') + return `data:${contentType};base64,${base64}` + } catch (error) { + console.error('Failed to fetch site icon:', error) + return null + } + } } export { AppService } diff --git a/src/renderer/src/data/popularSites.ts b/src/renderer/src/data/popularSites.ts index c99284f..34714e9 100644 --- a/src/renderer/src/data/popularSites.ts +++ b/src/renderer/src/data/popularSites.ts @@ -1,24 +1,26 @@ export interface PopularSite { id: string + url: string + domain: string } export const popularSites: PopularSite[] = [ - { id: 'youtube' }, - { id: 'youtubemusic' }, - { id: 'tiktok' }, - { id: 'facebook' }, - { id: 'instagram' }, - { id: 'twitter' }, - { id: 'soundcloud' }, - { id: 'reddit' }, - { id: 'vimeo' }, - { id: 'dailymotion' }, - { id: 'twitch' }, - { id: 'linkedin' }, - { id: 'pinterest' }, - { id: 'tumblr' }, - { id: 'mixcloud' }, - { id: 'niconico' }, - { id: 'kick' }, - { id: 'bandcamp' } + { id: 'youtube', url: 'https://www.youtube.com', domain: 'youtube.com' }, + { id: 'youtubemusic', url: 'https://music.youtube.com', domain: 'youtube.com' }, + { id: 'tiktok', url: 'https://www.tiktok.com', domain: 'tiktok.com' }, + { id: 'facebook', url: 'https://www.facebook.com', domain: 'facebook.com' }, + { id: 'instagram', url: 'https://www.instagram.com', domain: 'instagram.com' }, + { id: 'twitter', url: 'https://twitter.com', domain: 'twitter.com' }, + { id: 'soundcloud', url: 'https://soundcloud.com', domain: 'soundcloud.com' }, + { id: 'reddit', url: 'https://www.reddit.com', domain: 'reddit.com' }, + { id: 'vimeo', url: 'https://vimeo.com', domain: 'vimeo.com' }, + { id: 'dailymotion', url: 'https://www.dailymotion.com', domain: 'dailymotion.com' }, + { id: 'twitch', url: 'https://www.twitch.tv', domain: 'twitch.tv' }, + { id: 'linkedin', url: 'https://www.linkedin.com', domain: 'linkedin.com' }, + { id: 'pinterest', url: 'https://www.pinterest.com', domain: 'pinterest.com' }, + { id: 'tumblr', url: 'https://www.tumblr.com', domain: 'tumblr.com' }, + { id: 'mixcloud', url: 'https://www.mixcloud.com', domain: 'mixcloud.com' }, + { id: 'niconico', url: 'https://www.nicovideo.jp', domain: 'nicovideo.jp' }, + { id: 'kick', url: 'https://kick.com', domain: 'kick.com' }, + { id: 'bandcamp', url: 'https://bandcamp.com', domain: 'bandcamp.com' } ] diff --git a/src/renderer/src/pages/SupportedSites.tsx b/src/renderer/src/pages/SupportedSites.tsx index ff954b6..ed117a3 100644 --- a/src/renderer/src/pages/SupportedSites.tsx +++ b/src/renderer/src/pages/SupportedSites.tsx @@ -6,11 +6,45 @@ import { CardHeader, CardTitle } from '@renderer/components/ui/card' +import { ImageWithPlaceholder } from '@renderer/components/ui/image-with-placeholder' import { popularSites } from '@renderer/data/popularSites' +import { ipcServices } from '@renderer/lib/ipc' +import { ExternalLink } from 'lucide-react' +import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' const referenceUrl = 'https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md' +function SiteIcon({ domain, alt }: { domain: string; alt: string }) { + const [iconUrl, setIconUrl] = useState(null) + + useEffect(() => { + let cancelled = false + + const loadIcon = async () => { + try { + const dataUrl = await ipcServices.app.getSiteIcon(domain) + if (!cancelled) { + setIconUrl(dataUrl) + } + } catch (error) { + console.error('Failed to load site icon:', error) + if (!cancelled) { + setIconUrl(null) + } + } + } + + void loadIcon() + + return () => { + cancelled = true + } + }, [domain]) + + return +} + export function SupportedSites() { const { t } = useTranslation() @@ -28,7 +62,7 @@ export function SupportedSites() {

{t('sites.popularSection')}

-
    +
      {popularSites.map((site) => { const labelKey = `sites.popular.${site.id}.label` const descriptionKey = `sites.popular.${site.id}.description` @@ -37,11 +71,28 @@ export function SupportedSites() { const hasDescription = description !== descriptionKey return ( -
    • -

      {label}

      - {hasDescription ? ( -

      {description}

      - ) : null} +
    • + +
      + +
      +
      +
      +

      {label}

      + +
      + {hasDescription ? ( +

      + {description} +

      + ) : null} +
      +
    • ) })}