diff --git a/.github/workflows/deploy-website.yml b/.github/workflows/deploy-website.yml new file mode 100644 index 000000000..d34ac6f22 --- /dev/null +++ b/.github/workflows/deploy-website.yml @@ -0,0 +1,61 @@ +name: Deploy Website to GitHub Pages + +on: + push: + branches: + - master + paths: + - 'apps/website/**' + - '.github/workflows/deploy-website.yml' + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: 'pages' + cancel-in-progress: true + +jobs: + build: + name: Build Website + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --no-frozen-lockfile + + - name: Build website + run: npx nx build website + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: dist/apps/website + + deploy: + name: Deploy to GitHub Pages + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index ab4096c76..a1361efa1 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,7 @@ playwright-report server.js # dependencies -/node_modules +node_modules # IDEs and editors /.idea @@ -61,5 +61,6 @@ testem.log # System Files .DS_Store -Thumbs.db +Thumbs.db .angular +.astro diff --git a/apps/website/astro.config.mjs b/apps/website/astro.config.mjs new file mode 100644 index 000000000..59e9902f5 --- /dev/null +++ b/apps/website/astro.config.mjs @@ -0,0 +1,13 @@ +// @ts-check +import { defineConfig } from 'astro/config'; +import tailwind from '@astrojs/tailwind'; +import sitemap from '@astrojs/sitemap'; +import mdx from '@astrojs/mdx'; + +// https://astro.build/config +export default defineConfig({ + site: 'https://4gray.github.io', + base: '/iptvnator', + outDir: '../../dist/apps/website', + integrations: [tailwind(), sitemap(), mdx()], +}); diff --git a/apps/website/package.json b/apps/website/package.json new file mode 100644 index 000000000..95ad56b4b --- /dev/null +++ b/apps/website/package.json @@ -0,0 +1,5 @@ +{ + "name": "website", + "private": true, + "type": "module" +} diff --git a/apps/website/project.json b/apps/website/project.json new file mode 100644 index 000000000..3d5e4f83d --- /dev/null +++ b/apps/website/project.json @@ -0,0 +1,33 @@ +{ + "name": "website", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/website/src", + "tags": ["type:website"], + "targets": { + "build": { + "executor": "nx:run-commands", + "outputs": ["{workspaceRoot}/dist/apps/website"], + "inputs": ["production", "^production"], + "options": { + "command": "npx astro build", + "cwd": "apps/website" + } + }, + "serve": { + "executor": "nx:run-commands", + "options": { + "command": "npx astro dev --port 4321", + "cwd": "apps/website" + } + }, + "preview": { + "executor": "nx:run-commands", + "dependsOn": ["build"], + "options": { + "command": "npx astro preview --port 4322", + "cwd": "apps/website" + } + } + } +} diff --git a/apps/website/public/favicon.ico b/apps/website/public/favicon.ico new file mode 100644 index 000000000..1bd12fad7 Binary files /dev/null and b/apps/website/public/favicon.ico differ diff --git a/apps/website/public/images/broken-tv.svg b/apps/website/public/images/broken-tv.svg new file mode 100644 index 000000000..0d37bd66f --- /dev/null +++ b/apps/website/public/images/broken-tv.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/website/public/iptvnator/blog/epg.png b/apps/website/public/iptvnator/blog/epg.png new file mode 100644 index 000000000..5c7a857f3 Binary files /dev/null and b/apps/website/public/iptvnator/blog/epg.png differ diff --git a/apps/website/public/iptvnator/blog/player.png b/apps/website/public/iptvnator/blog/player.png new file mode 100644 index 000000000..fa953d889 Binary files /dev/null and b/apps/website/public/iptvnator/blog/player.png differ diff --git a/apps/website/public/og-image.png b/apps/website/public/og-image.png new file mode 100644 index 000000000..4551b7951 Binary files /dev/null and b/apps/website/public/og-image.png differ diff --git a/apps/website/src/assets/logo.png b/apps/website/src/assets/logo.png new file mode 100644 index 000000000..d3283a33a Binary files /dev/null and b/apps/website/src/assets/logo.png differ diff --git a/apps/website/src/assets/screenshots/epg.png b/apps/website/src/assets/screenshots/epg.png new file mode 100644 index 000000000..5c7a857f3 Binary files /dev/null and b/apps/website/src/assets/screenshots/epg.png differ diff --git a/apps/website/src/assets/screenshots/hero-dark.png b/apps/website/src/assets/screenshots/hero-dark.png new file mode 100644 index 000000000..4551b7951 Binary files /dev/null and b/apps/website/src/assets/screenshots/hero-dark.png differ diff --git a/apps/website/src/assets/screenshots/player.png b/apps/website/src/assets/screenshots/player.png new file mode 100644 index 000000000..fa953d889 Binary files /dev/null and b/apps/website/src/assets/screenshots/player.png differ diff --git a/apps/website/src/assets/screenshots/playlists.png b/apps/website/src/assets/screenshots/playlists.png new file mode 100644 index 000000000..6fd4de312 Binary files /dev/null and b/apps/website/src/assets/screenshots/playlists.png differ diff --git a/apps/website/src/assets/screenshots/settings.png b/apps/website/src/assets/screenshots/settings.png new file mode 100644 index 000000000..e6a68a0dc Binary files /dev/null and b/apps/website/src/assets/screenshots/settings.png differ diff --git a/apps/website/src/assets/screenshots/upload-file.png b/apps/website/src/assets/screenshots/upload-file.png new file mode 100644 index 000000000..d9bf3c1fa Binary files /dev/null and b/apps/website/src/assets/screenshots/upload-file.png differ diff --git a/apps/website/src/assets/screenshots/upload-url.png b/apps/website/src/assets/screenshots/upload-url.png new file mode 100644 index 000000000..95cdc010f Binary files /dev/null and b/apps/website/src/assets/screenshots/upload-url.png differ diff --git a/apps/website/src/components/BaseHead.astro b/apps/website/src/components/BaseHead.astro new file mode 100644 index 000000000..1d978ffff --- /dev/null +++ b/apps/website/src/components/BaseHead.astro @@ -0,0 +1,45 @@ +--- +interface Props { + title: string; + description: string; + image?: string; +} + +const canonicalURL = new URL(Astro.url.pathname, Astro.site); +const { title, description, image = '/iptvnator/og-image.png' } = Astro.props; +--- + + + + + + + + + + + + + + + +{title} + + + + + + + + + + + + + + + + diff --git a/apps/website/src/components/BlogPostCard.astro b/apps/website/src/components/BlogPostCard.astro new file mode 100644 index 000000000..ea918eb56 --- /dev/null +++ b/apps/website/src/components/BlogPostCard.astro @@ -0,0 +1,71 @@ +--- +interface Props { + title: string; + description: string; + pubDate: Date; + slug: string; + tags?: string[]; + heroImage?: string; +} + +const { title, description, pubDate, slug, tags = [], heroImage } = Astro.props; + +const formattedDate = pubDate.toLocaleDateString('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric', +}); +--- + + + {heroImage && ( +
+ +
+ )} +
+ + { + tags.length > 0 && ( + <> + · + {tags.map((tag) => ( + + {tag} + + ))} + + ) + } +
+

