feat(zitare): add @zitare/content package for shared quotes

- Create new @zitare/content package with 50 German quotes
- Include 10 categories: motivation, weisheit, liebe, leben, erfolg,
  glueck, freundschaft, mut, hoffnung, natur
- Add utility functions: getRandomQuote, getDailyQuote, searchQuotes,
  getQuotesByCategory, formatQuote, etc.
- Migrate matrix-zitare-bot to use the shared package
- Remove hardcoded quotes from bot configuration
This commit is contained in:
Till-JS 2026-02-13 12:30:41 +01:00
parent 9924eb545a
commit 74c1cfed4f
13 changed files with 1069 additions and 660 deletions

View file

@ -0,0 +1,24 @@
{
"name": "@zitare/content",
"version": "1.0.0",
"description": "Static quote content for Zitare",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
},
"scripts": {
"build": "tsup",
"type-check": "tsc --noEmit"
},
"devDependencies": {
"tsup": "^8.0.0",
"typescript": "^5.3.0"
}
}

View file

@ -0,0 +1,47 @@
/**
* Quote categories
*/
export const CATEGORIES = [
'motivation',
'weisheit',
'liebe',
'leben',
'erfolg',
'glueck',
'freundschaft',
'mut',
'hoffnung',
'natur',
] as const;
export type Category = (typeof CATEGORIES)[number];
/**
* German labels for categories
*/
export const CATEGORY_LABELS: Record<Category, string> = {
motivation: 'Motivation',
weisheit: 'Weisheit',
liebe: 'Liebe',
leben: 'Leben',
erfolg: 'Erfolg',
glueck: 'Glueck',
freundschaft: 'Freundschaft',
mut: 'Mut',
hoffnung: 'Hoffnung',
natur: 'Natur',
};
/**
* Get label for a category
*/
export function getCategoryLabel(category: Category): string {
return CATEGORY_LABELS[category];
}
/**
* Check if a string is a valid category
*/
export function isValidCategory(value: string): value is Category {
return CATEGORIES.includes(value as Category);
}

View file

@ -0,0 +1,25 @@
// Types
export type { Quote } from './types';
export type { Category } from './categories';
// Data
export { QUOTES, QUOTE_COUNT } from './quotes';
export { CATEGORIES, CATEGORY_LABELS } from './categories';
// Utilities
export {
getRandomQuote,
getDailyQuote,
getQuotesByCategory,
getRandomQuoteByCategory,
searchQuotes,
getQuoteById,
getQuoteByIndex,
getAllCategories,
getCategoryByName,
formatQuote,
formatQuoteWithNumber,
getTotalCount,
} from './utils';
export { getCategoryLabel, isValidCategory } from './categories';

View file

