CI / build-and-test (push) Successful in 13m34s
- Strategy Pattern front: ChannelProviderInterface + 6 providers (yt/dm/tw/pt/od/ru) + factory (ids longs/courts) - ChannelContentService: cache par onglet/tri/recherche (TTL 5min), pagination nextPage - ChannelPage: header (banniere/avatar/subs/description ...plus), tabs dynamiques par capabilities, grilles videos/shorts 9:16/playlists/live, recherche debounced, tri recent/populaire, infinite scroll IntersectionObserver, skeletons/empty/error - Backend: GET /api/channels/:provider/:id/content (videos/shorts/playlists/live) natif par provider
65 lines
2.2 KiB
TypeScript
65 lines
2.2 KiB
TypeScript
import type { ChannelMeta, ProviderId } from './channel.model';
|
|
import type { VideoItem } from './video-item.model';
|
|
|
|
export type ChannelTabId = 'videos' | 'shorts' | 'playlists' | 'live' | 'about';
|
|
export type ChannelSort = 'recent' | 'popular';
|
|
export type ChannelContentType = 'videos' | 'shorts' | 'playlists' | 'live';
|
|
|
|
export interface ChannelCapabilities {
|
|
videos: boolean;
|
|
shorts: boolean;
|
|
playlists: boolean;
|
|
live: boolean;
|
|
about: boolean;
|
|
searchInChannel: boolean;
|
|
}
|
|
|
|
export interface ChannelDetail extends ChannelMeta {
|
|
bannerUrl?: string | null;
|
|
description?: string | null;
|
|
videoCount?: number | null;
|
|
viewCount?: number | null;
|
|
createdAt?: string | null;
|
|
links?: { label: string; url: string }[];
|
|
capabilities: ChannelCapabilities;
|
|
}
|
|
|
|
export interface ChannelContentPage<T> {
|
|
items: T[];
|
|
nextPage: number | null;
|
|
total?: number | null;
|
|
}
|
|
|
|
export interface ChannelPlaylist {
|
|
id: string;
|
|
provider: ProviderId;
|
|
title: string;
|
|
thumbnailUrl?: string | null;
|
|
videoCount?: number | null;
|
|
updatedAt?: string | null;
|
|
}
|
|
|
|
export const DEFAULT_CAPABILITIES: Record<ProviderId, ChannelCapabilities> = {
|
|
yt: { videos: true, shorts: true, playlists: true, live: true, about: true, searchInChannel: true },
|
|
dm: { videos: true, shorts: false, playlists: true, live: false, about: true, searchInChannel: true },
|
|
tw: { videos: true, shorts: false, playlists: false, live: true, about: true, searchInChannel: true },
|
|
pt: { videos: true, shorts: false, playlists: true, live: false, about: true, searchInChannel: true },
|
|
od: { videos: true, shorts: false, playlists: false, live: false, about: true, searchInChannel: true },
|
|
ru: { videos: true, shorts: false, playlists: false, live: false, about: true, searchInChannel: true },
|
|
};
|
|
|
|
export function buildChannelDetail(meta: ChannelMeta, extra?: Partial<ChannelDetail>): ChannelDetail {
|
|
return {
|
|
...meta,
|
|
bannerUrl: extra?.bannerUrl ?? null,
|
|
description: extra?.description ?? null,
|
|
videoCount: extra?.videoCount ?? null,
|
|
viewCount: extra?.viewCount ?? null,
|
|
createdAt: extra?.createdAt ?? null,
|
|
links: extra?.links ?? [],
|
|
capabilities: extra?.capabilities ?? DEFAULT_CAPABILITIES[meta.provider],
|
|
};
|
|
}
|
|
|
|
export type { VideoItem };
|