feat: integrate zitat-service.de API for DE/EN/ES quotes
- Add zitat-service.de as built-in multilingual fallback in goal API:
tries the user's preferred language (de/en/es) automatically before
falling back to ZenQuotes (EN) and then local curated quotes
- Parser now also handles {quote, authorName} response format from
zitat-service.de alongside all previously supported formats
- Preset source pills in settings: add Zitat-Service (DE), (EN), (ES)
(supports de, en, es — no fr/it available from that API)
- Remove Forismatic from presets (unreliable, often returns empty)
- Update hint text to reflect DE/EN/ES API availability vs FR/IT local
v1.84.1
This commit is contained in:
parent
2ec1278b19
commit
04b72a326a
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "my-weekly-todo-list",
|
"name": "my-weekly-todo-list",
|
||||||
"version": "1.84.0",
|
"version": "1.84.1",
|
||||||
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -111,14 +111,16 @@ export async function GET(req: Request) {
|
|||||||
// Quotable: {content, author}
|
// Quotable: {content, author}
|
||||||
if (data.content && data.author) return `${data.content} — ${data.author}`;
|
if (data.content && data.author) return `${data.content} — ${data.author}`;
|
||||||
// Forismatic: {quoteText, quoteAuthor}
|
// Forismatic: {quoteText, quoteAuthor}
|
||||||
if (data.quoteText) return data.quoteAuthor ? `${data.quoteText.trim()} — ${data.quoteAuthor.trim()}` : data.quoteText.trim();
|
if (data.quoteText) return data.quoteAuthor?.trim() ? `${data.quoteText.trim()} — ${data.quoteAuthor.trim()}` : data.quoteText.trim();
|
||||||
// Common: {text, author} or {quote, author}
|
// zitat-service.de: {quote, authorName}
|
||||||
|
if (data.quote && data.authorName) return `${data.quote} — ${data.authorName}`;
|
||||||
|
// Common: {text, author} or {quote, author} or {body, ...}
|
||||||
const text = data.text || data.quote || data.body || data.sentence;
|
const text = data.text || data.quote || data.body || data.sentence;
|
||||||
const author = data.author || data.by || data.from || data.speaker;
|
const author = data.author || data.authorName || data.by || data.from || data.speaker;
|
||||||
if (text) return author ? `${text} — ${author}` : text;
|
if (text) return author ? `${text} — ${author}` : text;
|
||||||
// Nested: {data: {quote, author}}
|
// Nested: {data: {...}}
|
||||||
if (data.data) return parseQuoteResponse(data.data);
|
if (data.data) return parseQuoteResponse(data.data);
|
||||||
// Nested: {slip: {advice}}
|
// Advice Slip: {slip: {advice}}
|
||||||
if (data.slip?.advice) return data.slip.advice;
|
if (data.slip?.advice) return data.slip.advice;
|
||||||
} catch { /* ignore */ }
|
} catch { /* ignore */ }
|
||||||
return null;
|
return null;
|
||||||
@ -139,7 +141,23 @@ export async function GET(req: Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZenQuotes as built-in English fallback
|
// Built-in multilingual fallbacks via zitat-service.de (de, en, es) + ZenQuotes (en)
|
||||||
|
const zitatLangMap: Record<string, string> = { de: 'de', en: 'en', es: 'es' };
|
||||||
|
const zitatLang = quoteLangs.find(l => zitatLangMap[l]);
|
||||||
|
if (zitatLang) {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`https://api.zitat-service.de/v1/quote?language=${zitatLangMap[zitatLang]}`, { signal: AbortSignal.timeout(4000) });
|
||||||
|
if (res.ok) {
|
||||||
|
const data = await res.json();
|
||||||
|
const parsed = parseQuoteResponse(data);
|
||||||
|
if (parsed) return NextResponse.json({ goal: parsed, isQuote: true });
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to fetch from zitat-service.de:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZenQuotes as English fallback
|
||||||
if (quoteLangs.includes('en')) {
|
if (quoteLangs.includes('en')) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('https://zenquotes.io/api/random', { signal: AbortSignal.timeout(3000) });
|
const res = await fetch('https://zenquotes.io/api/random', { signal: AbortSignal.timeout(3000) });
|
||||||
|
|||||||
@ -3782,8 +3782,10 @@ function SettingsSidebar({
|
|||||||
{ label: "ZenQuotes (EN)", url: "https://zenquotes.io/api/random" },
|
{ label: "ZenQuotes (EN)", url: "https://zenquotes.io/api/random" },
|
||||||
{ label: "Stoic Quotes (EN)", url: "https://stoic.tekloon.net/stoic-quote" },
|
{ label: "Stoic Quotes (EN)", url: "https://stoic.tekloon.net/stoic-quote" },
|
||||||
{ label: "Quotable (EN)", url: "https://api.quotable.io/quotes/random" },
|
{ label: "Quotable (EN)", url: "https://api.quotable.io/quotes/random" },
|
||||||
{ label: "Forismatic (EN)", url: "https://api.forismatic.com/api/1.0/?method=getQuote&format=json&lang=en" },
|
|
||||||
{ label: "Advice Slip (EN)", url: "https://api.adviceslip.com/advice" },
|
{ label: "Advice Slip (EN)", url: "https://api.adviceslip.com/advice" },
|
||||||
|
{ label: "Zitat-Service (DE)", url: "https://api.zitat-service.de/v1/quote?language=de" },
|
||||||
|
{ label: "Zitat-Service (EN)", url: "https://api.zitat-service.de/v1/quote?language=en" },
|
||||||
|
{ label: "Zitat-Service (ES)", url: "https://api.zitat-service.de/v1/quote?language=es" },
|
||||||
].map(({ label, url }) => {
|
].map(({ label, url }) => {
|
||||||
const current: string[] = profile.quoteSourceUrls || [];
|
const current: string[] = profile.quoteSourceUrls || [];
|
||||||
const already = current.includes(url);
|
const already = current.includes(url);
|
||||||
@ -3815,8 +3817,8 @@ function SettingsSidebar({
|
|||||||
</div>
|
</div>
|
||||||
<p style={{ fontSize: "0.72rem", color: "var(--weekly-text-light)", marginTop: "6px", fontStyle: "italic" }}>
|
<p style={{ fontSize: "0.72rem", color: "var(--weekly-text-light)", marginTop: "6px", fontStyle: "italic" }}>
|
||||||
{profile.language === "de"
|
{profile.language === "de"
|
||||||
? "Für DE, FR, IT, ES werden kuratierte lokale Zitate verwendet."
|
? "DE/EN/ES: auch über Zitat-Service API verfügbar. FR/IT: kuratierte lokale Sammlung."
|
||||||
: "For DE, FR, IT, ES, curated local quotes are used automatically."}
|
: "DE/EN/ES: also available via Zitat-Service API. FR/IT: curated local collection."}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user