discovery-media-player 0.1.29 → 0.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server/handler.js +50 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "discovery-media-player",
3
- "version": "0.1.29",
3
+ "version": "0.1.30",
4
4
  "description": "Self-hosted document viewer: per-recipient tracked links, reading analytics, live presentation. The core knows nothing about the application hosting it — everything it borrows arrives through an injected context.",
5
5
  "keywords": [
6
6
  "pdf-viewer",
package/server/handler.js CHANGED
@@ -241,7 +241,8 @@ var Live=(function(){
241
241
  function toggleMute(){ MUTED=!MUTED; try{ localStorage.setItem('3dd-present-mute',MUTED?'1':'0'); }catch(e){} if(MUTED)hidePeek(); applyMute(); }
242
242
  // Flèche « envoyer » : visible seulement si le champ contient du texte et qu'on peut poster.
243
243
  function toggleSend(){ var s=document.getElementById('chatSend'),t=document.getElementById('chatText'); if(!s||!t)return; var can=!(LOCKED&&!canMod()); s.classList.toggle('on', can && (t.value||'').trim().length>0); }
244
- function sendMap(p){try{if(ch)ch.send({type:'broadcast',event:'map',payload:p});}catch(e){}}
244
+ // Un SIGNAL, plus une position : la charge utile était crue par l'audience sur un canal public.
245
+ function sendMap(){try{if(ch)ch.send({type:'broadcast',event:'map',payload:{}});}catch(e){}}
245
246
  function onMap(fn){_onMap=fn;}
246
247
  // État de la présentation diffusé par le présentateur — même canal que la carte. Sert à se
247
248
  // passer de la lecture anonyme des tables : l'audience n'a plus besoin de lire la ligne.
@@ -476,6 +477,10 @@ var Live=(function(){
476
477
  },{minMs:400});
477
478
  }
478
479
  var _ordEtat=relireAvec('&state=1',function(d){if(d.state)etatDuServeur(d.state);});
480
+ // ⚠️ Exposé hors de cette fermeture : la carte vit dans un AUTRE bloc de script et doit
481
+ // pouvoir déclencher la relecture. Même raison que window.__presAppliquerEtat — un nom
482
+ // référencé depuis la mauvaise portée part dans un catch muet, et l'audience se fige.
483
+ window.__presRelireEtat=function(){_ordEtat.signaler();};
479
484
  function relireEtat(){_ordEtat.signaler();}
480
485
  function relireChat(){_ordChat.signaler();}
481
486
  var _ordChat=relireAvec('&chat=1',function(d){
@@ -517,7 +522,10 @@ var Live=(function(){
517
522
  ch.on('broadcast',{event:'lock'},function(){relireChat();});
518
523
  ch.on('broadcast',{event:'state'},function(){relireEtat();});
519
524
  ch.on('broadcast',{event:'typing'},function(p){onTyping(p&&p.payload);});
520
- ch.on('broadcast',{event:'map'},function(p){if(_onMap&&p&&p.payload)_onMap(p.payload);});
525
+ // ⚠️ AUCUNE CHARGE NE PASSE. Elle est ignorée plus loin, mais s'arrêter là serait une défense
526
+ // par accident : le jour où quelqu'un rebranche un paramètre, la charge d'un canal public
527
+ // redeviendrait crue sans que rien ne le signale. On coupe le chemin, pas seulement l'usage.
528
+ ch.on('broadcast',{event:'map'},function(){if(_onMap)_onMap();});
521
529
  ch.subscribe(function(st){if(st==='SUBSCRIBED'){ch.track({name:me.name,email:me.email,avatar:me.avatar,role:me.role,member:!!me.member,uid:attKey(me)});sendAttend();}});
522
530
  _tyIv=setInterval(renderTyping,1500);
523
531
  _atIv=setInterval(sendAttend,25000);
@@ -592,8 +600,34 @@ var Map3DD=(function(){
592
600
  function state(){ if(!map)return null; if(useG){ var c=map.getCenter(); return {kind:'map',center:[c.lat(),c.lng()],zoom:map.getZoom(),marker:marker?[marker.getPosition().lat(),marker.getPosition().lng()]:null,mapType:map.getMapTypeId()}; }
593
601
  var c2=map.getCenter(); return {kind:'map',center:[c2.lat,c2.lng],zoom:map.getZoom(),marker:marker?[marker.getLatLng().lat,marker.getLatLng().lng]:null}; }
594
602
  function setCenterZoom(ll,z){ if(useG){ map.setCenter({lat:ll[0],lng:ll[1]}); map.setZoom(z); } else { map.setView(ll,z); } }
595
- function broadcast(){ var n=Date.now(); if(n-_bcT<100||!map)return; _bcT=n; var s=state(); if(s){try{ if(window.Live) Live.sendMap(s); }catch(e){}} }
596
- function schedPersist(){ clearTimeout(_psT); _psT=setTimeout(function(){ if(map&&persist)persist(state()); },700); }
603
+ // ⚠️ LA POSITION NE VOYAGE PLUS DANS LA DIFFUSION.
604
+ //
605
+ // Elle y voyageait, et l'audience l'appliquait telle quelle. Le canal étant public, n'importe quel
606
+ // participant déplaçait donc la carte de tout le monde, avec les coordonnées de son choix. C'était
607
+ // assumé en 0.1.19 au motif que le signal est « éphémère et sans vérité serveur » — l'argument ne
608
+ // tient pas : PENDANT UN MODE CARTE, CE SIGNAL EST L'IMAGE QUE VOIT L'AUDIENCE. 'typing' peut
609
+ // rester cosmétique, 'map' non. (audit P0-1)
610
+ //
611
+ // Le présentateur persiste sa position (route gatée par JWT), puis émet un signal VIDE. L'audience
612
+ // relit l'état et applique ce que le serveur lui donne. Un participant hostile peut toujours
613
+ // émettre le signal : il provoque une relecture, et n'obtient rien.
614
+ //
615
+ // ⚠️ ORDONNANCEUR ET NON DEBOUNCE, et c'est le cœur du problème. schedPersist repoussait
616
+ // l'écriture de 700 ms à chaque mouvement : pendant un déplacement CONTINU, elle ne partait
617
+ // jamais. C'est précisément pour ça que la position voyageait dans la diffusion. Un ordonnanceur
618
+ // écrit au plus une fois par 500 ms ET sert toujours la dernière position — donc l'audience suit
619
+ // pendant le mouvement, pas seulement à l'arrêt.
620
+ //
621
+ // Le suivi devient PAR PALIERS au lieu d'être continu (environ deux fois par seconde). C'est le
622
+ // prix pour que personne d'autre que le présentateur ne pilote l'écran de l'audience.
623
+ var _ordPersist=null;
624
+ function persistOrd(){ if(!_ordPersist&&window.Player&&Player.live&&Player.live.createScheduler){
625
+ _ordPersist=Player.live.createScheduler(function(fini){ try{ if(map&&persist)persist(state()); }catch(e){} fini(); },{minMs:500}); }
626
+ return _ordPersist; }
627
+ function broadcast(){ if(!map)return; var n=Date.now(); if(n-_bcT<200)return; _bcT=n;
628
+ var o=persistOrd(); if(o)o.signaler();
629
+ try{ if(window.Live) Live.sendMap(); }catch(e){} }
630
+ function schedPersist(){ var o=persistOrd(); if(o)o.signaler(); else { clearTimeout(_psT); _psT=setTimeout(function(){ if(map&&persist)persist(state()); },700); } }
597
631
  function enter(content,presenter,persistFn){ isPres=!!presenter; if(persistFn)persist=persistFn;
598
632
  if(content&&content.mapType)mapType=content.mapType;
599
633
  var wrap=document.getElementById('mapWrap'); var on=wrap&&wrap.classList.contains('on');
@@ -632,7 +666,14 @@ var Map3DD=(function(){
632
666
  function goSV(center){ if(!GMAPS_KEY){tempHint('Street View indisponible.');return;} tempHint('Recherche Street View…');
633
667
  loadGoogle(function(){ try{ new google.maps.StreetViewService().getPanorama({location:{lat:center[0],lng:center[1]},radius:80},function(data,status){ if(status==='OK'&&data&&data.location){ var ll=data.location.latLng; var content={kind:'streetview',position:[ll.lat(),ll.lng()],pov:{heading:0,pitch:0},zoom:1}; if(persist)persist(content); enterSV(content,true,persist); } else { tempHint('Pas de Street View à cet endroit.'); } }); }catch(e){ tempHint('Street View indisponible.'); } }); }
634
668
  function svState(){ if(!pano)return null; var p=pano.getPosition(),v=pano.getPov(); if(!p)return null; return {kind:'streetview',position:[p.lat(),p.lng()],pov:{heading:v.heading,pitch:v.pitch},zoom:pano.getZoom()}; }
635
- function svBcast(){ var n=Date.now(); if(n-_svBcT<120)return; _svBcT=n; var s=svState(); if(!s)return; try{ if(window.Live)Live.sendMap(s); }catch(e){} clearTimeout(_psT); _psT=setTimeout(function(){ if(persist&&pano)persist(svState()); },800); }
669
+ // Même règle qu'au-dessus : on persiste, on signale, on ne transporte pas la position.
670
+ var _ordSv=null;
671
+ function svOrd(){ if(!_ordSv&&window.Player&&Player.live&&Player.live.createScheduler){
672
+ _ordSv=Player.live.createScheduler(function(fini){ try{ if(persist&&pano)persist(svState()); }catch(e){} fini(); },{minMs:500}); }
673
+ return _ordSv; }
674
+ function svBcast(){ var n=Date.now(); if(n-_svBcT<200)return; _svBcT=n; if(!svState())return;
675
+ var o=svOrd(); if(o)o.signaler();
676
+ try{ if(window.Live)Live.sendMap(); }catch(e){} }
636
677
  function svApply(p){ if(!pano||!p)return; try{ if(p.position)pano.setPosition({lat:p.position[0],lng:p.position[1]}); if(p.pov)pano.setPov({heading:p.pov.heading||0,pitch:p.pov.pitch||0}); if(typeof p.zoom!=='undefined')pano.setZoom(p.zoom); }catch(e){} }
637
678
  function ensurePano(content){ var el=document.getElementById('svPano'); if(!el||!window.google||!window.google.maps)return;
638
679
  var pos=content&&content.position?{lat:content.position[0],lng:content.position[1]}:{lat:48.8584,lng:2.2945};
@@ -2374,7 +2415,10 @@ function presentHtml(pres, nonce, logoUrl, supaUrl, supaKey) {
2374
2415
  (function(){
2375
2416
  var slug=${JSON.stringify(pres.slug)};
2376
2417
  // Carte live : suivre en direct les mouvements du présentateur (broadcast).
2377
- try{ if(window.Live&&window.Map3DD) Live.onMap(function(p){ Map3DD.apply(p); }); }catch(e){}
2418
+ // ⚠️ ON NE CROIT PLUS LA CHARGE. Le signal dit « quelque chose a bougé » ; ce qui a bougé vient
2419
+ // de la relecture d'état, gatée par l'écriture du présentateur. Un participant hostile peut
2420
+ // émettre : il déclenche une relecture bornée, et n'obtient rien.
2421
+ try{ if(window.Live&&window.Map3DD) Live.onMap(function(){ if(window.__presRelireEtat)window.__presRelireEtat(); }); }catch(e){}
2378
2422
  // L'état arrive maintenant par DEUX voies : la table (historique) et la diffusion du
2379
2423
  // présentateur (nouvelle). Les deux passent par le même filtre, qui ignore un état déjà
2380
2424
  // appliqué — recevoir deux fois la même chose ne doit pas re-rendre la page.