fix(shorts): son par defaut, avance auto, anti-Forbidden DM, autoplay Twitch/Rumble
CI / build-and-test (push) Successful in 14m56s
CI / build-and-test (push) Successful in 14m56s
Son active par defaut (YT/OD/DM/PT avec son ; clips Twitch en muet force, sans API de volume). Avance auto en fin de lecture (infoDelivery YT + minuteur duree generique garde par index/videoId, ignore si onglet cache). Dailymotion : allow_embed demande cote serveur, mappe en embeddable, propage en raw.allowEmbed pour le garde isPlayable (fini les Forbidden). Rumble autoplay=1/2 selon muet + nudge playVideo YT.
This commit is contained in:
@@ -35,6 +35,11 @@ export class DmAdapter implements ProviderAdapter<VideoItem> {
|
||||
publishedAt: undefined, // Dailymotion API does not provide published date in search results
|
||||
channelExternalId: serverRefValue(it.channelRef, 'dm') || it.channelId || undefined,
|
||||
channelAvatarUrl: it.uploaderAvatar || undefined,
|
||||
// Jouabilité : `allow_embed=false` (propriétaire) => le player répond
|
||||
// "Forbidden". Propagé tel quel : `accepts()` l'exclut via le garde
|
||||
// `raw.allowEmbed` (même garde que le chemin historique direct).
|
||||
// Champ absent = on ne sait pas (jamais de `false` inventé).
|
||||
embeddable: typeof it.embeddable === 'boolean' ? it.embeddable : undefined,
|
||||
// Signaux de type pour le raffinement client des filtres.
|
||||
type: typeof it.type === 'string' ? it.type : undefined,
|
||||
isShort: it.isShort === true ? true : undefined,
|
||||
|
||||
@@ -84,6 +84,26 @@ assertEqual(formatCapturedAgo(NOW - 30000, NOW), 'capturé à l’instant', 'fra
|
||||
assertEqual(formatCapturedAgo(NOW - 4 * 60000, NOW), 'capturé il y a 4 min', 'minutes');
|
||||
assertEqual(formatCapturedAgo(NOW + 60000, NOW), 'capturé à l’instant', 'futur → à l’instant (jamais « dans 1 min »)');
|
||||
|
||||
console.log('--- allowEmbed (Dailymotion Forbidden) ---');
|
||||
{
|
||||
const v: any = catalogShortToVideo({
|
||||
id: 'd1', provider: 'dailymotion', title: 'D', thumbnailUrl: '', channelName: 'C', embeddable: false,
|
||||
} as any);
|
||||
assertEqual(v?.raw?.allowEmbed, false, 'embeddable=false → raw.allowEmbed=false (garde isPlayable)');
|
||||
}
|
||||
{
|
||||
const v: any = catalogShortToVideo({
|
||||
id: 'd2', provider: 'dailymotion', title: 'D', thumbnailUrl: '', channelName: 'C', embeddable: true,
|
||||
} as any);
|
||||
assertEqual(v?.raw?.allowEmbed, true, 'embeddable=true propagé');
|
||||
}
|
||||
{
|
||||
const v: any = catalogShortToVideo({
|
||||
id: 'd3', provider: 'dailymotion', title: 'D', thumbnailUrl: '', channelName: 'C',
|
||||
} as any);
|
||||
assertEqual(v?.raw, undefined, 'embeddable absent → raw absent (doute profite à la vidéo)');
|
||||
}
|
||||
|
||||
console.log('--- constantes ---');
|
||||
assertEqual(SHORTS_CATALOG_PAGE_SIZE, 25, 'page catalogue 25 (serveur plafonne à 50)');
|
||||
assertEqual(SHORTS_CATALOG_MIN_ITEMS, 3, 'seuil de repli legacy');
|
||||
|
||||
@@ -49,6 +49,12 @@ export function catalogShortToVideo(item: VideoItem | null | undefined): Video |
|
||||
const kind = kindRaw === 'clip' || kindRaw === 'vod' || kindRaw === 'short' || kindRaw === 'channel'
|
||||
? kindRaw
|
||||
: undefined;
|
||||
// Jouabilité Dailymotion : `embeddable === false` (serveur lit `allow_embed`)
|
||||
// => le player répondrait "Forbidden". Transmis dans `raw` pour que le garde
|
||||
// existant `isPlayable` (`v?.raw?.allowEmbed === false`) l'exclue du flux,
|
||||
// exactement comme le chemin historique direct. Absent = on ne sait pas.
|
||||
const embeddableRaw = (item as { embeddable?: unknown }).embeddable;
|
||||
const allowEmbed = typeof embeddableRaw === 'boolean' ? embeddableRaw : undefined;
|
||||
return {
|
||||
url: provider === 'odysee' && slug ? `https://odysee.com/${slug}` : '',
|
||||
type: item.isLive === true ? 'live' : (item.isShort === true ? 'short' : 'video'),
|
||||
@@ -71,8 +77,14 @@ export function catalogShortToVideo(item: VideoItem | null | undefined): Video |
|
||||
language: typeof item.language === 'string' ? item.language : undefined,
|
||||
// Provenance catalogue : le flux l'affiche (« capturé il y a X »), le
|
||||
// modèle historique n'a pas ces champs → repli `raw`, jamais de perte.
|
||||
raw: (slug || capturedAt !== undefined || source)
|
||||
? { ...(slug ? { slug } : {}), ...(capturedAt !== undefined ? { capturedAt } : {}), ...(source ? { source } : {}) }
|
||||
// (`allowEmbed` y voyage aussi : c'est la clé lue par `isPlayable`.)
|
||||
raw: (slug || capturedAt !== undefined || source || allowEmbed !== undefined)
|
||||
? {
|
||||
...(slug ? { slug } : {}),
|
||||
...(capturedAt !== undefined ? { capturedAt } : {}),
|
||||
...(source ? { source } : {}),
|
||||
...(allowEmbed !== undefined ? { allowEmbed } : {}),
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user