From 7931127aa615e8b438ada9cef51f8074929a0475 Mon Sep 17 00:00:00 2001 From: 4gray Date: Sun, 15 Feb 2026 01:22:59 +0100 Subject: [PATCH] chore(website): enhance SEO with structured data and meta tags in various components --- README.md | 2 +- apps/website/public/llms.txt | 26 +++++++++++ apps/website/public/robots.txt | 4 ++ apps/website/src/components/BaseHead.astro | 53 +++++++++++++++++++--- apps/website/src/layouts/BaseLayout.astro | 20 +++++++- apps/website/src/layouts/BlogPost.astro | 36 ++++++++++++++- apps/website/src/pages/404.astro | 6 ++- apps/website/src/pages/blog/index.astro | 1 + apps/website/src/pages/index.astro | 36 +++++++++++++++ 9 files changed, 172 insertions(+), 12 deletions(-) create mode 100644 apps/website/public/llms.txt create mode 100644 apps/website/public/robots.txt diff --git a/README.md b/README.md index c7588e248..89960c228 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ GitHub Workflow Status Releases Codecov Telegram Bluesky

-Telegram channel for discussions | Buy me a coffee | GitHub Sponsors +🌐 **[Website](https://4gray.github.io/iptvnator/)** | Telegram channel for discussions | Buy me a coffee | GitHub Sponsors **IPTVnator** is a video player application that provides support for IPTV playlist playback (m3u, m3u8). The application allows users to import playlists using remote URLs or by uploading files from the local file system. Additionally, it supports EPG information in XMLTV format which can be provided via URL. diff --git a/apps/website/public/llms.txt b/apps/website/public/llms.txt new file mode 100644 index 000000000..cb6148c39 --- /dev/null +++ b/apps/website/public/llms.txt @@ -0,0 +1,26 @@ +# IPTVnator + +> IPTVnator is an open-source cross-platform IPTV player (desktop + web) that supports M3U/M3U8 playlists, Xtream Codes API, Stalker portals, and XMLTV EPG. + +## Canonical URLs + +- Website: https://4gray.github.io/iptvnator/ +- Blog: https://4gray.github.io/iptvnator/blog/ +- Latest Release: https://github.com/4gray/iptvnator/releases/latest +- Release Notes (v0.18): https://4gray.github.io/iptvnator/blog/v0-18-release-notes/ +- Troubleshooting (macOS app damaged fix): https://4gray.github.io/iptvnator/blog/macos-arm-app-damaged-fix/ +- Source Code: https://github.com/4gray/iptvnator +- Telegram: https://t.me/iptvnator +- GitHub Sponsors: https://github.com/sponsors/4gray +- Ko-fi: https://ko-fi.com/4gray + +## Product Scope + +- IPTVnator is a media player application. +- It does not provide, host, or sell playlists, channels, or media content. +- Any channel names or metadata shown in screenshots/posts are demo examples only. + +## Machine-readable Discovery + +- Sitemap: https://4gray.github.io/iptvnator/sitemap-index.xml +- Robots: https://4gray.github.io/iptvnator/robots.txt diff --git a/apps/website/public/robots.txt b/apps/website/public/robots.txt new file mode 100644 index 000000000..ae84a0078 --- /dev/null +++ b/apps/website/public/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: / + +Sitemap: https://4gray.github.io/iptvnator/sitemap-index.xml diff --git a/apps/website/src/components/BaseHead.astro b/apps/website/src/components/BaseHead.astro index 1d978ffff..2e4f4b967 100644 --- a/apps/website/src/components/BaseHead.astro +++ b/apps/website/src/components/BaseHead.astro @@ -3,16 +3,46 @@ interface Props { title: string; description: string; image?: string; + type?: 'website' | 'article'; + noindex?: boolean; + keywords?: string[]; + publishedTime?: string; + modifiedTime?: string; + jsonLd?: Record | Array>; } const canonicalURL = new URL(Astro.url.pathname, Astro.site); -const { title, description, image = '/iptvnator/og-image.png' } = Astro.props; +const { + title, + description, + image = '/iptvnator/og-image.png', + type = 'website', + noindex = false, + keywords = [], + publishedTime, + modifiedTime, + jsonLd, +} = Astro.props; + +const absoluteImageURL = new URL(image, Astro.site); +const robotsContent = noindex + ? 'noindex, nofollow, noarchive' + : 'index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1'; +const schemaPayload = jsonLd + ? JSON.stringify(Array.isArray(jsonLd) ? jsonLd : [jsonLd]) + : null; --- + + + + + +{keywords.length > 0 && } @@ -23,7 +53,7 @@ const { title, description, image = '/iptvnator/og-image.png' } = Astro.props; /> - + {title} @@ -31,15 +61,24 @@ const { title, description, image = '/iptvnator/og-image.png' } = Astro.props; - - + + + + - + + +{type === 'article' && publishedTime && } +{type === 'article' && modifiedTime && } - + - + + +{schemaPayload && ( +