better cards

This commit is contained in:
2026-02-10 02:34:25 -05:00
parent b63c62a732
commit 03df2b3a6c
24 changed files with 669 additions and 127 deletions

View File

@@ -6,11 +6,26 @@ type YoutubeApiVideo = {
id: string;
url: string;
title: string;
summary?: string;
publishedAt: string;
thumbnailUrl?: string;
views?: number;
};
function stripHtml(s: string) {
return (s || "")
.replace(/<[^>]+>/g, " ")
.replace(/\s+/g, " ")
.trim();
}
function truncate(s: string, n: number) {
const t = stripHtml(s);
if (!t) return "";
if (t.length <= n) return t;
return `${t.slice(0, Math.max(0, n - 1)).trimEnd()}`;
}
export async function fetchYoutubeViaRss(channelId: string, limit = 20): Promise<ContentItem[]> {
const feedUrl = `https://www.youtube.com/feeds/videos.xml?channel_id=${encodeURIComponent(channelId)}`;
const parser = new Parser();
@@ -32,11 +47,16 @@ export function normalizeYoutubeRssFeedItems(items: any[], limit: number): Conte
const url = it.link || "";
const id = (it.id || url).toString();
const publishedAt = (it.isoDate || it.pubDate || new Date(0).toISOString()).toString();
const summary = truncate(
(it.contentSnippet || it.summary || it.content || it["content:encoded"] || "").toString(),
240,
);
return {
id,
source: "youtube" as const,
url,
title: (it.title || "").toString(),
summary: summary || undefined,
publishedAt: new Date(publishedAt).toISOString(),
thumbnailUrl: (it.enclosure?.url || undefined) as string | undefined,
};
@@ -47,7 +67,12 @@ export function normalizeYoutubeRssFeedItems(items: any[], limit: number): Conte
export function normalizeYoutubeApiVideos(
items: Array<{
id: string;
snippet: { title: string; publishedAt: string; thumbnails?: Record<string, { url: string }> };
snippet: {
title: string;
description?: string;
publishedAt: string;
thumbnails?: Record<string, { url: string }>;
};
statistics?: { viewCount?: string };
}>,
): ContentItem[] {
@@ -55,6 +80,7 @@ export function normalizeYoutubeApiVideos(
id: v.id,
url: `https://www.youtube.com/watch?v=${encodeURIComponent(v.id)}`,
title: v.snippet.title,
summary: v.snippet.description ? truncate(v.snippet.description, 240) : undefined,
publishedAt: new Date(v.snippet.publishedAt).toISOString(),
thumbnailUrl: v.snippet.thumbnails?.high?.url || v.snippet.thumbnails?.default?.url,
views: v.statistics?.viewCount ? Number(v.statistics.viewCount) : undefined,
@@ -65,6 +91,7 @@ export function normalizeYoutubeApiVideos(
source: "youtube",
url: v.url,
title: v.title,
summary: v.summary,
publishedAt: v.publishedAt,
thumbnailUrl: v.thumbnailUrl,
metrics: v.views !== undefined ? { views: v.views } : undefined,