← back to Nineoh Guide

apps/web/app/sitemap.ts

55 lines

import type { MetadataRoute } from "next";
import { pool } from "@/lib/db";
import { SITE_URL, episodePath, castPath, slugify } from "@nineoh/core";
import { GAMES } from "@/lib/games";

export const dynamic = "force-dynamic";

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const urls: MetadataRoute.Sitemap = [
    "",
    "/show",
    "/episodes",
    "/cast",
    "/characters",
    "/news",
    "/games",
    "/community",
    "/search",
    "/legal/disclaimer",
    "/legal/dmca",
    "/legal/privacy",
  ].map((p) => ({ url: `${SITE_URL}${p}`, changeFrequency: "weekly", priority: p === "" ? 1 : 0.6 }));

  for (const g of GAMES) {
    urls.push({ url: `${SITE_URL}/games/${g.file}`, changeFrequency: "monthly", priority: 0.5 });
  }

  try {
    const eps = await pool.query(
      `select season_number, episode_number from episodes order by season_number, episode_number`
    );
    for (const e of eps.rows) {
      urls.push({
        url: `${SITE_URL}${episodePath(e.season_number, e.episode_number)}`,
        changeFrequency: "monthly",
        priority: 0.7,
      });
    }
    const cast = await pool.query(`select name from cast_people order by name`);
    for (const c of cast.rows) {
      urls.push({ url: `${SITE_URL}${castPath(c.name)}`, changeFrequency: "monthly", priority: 0.5 });
    }
    const chars = await pool.query(
      `select name from characters where description_original is not null order by name`
    );
    for (const c of chars.rows) {
      urls.push({ url: `${SITE_URL}/characters/${slugify(c.name)}`, changeFrequency: "monthly", priority: 0.5 });
    }
  } catch {
    /* DB unreachable at build — static routes still returned */
  }

  return urls;
}