Dailymotion: "Playback Quality Control" Feature

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

当前为 2014-07-27 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @id www.dailymotion.com-6843eec7-c1ba-4a14-8700-738e52bcb8e6@http://foo.bar/baz
  3. // @name Dailymotion: "Playback Quality Control" Feature
  4. // @version 0.0.1
  5. // @namespace http://foo.bar/baz
  6. // @author David Toso
  7. // @description Add some site-wide video playback quality control settings to Dailymotion.
  8. // @include http://www.dailymotion.com/video/*
  9. // @require http://code.jquery.com/jquery-1.9.1.min.js
  10. // @run-at document-end
  11. // ==/UserScript==
  12.  
  13. (function($){
  14. var uwin = unsafeWindow;
  15. var doc = uwin.document;
  16. var vID = uwin.DM_CurrentVideoXID;
  17.  
  18. $('#player_main').css('background-color', '#00669d');
  19.  
  20. // Wait for element given by selector to become available
  21. var waitFor = function(selector, cb) {
  22. if ($(selector, doc).get(0)) return cb();
  23. else setTimeout(function(){ waitFor(selector, cb); }, 200);
  24. };
  25.  
  26. // Get a list of available 'quality' settings for the current video
  27. // (in *old* API format -- convert to numeric as per *new* API).
  28. var getAvailableResolutions = function (video_id, cb) {
  29. $('#player_main').html(
  30. '<div id="get_res" style="width: 100%; margin-top: 160px; font-size: '+
  31. '22px; text-align: center; color: white; font-weight: bold">Getting '+
  32. 'available resolutions...</div>');
  33.  
  34. var rest_apis = 'https://api.dailymotion.com';
  35. GM_xmlhttpRequest({
  36. method: "GET",
  37. url: rest_apis+"/video/"+video_id+"?fields=available_formats",
  38. onload: function(res) {
  39. var obj = JSON.parse(res.responseText);
  40. var avail = obj.available_formats;
  41. var fmts = [];
  42. for (var i=0; i<avail.length; i++) {
  43. switch(avail[i]) {
  44. case 'ld': fmts.push(240); break;
  45. case 'sd': fmts.push(380); break;
  46. case 'hq': fmts.push(480); break;
  47. case 'hd720': fmts.push(720); break;
  48. case 'hd1080': fmts.push(1080); break;
  49. }
  50. }
  51. cb(fmts);
  52. }
  53. });
  54. };
  55.  
  56. // Inject a 'Quality' video tab which shows the available resolutions
  57. // (current highlighted), and allows the user to select the maximum
  58. // resolution they'd like to set on future video views
  59. var build_quality_tab = function(best, max, avail, auto) {
  60.  
  61. avail = avail.map(function(e){ return e+'P'; }).join(", ");
  62. var re = new RegExp('(, )*('+best+'P)');
  63. avail = avail.replace(re, function(_all, _p, _f) { return _p+'<b>'+_f+'</b>'; });
  64.  
  65. // find tabs & corresponding panels
  66. var tabs = $('.pl_video_tabs ul.mo_tabs');
  67. var panels = $('.pl_video_tabs');
  68.  
  69. // Render tab
  70. tabs.append(
  71. '<li id="tab_myquality" class="pull-start mrg-end-lg"><a class="alt-link'+
  72. ' link-border-color-on-hvr" href="">Quality</li>');
  73. panels.append(
  74. '<div id="tab_myquality_content" class="pl_video_tabmyquality tab_content'+
  75. ' clearfix" style="display: none"></div>');
  76.  
  77. // Render panel
  78. var myPanel = $('#tab_myquality_content');
  79. myPanel.append(
  80. '<h3 class="tab_title clearfix" style="clear:both; font-weight: normal; '+
  81. 'font-size: 20px; color: #0079B8; font-family: arial;">Playback Quality '+
  82. 'Settings</h3>');
  83. myPanel.append(
  84. '<p style="font-weight: normal; margin-top: 15px; font-size: 15px; color:'+
  85. ' black; font-family: arial;"><span style="display: inline-block; width: '+
  86. '188px;">Resolutions available: </span>'+avail+'</p>');
  87. myPanel.append(
  88. '<p style="font-weight: normal; margin-top: 3px; font-size: 15px; color:'+
  89. ' black; font-family: arial;"><span style="display: inline-block; width: '+
  90. '188px;">Maximum desired quality: </span><select id="my_sel_qual" style="'+
  91. 'font-size: 12px; width: 230px; background-color: white;"><option value="'+
  92. '240">240P - I don\'t even</option><option value="380">380P - Low Quality'+
  93. '</option><option value="480">480P - Standard Definition</option><option '+
  94. 'value="720">720P - High Quality</option><option value="1080">1080P - '+
  95. 'Highest Quality</option></select></p>');
  96. myPanel.append(
  97. '<p style="font-weight: normal; margin-top: 3px; font-size: 15px; color:'+
  98. ' black; font-family: arial;"><span style="display: inline-block; width: '+
  99. '188px;">Automatic playback: </span><select id="my_auto_play" style="'+
  100. 'font-size: 12px; width: 230px; background-color: white;"><option value="'+
  101. 'Yes">Yes</option><option value="No">No</option></select></p>');
  102.  
  103. // Record changes to max desired playback quality setting
  104. $('#my_sel_qual')
  105. .val(max)
  106. .change(function(){
  107. GM_setValue('max_desired_quality', $('#my_sel_qual').eq(0).val()*1);
  108. });
  109. // Record changes to auto playback setting
  110. $('#my_auto_play')
  111. .val(auto)
  112. .change(function(){
  113. GM_setValue('auto_playback', $('#my_auto_play').eq(0).val());
  114. });
  115. };
  116.  
  117. // Select the best resolution available (from the given list) or
  118. // the maximum desired resolution (as previously recorded) whichever
  119. // is lowest.
  120. var select_best_resolution = function (resolutions, cb) {
  121.  
  122. // set 1080p as max desired resolution if setting has never been recorded
  123. if (GM_getValue('max_desired_quality',null) == null) {
  124. GM_setValue('max_desired_quality', 1080);
  125. }
  126.  
  127. // set Yes as auto playback setting if setting has never been recorded
  128. if (GM_getValue('auto_playback',null) == null) {
  129. GM_setValue('auto_playback', 'Yes');
  130. }
  131.  
  132. // choose best available resolution
  133. var avail = resolutions.slice(0);
  134. var best = resolutions.pop();
  135.  
  136. // downgrade to desired maximum if required
  137. var max = GM_getValue('max_desired_quality',null);
  138. var auto = GM_getValue('auto_playback');
  139. while (best > max) { best = resolutions.pop(); }
  140.  
  141. // fall back to 380 (seems to always be available)
  142. if (best == null) best = 380;
  143.  
  144. // notify of selected resolution
  145. $('#player_main').html(
  146. '<div id="sel_res" style="width: 100%; margin-top: 160px; font-size: 22px;'+
  147. ' text-align: center; color: white; font-weight: bold">Selected: '+best+
  148. 'P</div>');
  149. $('#sel_res')
  150. .fadeOut(1500, function(){
  151. $(this).remove();
  152. cb(best, auto);
  153. });
  154.  
  155. // asynchronously: build quality tab
  156. setTimeout(function(){ build_quality_tab(best, max, avail, auto); },1);
  157. };
  158.  
  159. // Load the video associated with the current Dailymotion video page using
  160. // their public video embedding JavaScript API. This has some limitations
  161. // and quirks which need to be addressed.
  162. var load_video = function(video_id, quality, auto) {
  163.  
  164. // Asynchronously load the embedding library
  165. //
  166. // XXX: This is absolutely full of advertising crap... can we get rid of that
  167. // stuff while remaining clear of copyright concerns?
  168. (function() {
  169. var e = document.createElement('script');
  170. e.async = true;
  171. e.src = document.location.protocol + '//api.dmcdn.net/all.js';
  172. var s = document.getElementsByTagName('script')[0];
  173. s.parentNode.insertBefore(e, s);
  174. }());
  175.  
  176. // when the flash, iframe & API are all ready, execute some user code...
  177. uwin.dmAsyncInit = function()
  178. {
  179. // Configure player with previously chosen video quality.
  180. var params = {
  181. api: 1,
  182. quality: quality,
  183. related: 0,
  184. logo: 0,
  185. info: 0,
  186. autoplay: auto=='Yes'?1:0
  187. };
  188.  
  189. // Actually ask for the video to be loaded!
  190. var player = uwin.DM.player('player_main', {
  191. video: vID,
  192. width: 620,
  193. height: 348,
  194. params: params
  195. });
  196.  
  197. // when we can talk to the flash player via JavaScript...
  198. player.addEventListener("apiready", function(e)
  199. {
  200. var x = e.target.contentWindow;
  201. var ool = x.onload;
  202. //console.log(x);
  203. x.onload = function() {
  204. //console.log("TESTING! [iframe onload]");
  205. if (ool) ool.apply(this, arguments);
  206. };
  207. });
  208. };
  209. };
  210.  
  211. // Prevent the normal Dailymotion player from runnning...
  212. waitFor('#video_player_main', function(){
  213. $('#video_player_main').remove();
  214.  
  215. // XXX: For some reason the GM_xmlhttpRequest on the REST API fails
  216. // unless we wait til some other things have completed.
  217. waitFor('.pl_video_tabs ul.mo_tabs', function(){
  218.  
  219. // Get the available video resolutions via the REST API
  220. getAvailableResolutions(vID, function(resolutions) {
  221.  
  222. // Select the appropriate video resolution and start to render
  223. // the 'Quality' configuration video tab interface
  224. select_best_resolution(resolutions, function(best, auto) {
  225. // Request that the video be loaded by the embedded player API
  226. load_video(vID, best, auto);
  227. });
  228. });
  229. });
  230. });
  231. })(jQuery);
  232.