@ -0,0 +1,375 @@
import type { Quote } from './types';
/**
* German inspirational quotes collection
*/
export const QUOTES: Quote[] = [
// ============================================
// MOTIVATION
// ============================================
{
id: 'mot-1',
text: 'Der einzige Weg, grossartige Arbeit zu leisten, ist zu lieben, was man tut.',
author: 'Steve Jobs',
category: 'motivation',
},
{
id: 'mot-2',
text: 'Erfolg ist nicht endgueltig, Misserfolg ist nicht fatal: Was zaehlt, ist der Mut weiterzumachen.',
author: 'Winston Churchill',
category: 'motivation',
},
{
id: 'mot-3',
text: 'Die Zukunft gehoert denen, die an die Schoenheit ihrer Traeume glauben.',
author: 'Eleanor Roosevelt',
category: 'motivation',
},
{
id: 'mot-4',
text: 'Es ist nie zu spaet, das zu werden, was man haette sein koennen.',
author: 'George Eliot',
category: 'motivation',
},
{
id: 'mot-5',
text: 'Gib jedem Tag die Chance, der schoenste deines Lebens zu werden.',
author: 'Mark Twain',
category: 'motivation',
},
{
id: 'mot-6',
text: 'Der Anfang ist die Haelfte des Ganzen.',
author: 'Aristoteles',
category: 'motivation',
},
{
id: 'mot-7',
text: 'Tue heute etwas, wofuer dein zukuenftiges Ich dir danken wird.',
author: 'Sean Patrick Flanery',
category: 'motivation',
},
{
id: 'mot-8',
text: 'Der beste Zeitpunkt einen Baum zu pflanzen war vor 20 Jahren. Der zweitbeste ist jetzt.',
author: 'Chinesisches Sprichwort',
category: 'motivation',
},
// ============================================
// WEISHEIT
// ============================================
{
id: 'weis-1',
text: 'Der Weg ist das Ziel.',
author: 'Konfuzius',
category: 'weisheit',
},
{
id: 'weis-2',
text: 'Wer kaempft, kann verlieren. Wer nicht kaempft, hat schon verloren.',
author: 'Bertolt Brecht',
category: 'weisheit',
},
{
id: 'weis-3',
text: 'Man sieht nur mit dem Herzen gut. Das Wesentliche ist fuer die Augen unsichtbar.',
author: 'Antoine de Saint-Exupery',
category: 'weisheit',
},
{
id: 'weis-4',
text: 'Nicht weil es schwer ist, wagen wir es nicht, sondern weil wir es nicht wagen, ist es schwer.',
author: 'Seneca',
category: 'weisheit',
},
{
id: 'weis-5',
text: 'Wissen ist Macht.',
author: 'Francis Bacon',
category: 'weisheit',
},
{
id: 'weis-6',
text: 'Ich weiss, dass ich nichts weiss.',
author: 'Sokrates',
category: 'weisheit',
},
{
id: 'weis-7',
text: 'Die einzige Konstante im Leben ist die Veraenderung.',
author: 'Heraklit',
category: 'weisheit',
},
{
id: 'weis-8',
text: 'Handle nur nach derjenigen Maxime, durch die du zugleich wollen kannst, dass sie ein allgemeines Gesetz werde.',
author: 'Immanuel Kant',
category: 'weisheit',
},
// ============================================
// LIEBE
// ============================================
{
id: 'liebe-1',
text: 'Wo Liebe ist, da ist auch Leben.',
author: 'Mahatma Gandhi',
category: 'liebe',
},
{
id: 'liebe-2',
text: 'Die Liebe allein versteht das Geheimnis, andere zu beschenken und dabei selbst reich zu werden.',
author: 'Clemens Brentano',
category: 'liebe',
},
{
id: 'liebe-3',
text: 'Es gibt nur ein Glueck in diesem Leben: zu lieben und geliebt zu werden.',
author: 'George Sand',
category: 'liebe',
},
{
id: 'liebe-4',
text: 'Liebe ist das einzige, was waechst, wenn wir es verschwenden.',
author: 'Ricarda Huch',
category: 'liebe',
},
{
id: 'liebe-5',
text: 'Die groesste Sache der Welt ist es, zu wissen, wie man sich selbst gehoert.',
author: 'Michel de Montaigne',
category: 'liebe',
},
// ============================================
// LEBEN
// ============================================
{
id: 'leben-1',
text: 'Das Leben ist wie Fahrrad fahren. Um die Balance zu halten, musst du in Bewegung bleiben.',
author: 'Albert Einstein',
category: 'leben',
},
{
id: 'leben-2',
text: 'Leben ist das, was passiert, waehrend du damit beschaeftigt bist, andere Plaene zu machen.',
author: 'John Lennon',
category: 'leben',
},
{
id: 'leben-3',
text: 'Das Leben ist zu kurz fuer spaeter.',
author: 'Alexandra Reinwarth',
category: 'leben',
},
{
id: 'leben-4',
text: 'Lebe jeden Tag, als waere es dein letzter.',
author: 'Marcus Aurelius',
category: 'leben',
},
{
id: 'leben-5',
text: 'Das Leben ist kein Problem, das geloest werden muss, sondern eine Wirklichkeit, die erfahren werden will.',
author: 'Soeren Kierkegaard',
category: 'leben',
},
{
id: 'leben-6',
text: 'Wer sein Leben so einrichtet, dass er niemals auf die Nase fallen kann, der kann nur auf dem Bauch kriechen.',
author: 'Heinz Riesenhuber',
category: 'leben',
},
// ============================================
// ERFOLG
// ============================================
{
id: 'erfolg-1',
text: 'Erfolg besteht darin, dass man genau die Faehigkeiten hat, die im Moment gefragt sind.',
author: 'Henry Ford',
category: 'erfolg',
},
{
id: 'erfolg-2',
text: 'Der Preis des Erfolges ist Hingabe, harte Arbeit und unablaessiger Einsatz.',
author: 'Frank Lloyd Wright',
category: 'erfolg',
},
{
id: 'erfolg-3',
text: 'Ich habe nicht versagt. Ich habe nur 10.000 Wege gefunden, die nicht funktionieren.',
author: 'Thomas Edison',
category: 'erfolg',
},
{
id: 'erfolg-4',
text: 'Der Erfolg ist nicht das Endergebnis, das Scheitern ist nicht toedlich: Was zaehlt, ist der Mut, weiterzumachen.',
author: 'Winston Churchill',
category: 'erfolg',
},
{
id: 'erfolg-5',
text: 'Erfolg hat drei Buchstaben: TUN.',
author: 'Johann Wolfgang von Goethe',
category: 'erfolg',
},
// ============================================
// GLUECK
// ============================================
{
id: 'glueck-1',
text: 'Glueck ist das Einzige, das sich verdoppelt, wenn man es teilt.',
author: 'Albert Schweitzer',
category: 'glueck',
},
{
id: 'glueck-2',
text: 'Glueck ist kein Ziel, sondern ein Weg.',
author: 'Buddha',
category: 'glueck',
},
{
id: 'glueck-3',
text: 'Nicht die Gluecklichen sind dankbar. Es sind die Dankbaren, die gluecklich sind.',
author: 'Francis Bacon',
category: 'glueck',
},
{
id: 'glueck-4',
text: 'Das Vergleichen ist das Ende des Gluecks und der Anfang der Unzufriedenheit.',
author: 'Soeren Kierkegaard',
category: 'glueck',
},
{
id: 'glueck-5',
text: 'Glueck entsteht oft durch Aufmerksamkeit in kleinen Dingen, Unglueck oft durch Vernachlaessigung kleiner Dinge.',
author: 'Wilhelm Busch',
category: 'glueck',
},
// ============================================
// FREUNDSCHAFT
// ============================================
{
id: 'freund-1',
text: 'Ein wahrer Freund ist jemand, der die Melodie deines Herzens kennt und sie dir vorsingt, wenn du sie vergessen hast.',
author: 'Albert Einstein',
category: 'freundschaft',
},
{
id: 'freund-2',
text: 'Freundschaft ist eine Seele in zwei Koerpern.',
author: 'Aristoteles',
category: 'freundschaft',
},
{
id: 'freund-3',
text: 'Ein Freund ist ein Mensch, vor dem man laut denken kann.',
author: 'Ralph Waldo Emerson',
category: 'freundschaft',
},
{
id: 'freund-4',
text: 'Die Freundschaft gehoert zum Notwendigsten in unserem Leben.',
author: 'Aristoteles',
category: 'freundschaft',
},
// ============================================
// MUT
// ============================================
{
id: 'mut-1',
text: 'Mut steht am Anfang des Handelns, Glueck am Ende.',
author: 'Demokrit',
category: 'mut',
},
{
id: 'mut-2',
text: 'Wer wagt, gewinnt.',
author: 'Deutsches Sprichwort',
category: 'mut',
},
{
id: 'mut-3',
text: 'Der Mutige hat nicht weniger Angst, er handelt trotzdem.',
author: 'Mark Twain',
category: 'mut',
},
{
id: 'mut-4',
text: 'Mut ist nicht die Abwesenheit von Angst, sondern die Erkenntnis, dass etwas anderes wichtiger ist als Angst.',
author: 'Ambrose Redmoon',
category: 'mut',
},
{
id: 'mut-5',
text: 'Inmitten der Schwierigkeit liegt die Moeglichkeit.',
author: 'Albert Einstein',
category: 'mut',
},
// ============================================
// HOFFNUNG
// ============================================
{
id: 'hoff-1',
text: 'Hoffnung ist ein Vogel, der singt, wenn die Nacht noch dunkel ist.',
author: 'Rabindranath Tagore',
category: 'hoffnung',
},
{
id: 'hoff-2',
text: 'Nach jedem Sturm scheint auch wieder die Sonne.',
author: 'Deutsches Sprichwort',
category: 'hoffnung',
},
{
id: 'hoff-3',
text: 'Auch aus Steinen, die einem in den Weg gelegt werden, kann man Schoenes bauen.',
author: 'Johann Wolfgang von Goethe',
category: 'hoffnung',
},
{
id: 'hoff-4',
text: 'Das Licht am Ende des Tunnels ist kein Zug.',
author: 'Deutsches Sprichwort',
category: 'hoffnung',
},
// ============================================
// NATUR
// ============================================
{
id: 'natur-1',
text: 'In der Natur ist nichts isoliert; alles haengt mit allem zusammen.',
author: 'Johann Wolfgang von Goethe',
category: 'natur',
},
{
id: 'natur-2',
text: 'Schau tief in die Natur, und dann wirst du alles besser verstehen.',
author: 'Albert Einstein',
category: 'natur',
},
{
id: 'natur-3',
text: 'Die Natur macht keine Spruenge.',
author: 'Carl von Linne',
category: 'natur',
},
{
id: 'natur-4',
text: 'Vergiss nicht, dass die Erde sich freut, deine nackten Fuesse zu fuehlen, und die Winde sich danach sehnen, mit deinem Haar zu spielen.',
author: 'Khalil Gibran',
category: 'natur',
},
];
/**
* Total number of quotes
*/
export const QUOTE_COUNT = QUOTES.length;

