// これからの予定のRSSフィード(/kodaira/events/feed.xml)。 // ビルド時点の日付以降に開催される予定を、開催日の早い順に最大60件出力する。 import type { APIRoute } from 'astro'; import { items } from '@/lib/schedule-months'; import { entryDates } from '@/lib/schedule-dates'; import { SCHEDULE_BASE_PATH, SITE_URL } from '@/data/schedule/config'; const stripTags = (value: string) => value .replace(/<[^>]*>/g, '') .replace(/ /g, ' ') .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, "'") .replace(/\s+/g, ' ') .trim(); const escapeXml = (value: string) => value .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); const pad = (n: number) => String(n).padStart(2, '0'); const now = new Date(); const todayKey = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`; const toRfc822 = (date: string) => new Date(`${date}T00:00:00+09:00`).toUTCString(); const entries = items .map((item) => { const dates = entryDates(item.type, item.row.date, item.row.place); return { item, upcoming: dates.filter((date) => date >= todayKey) }; }) .filter(({ upcoming }) => upcoming.length > 0) .sort((a, b) => a.upcoming[0].localeCompare(b.upcoming[0])) .slice(0, 60); const itemXml = ({ item: { type, row }, upcoming }: (typeof entries)[number]) => { const title = stripTags(row.title); const description = [stripTags(row.place), stripTags(row.note)].filter(Boolean).join('/'); const datesLabel = upcoming .map((date) => `${Number(date.slice(5, 7))}月${Number(date.slice(8, 10))}日`) .join('、'); const link = `${SITE_URL}${SCHEDULE_BASE_PATH}${upcoming[0].slice(0, 7)}/`; const guid = `${SITE_URL}${SCHEDULE_BASE_PATH}#${type}-${upcoming[0]}-${encodeURIComponent(title)}`; return ` ${escapeXml(title)} ${escapeXml(link)} ${escapeXml(guid)} ${type === 'meeting' ? '審議会等・市議会' : 'イベント'} ${toRfc822(upcoming[0])} ${escapeXml(`開催日:${datesLabel}${description ? `/${description}` : ''}`)} `; }; export const GET: APIRoute = () => { const xml = ` 小平市のイベント・行事予定(審議会・市議会の日程も掲載) ${SITE_URL}${SCHEDULE_BASE_PATH} 小平市のイベントと、審議会等・市議会の開催予定です。市報こだいら・市公式X・LoGoフォーム・市議会の行事予定表などをもとにまとめています。 ja ${now.toUTCString()} ${entries.map(itemXml).join('\n')} `; return new Response(xml, { headers: { 'Content-Type': 'application/rss+xml; charset=utf-8' }, }); };