@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/cli.js CHANGED
@@ -3062,49 +3062,146 @@ function generateLrsBridgeCode(options) {
3062
3062
  function setupMediaInterceptors() {
3063
3063
  if (!TRACK_MEDIA) return;
3064
3064
 
3065
- document.addEventListener('play', function(e) {
3066
- var target = e.target;
3067
- if (target.tagName === 'VIDEO' || target.tagName === 'AUDIO') {
3065
+ // Track which elements we've already attached listeners to
3066
+ var trackedMedia = new WeakSet();
3067
+
3068
+ // Helper to get media name/title from element or surrounding context
3069
+ function getMediaName(el) {
3070
+ // Check element attributes
3071
+ var name = el.title || el.getAttribute('aria-label') || el.getAttribute('data-name');
3072
+ if (name) return name;
3073
+
3074
+ // Check parent Rise video block for title
3075
+ var videoBlock = findClosest(el, '[data-block-type="video"], .blocks-video, .video-block');
3076
+ if (videoBlock) {
3077
+ var titleEl = videoBlock.querySelector('.video-title, .block-title, [class*="title"]');
3078
+ if (titleEl) return titleEl.textContent.trim();
3079
+ }
3080
+
3081
+ // Use src filename as fallback
3082
+ var src = el.src || el.currentSrc || '';
3083
+ if (src) {
3084
+ var filename = src.split('/').pop().split('?')[0];
3085
+ if (filename && filename.length < 100) return filename;
3086
+ }
3087
+
3088
+ return el.tagName.toLowerCase();
3089
+ }
3090
+
3091
+ // Attach media event listeners to a single element
3092
+ function attachMediaListeners(el) {
3093
+ if (trackedMedia.has(el)) return;
3094
+ trackedMedia.add(el);
3095
+
3096
+ var mediaType = el.tagName.toLowerCase();
3097
+ log('Attaching media listeners to:', mediaType, el.src || el.currentSrc || 'no-src');
3098
+
3099
+ el.addEventListener('play', function() {
3100
+ log('Media play event captured:', mediaType);
3068
3101
  LRS.mediaPlayed({
3069
- type: target.tagName.toLowerCase(),
3070
- src: target.src || target.currentSrc || '',
3071
- name: target.title || target.getAttribute('aria-label') || '',
3072
- currentTime: target.currentTime || 0,
3073
- duration: target.duration || 0,
3102
+ type: mediaType,
3103
+ src: el.src || el.currentSrc || '',
3104
+ name: getMediaName(el),
3105
+ currentTime: el.currentTime || 0,
3106
+ duration: el.duration || 0,
3074
3107
  action: 'play'
3075
3108
  });
3076
- }
3077
- }, true);
3109
+ });
3078
3110
 
3079
- document.addEventListener('pause', function(e) {
3080
- var target = e.target;
3081
- if (target.tagName === 'VIDEO' || target.tagName === 'AUDIO') {
3111
+ el.addEventListener('pause', function() {
3112
+ // Ignore pause events that fire right before ended
3113
+ if (el.ended) return;
3114
+ log('Media pause event captured:', mediaType);
3082
3115
  LRS.mediaPlayed({
3083
- type: target.tagName.toLowerCase(),
3084
- src: target.src || target.currentSrc || '',
3085
- name: target.title || target.getAttribute('aria-label') || '',
3086
- currentTime: target.currentTime || 0,
3087
- duration: target.duration || 0,
3116
+ type: mediaType,
3117
+ src: el.src || el.currentSrc || '',
3118
+ name: getMediaName(el),
3119
+ currentTime: el.currentTime || 0,
3120
+ duration: el.duration || 0,
3088
3121
  action: 'pause'
3089
3122
  });
3090
- }
3091
- }, true);
3123
+ });
3092
3124
 
3093
- document.addEventListener('ended', function(e) {
3094
- var target = e.target;
3095
- if (target.tagName === 'VIDEO' || target.tagName === 'AUDIO') {
3125
+ el.addEventListener('ended', function() {
3126
+ log('Media ended event captured:', mediaType);
3096
3127
  LRS.mediaPlayed({
3097
- type: target.tagName.toLowerCase(),
3098
- src: target.src || target.currentSrc || '',
3099
- name: target.title || target.getAttribute('aria-label') || '',
3100
- currentTime: target.duration || 0,
3101
- duration: target.duration || 0,
3128
+ type: mediaType,
3129
+ src: el.src || el.currentSrc || '',
3130
+ name: getMediaName(el),
3131
+ currentTime: el.duration || 0,
3132
+ duration: el.duration || 0,
3102
3133
  action: 'completed'
3103
3134
  });
3135
+ });
3136
+ }
3137
+
3138
+ // Scan for and attach listeners to all video/audio elements
3139
+ function scanForMedia(root) {
3140
+ var elements = (root || document).querySelectorAll('video, audio');
3141
+ log('Scanning for media elements, found:', elements.length);
3142
+ for (var i = 0; i < elements.length; i++) {
3143
+ attachMediaListeners(elements[i]);
3144
+ }
3145
+ }
3146
+
3147
+ // Initial scan
3148
+ scanForMedia();
3149
+
3150
+ // Document-level capture for any we might miss
3151
+ document.addEventListener('play', function(e) {
3152
+ var target = e.target;
3153
+ if (target.tagName === 'VIDEO' || target.tagName === 'AUDIO') {
3154
+ // Attach listeners if not already tracked
3155
+ if (!trackedMedia.has(target)) {
3156
+ log('Captured play from untracked media, attaching listeners');
3157
+ attachMediaListeners(target);
3158
+ }
3104
3159
  }
3105
3160
  }, true);
3106
3161
 
3107
- log('Media interceptors set up');
3162
+ // MutationObserver to detect dynamically added video/audio elements
3163
+ var mediaObserver = new MutationObserver(function(mutations) {
3164
+ var needsScan = false;
3165
+ mutations.forEach(function(mutation) {
3166
+ mutation.addedNodes.forEach(function(node) {
3167
+ if (node.nodeType === 1) {
3168
+ if (node.tagName === 'VIDEO' || node.tagName === 'AUDIO') {
3169
+ attachMediaListeners(node);
3170
+ } else if (node.querySelectorAll) {
3171
+ // Check for nested video/audio
3172
+ var nested = node.querySelectorAll('video, audio');
3173
+ if (nested.length > 0) {
3174
+ needsScan = true;
3175
+ }
3176
+ }
3177
+ }
3178
+ });
3179
+ });
3180
+ if (needsScan) {
3181
+ scanForMedia();
3182
+ }
3183
+ });
3184
+
3185
+ // Start observing once DOM is ready
3186
+ function startMediaObserver() {
3187
+ if (document.body) {
3188
+ mediaObserver.observe(document.body, {
3189
+ childList: true,
3190
+ subtree: true
3191
+ });
3192
+ log('Media mutation observer started');
3193
+ } else {
3194
+ setTimeout(startMediaObserver, 100);
3195
+ }
3196
+ }
3197
+ startMediaObserver();
3198
+
3199
+ // Periodic rescan for Rise lazy-loaded content
3200
+ setInterval(function() {
3201
+ scanForMedia();
3202
+ }, 3000);
3203
+
3204
+ log('Media interceptors set up (enhanced)');
3108
3205
  }
3109
3206
 
3110
3207
  function setupNavigationInterceptors() {
@@ -3345,7 +3442,7 @@ function generateLrsBridgeCode(options) {
3345
3442
  // ========================================================================
3346
3443
 
3347
3444
  function init() {
3348
- log('Initializing LRS bridge v2.2.0...');
3445
+ log('Initializing LRS bridge v2.3.0...');
3349
3446
 
3350
3447
  // Extract course info early
3351
3448
  extractCourseInfo();