Files
sendewerk/src/lib/server/previews.ts
T
2026-10-21 23:52:05 +02:00

184 lines
4.7 KiB
TypeScript

import { getDatabase } from './database.js';
import { getShow as getShowById, listShows } from './shows.js';
export type PreviewPiece = {
id: string;
title: string;
summary: string;
status: 'inbox' | 'preparing' | 'ready' | 'archived';
durationSeconds: number;
format: string;
category: string;
categoryColor: string;
topics: string[];
sourceCount: number;
};
export type PreviewUsage = {
id: string;
title: string;
durationSeconds: number;
status: 'open' | 'current' | 'done' | 'skipped';
intro: string;
moderation: string;
transition: string;
isReserve: boolean;
};
export type PreviewSection = {
id: string;
name: string;
category: string;
categoryColor: string;
durationSeconds: number;
usages: PreviewUsage[];
};
export type PreviewShow = {
id: string;
title: string;
startsAtUtc: string;
startsAtBerlin: string;
twitchTitle: string;
announcement: string;
status: string;
sections: PreviewSection[];
totalDurationSeconds: number;
};
type PieceRow = {
id: string;
title: string;
summary: string;
status: PreviewPiece['status'];
duration_seconds: number;
format: string;
category: string | null;
category_color: string | null;
topics: string | null;
source_count: number;
};
export function getPieces(): PreviewPiece[] {
const rows = getDatabase()
.prepare(
`SELECT
p.id,
p.title,
p.summary,
p.status,
p.duration_seconds,
COALESCE(f.name, 'Ohne Format') AS format,
(
SELECT c.name FROM piece_category_suggestions pcs
JOIN section_categories c ON c.id = pcs.category_id
WHERE pcs.piece_id = p.id ORDER BY c.sort_order LIMIT 1
) AS category,
(
SELECT c.color FROM piece_category_suggestions pcs
JOIN section_categories c ON c.id = pcs.category_id
WHERE pcs.piece_id = p.id ORDER BY c.sort_order LIMIT 1
) AS category_color,
(
SELECT group_concat(t.name, '||') FROM piece_topics pt
JOIN topics t ON t.id = pt.topic_id WHERE pt.piece_id = p.id
) AS topics,
(SELECT count(*) FROM piece_sources ps WHERE ps.piece_id = p.id) AS source_count
FROM pieces p
LEFT JOIN formats f ON f.id = p.format_id
WHERE p.status IN ('preparing', 'ready')
ORDER BY CASE p.status WHEN 'ready' THEN 0 ELSE 1 END, p.title`
)
.all() as PieceRow[];
return rows.map((row) => ({
id: row.id,
title: row.title,
summary: row.summary,
status: row.status,
durationSeconds: row.duration_seconds,
format: row.format,
category: row.category ?? 'Offen',
categoryColor: row.category_color ?? '#8b8f98',
topics: row.topics?.split('||') ?? [],
sourceCount: row.source_count
}));
}
export function getShow(showId?: string): PreviewShow {
const latest = showId ? null : listShows().find((show) => show.startsAtUtc !== null);
const show = getShowById(showId ?? latest?.id ?? '');
if (!show) throw new Error('No preview show found. Run npm run db:seed.');
const sections: PreviewSection[] = show.sections.map((section) => ({
id: section.id,
name: section.name,
category: section.category ?? 'Offen',
categoryColor: section.categoryColor ?? '#8b8f98',
durationSeconds: section.durationSeconds,
usages: section.usages.map((usage) => ({
id: usage.id,
title: usage.title,
durationSeconds: usage.durationSeconds,
status: usage.status,
intro: usage.intro,
moderation: usage.moderation,
transition: usage.transition,
isReserve: false
}))
}));
const reserveHost = sections[Math.min(1, sections.length - 1)];
if (reserveHost) {
reserveHost.usages.push(
...show.reserve.map((usage) => ({
id: usage.id,
title: usage.title,
durationSeconds: usage.durationSeconds,
status: usage.status,
intro: usage.intro,
moderation: usage.moderation,
transition: usage.transition,
isReserve: true
}))
);
}
return {
id: show.id,
title: show.title,
startsAtUtc: show.startsAtUtc ?? '',
startsAtBerlin: show.startsAtUtc
? new Intl.DateTimeFormat('de-DE', {
timeZone: 'Europe/Berlin',
weekday: 'short',
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit'
}).format(new Date(show.startsAtUtc))
: 'Termin offen',
twitchTitle: show.twitchTitle,
announcement: show.announcementText,
status: show.status,
sections,
totalDurationSeconds: show.totalDurationSeconds
};
}
export function getTaxonomy() {
const database = getDatabase();
return {
categories: database
.prepare('SELECT id, name, color FROM section_categories ORDER BY sort_order')
.all() as { id: string; name: string; color: string }[],
formats: database.prepare('SELECT id, name FROM formats ORDER BY name').all() as {
id: string;
name: string;
}[],
topics: database.prepare('SELECT id, name FROM topics ORDER BY name').all() as {
id: string;
name: string;
}[]
};
}