+ {title} +

+

+ {description} +

+ + Read more + + + + +
diff --git a/apps/website/src/components/DownloadCTA.astro b/apps/website/src/components/DownloadCTA.astro new file mode 100644 index 000000000..cd7453398 --- /dev/null +++ b/apps/website/src/components/DownloadCTA.astro @@ -0,0 +1,122 @@ +--- +const platforms = [ + { + name: 'macOS', + icon: 'M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.8-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z', + href: 'https://github.com/4gray/iptvnator/releases/latest', + }, + { + name: 'Windows', + icon: 'M3 12V6.75l8-1.25V12H3zm0 .5h8v6.5l-8-1.25V12.5zM11.5 5.35L21 3.75V12h-9.5V5.35zm0 7.15H21v8.25l-9.5-1.6V12.5z', + href: 'https://github.com/4gray/iptvnator/releases/latest', + }, + { + name: 'Linux', + icon: 'M12.504 0c-.155 0-.315.008-.48.021-4.226.333-3.105 4.807-3.17 6.298-.076 1.092-.3 1.953-1.05 3.02-.885 1.051-2.127 2.75-2.716 4.521-.278.832-.41 1.684-.287 2.489a.424.424 0 00-.11.135c-.26.268-.45.6-.663.839-.199.199-.485.267-.797.4-.313.136-.658.269-.864.68-.09.189-.136.394-.132.602 0 .199.027.4.055.536.058.399.116.728.04.97-.249.68-.28 1.145-.106 1.484.174.334.535.47.94.601.81.2 1.91.135 2.774.6.926.466 1.866.67 2.616.47.526-.116.97-.464 1.208-.946.587-.003 1.23-.269 2.26-.334.699-.058 1.574.267 2.577.2.025.134.063.198.114.333l.003.003c.391.778 1.113 1.368 1.884 1.43.39.03.8-.066 1.109-.199.69-.3 1.286-1.065 1.09-1.745a21.03 21.03 0 01-.174-.606c-.101-.427-.2-.855-.29-1.283-.09-.428.04-.546.481-.735.463-.199.833-.338 1.073-.668.24-.33.364-.8.269-1.437-.14-.98-.689-2.072-1.329-3.069-.645-1-.34-1.665-.34-2.863.006-1.497-.898-2.987-1.792-4.048-.89-1.06-1.78-1.835-2.085-2.748-.228-.68-.098-1.401.128-2.056.112-.322.254-.631.325-.933.07-.303.072-.622-.058-.853C13.56.199 13.04 0 12.504 0z', + href: 'https://github.com/4gray/iptvnator/releases/latest', + }, +]; + +const packageManagers = [ + { label: 'Homebrew', command: 'brew install --cask iptvnator' }, + { label: 'Snap', command: 'sudo snap install iptvnator' }, +]; +--- + +
+
+ + +
+ +
+ +
+ + Get started + +

