fix(dailymotion): Player ID obligatoire dans l'URL d'embed
CI / build-and-test (push) Successful in 14m58s
CI / build-and-test (push) Successful in 14m58s
Dailymotion exige désormais un Player ID (fév. 2026) : player.html?video=...
sans Player ID répond HTTP 403 'Forbidden'. L'URL correcte est
geo.dailymotion.com/player/{PLAYER_ID}.html?video=...
- helper dailymotionPlayerId()/dailymotionEmbedBase() (config window.DAILYMOTION_PLAYER_ID, repli demo x8lr5)
- /watch et /shorts utilisent le nouvel endpoint avec Player ID
- config.local.example.js documente la config
This commit is contained in:
@@ -11,6 +11,13 @@
|
|||||||
// YouTube Data API v3 key (browser-safe only if properly restricted by HTTP referrer)
|
// YouTube Data API v3 key (browser-safe only if properly restricted by HTTP referrer)
|
||||||
window.YOUTUBE_API_KEY = 'PUT_YOUR_YOUTUBE_API_KEY_HERE';
|
window.YOUTUBE_API_KEY = 'PUT_YOUR_YOUTUBE_API_KEY_HERE';
|
||||||
|
|
||||||
|
// Dailymotion Player ID (required since Feb 2026: embeds without a Player ID
|
||||||
|
// return HTTP 403 "Forbidden"). Create a Player in Dailymotion Studio
|
||||||
|
// (https://www.dailymotion.com/partner/embed/players) — ideally a vertical
|
||||||
|
// player (aspect_ratio 9:16) for Shorts — and set its ID here.
|
||||||
|
// If unset, the app falls back to a public demo player ID (x8lr5).
|
||||||
|
// window.DAILYMOTION_PLAYER_ID = 'x8lr5';
|
||||||
|
|
||||||
// Optional: you can also provide multiple keys (CSV) via server env YOUTUBE_API_KEYS.
|
// Optional: you can also provide multiple keys (CSV) via server env YOUTUBE_API_KEYS.
|
||||||
|
|
||||||
// Rumble API key (optional — Rumble now works via server-side scraping)
|
// Rumble API key (optional — Rumble now works via server-side scraping)
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* Dailymotion : Player ID obligatoire (fév. 2026).
|
||||||
|
*
|
||||||
|
* Dailymotion a rendu le Player ID obligatoire sur le nouvel endpoint
|
||||||
|
* d'embed : `https://geo.dailymotion.com/player.html?video=…` SANS Player ID
|
||||||
|
* répond désormais HTTP 403 « Forbidden ». L'URL correcte est
|
||||||
|
* `https://geo.dailymotion.com/player/{PLAYER_ID}.html?video=…`.
|
||||||
|
*
|
||||||
|
* Configurable via `window.DAILYMOTION_PLAYER_ID` (assets/config.local.js).
|
||||||
|
* Repli sur un Player ID de démonstration public (`x8lr5`, fourni par la
|
||||||
|
* documentation Dailymotion) pour que l'embed fonctionne sans configuration.
|
||||||
|
* En production, créez votre propre Player (Dailymotion Studio → Players) et
|
||||||
|
* renseignez son ID — idéalement un player vertical (aspect_ratio 9:16) pour
|
||||||
|
* les Shorts.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const DM_PLAYER_ID_DEFAULT = 'x8lr5';
|
||||||
|
|
||||||
|
/** Player ID Dailymotion effectif (config explicite sinon démonstration). */
|
||||||
|
export function dailymotionPlayerId(): string {
|
||||||
|
try {
|
||||||
|
const g = globalThis as any;
|
||||||
|
const raw = g?.DAILYMOTION_PLAYER_ID;
|
||||||
|
const v = typeof raw === 'string' ? raw.trim() : '';
|
||||||
|
if (v) return v;
|
||||||
|
} catch {}
|
||||||
|
return DM_PLAYER_ID_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Base de l'URL d'embed Dailymotion (nouveau endpoint + Player ID). */
|
||||||
|
export function dailymotionEmbedBase(videoId: string): string {
|
||||||
|
return `https://geo.dailymotion.com/player/${encodeURIComponent(dailymotionPlayerId())}.html?video=${encodeURIComponent(videoId)}`;
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ import { AuthService } from '../../services/auth.service';
|
|||||||
import { Video } from '../../models/video.model';
|
import { Video } from '../../models/video.model';
|
||||||
import { shortsFeedAccepts, isPlayable as isPlayablePolicy, type PlayableContext } from '../../app/shared/utils/section-policy';
|
import { shortsFeedAccepts, isPlayable as isPlayablePolicy, type PlayableContext } from '../../app/shared/utils/section-policy';
|
||||||
import { SHORT_TO_LONG, type ProviderId } from '../../app/shared/providers/provider-ids';
|
import { SHORT_TO_LONG, type ProviderId } from '../../app/shared/providers/provider-ids';
|
||||||
|
import { dailymotionEmbedBase } from '../../app/shared/providers/dailymotion-player';
|
||||||
import { SearchService } from '../../app/search/search.service';
|
import { SearchService } from '../../app/search/search.service';
|
||||||
import { ChannelProviderFactory } from '../../app/core/providers/channel/channel-provider.factory';
|
import { ChannelProviderFactory } from '../../app/core/providers/channel/channel-provider.factory';
|
||||||
import {
|
import {
|
||||||
@@ -375,18 +376,11 @@ export class WatchShortComponent implements OnDestroy {
|
|||||||
return this.sanitizer.bypassSecurityTrustResourceUrl(u);
|
return this.sanitizer.bypassSecurityTrustResourceUrl(u);
|
||||||
}
|
}
|
||||||
if (p === 'dailymotion' && v.videoId) {
|
if (p === 'dailymotion' && v.videoId) {
|
||||||
// Nouveau player obligatoire depuis fév. 2026 (l'ancien /embed est
|
// Nouveau player + Player ID obligatoire depuis fév. 2026 (player.html
|
||||||
// coupé et répond "Forbidden"). Seuls mute/startTime/loop passent
|
// sans Player ID répond "Forbidden"). Démarrage MUET (comme /watch),
|
||||||
// en query sans Player ID ; autoplay est tenté au mieux.
|
// son uniquement sur action explicite du bouton Son.
|
||||||
// Correctif bug "Forbidden" systématique en Shorts alors que /watch
|
|
||||||
// (toujours muet) joue la même vidéo : on démarre MUET comme /watch
|
|
||||||
// (même URL, mute=1) et on ne passe au son QUE sur action explicite
|
|
||||||
// du bouton Son — le clic EST le geste qui autorise le son (même
|
|
||||||
// motif que le player Odysee, cf. soundTouched). L'autoplay sonore
|
|
||||||
// sans geste préalable est bloqué et le player par défaut l'affiche
|
|
||||||
// comme "Forbidden".
|
|
||||||
const withSound = !this.muted() && this.soundTouched();
|
const withSound = !this.muted() && this.soundTouched();
|
||||||
const u = `https://geo.dailymotion.com/player.html?video=${encodeURIComponent(v.videoId)}&mute=${withSound ? 0 : 1}&autoplay=1`;
|
const u = `${dailymotionEmbedBase(v.videoId)}&mute=${withSound ? 0 : 1}&autoplay=1`;
|
||||||
return this.sanitizer.bypassSecurityTrustResourceUrl(u);
|
return this.sanitizer.bypassSecurityTrustResourceUrl(u);
|
||||||
}
|
}
|
||||||
if (p === 'twitch' && v.videoId) {
|
if (p === 'twitch' && v.videoId) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { ChannelsService } from '../../services/channels.service';
|
|||||||
import { SubscriptionsService } from '../../services/subscriptions.service';
|
import { SubscriptionsService } from '../../services/subscriptions.service';
|
||||||
import type { ChannelMeta, ProviderId } from '../../app/shared/models/channel.model';
|
import type { ChannelMeta, ProviderId } from '../../app/shared/models/channel.model';
|
||||||
import { toShortProviderId } from '../../app/shared/providers/provider-ids';
|
import { toShortProviderId } from '../../app/shared/providers/provider-ids';
|
||||||
|
import { dailymotionEmbedBase } from '../../app/shared/providers/dailymotion-player';
|
||||||
import { SubscribeButtonComponent } from '../../app/shared/components/subscribe-button/subscribe-button.component';
|
import { SubscribeButtonComponent } from '../../app/shared/components/subscribe-button/subscribe-button.component';
|
||||||
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
||||||
import { IframeProgressService } from '../../services/iframe-progress.service';
|
import { IframeProgressService } from '../../services/iframe-progress.service';
|
||||||
@@ -402,10 +403,9 @@ export class WatchComponent implements OnDestroy, AfterViewInit {
|
|||||||
return this.sanitizer.bypassSecurityTrustResourceUrl(u);
|
return this.sanitizer.bypassSecurityTrustResourceUrl(u);
|
||||||
}
|
}
|
||||||
if (p === 'dailymotion') {
|
if (p === 'dailymotion') {
|
||||||
// Nouveau player obligatoire depuis fév. 2026 (l'ancien /embed est
|
// Nouveau player + Player ID obligatoire depuis fév. 2026 (l'ancien
|
||||||
// coupé et répond "Forbidden"). Seuls mute/startTime/loop passent
|
// /embed et player.html sans Player ID répondent "Forbidden").
|
||||||
// en query sans Player ID.
|
let u = `${dailymotionEmbedBase(id)}&mute=1&autoplay=1`;
|
||||||
let u = `https://geo.dailymotion.com/player.html?video=${encodeURIComponent(id)}&mute=1&autoplay=1`;
|
|
||||||
if (start > 0) u += `&startTime=${start}`;
|
if (start > 0) u += `&startTime=${start}`;
|
||||||
return this.sanitizer.bypassSecurityTrustResourceUrl(u);
|
return this.sanitizer.bypassSecurityTrustResourceUrl(u);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user