@patch-adams/core 1.4.2 → 1.4.3

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.
package/dist/index.js CHANGED
@@ -2727,49 +2727,146 @@ function generateLrsBridgeCode(options) {
2727
2727
  function setupMediaInterceptors() {
2728
2728
  if (!TRACK_MEDIA) return;
2729
2729
 
2730
- document.addEventListener('play', function(e) {
2731
- var target = e.target;
2732
- if (target.tagName === 'VIDEO' || target.tagName === 'AUDIO') {
2730
+ // Track which elements we've already attached listeners to
2731
+ var trackedMedia = new WeakSet();
2732
+
2733
+ // Helper to get media name/title from element or surrounding context
2734
+ function getMediaName(el) {
2735
+ // Check element attributes
2736
+ var name = el.title || el.getAttribute('aria-label') || el.getAttribute('data-name');
2737
+ if (name) return name;
2738
+
2739
+ // Check parent Rise video block for title
2740
+ var videoBlock = findClosest(el, '[data-block-type="video"], .blocks-video, .video-block');
2741
+ if (videoBlock) {
2742
+ var titleEl = videoBlock.querySelector('.video-title, .block-title, [class*="title"]');
2743
+ if (titleEl) return titleEl.textContent.trim();
2744
+ }
2745
+
2746
+ // Use src filename as fallback
2747
+ var src = el.src || el.currentSrc || '';
2748
+ if (src) {
2749
+ var filename = src.split('/').pop().split('?')[0];
2750
+ if (filename && filename.length < 100) return filename;
2751
+ }
2752
+
2753
+ return el.tagName.toLowerCase();
2754
+ }
2755
+
2756
+ // Attach media event listeners to a single element
2757
+ function attachMediaListeners(el) {
2758
+ if (trackedMedia.has(el)) return;
2759
+ trackedMedia.add(el);
2760
+
2761
+ var mediaType = el.tagName.toLowerCase();
2762
+ log('Attaching media listeners to:', mediaType, el.src || el.currentSrc || 'no-src');
2763
+
2764
+ el.addEventListener('play', function() {
2765
+ log('Media play event captured:', mediaType);
2733
2766
  LRS.mediaPlayed({
2734
- type: target.tagName.toLowerCase(),
2735
- src: target.src || target.currentSrc || '',
2736
- name: target.title || target.getAttribute('aria-label') || '',
2737
- currentTime: target.currentTime || 0,
2738
- duration: target.duration || 0,
2767
+ type: mediaType,
2768
+ src: el.src || el.currentSrc || '',
2769
+ name: getMediaName(el),
2770
+ currentTime: el.currentTime || 0,
2771
+ duration: el.duration || 0,
2739
2772
  action: 'play'
2740
2773
  });
2741
- }
2742
- }, true);
2774
+ });
2743
2775
 
2744
- document.addEventListener('pause', function(e) {
2745
- var target = e.target;
2746
- if (target.tagName === 'VIDEO' || target.tagName === 'AUDIO') {
2776
+ el.addEventListener('pause', function() {
2777
+ // Ignore pause events that fire right before ended
2778
+ if (el.ended) return;
2779
+ log('Media pause event captured:', mediaType);
2747
2780
  LRS.mediaPlayed({
2748
- type: target.tagName.toLowerCase(),
2749
- src: target.src || target.currentSrc || '',
2750
- name: target.title || target.getAttribute('aria-label') || '',
2751
- currentTime: target.currentTime || 0,
2752
- duration: target.duration || 0,
2781
+ type: mediaType,
2782
+ src: el.src || el.currentSrc || '',
2783
+ name: getMediaName(el),
2784
+ currentTime: el.currentTime || 0,
2785
+ duration: el.duration || 0,
2753
2786
  action: 'pause'
2754
2787
  });
2755
- }
2756
- }, true);
2788
+ });
2757
2789
 
2758
- document.addEventListener('ended', function(e) {
2759
- var target = e.target;
2760
- if (target.tagName === 'VIDEO' || target.tagName === 'AUDIO') {
2790
+ el.addEventListener('ended', function() {
2791
+ log('Media ended event captured:', mediaType);
2761
2792
  LRS.mediaPlayed({
2762
- type: target.tagName.toLowerCase(),
2763
- src: target.src || target.currentSrc || '',
2764
- name: target.title || target.getAttribute('aria-label') || '',
2765
- currentTime: target.duration || 0,
2766
- duration: target.duration || 0,
2793
+ type: mediaType,
2794
+ src: el.src || el.currentSrc || '',
2795
+ name: getMediaName(el),
2796
+ currentTime: el.duration || 0,
2797
+ duration: el.duration || 0,
2767
2798
  action: 'completed'
2768
2799
  });
2800
+ });
2801
+ }
2802
+
2803
+ // Scan for and attach listeners to all video/audio elements
2804
+ function scanForMedia(root) {
2805
+ var elements = (root || document).querySelectorAll('video, audio');
2806
+ log('Scanning for media elements, found:', elements.length);
2807
+ for (var i = 0; i < elements.length; i++) {
2808
+ attachMediaListeners(elements[i]);
2809
+ }
2810
+ }
2811
+
2812
+ // Initial scan
2813
+ scanForMedia();
2814
+
2815
+ // Document-level capture for any we might miss
2816
+ document.addEventListener('play', function(e) {
2817
+ var target = e.target;
2818
+ if (target.tagName === 'VIDEO' || target.tagName === 'AUDIO') {
2819
+ // Attach listeners if not already tracked
2820
+ if (!trackedMedia.has(target)) {
2821
+ log('Captured play from untracked media, attaching listeners');
2822
+ attachMediaListeners(target);
2823
+ }
2769
2824
  }
2770
2825
  }, true);
2771
2826
 
2772
- log('Media interceptors set up');
2827
+ // MutationObserver to detect dynamically added video/audio elements
2828
+ var mediaObserver = new MutationObserver(function(mutations) {
2829
+ var needsScan = false;
2830
+ mutations.forEach(function(mutation) {
2831
+ mutation.addedNodes.forEach(function(node) {
2832
+ if (node.nodeType === 1) {
2833
+ if (node.tagName === 'VIDEO' || node.tagName === 'AUDIO') {
2834
+ attachMediaListeners(node);
2835
+ } else if (node.querySelectorAll) {
2836
+ // Check for nested video/audio
2837
+ var nested = node.querySelectorAll('video, audio');
2838
+ if (nested.length > 0) {
2839
+ needsScan = true;
2840
+ }
2841
+ }
2842
+ }
2843
+ });
2844
+ });
2845
+ if (needsScan) {
2846
+ scanForMedia();
2847
+ }
2848
+ });
2849
+
2850
+ // Start observing once DOM is ready
2851
+ function startMediaObserver() {
2852
+ if (document.body) {
2853
+ mediaObserver.observe(document.body, {
2854
+ childList: true,
2855
+ subtree: true
2856
+ });
2857
+ log('Media mutation observer started');
2858
+ } else {
2859
+ setTimeout(startMediaObserver, 100);
2860
+ }
2861
+ }
2862
+ startMediaObserver();
2863
+
2864
+ // Periodic rescan for Rise lazy-loaded content
2865
+ setInterval(function() {
2866
+ scanForMedia();
2867
+ }, 3000);
2868
+
2869
+ log('Media interceptors set up (enhanced)');
2773
2870
  }
2774
2871
 
2775
2872
  function setupNavigationInterceptors() {
@@ -3010,7 +3107,7 @@ function generateLrsBridgeCode(options) {
3010
3107
  // ========================================================================
3011
3108
 
3012
3109
  function init() {
3013
- log('Initializing LRS bridge v2.2.0...');
3110
+ log('Initializing LRS bridge v2.3.0...');
3014
3111
 
3015
3112
  // Extract course info early
3016
3113
  extractCourseInfo();