+ Get IPTVnator +

+

+ Download for your platform or use it directly in the browser. +

+
+ + +
+ { + platforms.map((platform) => ( + + + + +
+
Download for
+
{platform.name}
+
+
+ )) + } +
+ + +
+ { + packageManagers.map((pm) => ( +
+ + {pm.label} + + + {pm.command} + + +
+ )) + } +
+ + +
+

+ Or use it directly at{' '} + + iptvnator.vercel.app + +

+
+
+
+ + diff --git a/apps/website/src/components/FeatureGrid.astro b/apps/website/src/components/FeatureGrid.astro new file mode 100644 index 000000000..b16ecec7c --- /dev/null +++ b/apps/website/src/components/FeatureGrid.astro @@ -0,0 +1,188 @@ +--- +const heroFeatures = [ + { + icon: '', + title: 'M3U / M3U8 Playlists', + description: 'Import playlists from files or URLs with full M3U and M3U8 support.', + }, + { + icon: '', + title: 'Xtream Codes API', + description: 'Connect to Xtream Codes providers with live TV, VOD, and series.', + }, + { + icon: '', + title: 'Electronic Program Guide', + description: 'XMLTV-based EPG with current and upcoming program information.', + }, + { + icon: '', + title: 'Cross-Platform', + description: 'Runs on macOS, Windows, Linux as a desktop app or PWA in any browser.', + }, +]; + +const carouselFeatures = [ + { + icon: '', + title: 'Stalker Portals', + description: 'Browse and stream content from Stalker/Ministra portal providers.', + }, + { + icon: '', + title: 'Favorites & History', + description: 'Mark channels as favorites and keep track of recently watched.', + }, + { + icon: '', + title: 'Search & Filter', + description: 'Quickly find channels across playlists with full-text search.', + }, + { + icon: '', + title: 'Multi-Language', + description: 'Available in 16 languages with community-contributed translations.', + }, + { + icon: '', + title: 'External Players', + description: 'Open streams in MPV, VLC, or other external players from the app.', + }, + { + icon: '', + title: 'Light & Dark Themes', + description: 'Choose between light and dark themes for comfortable viewing.', + }, + { + icon: '', + title: 'Remote Control', + description: 'Control the player from your phone with the built-in remote.', + }, + { + icon: '', + title: 'Privacy First', + description: 'No tracking, no analytics. Your data stays on your device.', + }, +]; +--- + +
+
+ +
+ +
+ + Features + +

