Access Iframe Content

I'm trying to access a video inside an iframe, but I am getting the error "Permission denied to access property x on cross-origin object" for the innerDoc video. The iframe is youtube, so I have this as my userscript property:

// @include https://original-website.com/*
// @match *.youtube.com/*

And here is my javascript:

    var video, mode, iframe, innerDoc;

    $('.speed-control button').on('click', (evt) => {

        mode = $(event.target).attr('class').match(/speed-control-(.*)/)[1];        
        iframe = document.getElementById('videoPlayer_Youtube_api');
        innerDoc = (iframe.contentWindow || iframe.contentDocument);
        video = innerDoc.querySelectorAll('video');

        switch(mode){
            case 'slow':
                video.playbackRate  = 0.5;
                break;
            case 'normal':
                video.playbackRate  = 1;
                break;
            case 'fast':
                video.playbackRate  = 2;
                break;
            default:
        }

    });

Viestejä yhteensä

  • Modern browsers can't access a cross-domain iframe contents directly. Since your userscript runs both on the main page and inside the iframe you can use cross-window messaging:

    const MSG_PREFIX = GM_info.script.name + '\n';
    
    if (window === top) {
    
      $('.speed-control button').on('click', function () {
        const payload = JSON.stringify({
          action: 'speedControl',
          data: this.className.match(/speed-control-(.*)/)[1],
        });
        const iframe = document.getElementById('videoPlayer_Youtube_api');
        iframe.contentWindow.postMessage(MSG_PREFIX + payload, '*');
      });
    
    } else if (location.hostname.endsWith('youtube.com')) {
    
      const ACTIONS = {
        speedControl(mode) {
          switch (mode) {
            case 'slow':
              video.playbackRate = 0.5;
              break;
            case 'normal':
              video.playbackRate = 1;
              break;
            case 'fast':
              video.playbackRate = 2;
              break;
            default:
          }
        },
      };
    
      window.addEventListener('message', e => {
        if (typeof e.data === 'string' && e.data.startsWith(MSG_PREFIX)) {
          try {
            const payload = e.data.slice(MSG_PREFIX.length);
            const {action, data} = JSON.parse(payload);
            if (ACTIONS.hasOwnProperty(action)) {
              ACTIONS[action](data);
            }
          }
          catch (ex) {}
        }
      });
    
    }
    
  • Thank you so much! I just had to define the video variable but other than that, your code works really well. Gonna look into postMessage more to understand it better.

Kirjaudu sisään tai Rekisteröidy kommentoidaksesi.