Advertisement
Guest User

Untitled

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