+ Everything you need +

+

+ A full-featured IPTV player packed with the tools for the best viewing experience. +

+
+ + +
+ { + heroFeatures.map((feature) => ( +
+ +
+ +
+
+ + + +
+

{feature.title}

+

+ {feature.description} +

+
+
+ )) + } +
+ + +
+ + And more + +
+
+ + +
+ +
+
+ + + +
+
+ + diff --git a/apps/website/src/components/FeaturedBlogPost.astro b/apps/website/src/components/FeaturedBlogPost.astro new file mode 100644 index 000000000..1487a4204 --- /dev/null +++ b/apps/website/src/components/FeaturedBlogPost.astro @@ -0,0 +1,87 @@ +--- +interface Props { + title: string; + description: string; + pubDate: Date; + slug: string; + tags?: string[]; + heroImage?: string; +} + +const { title, description, pubDate, slug, tags = [], heroImage } = Astro.props; + +const formattedDate = pubDate.toLocaleDateString('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric', +}); +--- + + +
+ +
+ {heroImage ? ( + + ) : ( +
+ +
+ )} +
+ + +
+
+ Featured + · + +
+ + {tags.length > 0 && ( +
+ {tags.map((tag) => ( + + {tag} + + ))} +
+ )} + +

+ {title} +

+ +

+ {description} +

