438 lines
12 KiB
JavaScript
438 lines
12 KiB
JavaScript
import Database from 'better-sqlite3';
|
|
import { mkdirSync } from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { getPaths } from './config.mjs';
|
|
|
|
export function seed(databasePath = getPaths().database) {
|
|
mkdirSync(path.dirname(databasePath), { recursive: true });
|
|
const database = new Database(databasePath);
|
|
database.pragma('foreign_keys = ON');
|
|
|
|
const seedDatabase = database.transaction(() => {
|
|
const replace = (table, columns, rows) => {
|
|
const placeholders = columns.map(() => '?').join(', ');
|
|
const update = columns
|
|
.filter((column) => column !== 'id')
|
|
.map((column) => `${column} = excluded.${column}`)
|
|
.join(', ');
|
|
const statement = database.prepare(
|
|
`INSERT INTO ${table} (${columns.join(', ')}) VALUES (${placeholders})
|
|
ON CONFLICT(id) DO UPDATE SET ${update}`
|
|
);
|
|
for (const row of rows) statement.run(...row);
|
|
};
|
|
|
|
replace(
|
|
'section_categories',
|
|
['id', 'name', 'color', 'sort_order'],
|
|
[
|
|
['cat-jc', 'JC', '#67DDE8', 0],
|
|
['cat-reaction', 'Reaction', '#E7B957', 1],
|
|
['cat-game', 'Spiel', '#9B8AFB', 2]
|
|
]
|
|
);
|
|
replace(
|
|
'formats',
|
|
['id', 'name'],
|
|
[
|
|
['format-find', 'Fundstück'],
|
|
['format-talk', 'Gespräch'],
|
|
['format-quiz', 'Quiz']
|
|
]
|
|
);
|
|
replace(
|
|
'topics',
|
|
['id', 'name'],
|
|
[
|
|
['topic-gaming', 'Gaming'],
|
|
['topic-film', 'Film & Serien'],
|
|
['topic-internet', 'Netzkultur']
|
|
]
|
|
);
|
|
|
|
const timestamp = '2026-10-21T10:00:00.000Z';
|
|
replace(
|
|
'pieces',
|
|
[
|
|
'id',
|
|
'title',
|
|
'summary',
|
|
'format_id',
|
|
'status',
|
|
'duration_seconds',
|
|
'intro',
|
|
'moderation_notes',
|
|
'transition_text',
|
|
'presentation_text',
|
|
'created_at_utc',
|
|
'updated_at_utc'
|
|
],
|
|
[
|
|
[
|
|
'piece-console',
|
|
'Die kleine Konsole mit dem großen Dreh',
|
|
'Ein ungewöhnliches Handheld-Konzept sorgt für Diskussionsstoff.',
|
|
'format-find',
|
|
'ready',
|
|
480,
|
|
'Eine Kurbel, ein gelber Knopf und sehr viel Charme: Was macht kleine Hardware spannend?',
|
|
'Erst Formfaktor zeigen, dann über bewusst gesetzte Grenzen sprechen.',
|
|
'Von der kleinen Konsole geht es zur ganz großen Leinwand.',
|
|
'Weniger Leistung, mehr Idee.',
|
|
timestamp,
|
|
timestamp
|
|
],
|
|
[
|
|
'piece-effects',
|
|
'Warum praktische Effekte wieder auffallen',
|
|
'Neue Produktionen mischen Miniaturen, Masken und digitale Nacharbeit.',
|
|
'format-talk',
|
|
'ready',
|
|
720,
|
|
'Man sieht manchmal gerade deshalb weniger Trick, weil wieder mehr vor der Kamera passiert.',
|
|
'Beispiele vergleichen, nicht analog gegen digital ausspielen.',
|
|
'Nach so viel Handarbeit wird es spielerisch.',
|
|
'Wenn das Licht wirklich auf ein Modell fällt.',
|
|
timestamp,
|
|
timestamp
|
|
],
|
|
[
|
|
'piece-quiz',
|
|
'Drei Sounds, ein Spiel',
|
|
'Kurzes Audioquiz mit bekannten Inventar- und Menüklängen.',
|
|
'format-quiz',
|
|
'preparing',
|
|
600,
|
|
'Augen zu: Erkennt ihr das Spiel nur an seinem Inventar?',
|
|
'Drei Runden, Auflösung jeweils erst nach den Tipps.',
|
|
'Damit sind die Ohren warm für unser erstes Spiel.',
|
|
'Welches Spiel steckt hinter diesem Klang?',
|
|
timestamp,
|
|
timestamp
|
|
],
|
|
[
|
|
'piece-pixels',
|
|
'Pixelart, die nicht nostalgisch sein will',
|
|
'Wie moderne Spiele Pixel als Material statt als Rückblick einsetzen.',
|
|
'format-find',
|
|
'ready',
|
|
540,
|
|
'Pixel sind längst keine technische Notlösung mehr.',
|
|
'Großaufnahmen vorbereiten, drei Stilmittel benennen.',
|
|
'Genug Theorie, jetzt spielen wir selbst.',
|
|
'Pixel als bewusste Entscheidung.',
|
|
timestamp,
|
|
timestamp
|
|
],
|
|
[
|
|
'piece-inbox-link',
|
|
'Indie-Showcase nachhören',
|
|
'Ein Fundstück aus dem letzten Showcase, das noch eingeordnet werden muss.',
|
|
'format-find',
|
|
'inbox',
|
|
0,
|
|
'',
|
|
'',
|
|
'',
|
|
'',
|
|
timestamp,
|
|
timestamp
|
|
],
|
|
[
|
|
'piece-archive-demo',
|
|
'Controller mit eingebautem Bildschirm',
|
|
'Ein früheres Fundstück, das bewusst im Archiv liegt.',
|
|
'format-find',
|
|
'archived',
|
|
300,
|
|
'',
|
|
'',
|
|
'',
|
|
'',
|
|
timestamp,
|
|
timestamp
|
|
]
|
|
]
|
|
);
|
|
database
|
|
.prepare('UPDATE pieces SET research_text = ? WHERE id = ?')
|
|
.run(
|
|
'## Recherche\n\n- Herstellerangaben gegen unabhängige Tests prüfen\n- Fokus auf Bedienidee statt Leistungsdaten',
|
|
'piece-console'
|
|
);
|
|
database
|
|
.prepare('UPDATE pieces SET presentation_text = ? WHERE id = ?')
|
|
.run(
|
|
'## Weniger Leistung, mehr Idee\n\nDie Kurbel ist Teil des Spiels, nicht nur Dekoration.',
|
|
'piece-console'
|
|
);
|
|
|
|
database.prepare('DELETE FROM piece_topics WHERE piece_id LIKE ?').run('piece-%');
|
|
const addTopic = database.prepare(
|
|
'INSERT INTO piece_topics (piece_id, topic_id) VALUES (?, ?)'
|
|
);
|
|
for (const values of [
|
|
['piece-console', 'topic-gaming'],
|
|
['piece-effects', 'topic-film'],
|
|
['piece-quiz', 'topic-gaming'],
|
|
['piece-pixels', 'topic-gaming'],
|
|
['piece-pixels', 'topic-internet'],
|
|
['piece-inbox-link', 'topic-gaming'],
|
|
['piece-archive-demo', 'topic-gaming']
|
|
])
|
|
addTopic.run(...values);
|
|
|
|
database.prepare('DELETE FROM piece_category_suggestions WHERE piece_id LIKE ?').run('piece-%');
|
|
const addCategory = database.prepare(
|
|
'INSERT INTO piece_category_suggestions (piece_id, category_id) VALUES (?, ?)'
|
|
);
|
|
for (const values of [
|
|
['piece-console', 'cat-jc'],
|
|
['piece-effects', 'cat-reaction'],
|
|
['piece-quiz', 'cat-jc'],
|
|
['piece-pixels', 'cat-reaction'],
|
|
['piece-inbox-link', 'cat-reaction'],
|
|
['piece-archive-demo', 'cat-reaction']
|
|
])
|
|
addCategory.run(...values);
|
|
|
|
replace(
|
|
'piece_sources',
|
|
['id', 'piece_id', 'label', 'url', 'timecode_seconds', 'position'],
|
|
[
|
|
[
|
|
'source-console',
|
|
'piece-console',
|
|
'Herstellerseite',
|
|
'https://example.com/console',
|
|
null,
|
|
0
|
|
],
|
|
[
|
|
'source-effects',
|
|
'piece-effects',
|
|
'Werkstattbericht',
|
|
'https://example.com/effects',
|
|
95,
|
|
0
|
|
],
|
|
['source-pixels', 'piece-pixels', 'Galerie', 'https://example.com/pixels', null, 0],
|
|
[
|
|
'source-inbox-showcase',
|
|
'piece-inbox-link',
|
|
'Showcase-Aufzeichnung',
|
|
'https://example.com/showcase',
|
|
120,
|
|
0
|
|
]
|
|
]
|
|
);
|
|
|
|
replace(
|
|
'show_templates',
|
|
['id', 'name', 'description'],
|
|
[
|
|
['template-default', 'Standardablauf', 'Start, zwei JC-Blöcke und zwei Spiele.'],
|
|
['template-games', 'Spieleabend', 'Ein ruhiger Einstieg und drei flexible Spieleblöcke.']
|
|
]
|
|
);
|
|
replace(
|
|
'show_template_sections',
|
|
['id', 'template_id', 'name', 'category_id', 'position', 'explicit_duration_seconds'],
|
|
[
|
|
['template-default-start', 'template-default', 'Start', 'cat-jc', 0, 300],
|
|
[
|
|
'template-default-jc-reaction',
|
|
'template-default',
|
|
'JC / Reaction',
|
|
'cat-reaction',
|
|
1,
|
|
null
|
|
],
|
|
['template-default-game-1', 'template-default', 'Spiel 1', 'cat-game', 2, 3600],
|
|
['template-default-jc', 'template-default', 'JC', 'cat-jc', 3, null],
|
|
['template-default-game-2', 'template-default', 'Spiel 2', 'cat-game', 4, 3600],
|
|
['template-games-start', 'template-games', 'Start', 'cat-jc', 0, 300],
|
|
['template-games-game-1', 'template-games', 'Spiel 1', 'cat-game', 1, 2700],
|
|
['template-games-break', 'template-games', 'Pause & Chat', 'cat-jc', 2, 600],
|
|
['template-games-game-2', 'template-games', 'Spiel 2', 'cat-game', 3, 2700],
|
|
['template-games-game-3', 'template-games', 'Spiel 3', 'cat-game', 4, 2700]
|
|
]
|
|
);
|
|
|
|
replace(
|
|
'shows',
|
|
[
|
|
'id',
|
|
'title',
|
|
'starts_at_utc',
|
|
'twitch_title',
|
|
'announcement_text',
|
|
'status',
|
|
'revision',
|
|
'created_at_utc',
|
|
'updated_at_utc'
|
|
],
|
|
[
|
|
[
|
|
'show-october',
|
|
'Herbstsendung: Kleine Welten',
|
|
'2026-10-23T18:00:00.000Z',
|
|
'Kleine Welten, große Ideen | heinzlive',
|
|
'Heute schauen wir auf Hardware mit Kurbel, handgemachte Filmtricks und Pixel mit Haltung.',
|
|
'ready',
|
|
1,
|
|
timestamp,
|
|
timestamp
|
|
],
|
|
[
|
|
'show-games-evening',
|
|
'Spieleabend: Kurbeln & Pixel',
|
|
'2026-10-16T18:00:00.000Z',
|
|
'Kurbeln, Pixel und ein langer Spieleabend | heinzlive',
|
|
'Heute spielen wir uns von ungewöhnlicher Hardware bis zu moderner Pixelart.',
|
|
'draft',
|
|
1,
|
|
timestamp,
|
|
timestamp
|
|
]
|
|
]
|
|
);
|
|
|
|
replace(
|
|
'show_sections',
|
|
[
|
|
'id',
|
|
'show_id',
|
|
'name',
|
|
'category_id',
|
|
'position',
|
|
'explicit_duration_seconds',
|
|
'is_reserve_bank'
|
|
],
|
|
[
|
|
['section-start', 'show-october', 'Ankommen & Warmwerden', 'cat-jc', 0, 300, 0],
|
|
['section-stories', 'show-october', 'Kleine Welten', 'cat-reaction', 1, null, 0],
|
|
['section-game', 'show-october', 'Spiel 1', 'cat-game', 2, 3600, 0],
|
|
['reserve-bank-show-october', 'show-october', 'Reservebank', null, 3, null, 1],
|
|
['games-start', 'show-games-evening', 'Start', 'cat-jc', 0, 300, 0],
|
|
['games-first', 'show-games-evening', 'Spiel 1', 'cat-game', 1, 2700, 0],
|
|
['games-chat', 'show-games-evening', 'Pause & Chat', 'cat-jc', 2, 600, 0],
|
|
['games-second', 'show-games-evening', 'Spiel 2', 'cat-game', 3, 2700, 0],
|
|
['reserve-bank-show-games-evening', 'show-games-evening', 'Reservebank', null, 4, null, 1]
|
|
]
|
|
);
|
|
|
|
replace(
|
|
'piece_usages',
|
|
[
|
|
'id',
|
|
'show_section_id',
|
|
'original_piece_id',
|
|
'position',
|
|
'status',
|
|
'duration_seconds',
|
|
'title_snapshot',
|
|
'intro_snapshot',
|
|
'research_snapshot',
|
|
'moderation_snapshot',
|
|
'transition_snapshot',
|
|
'presentation_snapshot',
|
|
'own_notes',
|
|
'is_reserve'
|
|
],
|
|
[
|
|
[
|
|
'usage-console',
|
|
'section-stories',
|
|
'piece-console',
|
|
0,
|
|
'open',
|
|
480,
|
|
'Die kleine Konsole mit dem großen Dreh',
|
|
'Eine Kurbel, ein gelber Knopf und sehr viel Charme: Was macht kleine Hardware spannend?',
|
|
'## Recherche\n\n- Herstellerangaben gegen unabhängige Tests prüfen\n- Fokus auf Bedienidee statt Leistungsdaten',
|
|
'Erst Formfaktor zeigen, dann über bewusst gesetzte Grenzen sprechen.',
|
|
'Von der kleinen Konsole geht es zur ganz großen Leinwand.',
|
|
'Weniger Leistung, mehr Idee.',
|
|
'',
|
|
0
|
|
],
|
|
[
|
|
'usage-effects',
|
|
'section-stories',
|
|
'piece-effects',
|
|
1,
|
|
'open',
|
|
720,
|
|
'Warum praktische Effekte wieder auffallen',
|
|
'Man sieht manchmal gerade deshalb weniger Trick, weil wieder mehr vor der Kamera passiert.',
|
|
'',
|
|
'Beispiele vergleichen, nicht analog gegen digital ausspielen.',
|
|
'Nach so viel Handarbeit wird es spielerisch.',
|
|
'Wenn das Licht wirklich auf ein Modell fällt.',
|
|
'',
|
|
0
|
|
],
|
|
[
|
|
'usage-reserve',
|
|
'reserve-bank-show-october',
|
|
'piece-pixels',
|
|
0,
|
|
'open',
|
|
540,
|
|
'Pixelart, die nicht nostalgisch sein will',
|
|
'Pixel sind längst keine technische Notlösung mehr.',
|
|
'',
|
|
'Großaufnahmen vorbereiten, drei Stilmittel benennen.',
|
|
'Genug Theorie, jetzt spielen wir selbst.',
|
|
'Pixel als bewusste Entscheidung.',
|
|
'Ersatz, falls ein Spiel technisch ausfällt.',
|
|
1
|
|
],
|
|
[
|
|
'usage-games-console',
|
|
'games-first',
|
|
'piece-console',
|
|
0,
|
|
'open',
|
|
480,
|
|
'Die kleine Konsole mit dem großen Dreh',
|
|
'Wir beginnen mit Hardware, die ihr Spielprinzip gleich mitbringt.',
|
|
'Kurbelmechanik und verfügbare Spiele prüfen.',
|
|
'Konsole zeigen und Publikum nach Lieblingsmechaniken fragen.',
|
|
'Danach wechseln wir von Mechanik zu Grafik.',
|
|
'Eine Kurbel verändert, wie wir spielen.',
|
|
'Controller vor Sendungsbeginn laden.',
|
|
0
|
|
],
|
|
[
|
|
'usage-games-pixels',
|
|
'games-second',
|
|
'piece-pixels',
|
|
0,
|
|
'open',
|
|
540,
|
|
'Pixelart, die nicht nostalgisch sein will',
|
|
'Unser zweites Spiel nutzt Pixel nicht als Rückblick.',
|
|
'Drei aktuelle Beispiele vergleichen.',
|
|
'Auf Licht, Bewegung und Materialwirkung achten.',
|
|
'Zum Schluss sammeln wir eure Empfehlungen.',
|
|
'Pixel als bewusste Entscheidung.',
|
|
'',
|
|
0
|
|
]
|
|
]
|
|
);
|
|
});
|
|
|
|
seedDatabase();
|
|
database.close();
|
|
console.log(`Example data ready: ${databasePath}`);
|
|
}
|
|
|
|
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
seed();
|
|
}
|