Greasy Fork

Greasy Fork is available in English.

Dailymotion: "Playback Quality Control" Feature

Add some site-wide video playback quality control settings to Dailymotion.

目前为 2014-07-27 提交的版本。查看 最新版本

// ==UserScript==
// @id             www.dailymotion.com-6843eec7-c1ba-4a14-8700-738e52bcb8e6@http://foo.bar/baz
// @name           Dailymotion: "Playback Quality Control" Feature
// @version        0.0.1
// @namespace      http://foo.bar/baz
// @author         David Toso
// @description    Add some site-wide video playback quality control settings to Dailymotion.
// @include        http://www.dailymotion.com/video/*
// @require        http://code.jquery.com/jquery-1.9.1.min.js
// @run-at         document-end
// ==/UserScript==

(function($){
  var uwin = unsafeWindow;
  var doc  = uwin.document;
  var vID  = uwin.DM_CurrentVideoXID;

  $('#player_main').css('background-color', '#00669d');

  // Wait for element given by selector to become available
  var waitFor = function(selector, cb) {
    if ($(selector, doc).get(0)) return cb();
    else setTimeout(function(){ waitFor(selector, cb); }, 200);
  };

  // Get a list of available 'quality' settings for the current video 
  // (in *old* API format -- convert to numeric as per *new* API).
  var getAvailableResolutions = function (video_id, cb) {
    $('#player_main').html(
      '<div id="get_res" style="width: 100%; margin-top: 160px; font-size: '+
      '22px; text-align: center; color: white; font-weight: bold">Getting '+
      'available resolutions...</div>');

    var rest_apis = 'https://api.dailymotion.com';
    GM_xmlhttpRequest({
      method: "GET",
      url: rest_apis+"/video/"+video_id+"?fields=available_formats",
      onload: function(res) {
        var obj = JSON.parse(res.responseText);
        var avail = obj.available_formats;
        var fmts = [];
        for (var i=0; i<avail.length; i++) {
          switch(avail[i]) {
            case 'ld':     fmts.push(240);  break;
            case 'sd':     fmts.push(380);  break;
            case 'hq':     fmts.push(480);  break;
            case 'hd720':  fmts.push(720);  break;
            case 'hd1080': fmts.push(1080); break;
          }
        }
        cb(fmts);
      }
    });
  };

  // Inject a 'Quality' video tab which shows the available resolutions 
  // (current highlighted), and allows the user to select the maximum
  // resolution they'd like to set on future video views
  var build_quality_tab = function(best, max, avail, auto) {

    avail = avail.map(function(e){ return e+'P'; }).join(", ");
    var re = new RegExp('(, )*('+best+'P)');
    avail = avail.replace(re, function(_all, _p, _f) { return _p+'<b>'+_f+'</b>'; });

    // find tabs & corresponding panels
    var tabs = $('.pl_video_tabs ul.mo_tabs');
    var panels = $('.pl_video_tabs');

    // Render tab
    tabs.append(
      '<li id="tab_myquality" class="pull-start mrg-end-lg"><a class="alt-link'+
      ' link-border-color-on-hvr" href="">Quality</li>');
    panels.append(
      '<div id="tab_myquality_content" class="pl_video_tabmyquality tab_content'+
      ' clearfix" style="display: none"></div>');

    // Render panel
    var myPanel = $('#tab_myquality_content');
    myPanel.append(
      '<h3 class="tab_title clearfix" style="clear:both; font-weight: normal; '+
      'font-size: 20px; color: #0079B8; font-family: arial;">Playback Quality '+
      'Settings</h3>');
    myPanel.append(
      '<p style="font-weight: normal; margin-top: 15px; font-size: 15px; color:'+
      ' black; font-family: arial;"><span style="display: inline-block; width: '+
      '188px;">Resolutions available: </span>'+avail+'</p>');
    myPanel.append(
      '<p style="font-weight: normal; margin-top: 3px; font-size: 15px; color:'+
      ' black; font-family: arial;"><span style="display: inline-block; width: '+
      '188px;">Maximum desired quality: </span><select id="my_sel_qual" style="'+
      'font-size: 12px; width: 230px; background-color: white;"><option value="'+
      '240">240P - I don\'t even</option><option value="380">380P - Low Quality'+
      '</option><option value="480">480P - Standard Definition</option><option '+
      'value="720">720P - High Quality</option><option value="1080">1080P - '+
      'Highest Quality</option></select></p>');
    myPanel.append(
      '<p style="font-weight: normal; margin-top: 3px; font-size: 15px; color:'+
      ' black; font-family: arial;"><span style="display: inline-block; width: '+
      '188px;">Automatic playback: </span><select id="my_auto_play" style="'+
      'font-size: 12px; width: 230px; background-color: white;"><option value="'+
      'Yes">Yes</option><option value="No">No</option></select></p>');

    // Record changes to max desired playback quality setting
    $('#my_sel_qual')
      .val(max)
      .change(function(){ 
        GM_setValue('max_desired_quality', $('#my_sel_qual').eq(0).val()*1); 
      });
  
    // Record changes to auto playback setting
    $('#my_auto_play')
      .val(auto)
      .change(function(){
        GM_setValue('auto_playback', $('#my_auto_play').eq(0).val());
      });
  };

  // Select the best resolution available (from the given list) or
  // the maximum desired resolution (as previously recorded) whichever
  // is lowest.
  var select_best_resolution = function (resolutions, cb) {

    // set 1080p as max desired resolution if setting has never been recorded
    if (GM_getValue('max_desired_quality',null) == null) {
      GM_setValue('max_desired_quality', 1080);
    }

    // set Yes as auto playback setting if setting has never been recorded
    if (GM_getValue('auto_playback',null) == null) {
      GM_setValue('auto_playback', 'Yes');
    }

    // choose best available resolution
    var avail = resolutions.slice(0);
    var best = resolutions.pop();

    // downgrade to desired maximum if required
    var max = GM_getValue('max_desired_quality',null);
    var auto = GM_getValue('auto_playback');
    while (best > max) { best = resolutions.pop(); }

    // fall back to 380 (seems to always be available)
    if (best == null) best = 380;

    // notify of selected resolution
    $('#player_main').html(
      '<div id="sel_res" style="width: 100%; margin-top: 160px; font-size: 22px;'+
      ' text-align: center; color: white; font-weight: bold">Selected: '+best+
      'P</div>');
    $('#sel_res')
      .fadeOut(1500, function(){ 
        $(this).remove(); 
        cb(best, auto); 
      });

    // asynchronously: build quality tab
    setTimeout(function(){ build_quality_tab(best, max, avail, auto); },1);
  };

  // Load the video associated with the current Dailymotion video page using
  // their public video embedding JavaScript API. This has some limitations
  // and quirks which need to be addressed.
  var load_video = function(video_id, quality, auto) {

    // Asynchronously load the embedding library
    // 
    // XXX: This is absolutely full of advertising crap... can we get rid of that
    //      stuff while remaining clear of copyright concerns?
    (function() {
      var e = document.createElement('script'); 
      e.async = true;
      e.src = document.location.protocol + '//api.dmcdn.net/all.js';
      var s = document.getElementsByTagName('script')[0]; 
      s.parentNode.insertBefore(e, s);
    }());

    // when the flash, iframe & API are all ready, execute some user code...
    uwin.dmAsyncInit = function()
    {
      // Configure player with previously chosen video quality.
      var params = { 
        api:      1, 
        quality:  quality,
        related:  0, 
        logo:     0, 
        info:     0, 
        autoplay: auto=='Yes'?1:0
      };

      // Actually ask for the video to be loaded! 
      var player = uwin.DM.player('player_main', {
        video:    vID, 
        width:    620, 
        height:   348, 
        params:   params
      });

      // when we can talk to the flash player via JavaScript...
      player.addEventListener("apiready", function(e)
      {
        var x = e.target.contentWindow;
        var ool = x.onload;
        //console.log(x);
        x.onload = function() {
          //console.log("TESTING! [iframe onload]");
          if (ool) ool.apply(this, arguments);
        };
      });
    };
  };

  // Prevent the normal Dailymotion player from runnning...
  waitFor('#video_player_main', function(){
    $('#video_player_main').remove();

    // XXX: For some reason the GM_xmlhttpRequest on the REST API fails
    //      unless we wait til some other things have completed.
    waitFor('.pl_video_tabs ul.mo_tabs', function(){

      // Get the available video resolutions via the REST API
      getAvailableResolutions(vID, function(resolutions) {

        // Select the appropriate video resolution and start to render 
        // the 'Quality' configuration video tab interface
        select_best_resolution(resolutions, function(best, auto) {
          
          // Request that the video be loaded by the embedded player API
          load_video(vID, best, auto);
        });
      });
    });  
  });
})(jQuery);