+ + + Read more + + + + +
+
+
diff --git a/apps/website/src/components/Footer.astro b/apps/website/src/components/Footer.astro new file mode 100644 index 000000000..9bd259543 --- /dev/null +++ b/apps/website/src/components/Footer.astro @@ -0,0 +1,73 @@ +--- +const socialLinks = [ + { + label: 'GitHub', + href: 'https://github.com/4gray/iptvnator', + icon: 'M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z', + }, + { + label: 'Telegram', + href: 'https://t.me/iptvnator', + icon: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4.64 6.8c-.15 1.58-.8 5.42-1.13 7.19-.14.75-.42 1-.68 1.03-.58.05-1.02-.38-1.58-.75-.88-.58-1.38-.94-2.23-1.5-.99-.65-.35-1.01.22-1.59.15-.15 2.71-2.48 2.76-2.69.01-.03.01-.14-.07-.2-.08-.06-.19-.04-.27-.02-.12.03-1.99 1.27-5.62 3.72-.53.36-1.01.54-1.44.53-.47-.01-1.38-.27-2.06-.49-.83-.27-1.49-.42-1.43-.88.03-.24.37-.49 1.02-.74 3.99-1.74 6.65-2.89 7.99-3.44 3.81-1.58 4.6-1.86 5.12-1.87.11 0 .37.03.54.17.14.12.18.28.2.45-.01.06.01.24 0 .38z', + }, + { + label: 'Bluesky', + href: 'https://bsky.app/profile/4gray.bsky.social', + icon: 'M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm3.5 14.5c-1.5 0-2.7-.8-3.5-2-.8 1.2-2 2-3.5 2C6.6 16.5 5 14.9 5 13c0-3 3.5-6.5 7-9.5 3.5 3 7 6.5 7 9.5 0 1.9-1.6 3.5-3.5 3.5z', + }, + { + label: 'Sponsor', + href: 'https://ko-fi.com/4gray', + icon: 'M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z', + }, +]; +--- + +
+
+
+ +
+
+ IPTVnator logo + IPTVnator +
+

+ Open-source IPTV player for everyone. +

+
+ + +
+ { + socialLinks.map((link) => ( + + + + + + )) + } +
+
+ +
+

+ MIT License. Built with Astro. +

+

+ IPTVnator does not provide any playlists or content. +

+
+
+
diff --git a/apps/website/src/components/Header.astro b/apps/website/src/components/Header.astro new file mode 100644 index 000000000..ee1391036 --- /dev/null +++ b/apps/website/src/components/Header.astro @@ -0,0 +1,147 @@ +--- +const navLinks = [ + { label: 'Features', href: '/iptvnator/#features' }, + { label: 'Screenshots', href: '/iptvnator/#screenshots' }, + { label: 'Download', href: '/iptvnator/#download' }, + { label: 'Blog', href: '/iptvnator/blog/' }, +]; +--- + + + + diff --git a/apps/website/src/components/Hero.astro b/apps/website/src/components/Hero.astro new file mode 100644 index 000000000..07852aa5f --- /dev/null +++ b/apps/website/src/components/Hero.astro @@ -0,0 +1,127 @@ +--- +import { Image } from 'astro:assets'; +import heroImg from '../assets/screenshots/hero-dark.png'; +--- + +
+ +
+ +
+ +
+ +
+ + Open source IPTV player + +
+ + +

+ Watch, your way. +

+ +

+ A cross-platform player for M3U/M3U8 playlists, Xtream Codes API, and + Stalker portals. Desktop app and Progressive Web App. +

+ + + + + +
+ GitHub stars + Latest release + Total downloads +
+
+ + +
+ +
+ + +
+ +
+
+ + + +
+ IPTVnator +
+ + +
+
+
+
+ IPTVnator application interface showing dark theme with channel list and video player +
+
+
+
+
diff --git a/apps/website/src/components/ScreenshotShowcase.astro b/apps/website/src/components/ScreenshotShowcase.astro new file mode 100644 index 000000000..ef5c77358 --- /dev/null +++ b/apps/website/src/components/ScreenshotShowcase.astro @@ -0,0 +1,128 @@ +--- +import { Image } from 'astro:assets'; +import playerImg from '../assets/screenshots/player.png'; +import epgImg from '../assets/screenshots/epg.png'; +import playlistsImg from '../assets/screenshots/playlists.png'; +import settingsImg from '../assets/screenshots/settings.png'; +import uploadFileImg from '../assets/screenshots/upload-file.png'; + +const tabs = [ + { id: 'player', label: 'Player', image: playerImg, alt: 'IPTVnator video player interface' }, + { id: 'epg', label: 'EPG Guide', image: epgImg, alt: 'Electronic program guide view' }, + { id: 'playlists', label: 'Playlists', image: playlistsImg, alt: 'Playlist management screen' }, + { id: 'settings', label: 'Settings', image: settingsImg, alt: 'Application settings' }, + { id: 'upload', label: 'Add Playlist', image: uploadFileImg, alt: 'Add playlist dialog' }, +]; +--- + +
+
+ +
+ +
+ + Interface + +

+ See it in action +

+

+ A clean, intuitive interface designed for the best viewing experience. +

+
+ +
+ +
+ { + tabs.map((tab, i) => ( + + )) + } +
+ + +
+ { + tabs.map((tab, i) => ( +
+
+ +
+ + +
+
+
+ + + +
+ {tab.label} +
+ {tab.alt} +
+
+
+ )) + } +
+
+
+
+ + diff --git a/apps/website/src/content.config.ts b/apps/website/src/content.config.ts new file mode 100644 index 000000000..372b3f84f --- /dev/null +++ b/apps/website/src/content.config.ts @@ -0,0 +1,18 @@ +import { glob } from 'astro/loaders'; +import { defineCollection, z } from 'astro:content'; + +const blog = defineCollection({ + loader: glob({ pattern: '**/[^_]*.{md,mdx}', base: './src/content/blog' }), + schema: z.object({ + title: z.string(), + description: z.string(), + pubDate: z.coerce.date(), + updatedDate: z.coerce.date().optional(), + author: z.string().default('4gray'), + heroImage: z.string().optional(), + tags: z.array(z.string()).default([]), + draft: z.boolean().default(false), + }), +}); + +export const collections = { blog }; diff --git a/apps/website/src/content/blog/epg-guide.md b/apps/website/src/content/blog/epg-guide.md new file mode 100644 index 000000000..689e15e40 --- /dev/null +++ b/apps/website/src/content/blog/epg-guide.md @@ -0,0 +1,45 @@ +--- +title: 'Understanding the Electronic Program Guide' +description: 'Learn how IPTVnator uses XMLTV data to display current and upcoming programs alongside your live TV channels.' +pubDate: 2025-02-15 +author: '4gray' +heroImage: '/iptvnator/blog/epg.png' +tags: ['tutorial', 'epg'] +--- + +One of the most useful features in IPTVnator is the built-in Electronic Program Guide (EPG). Here is how it works and how to set it up. + +## What is EPG? + +The Electronic Program Guide displays a schedule of current and upcoming TV programs for your channels. IPTVnator supports EPG data in the **XMLTV format**, which is the standard used by most IPTV providers. + +## Setting up EPG + +To enable EPG in IPTVnator: + +1. **Open your playlist** and navigate to the Settings tab +2. **Add an EPG URL** — your IPTV provider should supply a URL ending in `.xml` or `.xml.gz` +3. **Refresh the EPG data** — IPTVnator will download and parse the program information in the background + +The EPG data is parsed in a background worker thread, so it won't slow down the main application even with large files. + +## EPG in action + +Once configured, you will see: + +- **Current program** displayed next to each channel in the channel list +- **Progress bar** showing how far through the current program you are +- **Program details** in the right sidebar when you select a channel +- **Upcoming schedule** with times and descriptions for future programs + +## Channel matching + +IPTVnator matches EPG data to channels using the `tvg-id` attribute from your M3U playlist. Make sure your playlist includes these IDs for the best EPG experience. + +## Tips + +- EPG files can be large — IPTVnator caches parsed data in the database (Electron) or IndexedDB (PWA) for faster loading +- You can add multiple EPG sources per playlist +- The EPG automatically refreshes periodically to keep the schedule up to date + +Check the [GitHub repository](https://github.com/4gray/iptvnator) for more information on supported EPG formats. diff --git a/apps/website/src/content/blog/welcome.md b/apps/website/src/content/blog/welcome.md new file mode 100644 index 000000000..17d6ecb5a --- /dev/null +++ b/apps/website/src/content/blog/welcome.md @@ -0,0 +1,27 @@ +--- +title: 'Introducing the IPTVnator Website' +description: 'We are excited to launch the official IPTVnator website and developer blog. Stay tuned for release notes, tutorials, and roadmap updates.' +pubDate: 2025-02-14 +author: '4gray' +heroImage: '/iptvnator/blog/player.png' +tags: ['announcement'] +--- + +We are excited to launch the official IPTVnator website and developer blog! + +## What is IPTVnator? + +IPTVnator is a free, open-source IPTV player application that supports M3U/M3U8 playlists, Xtream Codes API, and Stalker portals. It runs as a desktop application (via Electron) and as a Progressive Web App directly in your browser. + +## What to expect from this blog + +This blog will be the home for: + +- **Release notes** for new versions +- **Tutorials** on how to get the most out of IPTVnator +- **Roadmap updates** so you know what features are coming next +- **Technical deep dives** into the architecture and development process + +## Get involved + +IPTVnator is open source and we welcome contributions! Check out our [GitHub repository](https://github.com/4gray/iptvnator) to get started. diff --git a/apps/website/src/layouts/BaseLayout.astro b/apps/website/src/layouts/BaseLayout.astro new file mode 100644 index 000000000..da93d87f2 --- /dev/null +++ b/apps/website/src/layouts/BaseLayout.astro @@ -0,0 +1,28 @@ +--- +import BaseHead from '../components/BaseHead.astro'; +import Header from '../components/Header.astro'; +import Footer from '../components/Footer.astro'; +import '../styles/global.css'; + +interface Props { + title: string; + description: string; + image?: string; +} + +const { title, description, image } = Astro.props; +--- + + + + + + + +
+
+ +
+