diff --git a/src/content/internet-telewizja/telewizja-mozliwosci.yaml b/src/content/internet-telewizja/telewizja-mozliwosci.yaml
index 0c3c289..a2e0a47 100644
--- a/src/content/internet-telewizja/telewizja-mozliwosci.yaml
+++ b/src/content/internet-telewizja/telewizja-mozliwosci.yaml
@@ -1,5 +1,5 @@
title: Możliwości telewizji JAMBOX
-description: Funkcje i udogodnienia dostępne w JAMBOX.
+description: Poznaj funkcje i udogodnienia dostępne na dekoderach telewizji JAMBOX.
sections:
- title: CatchUp - Archiwum TV
image: https://www.jambox.pl/sites/default/files/jambox-kyanit-catchup1.png
diff --git a/src/layouts/BaseHead.astro b/src/layouts/BaseHead.astro
index e6dfe19..03fa16c 100644
--- a/src/layouts/BaseHead.astro
+++ b/src/layouts/BaseHead.astro
@@ -52,6 +52,7 @@ const jsonExtra = meta.extraSchema ? JSON.stringify(meta.extraSchema) : null;
/>
+
diff --git a/src/lib/astro-helpers.ts b/src/lib/astro-helpers.ts
index c53e82d..7470809 100644
--- a/src/lib/astro-helpers.ts
+++ b/src/lib/astro-helpers.ts
@@ -395,4 +395,91 @@ export function getRequiredEnv(key: string): string {
}
return value;
+}
+
+// ==================== SITEMAP HELPERS ====================
+
+export type SitemapUrl = {
+ loc: string;
+ lastmod?: string;
+ changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
+ priority?: number;
+};
+
+/**
+ * Generuje sitemap XML z listy URL-i
+ * @param urls - Tablica URL-i do sitemap
+ * @returns String z XML sitemap
+ *
+ * @example
+ * const urls = [
+ * { loc: 'https://example.com/', priority: 1.0, changefreq: 'daily' },
+ * { loc: 'https://example.com/about', priority: 0.8, changefreq: 'monthly' }
+ * ];
+ * const xml = generateSitemapXml(urls);
+ */
+export function generateSitemapXml(urls: SitemapUrl[]): string {
+ const urlEntries = urls.map(url => {
+ const parts = [
+ ' ',
+ ` ${url.loc}`,
+ ];
+
+ if (url.lastmod) {
+ parts.push(` ${url.lastmod}`);
+ }
+
+ if (url.changefreq) {
+ parts.push(` ${url.changefreq}`);
+ }
+
+ if (url.priority !== undefined) {
+ parts.push(` ${url.priority.toFixed(1)}`);
+ }
+
+ parts.push(' ');
+ return parts.join('\n');
+ }).join('\n');
+
+ return `
+
+${urlEntries}
+`;
+}
+
+/**
+ * Automatyczne określenie changefreq na podstawie ścieżki URL
+ * @param path - Ścieżka URL (np. "/internet-swiatlowodowy")
+ * @returns Częstotliwość zmian
+ *
+ * @example
+ * inferChangeFreq('/') // => 'daily'
+ * inferChangeFreq('/dokumenty/regulamin') // => 'yearly'
+ */
+export function inferChangeFreq(path: string): SitemapUrl['changefreq'] {
+ if (path === '/') return 'daily';
+ if (path.includes('/internet-') || path.includes('/telefon')) return 'weekly';
+ if (path.includes('/mapa-zasiegu') || path.includes('/kontakt')) return 'monthly';
+ if (path.includes('/dokumenty')) return 'yearly';
+ if (path.includes('/premium')) return 'monthly';
+ return 'weekly';
+}
+
+/**
+ * Automatyczne określenie priority na podstawie ścieżki URL
+ * @param path - Ścieżka URL
+ * @returns Priorytet (0.0 - 1.0)
+ *
+ * @example
+ * inferPriority('/') // => 1.0
+ * inferPriority('/dokumenty/polityka-prywatnosci') // => 0.5
+ */
+export function inferPriority(path: string): number {
+ if (path === '/') return 1.0;
+ if (path.includes('/internet-') || path.includes('/telefon')) return 0.9;
+ if (path.includes('/mapa-zasiegu') || path.includes('/kontakt')) return 0.8;
+ if (path.includes('/premium')) return 0.7;
+ if (path.includes('/telewizja-mozliwosci')) return 0.7;
+ if (path.includes('/dokumenty')) return 0.5;
+ return 0.7;
}
\ No newline at end of file
diff --git a/src/pages/sitemap.xml.js b/src/pages/sitemap.xml.js
deleted file mode 100644
index 498e07e..0000000
--- a/src/pages/sitemap.xml.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import { globby } from 'globby';
-
-export async function GET() {
- const base = "https://www.fuz.pl";
-
- // Pobieramy wszystkie pliki .astro
- const files = await globby([
- "src/pages/**/*.astro",
- "!src/pages/_*.astro", // pomiń pliki zaczynające się od _
- "!src/pages/**/[...*", // pomiń catch-all
- "!src/pages/**/[**", // pomiń dynamiczne parametry
- "!src/pages/sitemap.xml.js", // pomiń samą sitemapę
- "!src/pages/api/**" // pomiń API endpoints
- ]);
-
- // Konwersja ścieżek plikowych → URL-e
- const urls = files.map((file) => {
- let url = file
- .replace("src/pages", "")
- .replace(".astro", "");
-
- // obsługa index: /index.astro → /
- if (url.endsWith("/index")) {
- url = url.replace("/index", "");
- }
-
- return url;
- });
-
- const body = `
-
- ${urls
- .map((url) => {
- return `
-
- ${base}${url}
- weekly
- ${url === "/" ? "1.0" : "0.8"}
- `;
- })
- .join("")}
- `;
-
- return new Response(body, {
- headers: {
- "Content-Type": "application/xml",
- },
- });
-}
diff --git a/src/pages/sitemap.xml.ts b/src/pages/sitemap.xml.ts
new file mode 100644
index 0000000..882e0ff
--- /dev/null
+++ b/src/pages/sitemap.xml.ts
@@ -0,0 +1,100 @@
+import type { APIRoute } from 'astro';
+import {
+ getEnv,
+ generateSitemapXml,
+ inferChangeFreq,
+ inferPriority,
+ type SitemapUrl
+} from '../lib/astro-helpers';
+import { listDocuments } from '../lib/documents';
+
+/**
+ * Dynamiczny sitemap generator
+ * GET /sitemap.xml
+ */
+export const GET: APIRoute = async ({ site }) => {
+ const base = site?.toString().replace(/\/$/, '') ||
+ getEnv('PUBLIC_SITE_URL') ||
+ "https://www.fuz.pl";
+
+ const now = new Date().toISOString();
+ const urls: SitemapUrl[] = [];
+
+ // ========================================
+ // STATYCZNE STRONY
+ // ========================================
+ const staticPages = [
+ '/',
+ '/internet-swiatlowodowy',
+ '/internet-telewizja',
+ '/telefon',
+ '/mapa-zasiegu',
+ '/kontakt',
+ '/dokumenty',
+ '/premium',
+ '/telewizja-mozliwosci',
+ ];
+
+ staticPages.forEach(path => {
+ urls.push({
+ loc: `${base}${path}`,
+ lastmod: now,
+ changefreq: inferChangeFreq(path),
+ priority: inferPriority(path),
+ });
+ });
+
+ // ========================================
+ // DYNAMICZNE STRONY: Dokumenty
+ // ========================================
+ try {
+ const docs = listDocuments();
+
+ docs
+ .filter(d => d.visible === true)
+ .forEach(d => {
+ const path = `/dokumenty/${d.slug}`;
+ urls.push({
+ loc: `${base}${path}`,
+ lastmod: now,
+ changefreq: 'yearly',
+ priority: 0.5,
+ });
+ });
+ } catch (e) {
+ console.warn('⚠️ Sitemap: Could not load documents:', e);
+ }
+
+ // ========================================
+ // DYNAMICZNE STRONY: Premium packages (opcjonalnie)
+ // ========================================
+ // TODO: Jeśli masz dynamiczne pakiety premium, dodaj tutaj:
+ /*
+ try {
+ const packages = await loadPremiumPackages();
+ packages.forEach(p => {
+ urls.push({
+ loc: `${base}/premium/${p.tid}`,
+ lastmod: now,
+ changefreq: 'monthly',
+ priority: 0.7,
+ });
+ });
+ } catch (e) {
+ console.warn('⚠️ Sitemap: Could not load premium packages:', e);
+ }
+ */
+
+ // ========================================
+ // GENERUJ XML
+ // ========================================
+ const sitemap = generateSitemapXml(urls);
+
+ return new Response(sitemap, {
+ status: 200,
+ headers: {
+ 'Content-Type': 'application/xml; charset=utf-8',
+ 'Cache-Control': 'public, max-age=3600', // 1h cache
+ },
+ });
+};
\ No newline at end of file