View file

@ -0,0 +1,15 @@
import type { Category } from './categories';
/**
* A quote with author and category
*/
export interface Quote {
/** Unique identifier (e.g., 'mot-1', 'weis-2') */
id: string;
/** The quote text in German */
text: string;
/** Author name */
author: string;
/** Category for filtering */
category: Category;
}

View file

@ -0,0 +1,133 @@
import { QUOTES } from './quotes';
import { CATEGORIES, CATEGORY_LABELS, type Category } from './categories';
import type { Quote } from './types';
/**
* Get a random quote
*/
export function getRandomQuote(): Quote {
const index = Math.floor(Math.random() * QUOTES.length);
return QUOTES[index];
}
/**
* Get deterministic daily quote based on date
*/
export function getDailyQuote(date: Date = new Date()): Quote {
const dateStr = date.toISOString().split('T')[0];
const hash = hashString(dateStr);
const index = Math.abs(hash) % QUOTES.length;
return QUOTES[index];
}
/**
* Get quotes by category
*/
export function getQuotesByCategory(category: Category): Quote[] {
return QUOTES.filter((q) => q.category === category);
}
/**
* Get a random quote from a specific category
*/
export function getRandomQuoteByCategory(category: Category): Quote | null {
const quotes = getQuotesByCategory(category);
if (quotes.length === 0) return null;
const index = Math.floor(Math.random() * quotes.length);
return quotes[index];
}
/**
* Search quotes by text or author
*/
export function searchQuotes(searchText: string): Quote[] {
const lowerSearch = searchText.toLowerCase();
return QUOTES.filter(
(q) =>
q.text.toLowerCase().includes(lowerSearch) || q.author.toLowerCase().includes(lowerSearch)
);
}
/**
* Get a quote by ID
*/
export function getQuoteById(id: string): Quote | undefined {
return QUOTES.find((q) => q.id === id);
}
/**
* Get quote by index (1-based)
*/
export function getQuoteByIndex(index: number): Quote | null {
if (index < 1 || index > QUOTES.length) return null;
return QUOTES[index - 1];
}
/**
* Get all categories with counts
*/
export function getAllCategories(): { category: Category; label: string; count: number }[] {
return CATEGORIES.map((category) => ({
category,
label: CATEGORY_LABELS[category],
count: QUOTES.filter((q) => q.category === category).length,
}));
}
/**
* Find category by name (partial match)
*/
export function getCategoryByName(name: string): Category | null {
const lowerName = name.toLowerCase();
// Exact match first
if (CATEGORIES.includes(lowerName as Category)) {
return lowerName as Category;
}
// Partial match
for (const category of CATEGORIES) {
if (
category.startsWith(lowerName) ||
CATEGORY_LABELS[category].toLowerCase().startsWith(lowerName)
) {
return category;
}
}
return null;
}
/**
* Format a quote for display
*/
export function formatQuote(quote: Quote): string {
const categoryLabel = CATEGORY_LABELS[quote.category];
return `"${quote.text}"\n\n— *${quote.author}*\n\n[${categoryLabel}]`;
}
/**
* Format a quote with number
*/
export function formatQuoteWithNumber(quote: Quote, number: number): string {
const categoryLabel = CATEGORY_LABELS[quote.category];
return `**#${number}**\n"${quote.text}"\n\n— *${quote.author}* [${categoryLabel}]`;
}
/**
* Get total quote count
*/
export function getTotalCount(): number {
return QUOTES.length;
}
// Helper function
function hashString(str: string): number {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash;
}
return hash;
}

