Advertisement
Guest User

Untitled

a guest
Jan 26th, 2020
145
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.10 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. // @include https://agare.moe:8443/r/Agarestream
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement