Guest User

Untitled

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