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