Moodle
  1. Moodle
  2. MDL-35365

Allow repository plug-ins determine how to preview it's files

    Details

    • Affected Branches:
      MOODLE_23_STABLE, MOODLE_24_STABLE
    • Rank:
      44040

      Description

      Problem

      I'm creating a video repository for Kaltura where all videos are uploaded and housed on a remote server. Nothing is downloaded onto the Moodle file system. All media on Kaltura is reference via a unique URL (similar to YouTube).

      The purpose of the plug-in is to allow the user to browse and select videos that belong to their Kaltura account. None of the Kaltura videos are physically stored in Moodle, instead the Kaltura repository plug-in uses the external file repository type and uses a URL address that pertains to a specific media file (for example: http://www.kaltura.com/index.php/kwidget/wid/_1234/uiconf_id/456/entry_id/asdf123/v/flash#<video name>). Navigating to this link will display the video in a Kaltura branded flash player.

      However, in Moodle 2.3 and 2.4 there is a problem when previewing a video selected from the Kaltura repository plug-in. When a video is selected, the preview iframe is blank (in the case of Moodle 2.4 it returns an error message).

      I've been able to determine the cause of the problem in Moodle 2.3 and 2.4, when it previously was not a problem in Moodle 2.0 - 2.2.

      In pre Moodle 2.3 the core code was written to specifically handle youtube links in order for it to display properly (details in MDL-33390). Luckily I was able to add a workaround to have the Kaltura videos display properly. The workaround was to add a /v/flash#video_name to the end of the URL to instruct Moodle to create the proper embed markup.

      With Moodle 2.3 (and 2.4) this system has changed with the introduction of using an iframe in the preview dialog and relying on lib/medialib.php to determine the file extension (or URL) and using a player that suits the cirteria (similar to how the filter plug-ins work). Youtube (which is a video repository much like Kaltura is) gets core treatment in this area in order for it to work properly.

      The main problem is that the Kaltura video links do not match any criteria used by Moodle standard media players in addition to the fact that there is no way for a repository plug-in to determine how to preview the selected file. The former is not an issue becuase a filter plug-in can be created to handle the links. However the latter is the issue of most concern as core code handles it.

      Examples in the code

      The following code snippets (from Moodle 2.3) are meant to help illustrate the problem I'm having with the preview code.

      In the Kaltura repository code, a video listing is generated. Kaltura has the ability for user to upload video, images and music files. The purpose of the $video->name . '.mpg' line is to force Moodle to display a video listing icon (when not viewing files in icon mode in the file picker). The source URL is created and all other array elements are generically created. Notice the source url http://www.kaltura.com/index.php/kwidget/wid/_787032/uiconf_id/6709411/entry_id/1_h2no1nvq/v/flash

              switch ($video->mediaType) {
                  case KalturaMediaType::AUDIO:  // May need a special case to handle audio files
                  case KalturaMediaType::VIDEO:
                      $name = $video->name . '.mpg'; // Manually adding an image extension.  This is only to force moodle to display the correct icons
                      $source = $uri .'/index.php/kwidget/wid/_'.$partner_id.
                                '/uiconf_id/'.$uiconf_id.'/entry_id/' . $video->id . '/v/flash#'.
                                $video->name .'';
                      break;
      
                  case KalturaMediaType::IMAGE:
                      $name = $video->name . '.png'; // Manually adding an image extension.  This is only to force moodle to display the correct icons
                      $source = $video->thumbnailUrl . '/height/200/width/300/type/1/v/flash#'. $video->name;
                      break;
                  default:
                      $name   = 'Unknown Media Type';
                      $source = 'Unknown Media Type';
      
              }
      
              $results[] = array('title' => $name,
                                 'shorttitle' => $video->name,
                                 'date' => userdate($video->updatedAt),
                                 'thumbnail' => $video->thumbnailUrl,
                                 'thumbnail_width' => 150,
                                 'thumbnail_height' => 70,
                                 'source' =>  $source,
                                 'hasauthor' => true,
                                 //'url' => '',
                                 'haslicense' => true
                                  );
      

      When the user selects a file from the repository, the lib/editor/tinymce/tiny_mce/3.5.1.1/plugins/moodlemedia/js/media.js script changes the inner HTML of a div to an iframe where the source url is *http://localhost/ack/kaltura.git/lib/editor/tinymce/tiny_mce/3.5.1.1/plugins/moodlemedia/preview.php?path=http://www.kaltura.com/index.php/kwidget/wid/_787032/uiconf_id/6709411/entry_id/1_h2no1nvq/v/flash*.

      function generatePreview(c) {
          var f = document.forms[0], p = document.getElementById('prev');
      
          p.innerHTML = '<!-- x --->';
          var re = new RegExp("(.+)\#(.+)", "i");
          var result = f.src.value.match(re);
          if (result) {
              f.src.value = result[1];
              f.filename.value = result[2];
          } else {
              f.src.value = f.src.value;
              f.filename.value = f.src.value;
          }
      
          // After constrain
          var pl = serializeParameters();
          if (pl == '') {
                  p.innerHTML = '';
                  return;
          }
      
          pl = tinyMCEPopup.editor.plugins.moodlemedia._parse(pl);
      
          if (!pl.src) {
                  p.innerHTML = '';
                  return;
          }
      
          pl.src = tinyMCEPopup.editor.documentBaseURI.toAbsolute(pl.src);
          // NOTE: Do not try to prevent https security popups here - users would get them later on real page anyway!
      
          // We can not include URL directly in parameters because some security filters might block it.
          p.innerHTML = '<iframe src="' + tinyMCE.baseURL + '/plugins/moodlemedia/preview.php'
              + '?path=' + encodeURIComponent(encode64(pl.src.toString()))
              + '&sesskey=' + encodeURIComponent(parent.M.cfg.sesskey)
              + '" width="100%" height="100%"></iframe>';
      }
      

      In preview.php the core media renderer is passed the URL. Inside the core media renderer all of the media players are passed the URL to determine whether it is a file that can be played. Most of them check the extension of the file contained in the URL. The youtube media player class checks to see if www.youtube.com is found in the URL; then returns the embed markup needed to display a Youtube video

      // URL to the media.
      $path = required_param('path', PARAM_RAW);
      $path = base64_decode($path);
      $url = clean_param($path, PARAM_URL);
      $url = new moodle_url($url);
      
      $editor = new tinymce_texteditor();
      
      // Now output this file which is super-simple.
      $PAGE->set_pagelayout('embedded');
      $PAGE->set_url(new moodle_url('/lib/editor/tinymce/tiny_mce/'.$editor->version.'/plugins/moodlemedia/preview.php',
              array('path' => base64_encode($path))));
      $PAGE->set_context(context_system::instance());
      $PAGE->add_body_class('core_media_preview');
      
      echo $OUTPUT->header();
      
      $mediarenderer = $PAGE->get_renderer('core', 'media');
      
      if ($mediarenderer->can_embed_url($url)) {
          echo $mediarenderer->embed_url($url);
      }
      echo $url;
      
      echo $OUTPUT->footer();
      
      /**
       * Player that creates YouTube embedding.
       *
       * @copyright 2011 The Open University
       * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
       */
      class core_media_player_youtube extends core_media_player_external {
          protected function embed_external(moodle_url $url, $name, $width, $height, $options) {
              global $CFG;
      
              $site = 'www.youtube.com';
              $videoid = end($this->matches);
      
              $info = trim($name);
              if (empty($info) or strpos($info, 'http') === 0) {
                  $info = get_string('siteyoutube', 'core_media');
              }
              $info = s($info);
      
              self::pick_video_size($width, $height);
      
              if (empty($CFG->xmlstrictheaders)) {
                  return <<<OET
      <span class="mediaplugin mediaplugin_youtube">
      <iframe title="$info" width="$width" height="$height" src="https://$site/embed/$videoid?rel=0&wmode=transparent" frameborder="0" allowfullscreen="1"></iframe>
      </span>
      OET;
              }
      
              // NOTE: we can not use any link fallback because it breaks built-in
              // player on iOS devices.
              $output = <<<OET
      <span class="mediaplugin mediaplugin_youtube">
      <object title="$info" type="application/x-shockwave-flash"
        data="https://$site/v/$videoid&amp;fs=1&amp;rel=0" width="$width" height="$height">
       <param name="movie" value="$site/v/$videoid&amp;fs=1&amp;rel=0" />
       <param name="FlashVars" value="playerMode=embedded" />
       <param name="allowFullScreen" value="true" />
      </object>
      </span>
      OET;
      
              return $output;
          }
      
          protected function get_regex() {
              // Regex for standard youtube link
               $link = '(youtube(-nocookie)?\.com/(?:watch\?v=|v/))';
              // Regex for shortened youtube link
              $shortlink = '((youtu|y2u)\.be/)';
      
              // Initial part of link.
               $start = '~^https?://(www\.)?(' . $link . '|' . $shortlink . ')';
              // Middle bit: Video key value
              $middle = '([a-z0-9\-_]+)';
              return $start . $middle . core_media_player_external::END_LINK_REGEX_PART;
          }
      
          public function get_rank() {
              // I decided to make the link-embedding ones (that don't handle file
              // formats) have ranking in the 1000 range.
              return 1001;
          }
      
          public function get_embeddable_markers() {
              return array('youtube.com', 'youtube-nocookie.com', 'youtu.be', 'y2u.be');
          }
      }
      

      As you can see the core code doesn't allow for external media repositories (that use URL with no file extention information) to properly preview the coutent before it is inserted by the user.

      Proposal

      Allow repository plug-ins to generate their own embed/preview markup that can be used by the preview popup. Have an abstract preview class that can be overridden by a repository sub class, where embed markup can be returned to preview.php and the output echoed back to the iframe inner HTML.

      The preview.php script can determine exactly which repository plug-in the URL is from if it is passed the repository id; once the id is passed to preview.php it can use the repository static method public static function get_repository_by_id($repositoryid, $context, $options = array()) and then call the preview overridden method.

      Why change the way it works

      1. Media repositories that work along the same lines as Youtube will run into the same difficult where Moodle core renderer will not know what to do with the URL.
      2. Greater flexibility to determine how to handle the previewing of a file (example: having a company branded player used to preview the media file, or better handling of a non standard media format)
      3. When changes need to be made maintainers only need to update code for their plug-in and not core rendering code

      Let's open a discussion

      I'm interested in hearing your thoughs about this proposal. As it has an effect on Moodle 2.3 and Moodle 2.4 (I've already tested against master) which is currently in development and I would like to create a plug-in that is fully supported by Moodle's core code.

      Thanks

        Issue Links

          Activity

          Hide
          Akin Delamarre added a comment -

          Just checking in to see if there is any comment or feedback regarding this improvement issue....

          Show
          Akin Delamarre added a comment - Just checking in to see if there is any comment or feedback regarding this improvement issue....
          Hide
          Akin Delamarre added a comment -

          Updating this proposal to include Moodle 2.4 is having this problem. Let's start a discussion on how to make things better.

          Show
          Akin Delamarre added a comment - Updating this proposal to include Moodle 2.4 is having this problem. Let's start a discussion on how to make things better.
          Hide
          Akin Delamarre added a comment -

          Ping? Thoughts?

          Show
          Akin Delamarre added a comment - Ping? Thoughts?
          Hide
          Jean-Michel Vedrine added a comment -

          Hello Akin,
          Have you seen MDL-35729 which is currently waiting integration ?
          I suggest to study if it could satisfy the need of your Kaltura plugin.

          Show
          Jean-Michel Vedrine added a comment - Hello Akin, Have you seen MDL-35729 which is currently waiting integration ? I suggest to study if it could satisfy the need of your Kaltura plugin.
          Hide
          Akin Delamarre added a comment -

          Thanks for the heads up Jean-Michael. I have posted a comment in the task. Based on the discussion, it seems that it only pertains to repositories that host image files. However having repository utilize a preview callback it definitely on the right track.

          Hopefully I can bring some more attention to this issue. Fingers crossed.

          Show
          Akin Delamarre added a comment - Thanks for the heads up Jean-Michael. I have posted a comment in the task. Based on the discussion, it seems that it only pertains to repositories that host image files. However having repository utilize a preview callback it definitely on the right track. Hopefully I can bring some more attention to this issue. Fingers crossed.
          Hide
          Akin Delamarre added a comment -

          Jean, any word on considering this improvement? I stress this issue because with the way Moodle has implemented their filepicker preview, other video repositories (similar to youtube) will not have the ability to display a preview of their videos.

          Show
          Akin Delamarre added a comment - Jean, any word on considering this improvement? I stress this issue because with the way Moodle has implemented their filepicker preview, other video repositories (similar to youtube) will not have the ability to display a preview of their videos.
          Hide
          Jean-Michel Vedrine added a comment -

          Hello Akin,
          I only pointed the relations between this issue and MDL-35729 so that you can be warned that somebody else(Dongsheng Cai) has submitted code in the same area, but you should discuss this not with me but with Marina Glancy or Frederic Massard because they are the people that can consider your proposal and say yes or not.
          I also suggest you wait that MDL-35729 be integrated before going further because maybe modifications to the code in MDL-35729 will be made during the integration process.

          Show
          Jean-Michel Vedrine added a comment - Hello Akin, I only pointed the relations between this issue and MDL-35729 so that you can be warned that somebody else(Dongsheng Cai) has submitted code in the same area, but you should discuss this not with me but with Marina Glancy or Frederic Massard because they are the people that can consider your proposal and say yes or not. I also suggest you wait that MDL-35729 be integrated before going further because maybe modifications to the code in MDL-35729 will be made during the integration process.
          Hide
          Marina Glancy added a comment -

          This very much looks like a duplicate of MDL-35729

          This issue was assigned to me automatically, however I will not be able to work on this issue in the immediate future. In order to create a truer sense of the state of this issue and to allow other developers to have chance to become involved, I am removing myself as the assignee of this issue.

          For more information, see http://docs.moodle.org/dev/Changes_to_issue_assignment

          Show
          Marina Glancy added a comment - This very much looks like a duplicate of MDL-35729 This issue was assigned to me automatically, however I will not be able to work on this issue in the immediate future. In order to create a truer sense of the state of this issue and to allow other developers to have chance to become involved, I am removing myself as the assignee of this issue. For more information, see http://docs.moodle.org/dev/Changes_to_issue_assignment

            People

            • Votes:
              1 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated: