feat(channel): page details chaine multi-providers avec onglets et infinite scroll
CI / build-and-test (push) Successful in 13m34s
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
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
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 };
|
||||
Reference in New Issue
Block a user