Files
MyClub/frontend/src/services/youtube.ts
T
Tomas Dvorak b9cea0cd77 dev day #79
2025-11-02 01:04:02 +01:00

80 lines
2.8 KiB
TypeScript

import api, { API_URL } from './api';
export type YouTubeVideo = {
video_id: string;
title: string;
thumbnail_url: string;
views_text?: string;
views?: number;
published_text?: string;
published_date?: string; // YYYY-MM-DD
};
export type YouTubeChannelPayload = {
channel: string;
channel_url: string;
subscribers_text?: string;
subscribers?: number;
videos: YouTubeVideo[];
};
// Simple in-memory cache for YouTube payload (per-session)
let ytMemCache: { payload: YouTubeChannelPayload | null; fetchedAt: number } | null = null;
const YT_CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
export const getCachedYouTube = async (): Promise<YouTubeChannelPayload | null> => {
const now = Date.now();
if (ytMemCache && now - ytMemCache.fetchedAt < YT_CACHE_TTL_MS) {
return sortByPublishedDate(ytMemCache.payload) as YouTubeChannelPayload | null;
}
try {
const res = await api.get('/youtube/videos');
const primary = res?.data as YouTubeChannelPayload | undefined;
const hasVideos = Array.isArray(primary?.videos) && (primary!.videos.length > 0);
// If backend responded with 204 or empty payload, fall back to the static cached JSON
let out: YouTubeChannelPayload | null = null;
if (res.status === 204 || !primary || !hasVideos) {
out = await fetchStaticYouTubeCache();
} else {
out = primary || null;
}
if (out) {
ytMemCache = { payload: out, fetchedAt: now };
}
return sortByPublishedDate(out) as YouTubeChannelPayload | null;
} catch {
// Fallback: fetch static cached JSON directly from backend /cache path to avoid stressing external API
const out = await fetchStaticYouTubeCache();
if (out) {
ytMemCache = { payload: out, fetchedAt: now };
}
return out;
}
};
// Helper: fetch static cached JSON from /cache/prefetch
const fetchStaticYouTubeCache = async (): Promise<YouTubeChannelPayload | null> => {
try {
const origin = new URL(API_URL, typeof window !== 'undefined' ? window.location.origin : 'http://localhost:3000').origin;
const url = `${origin}/cache/prefetch/youtube_channel.json`;
const resp = await fetch(url, { cache: 'force-cache' });
if (!resp.ok) return null;
const data = (await resp.json()) as YouTubeChannelPayload;
return sortByPublishedDate(data);
} catch {
return null;
}
};
// Helper: ensure videos are sorted by most recent published_date
const sortByPublishedDate = (payload: YouTubeChannelPayload | null | undefined): YouTubeChannelPayload | null => {
if (!payload || !Array.isArray(payload.videos)) return payload ?? null;
const copy: YouTubeChannelPayload = { ...payload, videos: [...payload.videos] };
copy.videos.sort((a, b) => {
const ta = Date.parse(a.published_date || '') || 0;
const tb = Date.parse(b.published_date || '') || 0;
return tb - ta; // newest first
});
return copy;
};