feat(channel): identite chaine partagee cliquable partout + logos fiabilises
CI / build-and-test (push) Successful in 13m25s
CI / build-and-test (push) Successful in 13m25s
- Nouveau app-channel-identity (avatar+nom -> /channel, fallback resolve /api/channels, initiales sinon) - ProviderBadge: accepte les ids courts yt/dm/tw/pt/od/ru - Search adapters yt/dm/pt/od: conservent channelExternalId/channelAvatarUrl (pt derive instance|channel) - video-card/themes/watch/related/suggestions/subscriptions/channel-header uniformises sur l'identite partagee
This commit is contained in:
@@ -22,6 +22,8 @@ export class DmAdapter implements ProviderAdapter<VideoItem> {
|
||||
thumbnailUrl: it.thumbnail,
|
||||
viewCount: undefined, // Dailymotion API does not provide view count in search results
|
||||
publishedAt: undefined, // Dailymotion API does not provide published date in search results
|
||||
channelExternalId: it.channelId || undefined,
|
||||
channelAvatarUrl: it.uploaderAvatar || undefined,
|
||||
}));
|
||||
return { items, total: Array.isArray(res?.groups?.dm) ? res.groups.dm.length : 0 };
|
||||
}
|
||||
|
||||
@@ -30,6 +30,9 @@ export class OdAdapter implements ProviderAdapter<VideoItem> {
|
||||
viewCount: undefined,
|
||||
publishedAt: undefined,
|
||||
slug,
|
||||
// Nom de chaîne LBRY (ex. @MaChaine) : le backend /api/channels/od
|
||||
// sait le résoudre avec ou sans préfixe @.
|
||||
channelExternalId: it.uploaderName || undefined,
|
||||
} as VideoItem;
|
||||
});
|
||||
return { items, total: Array.isArray(res?.groups?.od) ? res.groups.od.length : 0 };
|
||||
|
||||
@@ -12,16 +12,26 @@ export class PtAdapter implements ProviderAdapter<VideoItem> {
|
||||
if (params.pageToken) httpParams = httpParams.set('page', params.pageToken);
|
||||
if (params.sort) httpParams = httpParams.set('sort', params.sort);
|
||||
const res = await firstValueFrom(this.http.get<any>(`/api/search`, { params: httpParams }));
|
||||
const items: VideoItem[] = (res?.groups?.pt || []).map((it: any) => ({
|
||||
id: it.id,
|
||||
provider: 'peertube',
|
||||
title: it.title,
|
||||
channelName: it.uploaderName,
|
||||
durationSec: it.duration,
|
||||
thumbnailUrl: it.thumbnail,
|
||||
viewCount: undefined,
|
||||
publishedAt: undefined,
|
||||
}));
|
||||
const items: VideoItem[] = (res?.groups?.pt || []).map((it: any) => {
|
||||
// PeerTube identifie une chaîne par `instance|channel` : l'instance est
|
||||
// dérivée de l'URL vidéo, le nom de chaîne de `channelId`.
|
||||
let channelExternalId: string | undefined;
|
||||
try {
|
||||
const host = it?.url ? new URL(String(it.url)).hostname : '';
|
||||
if (host && it?.channelId) channelExternalId = `${host}|${it.channelId}`;
|
||||
} catch {}
|
||||
return {
|
||||
id: it.id,
|
||||
provider: 'peertube',
|
||||
title: it.title,
|
||||
channelName: it.uploaderName,
|
||||
durationSec: it.duration,
|
||||
thumbnailUrl: it.thumbnail,
|
||||
viewCount: undefined,
|
||||
publishedAt: undefined,
|
||||
channelExternalId,
|
||||
};
|
||||
});
|
||||
return { items, total: Array.isArray(res?.groups?.pt) ? res.groups.pt.length : 0 };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@ export class YtAdapter implements ProviderAdapter<VideoItem> {
|
||||
thumbnailUrl: it.thumbnail,
|
||||
viewCount: typeof it.views === 'number' ? it.views : (typeof it.viewCount === 'number' ? it.viewCount : undefined),
|
||||
publishedAt: it.publishedAt,
|
||||
// ID chaîne conservé : rend le logo/nom cliquables vers /channel
|
||||
// (l'avatar est résolu via /api/channels, l'API search n'en fournit pas).
|
||||
channelExternalId: it.channelExternalId || it.channelId || undefined,
|
||||
}));
|
||||
return { items, total: Array.isArray(res?.groups?.yt) ? res.groups.yt.length : 0 };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user