import { isVideoId } from './video-id.js'; const PAGES = new Set(['home', 'watch', 'search', 'channel']); const MAX_TEXT = 300; export function shouldSave({ views, outlierScore }, { threshold, minViews }) { return typeof outlierScore === 'number' && outlierScore >= threshold && views >= minViews; } const finiteOrNull = (value) => (typeof value === 'number' && Number.isFinite(value) ? value : null); const textOrNull = (value) => (typeof value === 'string' && value.trim() ? value.trim().slice(0, MAX_TEXT) : null); const urlOrNull = (value, prefix) => (typeof value === 'string' && value.startsWith(prefix) ? value : null); // Validates a message coming from the content script before anything is stored. export function sanitizeItem(raw) { if (!raw || !isVideoId(raw.videoId)) return null; const outlierScore = finiteOrNull(raw.outlierScore); const views = finiteOrNull(raw.views); if (outlierScore === null || outlierScore < 0 || views === null || views < 0) return null; const subscribers = finiteOrNull(raw.subscribers); return { videoId: raw.videoId, title: textOrNull(raw.title), thumbnailUrl: urlOrNull(raw.thumbnailUrl, 'https://i.ytimg.com/'), channelTitle: textOrNull(raw.channelTitle), channelUrl: urlOrNull(raw.channelUrl, 'https://www.youtube.com/'), subscribers: subscribers !== null && subscribers >= 0 ? subscribers : null, views, outlierScore: Math.round(outlierScore * 100) / 100, isShort: raw.isShort === true, page: PAGES.has(raw.page) ? raw.page : 'home', }; } export function buildRecord(item, previous, settings, now = new Date()) { if (!previous && !shouldSave(item, settings)) return null; const nowIso = now.toISOString(); return { videoId: item.videoId, title: item.title ?? previous?.title ?? item.videoId, url: `https://www.youtube.com/watch?v=${item.videoId}`, thumbnailUrl: item.thumbnailUrl ?? previous?.thumbnailUrl ?? null, channelTitle: item.channelTitle ?? previous?.channelTitle ?? null, channelUrl: item.channelUrl ?? previous?.channelUrl ?? null, subscribers: item.subscribers ?? previous?.subscribers ?? null, views: item.views, outlierScore: item.outlierScore, isShort: item.isShort || previous?.isShort || false, foundOn: previous?.foundOn ?? item.page, firstSeenAt: previous?.firstSeenAt ?? nowIso, updatedAt: nowIso, }; }