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-31 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @id             www.dailymotion.com-6843eec7-c1ba-4a14-8700-738e52bcb8e6@http://foo.bar/baz
// @name           Dailymotion: "Playback Quality Control" Feature
// @version        0.0.5
// @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/*
// @require        http://code.jquery.com/jquery-1.9.1.min.js
// @run-at         document-start
// ==/UserScript==

// Magic Sauce: prevent the standard Dailymotion Player's JavaScript 
// from ever loading!
window.addEventListener('beforescriptexecute', function(e) {
  if (/window\.DM_Player_Type/.test(e.target.text)) {
    // attempt to block the standard player JS from loading
    // for video & member pages
    console.log("stopped standard player from loading! [DM_Player_Type]");
    e.stopPropagation();
    e.preventDefault();
  } else if (/playerPlaying/.test(e.target.text)) {
    // attempt to block the standard player JS from loading
    // for playlist pages
    console.log("stopped standard player from loading! [playerPlaying]");
    e.stopPropagation();
    e.preventDefault();
  }
}, true);

// 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 (vID, cID, cb) {
  console.log("inside GAR");
  $('#'+cID).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/"+vID+"?fields=available_formats",
    onload: function(res) {
      console.log("GOT resolutions");
      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);
    },
    onerror: function(res) {
      console.log("problem getting available resolutions!");
    }
  });
};


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

// 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, cID, 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
  $('#'+cID).html(
    '<div id="sel_res" style="width: 100%; margin-top: 130px; font-size: 55px;'+
    ' text-align: center; color: white; font-weight: bold">'+best+'P</div>');
  $('#sel_res')
    .fadeOut(1500, function(){ 
      $(this).remove(); 
      cb(best, auto); 
    });

  // asynchronously: build quality tab
  waitFor(document,'.pl_video_tabs ul.mo_tabs', function(){
    build_quality_tab(best, max, avail, auto);
  });
};

// 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());
    });
};

// synchronize readiness of DM Player embedding API and Quality Selection
var when_ready = function(uwin, cb) {
  if ((uwin.__DM_JS_READY == 1) && (uwin.__RES_CHOSEN == 1)) return cb();
  else setTimeout(function(){ when_ready(uwin, cb); }, 50);
};

// load the dailymotion embedded player
var load_embedded_player = function(uwin, quality, auto, cID, vID) {

  // 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(cID, {
    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;
    x.onload = function() {

      //$('#player_container').css({ height: 348 });
      console.log("FLASHPLAYER JS API is ready!");
    };
  });
};

// main script entry point
var once = 0;
window.addEventListener('DOMContentLoaded', function(e) {
  if (once) return; once = 1;
  var uwin = unsafeWindow;
  var doc  = uwin.document;

  // Determine whether we're dealing with a Video page, a Playlist page, or a 
  // Member's home page (the User Interface Mode)
  var uiMode;
  if (uwin.DM_CurrentVideoXID) uiMode = 'video';
  if ($('#js-playlist-name').get(0)) uiMode = 'playlist';
  if ($('.user-screenname-inner').get(0)) uiMode = 'member';
  if (!uiMode) return; // don't bother doing the rest if there's no player
  console.log("uiMode="+uiMode);

  // Wait until both Player & Quality selection are ready
  when_ready(uwin, function(){
    console.log("BOTH ARE READY!");
    //if (uiMode != 'video') return;
    load_embedded_player(uwin, 
      uwin.__RES_SETTINGS.quality,
      uwin.__RES_SETTINGS.autoplay,
      uwin.__RES_SETTINGS.container,
      uwin.__RES_SETTINGS.video);
  });

  // Async-load the DM embedded JS API
  (function() {
    var e = doc.createElement('script'); 
    e.async = true;
    e.src = doc.location.protocol + '//api.dmcdn.net/all.js';
    var s = doc.getElementsByTagName('script')[0]; 
    uwin.dmAsyncInit = function() {
      console.log("DM Player API loaded!");
      uwin.__DM_JS_READY = 1;
    };
    s.parentNode.insertBefore(e, s);
  }());

  // Based on the uiMode, find the "currently playing" video ID as well as the
  // container element that will house the embedded DM video player
  var vID, pID, cID;
  switch(uiMode) {
    case 'video': 
      vID = uwin.DM_CurrentVideoXID; 
      cID = 'container_player_main';
      break;
    case 'playlist': 
      vID = $('.js-list-list > div.media > div.media-img',doc)
        .eq(0).attr('data-id'); 
      cID = 'container_main_player';
      break;
    case 'member':
      $('#js-featured-card-title > a')
        .eq(0).attr('href').replace(/\/video\/([^_]+)/, function(_m, _x) { 
          vID = _x; });
      cID = 'container_player_main';
      break; 
  }
  console.log("VID="+vID);

  // Get a list of available resolutions for the "currently playing" video, 
  // then compare that to the users's max desired quality & autoplay
  // preferences before configuring and loading the DM embedded player.
  $('#'+cID).css('background-color', '#00669d');
  getAvailableResolutions(vID, cID, function(resolutions){
    console.log("smeg");
    select_best_resolution(resolutions, cID, function(chosen, auto){
      console.log("selected="+chosen+",autoplay="+auto);
      uwin.__RES_SETTINGS = { 
        quality:    chosen, 
        autoplay:   auto, 
        container:  cID, 
        video:      vID 
      };
      uwin.__RES_CHOSEN = 1;  
    });
  });  

}, true);