View file

@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"declaration": true,
"declarationMap": true,
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

View file

@ -0,0 +1,9 @@
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
clean: true,
sourcemap: true,
});

736
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -25,6 +25,7 @@
"dependencies": {
"@manacore/bot-services": "workspace:*",
"@manacore/matrix-bot-common": "workspace:*",
"@zitare/content": "workspace:*",
"@nestjs/common": "^10.4.15",
"@nestjs/config": "^3.3.0",
"@nestjs/core": "^10.4.15",

View file

@ -10,7 +10,8 @@ import {
import { QuotesService } from '../quotes/quotes.service';
import { ZitareService } from '../quotes/zitare.service';
import { SessionService, TranscriptionService, CreditService } from '@manacore/bot-services';
import { HELP_MESSAGE, Category } from '../config/configuration';
import { HELP_MESSAGE } from '../config/configuration';
import type { Category } from '@zitare/content';
@Injectable()
export class MatrixService extends BaseMatrixService {

View file

@ -18,10 +18,10 @@ export default () => ({
},
});
export const HELP_MESSAGE = `**Zitare Bot - Tagliche Inspiration**
export const HELP_MESSAGE = `**Zitare Bot - Taegliche Inspiration**
**Zitate:**
- \`!zitat\` - Zufalliges Zitat
- \`!zitat\` - Zufaelliges Zitat
- \`!heute\` - Zitat des Tages
- \`!suche [text]\` - Zitate suchen
- \`!kategorie [name]\` - Zitate nach Kategorie
@ -36,7 +36,7 @@ export const HELP_MESSAGE = `**Zitare Bot - Tagliche Inspiration**
**Listen:** (Login erforderlich)
- \`!listen\` - Alle Listen anzeigen
- \`!liste [name]\` - Neue Liste erstellen
- \`!addliste [nr] [zitat-nr]\` - Zitat zur Liste hinzufugen
- \`!addliste [nr] [zitat-nr]\` - Zitat zur Liste hinzufuegen
**Sonstiges:**
- \`!status\` - Bot-Status
@ -45,250 +45,11 @@ export const HELP_MESSAGE = `**Zitare Bot - Tagliche Inspiration**
**Sprachnotizen:**
Sende eine Sprachnotiz mit Befehlen wie "Zitat", "Motivation" oder einem Suchbegriff.
**Naturliche Sprache:**
- "zitat", "inspiration" -> Zufalliges Zitat
**Natuerliche Sprache:**
- "zitat", "inspiration" -> Zufaelliges Zitat
- "motiviere mich" -> Motivation-Zitat
- "guten morgen" -> Morgenzitat`;
// Quote categories
export const CATEGORIES = [
'motivation',
'weisheit',
'liebe',
'leben',
'erfolg',
'glueck',
'freundschaft',
'mut',
'hoffnung',
'natur',
] as const;
export type Category = (typeof CATEGORIES)[number];
// German inspirational quotes collection
export interface Quote {
id: string;
text: string;
author: string;
category: Category;
}
export const QUOTES: Quote[] = [
// Motivation
{
id: 'mot-1',
text: 'Der einzige Weg, grossartige Arbeit zu leisten, ist zu lieben, was man tut.',
author: 'Steve Jobs',
category: 'motivation',
},
{
id: 'mot-2',
text: 'Erfolg ist nicht endgultig, Misserfolg ist nicht fatal: Was zahlt, ist der Mut weiterzumachen.',
author: 'Winston Churchill',
category: 'motivation',
},
{
id: 'mot-3',
text: 'Die Zukunft gehort denen, die an die Schonheit ihrer Traume glauben.',
author: 'Eleanor Roosevelt',
category: 'motivation',
},
{
id: 'mot-4',
text: 'Es ist nie zu spat, das zu werden, was man hatte sein konnen.',
author: 'George Eliot',
category: 'motivation',
},
{
id: 'mot-5',
text: 'Gib jedem Tag die Chance, der schonste deines Lebens zu werden.',
author: 'Mark Twain',
category: 'motivation',
},
// Weisheit
{
id: 'weis-1',
text: 'Der Weg ist das Ziel.',
author: 'Konfuzius',
category: 'weisheit',
},
{
id: 'weis-2',
text: 'Wer kampft, kann verlieren. Wer nicht kampft, hat schon verloren.',
author: 'Bertolt Brecht',
category: 'weisheit',
},
{
id: 'weis-3',
text: 'Man sieht nur mit dem Herzen gut. Das Wesentliche ist fur die Augen unsichtbar.',
author: 'Antoine de Saint-Exupery',
category: 'weisheit',
},
{
id: 'weis-4',
text: 'Nicht weil es schwer ist, wagen wir es nicht, sondern weil wir es nicht wagen, ist es schwer.',
author: 'Seneca',
category: 'weisheit',
},
{
id: 'weis-5',
text: 'Wissen ist Macht.',
author: 'Francis Bacon',
category: 'weisheit',
},
// Liebe
{
id: 'liebe-1',
text: 'Wo Liebe ist, da ist auch Leben.',
author: 'Mahatma Gandhi',
category: 'liebe',
},
{
id: 'liebe-2',
text: 'Die Liebe allein versteht das Geheimnis, andere zu beschenken und dabei selbst reich zu werden.',
author: 'Clemens Brentano',
category: 'liebe',
},
{
id: 'liebe-3',
text: 'Es gibt nur ein Gluck in diesem Leben: zu lieben und geliebt zu werden.',
author: 'George Sand',
category: 'liebe',
},
// Leben
{
id: 'leben-1',
text: 'Das Leben ist wie Fahrrad fahren. Um die Balance zu halten, musst du in Bewegung bleiben.',
author: 'Albert Einstein',
category: 'leben',
},
{
id: 'leben-2',
text: 'Leben ist das, was passiert, wahrend du damit beschaftigt bist, andere Plane zu machen.',
author: 'John Lennon',
category: 'leben',
},
{
id: 'leben-3',
text: 'Das Leben ist zu kurz fur spater.',
author: 'Alexandra Reinwarth',
category: 'leben',
},
{
id: 'leben-4',
text: 'Lebe jeden Tag, als ware es dein letzter.',
author: 'Marcus Aurelius',
category: 'leben',
},
// Erfolg
{
id: 'erfolg-1',
text: 'Erfolg besteht darin, dass man genau die Fahigkeiten hat, die im Moment gefragt sind.',
author: 'Henry Ford',
category: 'erfolg',
},
{
id: 'erfolg-2',
text: 'Der Preis des Erfolges ist Hingabe, harte Arbeit und unablassiger Einsatz.',
author: 'Frank Lloyd Wright',
category: 'erfolg',
},
{
id: 'erfolg-3',
text: 'Ich habe nicht versagt. Ich habe nur 10.000 Wege gefunden, die nicht funktionieren.',
author: 'Thomas Edison',
category: 'erfolg',
},
// Glueck
{
id: 'glueck-1',
text: 'Gluck ist das Einzige, das sich verdoppelt, wenn man es teilt.',
author: 'Albert Schweitzer',
category: 'glueck',
},
{
id: 'glueck-2',
text: 'Gluck ist kein Ziel, sondern ein Weg.',
author: 'Buddha',
category: 'glueck',
},
{
id: 'glueck-3',
text: 'Nicht die Glucklichen sind dankbar. Es sind die Dankbaren, die glucklich sind.',
author: 'Francis Bacon',
category: 'glueck',
},
// Freundschaft
{
id: 'freund-1',
text: 'Ein wahrer Freund ist jemand, der die Melodie deines Herzens kennt und sie dir vorsingt, wenn du sie vergessen hast.',
author: 'Albert Einstein',
category: 'freundschaft',
},
{
id: 'freund-2',
text: 'Freundschaft ist eine Seele in zwei Korpern.',
author: 'Aristoteles',
category: 'freundschaft',
},
// Mut
{
id: 'mut-1',
text: 'Mut steht am Anfang des Handelns, Gluck am Ende.',
author: 'Demokrit',
category: 'mut',
},
{
id: 'mut-2',
text: 'Wer wagt, gewinnt.',
author: 'Deutsches Sprichwort',
category: 'mut',
},
{
id: 'mut-3',
text: 'Der Mutige hat nicht weniger Angst, er handelt trotzdem.',
author: 'Mark Twain',
category: 'mut',
},
// Hoffnung
{
id: 'hoff-1',
text: 'Hoffnung ist ein Vogel, der singt, wenn die Nacht noch dunkel ist.',
author: 'Rabindranath Tagore',
category: 'hoffnung',
},
{
id: 'hoff-2',
text: 'Nach jedem Sturm scheint auch wieder die Sonne.',
author: 'Deutsches Sprichwort',
category: 'hoffnung',
},
// Natur
{
id: 'natur-1',
text: 'In der Natur ist nichts isoliert; alles hangt mit allem zusammen.',
author: 'Johann Wolfgang von Goethe',
category: 'natur',
},
{
id: 'natur-2',
text: 'Schau tief in die Natur, und dann wirst du alles besser verstehen.',
author: 'Albert Einstein',
category: 'natur',
},
];
// Category labels in German
export const CATEGORY_LABELS: Record<Category, string> = {
motivation: 'Motivation',
weisheit: 'Weisheit',
liebe: 'Liebe',
leben: 'Leben',
erfolg: 'Erfolg',
glueck: 'Gluck',
freundschaft: 'Freundschaft',
mut: 'Mut',
hoffnung: 'Hoffnung',
natur: 'Natur',
};
// Re-export types and utilities from @zitare/content
export type { Quote, Category } from '@zitare/content';
export { CATEGORIES, CATEGORY_LABELS } from '@zitare/content';

View file

@ -1,5 +1,23 @@
import { Injectable, Logger } from '@nestjs/common';
import { QUOTES, Quote, Category, CATEGORIES, CATEGORY_LABELS } from '../config/configuration';
import {
type Quote,
type Category,
QUOTES,
CATEGORIES,
CATEGORY_LABELS,
getRandomQuote,
getDailyQuote,
getQuotesByCategory,
getRandomQuoteByCategory,
searchQuotes,
getQuoteById,
getQuoteByIndex,
getAllCategories,
getCategoryByName,
formatQuote,
formatQuoteWithNumber,
getTotalCount,
} from '@zitare/content';
@Injectable()
export class QuotesService {
@ -7,8 +25,7 @@ export class QuotesService {
private dailyQuoteCache: { date: string; quote: Quote } | null = null;
getRandomQuote(): Quote {
const index = Math.floor(Math.random() * QUOTES.length);
return QUOTES[index];
return getRandomQuote();
}
getDailyQuote(): Quote {
@ -19,95 +36,50 @@ export class QuotesService {
return this.dailyQuoteCache.quote;
}
// Generate deterministic quote based on date
const dateHash = this.hashDate(today);
const index = dateHash % QUOTES.length;
const quote = QUOTES[index];
const quote = getDailyQuote();
this.dailyQuoteCache = { date: today, quote };
this.logger.log(`Daily quote for ${today}: "${quote.text.substring(0, 30)}..."`);
return quote;
}
private hashDate(dateStr: string): number {
let hash = 0;
for (let i = 0; i < dateStr.length; i++) {
const char = dateStr.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash; // Convert to 32-bit integer
}
return Math.abs(hash);
}
getQuotesByCategory(category: Category): Quote[] {
return QUOTES.filter((q) => q.category === category);
return getQuotesByCategory(category);
}
getRandomQuoteByCategory(category: Category): Quote | null {
const quotes = this.getQuotesByCategory(category);
if (quotes.length === 0) return null;
const index = Math.floor(Math.random() * quotes.length);
return quotes[index];
return getRandomQuoteByCategory(category);
}
searchQuotes(searchText: string): Quote[] {
const lowerSearch = searchText.toLowerCase();
return QUOTES.filter(
(q) =>
q.text.toLowerCase().includes(lowerSearch) || q.author.toLowerCase().includes(lowerSearch)
);
return searchQuotes(searchText);
}
getQuoteById(id: string): Quote | undefined {
return QUOTES.find((q) => q.id === id);
return getQuoteById(id);
}
getQuoteByIndex(index: number): Quote | null {
if (index < 1 || index > QUOTES.length) return null;
return QUOTES[index - 1];
return getQuoteByIndex(index);
}
getAllCategories(): { category: Category; label: string; count: number }[] {
return CATEGORIES.map((category) => ({
category,
label: CATEGORY_LABELS[category],
count: QUOTES.filter((q) => q.category === category).length,
}));
return getAllCategories();
}
getCategoryByName(name: string): Category | null {
const lowerName = name.toLowerCase();
// Try exact match first
if (CATEGORIES.includes(lowerName as Category)) {
return lowerName as Category;
}
// Try partial match
for (const category of CATEGORIES) {
if (
category.startsWith(lowerName) ||
CATEGORY_LABELS[category].toLowerCase().startsWith(lowerName)
) {
return category;
}
}
return null;
return getCategoryByName(name);
}
getTotalCount(): number {
return QUOTES.length;
return getTotalCount();
}
formatQuote(quote: Quote): string {
const categoryLabel = CATEGORY_LABELS[quote.category];
return `"${quote.text}"\n\n— *${quote.author}*\n\n[${categoryLabel}]`;
return formatQuote(quote);
}
formatQuoteWithNumber(quote: Quote, number: number): string {
const categoryLabel = CATEGORY_LABELS[quote.category];
return `**#${number}**\n"${quote.text}"\n\n— *${quote.author}* [${categoryLabel}]`;
return formatQuoteWithNumber(quote, number);
}
}