Advertisement
Guest User

Untitled

a guest
Jan 14th, 2021
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name Google Drive Video Player for CyTube
  3. // @namespace gdcytube
  4. // @description Play Google Drive videos on CyTube
  5. // @include https://cytu.be/r/*
  6. // @include https://www.cytu.be/r/*
  7. // @include https://beta.synchtube.me/r/*
  8. // @grant unsafeWindow
  9. // @grant GM_xmlhttpRequest
  10. // @grant GM.xmlHttpRequest
  11. // @connect docs.google.com
  12. // @run-at document-end
  13. // @version 1.7.0
  14. // ==/UserScript==
  15.  
  16. try {
  17.     function debug(message) {
  18.         try {
  19.             unsafeWindow.console.log('[Drive]', message);
  20.         } catch (error) {
  21.             unsafeWindow.console.error(error);
  22.         }
  23.     }
  24.  
  25.     function httpRequest(opts) {
  26.         if (typeof GM_xmlhttpRequest === 'undefined') {
  27.             // Assume GM4.0
  28.             debug('Using GM4.0 GM.xmlHttpRequest');
  29.             GM.xmlHttpRequest(opts);
  30.         } else {
  31.             debug('Using old-style GM_xmlhttpRequest');
  32.             GM_xmlhttpRequest(opts);
  33.         }
  34.     }
  35.  
  36.     var ITAG_QMAP = {
  37.         37: 1080,
  38.         46: 1080,
  39.         22: 720,
  40.         45: 720,
  41.         59: 480,
  42.         44: 480,
  43.         35: 480,
  44.         18: 360,
  45.         43: 360,
  46.         34: 360
  47.     };
  48.  
  49.     var ITAG_CMAP = {
  50.         43: 'video/webm',
  51.         44: 'video/webm',
  52.         45: 'video/webm',
  53.         46: 'video/webm',
  54.         18: 'video/mp4',
  55.         22: 'video/mp4',
  56.         37: 'video/mp4',
  57.         59: 'video/mp4',
  58.         35: 'video/flv',
  59.         34: 'video/flv'
  60.     };
  61.  
  62.     function getVideoInfo(id, cb) {
  63.         var url = 'https://docs.google.com/get_video_info?authuser='
  64.                 + '&docid=' + id
  65.                 + '&sle=true'
  66.                 + '&hl=en';
  67.         debug('Fetching ' + url);
  68.  
  69.         httpRequest({
  70.             method: 'GET',
  71.             url: url,
  72.             onload: function (res) {
  73.                 try {
  74.                     debug('Got response ' + res.responseText);
  75.  
  76.                     if (res.status !== 200) {
  77.                         debug('Response status not 200: ' + res.status);
  78.                         return cb(
  79.                             'Google Drive request failed: HTTP ' + res.status
  80.                         );
  81.                     }
  82.  
  83.                     var data = {};
  84.                     var error;
  85.                     // Google Santa sometimes eats login cookies and gets mad if there aren't any.
  86.                     if(/accounts\.google\.com\/ServiceLogin/.test(res.responseText)){
  87.                         error = 'Google Docs request failed: ' +
  88.                                 'This video requires you be logged into a Google account. ' +
  89.                                 'Open your Gmail in another tab and then refresh video.';
  90.                         return cb(error);
  91.                     }
  92.  
  93.                     res.responseText.split('&').forEach(function (kv) {
  94.                         var pair = kv.split('=');
  95.                         data[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
  96.                     });
  97.  
  98.                     if (data.status === 'fail') {
  99.                         error = 'Google Drive request failed: ' +
  100.                                 unescape(data.reason).replace(/\+/g, ' ');
  101.                         return cb(error);
  102.                     }
  103.  
  104.                     if (!data.fmt_stream_map) {
  105.                         error = (
  106.                             'Google has removed the video streams associated' +
  107.                             ' with this item.  It can no longer be played.'
  108.                         );
  109.  
  110.                         return cb(error);
  111.                     }
  112.  
  113.                     data.links = {};
  114.                     data.fmt_stream_map.split(',').forEach(function (item) {
  115.                         var pair = item.split('|');
  116.                         data.links[pair[0]] = pair[1];
  117.                     });
  118.                     data.videoMap = mapLinks(data.links);
  119.  
  120.                     cb(null, data);
  121.                 } catch (error) {
  122.                     unsafeWindow.console.error(error);
  123.                 }
  124.             },
  125.  
  126.             onerror: function () {
  127.                 var error = 'Google Drive request failed: ' +
  128.                             'metadata lookup HTTP request failed';
  129.                 error.reason = 'HTTP_ONERROR';
  130.                 return cb(error);
  131.             }
  132.         });
  133.     }
  134.  
  135.     function mapLinks(links) {
  136.         var videos = {
  137.             1080: [],
  138.             720: [],
  139.             480: [],
  140.             360: []
  141.         };
  142.  
  143.         Object.keys(links).forEach(function (itag) {
  144.             itag = parseInt(itag, 10);
  145.             if (!ITAG_QMAP.hasOwnProperty(itag)) {
  146.                 return;
  147.             }
  148.  
  149.             videos[ITAG_QMAP[itag]].push({
  150.                 itag: itag,
  151.                 contentType: ITAG_CMAP[itag],
  152.                 link: links[itag]
  153.             });
  154.         });
  155.  
  156.         return videos;
  157.     }
  158.  
  159.     /*
  160.      * Greasemonkey 2.0 has this wonderful sandbox that attempts
  161.      * to prevent script developers from shooting themselves in
  162.      * the foot by removing the trigger from the gun, i.e. it's
  163.      * impossible to cross the boundary between the browser JS VM
  164.      * and the privileged sandbox that can run GM_xmlhttpRequest().
  165.      *
  166.      * So in this case, we have to resort to polling a special
  167.      * variable to see if getGoogleDriveMetadata needs to be called
  168.      * and deliver the result into another special variable that is
  169.      * being polled on the browser side.
  170.      */
  171.  
  172.     /*
  173.      * Browser side function -- sets gdUserscript.pollID to the
  174.      * ID of the Drive video to be queried and polls
  175.      * gdUserscript.pollResult for the result.
  176.      */
  177.     function getGoogleDriveMetadata_GM(id, callback) {
  178.         debug('Setting GD poll ID to ' + id);
  179.         unsafeWindow.gdUserscript.pollID = id;
  180.         var tries = 0;
  181.         var i = setInterval(function () {
  182.             if (unsafeWindow.gdUserscript.pollResult) {
  183.                 debug('Got result');
  184.                 clearInterval(i);
  185.                 var result = unsafeWindow.gdUserscript.pollResult;
  186.                 unsafeWindow.gdUserscript.pollResult = null;
  187.                 callback(result.error, result.result);
  188.             } else if (++tries > 100) {
  189.                 // Took longer than 10 seconds, give up
  190.                 clearInterval(i);
  191.             }
  192.         }, 100);
  193.     }
  194.  
  195.     /*
  196.      * Sandbox side function -- polls gdUserscript.pollID for
  197.      * the ID of a Drive video to be queried, looks up the
  198.      * metadata, and stores it in gdUserscript.pollResult
  199.      */
  200.     function setupGDPoll() {
  201.         unsafeWindow.gdUserscript = cloneInto({}, unsafeWindow);
  202.         var pollInterval = setInterval(function () {
  203.             if (unsafeWindow.gdUserscript.pollID) {
  204.                 var id = unsafeWindow.gdUserscript.pollID;
  205.                 unsafeWindow.gdUserscript.pollID = null;
  206.                 debug('Polled and got ' + id);
  207.                 getVideoInfo(id, function (error, data) {
  208.                     unsafeWindow.gdUserscript.pollResult = cloneInto({
  209.                         error: error,
  210.                         result: data
  211.                     }, unsafeWindow);
  212.                 });
  213.             }
  214.         }, 1000);
  215.     }
  216.  
  217.     var TM_COMPATIBLES = [
  218.         'Tampermonkey',
  219.         'Violentmonkey' // https://github.com/calzoneman/sync/issues/713
  220.     ];
  221.  
  222.     function isTampermonkeyCompatible() {
  223.         try {
  224.             return TM_COMPATIBLES.indexOf(GM_info.scriptHandler) >= 0;
  225.         } catch (error) {
  226.             return false;
  227.         }
  228.     }
  229.  
  230.     if (isTampermonkeyCompatible()) {
  231.         unsafeWindow.getGoogleDriveMetadata = getVideoInfo;
  232.     } else {
  233.         debug('Using non-TM polling workaround');
  234.         unsafeWindow.getGoogleDriveMetadata = exportFunction(
  235.                 getGoogleDriveMetadata_GM, unsafeWindow);
  236.         setupGDPoll();
  237.     }
  238.  
  239.     unsafeWindow.console.log('Initialized userscript Google Drive player');
  240.     unsafeWindow.hasDriveUserscript = true;
  241.     // Checked against GS_VERSION from data.js
  242.     unsafeWindow.driveUserscriptVersion = '1.7';
  243. } catch (error) {
  244.     unsafeWindow.console.error(error);
  245. }
  246.  
  247.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement