{(question.choices ?? []).map((choice, index) => (
diff --git a/apps/web/src/i18n/en.ts b/apps/web/src/i18n/en.ts
index 785fbaa..f0da3a4 100644
--- a/apps/web/src/i18n/en.ts
+++ b/apps/web/src/i18n/en.ts
@@ -109,6 +109,7 @@ export const en: Dict = {
validate: "Submit",
},
blindtest: {
+ enableSound: "Enable sound",
djHint: "You're the DJ 🎧 — control playback (and vote like everyone)",
play: "Play",
pause: "Pause",
diff --git a/apps/web/src/i18n/fr.ts b/apps/web/src/i18n/fr.ts
index ce0220f..6b85d83 100644
--- a/apps/web/src/i18n/fr.ts
+++ b/apps/web/src/i18n/fr.ts
@@ -107,6 +107,7 @@ export const fr = {
validate: "Valider",
},
blindtest: {
+ enableSound: "Activer le son",
djHint: "Tu es le DJ 🎧 — pilote la lecture (et vote comme les autres)",
play: "Play",
pause: "Pause",
diff --git a/apps/web/src/lib/youtube.ts b/apps/web/src/lib/youtube.ts
index 13f47a0..945fd53 100644
--- a/apps/web/src/lib/youtube.ts
+++ b/apps/web/src/lib/youtube.ts
@@ -65,6 +65,10 @@ export function useYoutube(youtubeId: string) {
modestbranding: 1,
rel: 0,
playsinline: 1,
+ // Évite l'avertissement postMessage "target origin does not match"
+ // et fiabilise la transmission des commandes au lecteur.
+ enablejsapi: 1,
+ origin: window.location.origin,
},
events: {
onReady: () => {
diff --git a/apps/web/src/pages/room.tsx b/apps/web/src/pages/room.tsx
index 6e88854..ecdab75 100644
--- a/apps/web/src/pages/room.tsx
+++ b/apps/web/src/pages/room.tsx
@@ -129,7 +129,15 @@ export function RoomPage({ code }: { code: string }) {
{round?.type === "blindtest" ? (
diff --git a/apps/web/src/store/room.ts b/apps/web/src/store/room.ts
index 241afc0..fb76f6e 100644
--- a/apps/web/src/store/room.ts
+++ b/apps/web/src/store/room.ts
@@ -6,6 +6,7 @@ import {
type ErrorPayload,
type MediaControlPayload,
type MediaSyncPayload,
+ type MyTrackInfo,
type PlayerScore,
type RoomCreatedPayload,
type RoomSnapshot,
@@ -51,6 +52,8 @@ interface RoomState {
pseudoSet: boolean
snapshot: RoomSnapshot | null
lastError: ErrorPayload | null
+ /** Mes titres blindtest (renvoyés par le serveur, source de vérité). */
+ myTracks: MyTrackInfo[]
// État de jeu (poussé par le moteur serveur).
round: ActiveRound | null
@@ -96,6 +99,7 @@ export const useRoomStore = create
((set, get) => ({
pseudoSet: !!saved?.name,
snapshot: null,
lastError: null,
+ myTracks: [],
round: null,
voteProgress: null,
reveal: null,
@@ -242,6 +246,7 @@ export const useRoomStore = create((set, get) => ({
pseudoSet: false,
snapshot: null,
lastError: null,
+ myTracks: [],
round: null,
voteProgress: null,
reveal: null,
@@ -303,6 +308,9 @@ socket.on("room:state", (snapshot) =>
)
)
socket.on("error", (error) => useRoomStore.setState({ lastError: error }))
+socket.on("blindtest:myTracks", ({ tracks }) =>
+ useRoomStore.setState({ myTracks: tracks })
+)
socket.on("round:start", (payload) =>
useRoomStore.setState((s) => {
diff --git a/packages/shared/src/events.ts b/packages/shared/src/events.ts
index fb5090b..cd2daf6 100644
--- a/packages/shared/src/events.ts
+++ b/packages/shared/src/events.ts
@@ -78,6 +78,17 @@ export interface RemoveTrackPayload {
trackId: string
}
+/** Un titre soumis par le joueur lui-même (renvoyé en privé, source de vérité). */
+export interface MyTrackInfo {
+ trackId: string
+ title: string
+ youtubeId: string
+}
+
+export interface MyTracksPayload {
+ tracks: MyTrackInfo[]
+}
+
export interface RoundStartPayload {
type: RoundType
djId?: string
@@ -175,6 +186,7 @@ export interface ServerToClientEvents {
"player:left": (payload: PlayerRefPayload) => void
"player:rejoined": (payload: PlayerRefPayload) => void
"blindtest:submitOk": (payload: SubmitOkPayload) => void
+ "blindtest:myTracks": (payload: MyTracksPayload) => void
"round:start": (payload: RoundStartPayload) => void
"media:sync": (payload: MediaSyncPayload) => void
"round:voteAck": (payload: VoteAckPayload) => void