Hive - YouTube to Hive / Local Download

Inserts a download button on YouTube video pages and sends to hive -Major fixes

  1. /** YouTube link resolving Originally written by angelsl
  2. With contributions from Manish Burman http://mburman.com
  3. With contributions from LouCypher https://github.com/LouCypher
  4.  
  5. YTGrab is distributed under the GNU LGPL v3 or later and comes with no warranty.
  6. Full preamble at https://github.com/angelsl/misc-Scripts/blob/master/Greasemonkey/LICENSE.md#ytgrab
  7.  
  8. //===========DS===========//
  9. This is a DefSoul MOD for use with hive. All non hive related code is credited to angelsl and contributers above. (My code will have //===========DS===========// above it)
  10. angelsl's scripts can be found here > https://github.com/angelsl/misc-Scripts
  11. //===========DS===========\\
  12.  
  13. // ==UserScript==
  14. // @name Hive - YouTube to Hive / Local Download
  15. // @namespace https://openuserjs.org/users/DefSoul/scripts
  16. // @description Inserts a download button on YouTube video pages and sends to hive -Major fixes
  17. // @version 1.9 > added ability to send whole playlists to hive
  18. // @run-at document-end
  19. // @include http*://www.youtube.com/*
  20. // @include http*://api.hive.im/api/*
  21. // @include https://touch.hive.im/account/*
  22. // @exclude http*://*.google.com/*
  23. // @exclude http*://*.facebook.com/*
  24. // @exclude http*://facebook.com/*
  25. // @exclude about:blank
  26. // @exclude http*://*.stripe.com/*
  27. // @require https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js
  28. // @resource toastrCss http://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.min.css
  29. // @require http://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/js/toastr.min.js
  30. // @grant GM_xmlhttpRequest
  31. // @grant GM_getValue
  32. // @grant GM_setValue
  33. // @grant GM_log
  34. // @grant GM_getResourceText
  35. // @grant GM_addStyle
  36. // @grant unsafeWindow
  37. // ==/UserScript==
  38. */
  39. //===========DS===========//
  40. var nameB = "YouTube to Hive / Local Download: Test ";
  41. GM_log(nameB + location.href);
  42.  
  43. var folderName = "# YouTube #"; // CASE SENSITIVE
  44. var uploadFolderId;
  45. var auth;
  46. auth = GM_getValue("auth");
  47. var link;
  48. GM_setValue("ready", "false");
  49. //GM_deleteValue("auth");
  50.  
  51. var ru;
  52. var uploadToHive;
  53. var uploadPng = "data:image/png;base64,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";
  54. var downloadPng = "data:image/png;base64,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";
  55. function log(str){console.log('%c ' + str, 'background: #000000; color: #FFFFFF');} // CUSTOM LOG
  56.  
  57. var newCSS = GM_getResourceText ("toastrCss");
  58. GM_addStyle(newCSS);
  59.  
  60. toastr.options = {
  61. "closeButton": false,
  62. "debug": false,
  63. "newestOnTop": false,
  64. "progressBar": false,
  65. "positionClass": "toast-bottom-right",
  66. "preventDuplicates": true,
  67. "onclick": null,
  68. "showDuration": "300",
  69. "hideDuration": "1000",
  70. "timeOut": "12000",
  71. "extendedTimeOut": "1000",
  72. "showEasing": "swing",
  73. "hideEasing": "linear",
  74. "showMethod": "fadeIn",
  75. "hideMethod": "fadeOut"
  76. };
  77.  
  78.  
  79. $(document).on("click", "#hiveSwitch", function(){
  80. if ($("#hiveSwitch").attr("src") === uploadPng){
  81. uploadToHive = false;
  82. $("#hiveSwitch").attr("src", downloadPng);
  83. $("#hiveSwitch").attr("title", "Local download activated.");
  84. document.getElementById('btnDownload').innerHTML = 'Download';
  85. $("#hiveSwitch").css("right", "9px");
  86. if ($("#watch-action-panels").css("display") == "none")
  87. document.getElementById("btnDownload").click();
  88. }
  89. else{
  90. uploadToHive = true;
  91. $("#hiveSwitch").attr("src", uploadPng);
  92. $("#hiveSwitch").attr("title", "Upload to Hive activated.");
  93. document.getElementById('btnDownload').innerHTML = ' Upload ';
  94. $("#hiveSwitch").css("right", "0px");
  95. if ($("#watch-action-panels").css("display") == "none")
  96. document.getElementById("btnDownload").click();
  97. }
  98. });
  99. //===========DS===========\\
  100.  
  101. if (typeof unsafeWindow === 'undefined' || typeof unsafeWindow.ytplayer === 'undefined') {
  102. var p = document.createElement('p');
  103. p.setAttribute('onclick', 'return window;');
  104. unsafeWindow = p.onclick();
  105. }
  106.  
  107. function main(decipher) {
  108. var dashmpd = unsafeWindow.ytplayer.config.args.dashmpd, mpbsrgx = /\/s\/([\w\.]+)/, mpbs;
  109. if (typeof dashmpd !== 'undefined') {
  110. mpbs = mpbsrgx.exec(dashmpd); if(mpbs) dashmpd = dashmpd.replace(mpbsrgx, "/signature/"+decipher(mpbs[1]));
  111. GM_xmlhttpRequest({method: "GET", url: dashmpd, onload: function (t) { main2(t.responseText, decipher); }});
  112. } else main2(false, decipher);
  113. }
  114.  
  115. function main2(dashmpd, decipher) {
  116. "use strict";
  117. var
  118. uriencToMap = function (s) {
  119. var n = {}, a = s.split("&"), idy, c;
  120. for (idy = 0; idy < a.length; idy++) {
  121. c = a[idy].split("=");
  122. n[c[0]] = decodeURIComponent(c[1]);
  123. }
  124. return n;
  125. },
  126. uwyca = unsafeWindow.ytplayer.config.args,
  127. title = uwyca.title.replace(/[\/\\\:\*\?\"<\>\|]/g, ""),
  128. fmtrgx = /^[\-\w+]+\/(?:x-)?([\-\w+]+)/,
  129. fmt_map = {}, idx, idz, n, a, qual, fmt, fmt_list, map, uefmss, dashlist, ul, q, div,
  130. type, itag, maporder, fpsa, fpsb, fpsw = false;
  131.  
  132. fmt_list = uwyca.fmt_list.split(",");
  133. for (idx = 0; idx < fmt_list.length; idx++) {
  134. a = fmt_list[idx].split("/");
  135. fmt_map[a[0]] = a[1].split("x")[1] + "p";
  136. }
  137.  
  138. map = {};
  139. uefmss = uwyca.url_encoded_fmt_stream_map.split(",");
  140. for (idx = 0; idx < uefmss.length; idx++) {
  141. n = uriencToMap(uefmss[idx]);
  142. qual = fmt_map[n.itag];
  143.  
  144. if (!(qual in map)) { map[qual] = []; }
  145. fmt = fmtrgx.exec(n.type);
  146. map[qual].push($("<a>" + (fmt ? fmt[1] : "MISSINGNO.").toUpperCase() + "</a>").attr("href", n.url + ((n.url.indexOf("signature=") !== -1) ? "" : ("&signature=" + (n.sig || decipher(n.s)))) + "&title=" + title).attr("title", "Format ID: " + n.itag + " | Quality: " + n.quality + " | Mime: " + n.type));
  147. }
  148.  
  149. dashlist = uwyca.adaptive_fmts;
  150. if (typeof dashlist !== 'undefined') {
  151. dashlist = dashlist.split(",");
  152. for (idx = 0; idx < dashlist.length; idx++) {
  153. n = uriencToMap(dashlist[idx]);
  154. qual = n.type.indexOf("audio/") === 0 ? "Audio" : (("size" in n) ? (n.size.split('x')[1] + 'p' + n.fps) : (n.itag in fmt_map) ? (fmt_map[n.itag]) : ("Unknown"));
  155.  
  156. if (!(qual in map)) { map[qual] = []; }
  157. fmt = fmtrgx.exec(n.type);
  158. if (parseInt(n.fps) == 1) fpsw = 1;
  159. map[qual].push($("<a>DASH" + (fmt ? fmt[1] : "MISSINGNO.").toUpperCase() + "</a>").attr("href", n.url + ((n.url.indexOf("signature=") !== -1) ? "" : ("&signature=" + (n.sig || decipher(n.s)))) + "&title=" + title).attr("title", "Format ID: " + n.itag + " | Bitrate: " + n.bitrate + " | Mime: " + n.type + " | Res: " + n.size + " | FPS: " + n.fps));
  160. }
  161. }
  162. if (dashmpd !== false) {
  163. dashmpd = $($.parseXML(dashmpd));
  164. dashmpd.find("AdaptationSet").each(function() {
  165. q = $(this); type = q.attr("mimeType");
  166. q.children("Representation").each(function() {
  167. n = $(this); itag = n.attr("id");
  168. qual = type.indexOf("audio/") === 0 ? "Audio" : (n.attr("height") + 'p' + n.attr("frameRate"));
  169. if (!(qual in map)) { map[qual] = []; }
  170. fmt = fmtrgx.exec(type);
  171. if (parseInt(n.attr("frameRate")) == 1) fpsw = 1;
  172. map[qual].push($("<a>MPD" + (fmt ? fmt[1] : "MISSINGNO.").toUpperCase() + "</a>").attr("href", n.children("BaseURL").text() + "&title=" + title).attr("title", "Format ID: " + itag + " | Bitrate: " + n.attr("bandwidth") + " | Mime: " + type + (type.indexOf("audio/") === 0 ? " | Sample Rate: " + n.attr("audioSamplingRate") : " | Res: " + n.attr("width") + 'x' + n.attr("height") + " | FPS: " + n.attr("frameRate"))));
  173. });
  174. });
  175. }
  176.  
  177. maporder = Object.keys(map);
  178. maporder.sort(function(a,b) {
  179. if((a == "Audio" && b == "Unknown") || (b == "Audio" && a != "Unknown")) return -1;
  180. if ((b == "Audio" && a == "Unknown") || (a == "Audio" && b != "Unknown")) return 1;
  181. fpsa = a.split('p')[1] || 0; fpsb = b.split('p')[1] || 0; if (fpsa != fpsb) return parseInt(fpsb)-parseInt(fpsa);
  182. return parseInt(b)-parseInt(a); });
  183. ul = $("<ul class=\"watch-extras-section\" />");
  184. for (n = 0; n < maporder.length; ++n) {
  185. q = maporder[n];
  186. if (map[q].length < 1) { continue; }
  187. div = $("<div class=\"content\" />").append(map[q][0]);
  188. for (idz = 1; idz < map[q].length; idz++) {
  189. div.append(" ").append(map[q][idz]);
  190. }
  191. ul.append($("<li><h4 class=\"title\" style=\"font-weight: bold; color: #333333;\">" + q + "</h4></li>").append(div));
  192. }
  193.  
  194. $("#action-panel-share").after($("<div id=\"action-panel-sldownload\" class=\"action-panel-content hid\" data-panel-loaded=\"true\" />").append(ul));
  195. $("#watch8-secondary-actions").find("> div").eq(1).after($('<button class="yt-uix-button yt-uix-button-size-default yt-uix-button-opacity action-panel-trigger yt-uix-button-opacity yt-uix-tooltip" style="text-align: center;" type="button" onclick=";return false;" title="" id="btnDownload" data-trigger-for="action-panel-sldownload" data-button-toggle="true"><span class="yt-uix-button-content">Upload</span></button>')).size();
  196. //===========DS===========//
  197. //$("#hiveSwitch").css("display", "block");
  198. $("#watch8-secondary-actions").find("> div").eq(1).after($('<img title="Upload to Hive activated." src="' + uploadPng + '" type="button" onclick=";return false;" title="" id="hiveSwitch" style="right: 0px; bottom: 41px; z-index: 9999999; cursor: pointer; position: absolute; display: block; height: 50px; width: 50px; padding-left: 5px;" data-button-toggle="true"><span class=""></span></button>')).size();
  199. //===========DS===========\\
  200. if (fpsw) ul.after($("<p style='color: green;'>At this time Hive only accepts Mp4 & Flv video files, the other formats are for local downloading.</p>"));
  201. }
  202.  
  203. function run() {
  204. if (typeof unsafeWindow.ytplayer !== 'undefined')
  205. { GM_xmlhttpRequest({method: "GET", url: unsafeWindow.ytplayer.config.assets.js.replace(/^\/\//, "https://"), onload: function (t) { main((function (u) {
  206. "use strict"; var sres = /function ([a-zA-Z$0-9]+)\(a\)\{a=a\.split\(""\);([a-zA-Z0-9]*)\.?.*?return a\.join\(""\)\};/g.exec(u);
  207. if (!sres) { return function (v) { return v; }; }
  208. return eval("(function(s){" + (sres[2] !== "" ? (new RegExp("var " + sres[2] + "={.+?}};", "g").exec(u)[0]) : "") + sres[0] + "return " + sres[1] + "(s);})");
  209. }(t.responseText))); }}); }
  210. }
  211.  
  212. //DS//
  213. function run2(val) {
  214. log("run2 running");
  215. GM_xmlhttpRequest({
  216. method: "GET",
  217. url: val,
  218. onload: function(t){
  219.  
  220. json = JSON.parse(t.responseText);
  221. //for(var key in json) {
  222. // var value = json[key];
  223. // log(value);
  224. //}
  225. }});
  226. }
  227.  
  228. setInterval(function(){
  229. if ($(".playlist-actions").length && !$("#PlaylistToHive").length){
  230. $(".playlist-actions").append('<button id="PlaylistToHive" class="yt-uix-button yt-uix-button-size-default yt-uix-button-default yt-uix-button-has-icon no-icon-markup yt-uix-playlistlike yt-uix-tooltip" type="button" onclick=";return false;" aria-label="To Hive" title="To Hive" data-like-tooltip="Save to Playlists" data-unlike-tooltip="Remove" data-like-label="Save" data-unlike-label="Saved" data-tooltip-text="To Hive" aria-labelledby="yt-uix-tooltip95-arialabel" data-tooltip-hide-timer="235"><span class="yt-uix-button-content">To Hive</span></button>');
  231. }
  232. }, 1000);
  233.  
  234. //DS\\
  235.  
  236. waitForKeyElements("#watch8-secondary-actions", run);
  237.  
  238. //===========DS===========/
  239.  
  240. function createFolder(uploadFolderName){
  241. GM_xmlhttpRequest({ //CROSS DOMAIN POST REQUEST
  242. "method": "get",
  243. "url": "https://api.hive.im/api/hive/get/",
  244. "headers": {
  245. 'Content-Type': 'application/x-www-form-urlencoded;',
  246. 'Authorization': auth,
  247. 'Client-Type': 'Browser',
  248. 'Client-Version': '0.1',
  249. 'Referer': 'https://touch.hive.im/myfiles/videos',
  250. 'Origin': 'https://touch.hive.im/'
  251. },
  252. "onload": function(data){
  253. var r = data.responseText;
  254. var json = JSON.parse(r);
  255. for (var i = 0; i < json.data.length; i++){
  256. var id;
  257. if (json.data[i].title === "Videos"){ // FINDS INITIAL VIDEOS FOLDER ID
  258. //log("we got a video ova here", "green");
  259. parentId = json.data[i].parentId;
  260. id = json.data[i].id;
  261. GM_xmlhttpRequest({ //CROSS DOMAIN POST REQUEST
  262. "method": "post",
  263. "url": "https://api.hive.im/api/hive/get-children/",
  264. "data": "&parentId=" + id + "&limit=1000",
  265. "headers": {
  266. 'Content-Type': 'application/x-www-form-urlencoded;',
  267. 'Authorization': auth,
  268. 'Client-Type': 'Browser',
  269. 'Client-Version': '0.1',
  270. 'Referer': 'https://touch.hive.im/',
  271. 'Origin': 'https://touch.hive.im/'
  272. },
  273. "onload": function(data){
  274. var r = data.responseText;
  275. var json = JSON.parse(r);
  276. var hasFolderIndex;
  277. Object.keys(json.data).forEach(function(key) {
  278. //log(json.data[key].title, "blue");
  279. hasFolderIndex += json.data[key].title;
  280. if (json.data[key].title === uploadFolderName){
  281. uploadFolderId = json.data[key].id;
  282. log("<" + uploadFolderName + "> Already exists. " + uploadFolderId, "green");
  283. //return json.data[key].id;
  284. }
  285. });
  286. if (hasFolderIndex.indexOf(uploadFolderName) == -1){ // SEARCHES VIDEOS FOLDER TO SEE IF uploadFolderName EXISTS
  287. log("does not contain: " + uploadFolderName, "red");
  288. GM_xmlhttpRequest({ //CROSS DOMAIN POST REQUEST
  289. "method": "post",
  290. "url": "https://api.hive.im/api/hive/create/",
  291. "data": "filename=" + uploadFolderName + "&parent=" + id + "&locked=false",
  292. "headers": {
  293. 'Content-Type': 'application/x-www-form-urlencoded;',
  294. 'Authorization': auth,
  295. 'Client-Type': 'Browser',
  296. 'Client-Version': '0.1',
  297. 'Referer': 'https://touch.hive.im/',
  298. 'Origin': 'https://touch.hive.im/'
  299. },
  300. "onload": function(data){
  301. var r = data.responseText;
  302. var json = JSON.parse(r);
  303. uploadFolderId = json.data.id;
  304.  
  305. log("Create folder <" + uploadFolderName + "> " + json.data.id);
  306. return json.data.id;
  307. }
  308. });
  309. }
  310. else{
  311. //log("does contain: " + uploadFolderName, "green");
  312. }
  313. }
  314. });
  315. //log(parentId + "\n" + currentId);
  316. }
  317. //log(item, "blue");
  318. }
  319. //log(r, "blue");
  320. }
  321. });
  322. }
  323.  
  324. function cdReq(href, nameT, folderId){
  325. log("cdReq start: " + href);
  326. GM_xmlhttpRequest({ //CROSS DOMAIN POST REQUEST
  327. "method": "post",
  328. "url": "https://api.hive.im/api/transfer/add/",
  329. "data": "remoteUrl=" + window.btoa(href) + "&parentId=" + folderId,
  330. //"data": "remoteUrl=" + window.btoa(href),
  331. "headers": {
  332. 'Content-Type': 'application/x-www-form-urlencoded;',
  333. 'Authorization': GM_getValue("auth"),
  334. 'Client-Type': 'Browser',
  335. 'Client-Version': '0.1',
  336. 'Referer': 'https://touch.hive.im/',
  337. 'Origin': 'https://touch.hive.im/'
  338. },
  339. "onload": function(data){
  340. var r = data.responseText;
  341. var json = JSON.parse(r);
  342. if (json.status === "success"){
  343. toastr.success(nameT, "Status: " + json.data.status);
  344. log("========= " + nameT + " success =========", "green");
  345. log("Job ID: " + json.data.jobId, "blue");
  346. log("Data Status: " + json.data.status, "blue");
  347. log("Folder Id: " + folderId, "blue");
  348. log("", "red");
  349. }
  350. else{
  351. if (json.message === "quotaExceeded"){
  352. toastr.warning(nameT, "Quota Exceeded");
  353. }
  354. else if (json.message === "securityViolation"){
  355. toastr.error(nameT, "Security Violation");
  356. }
  357.  
  358. log("========= " + nameT + " error =========", "green");
  359. log("Message: " + json.message, "blue");
  360. log("", "red");
  361. }
  362. //log("cdReq >" + data.responseText);
  363. //transferItemsList(); // GO GET ITEMS IN CURRENT TRANSFER LIST
  364. }
  365. });
  366. }
  367.  
  368. $(document).on("click", "#PlaylistToHive", function(e){ // MAIN CLICK EVENT
  369. e.preventDefault();
  370. toastr.warning("Extracting links.", "Please don't navigate from page!");
  371. var tiles = document.getElementsByClassName("yt-uix-tile");
  372. var titlesClass = document.getElementsByClassName("pl-video-title-link");
  373. var titles = [];
  374. var vids = []; // CONTAINS ALL COMPLETE URLS OF ALL ITEMS IN PLAYLIST
  375. var mp4s = [];
  376. for (var i = 0; i < tiles.length; i++){
  377. var r = $(titlesClass[i]).html();
  378. r = r.replace(/(\r\n|\n|\r)/gm,"");
  379. r = r.trim();
  380. r = r.replace(/[`~!@#$%^&*()_|+\=÷¿?;:'",.<>\{\}\[\]\\\/]/gi, '%20');
  381. r = r.replace(/ /g, "%20");
  382. //r = "&title=" + r;
  383. //log(r);
  384. titles.push(r); // CREATES ARRAY OF VIDEO TITLES
  385. vids.push("https://www.youtube.com/watch?v=" + $(tiles[i]).attr("data-video-id")); // CREATES ARRAY OF VIDEO URLS
  386. }
  387.  
  388. var jjj = 0;
  389. for (var jI = 0; jI < vids.length; jI++){
  390. var toastTitle;
  391.  
  392. extract(vids[jI]).done(function (result) {
  393. for (var j = 0; j < result.formats.length; j++){
  394. if (result.formats[j].ext === "mp4" && typeof result.formats[j].format_note == "undefined"){
  395. toastTitle = titles[jjj];
  396. toastTitle = toastTitle.replace(/%20/g, " ");
  397. mp4s = [];
  398. mp4s.push(result.formats[j].url + "&title=" + titles[jjj]);
  399. }
  400. }
  401.  
  402. //log("MP4S 1: >>" + mp4s[0], "blue"); // HIGHEST QUALITY MP4
  403. cdReq(mp4s[0], toastTitle, uploadFolderId);
  404. jjj++;
  405. setTimeout(function(){
  406. if (jjj === jI){
  407. toastr.info("Finished!");
  408. }
  409. }, 5000);
  410. });
  411. }
  412.  
  413. });
  414.  
  415. if (window.top === window.self) {
  416. //=========MAIN WINDOW=========//
  417. if (document.location.href.indexOf("touch.hive.im") !== -1){
  418. return;
  419. }
  420. createFolder(folderName);
  421. if (!$("#iframeHive").length || typeof auth == "undefined"){
  422. var iframe = document.createElement('iframe');
  423. iframe.id = "iframeHive";
  424. iframe.src = "https://touch.hive.im/account/?1";
  425. iframe.style = "height: 0px; width: 0px; display: none; overflow:hidden";
  426. document.body.appendChild(iframe);
  427. $("#iframeHive").attr("style", "height: 0px; width: 0px; display: none; overflow:hidden");
  428. //$("#iframeHive").attr("style", "height: 600px; width: 600px; display: block; overflow:hidden");
  429. log("iframe created! " + nameB);
  430. }
  431. var onceB = 0;
  432. setInterval(function(){
  433. //log("AA: " + auth);
  434. if (onceB === 0 && typeof auth !== "undefined"){
  435. GM_setValue("ready", "true")
  436. GM_setValue("auth", auth);
  437. $("#iframeHive").remove();
  438. //log("TRUE: " + auth);
  439. }
  440. if (onceB === 0 && GM_getValue("ready") == "true"){
  441. onceB = 1;
  442. auth = GM_getValue("auth");
  443. log("A: " + auth);
  444. $("#iframeHive").remove();
  445. //init();
  446. }
  447. }, 250);
  448. $(document).on("click", "a", function(evt){ // MAIN CLICK EVENT
  449. if ($(this).attr('href').indexOf('googlevideo') !== -1){
  450. if (uploadToHive === false)
  451. return;
  452.  
  453. log($("#hiveSwitch").attr("src"));
  454. evt.preventDefault();
  455. ru = $(this).attr('href');
  456. //log("pre: " + ru);
  457. ru = ru.replace(/ /g, "%20");
  458. //log("post: " + ru);
  459. var vidTitle = $("#eow-title").attr("title");
  460. cdReq(ru, vidTitle, uploadFolderId);
  461. }
  462. });
  463. }
  464. else
  465. {
  466. //=========IFRAME WINDOW=========//
  467. try{
  468. auth = unsafeWindow.account.token;
  469. }
  470. catch(err){}
  471. var once = 0;
  472. setInterval(function(){ // EVENT FOR WHEN PAGE IS LOADED // RUNS ONCE
  473. if (once === 0 && $("#username").text().indexOf("My Account") !== -1){
  474. once = 1;
  475. log("ready");
  476. auth = unsafeWindow.account.token;
  477. GM_setValue("auth", unsafeWindow.account.token);
  478. GM_setValue("ready", "true");
  479. }
  480. else if (once === 1 && auth == "undefined"){
  481. GM_setValue("ready", "false");
  482. try{
  483. auth = unsafeWindow.account.token;
  484. }
  485. catch(err){}
  486. }
  487. }, 200);
  488. }
  489. //===========DS===========\\
  490.  
  491. // START YT-LINKS CODE //
  492. var YT_FORMATS = {
  493. '5': {'ext': 'flv', 'width': 400, 'height': 240},
  494. '6': {'ext': 'flv', 'width': 450, 'height': 270},
  495. '13': {'ext': '3gp'},
  496. '17': {'ext': '3gp', 'width': 176, 'height': 144},
  497. '18': {'ext': 'mp4', 'width': 640, 'height': 360},
  498. '22': {'ext': 'mp4', 'width': 1280, 'height': 720},
  499. '34': {'ext': 'flv', 'width': 640, 'height': 360},
  500. '35': {'ext': 'flv', 'width': 854, 'height': 480},
  501. '36': {'ext': '3gp', 'width': 320, 'height': 240},
  502. '37': {'ext': 'mp4', 'width': 1920, 'height': 1080},
  503. '38': {'ext': 'mp4', 'width': 4096, 'height': 3072},
  504. '43': {'ext': 'webm', 'width': 640, 'height': 360},
  505. '44': {'ext': 'webm', 'width': 854, 'height': 480},
  506. '45': {'ext': 'webm', 'width': 1280, 'height': 720},
  507. '46': {'ext': 'webm', 'width': 1920, 'height': 1080},
  508. '59': {'ext': 'mp4', 'width': 854, 'height': 480},
  509. '78': {'ext': 'mp4', 'width': 854, 'height': 480},
  510.  
  511. // 3d videos
  512. '82': {'ext': 'mp4', 'height': 360, 'format_note': '3D', 'preference': -20},
  513. '83': {'ext': 'mp4', 'height': 480, 'format_note': '3D', 'preference': -20},
  514. '84': {'ext': 'mp4', 'height': 720, 'format_note': '3D', 'preference': -20},
  515. '85': {'ext': 'mp4', 'height': 1080, 'format_note': '3D', 'preference': -20},
  516. '100': {'ext': 'webm', 'height': 360, 'format_note': '3D', 'preference': -20},
  517. '101': {'ext': 'webm', 'height': 480, 'format_note': '3D', 'preference': -20},
  518. '102': {'ext': 'webm', 'height': 720, 'format_note': '3D', 'preference': -20},
  519.  
  520. // Apple HTTP Live Streaming
  521. '92': {'ext': 'mp4', 'height': 240, 'format_note': 'HLS', 'preference': -10},
  522. '93': {'ext': 'mp4', 'height': 360, 'format_note': 'HLS', 'preference': -10},
  523. '94': {'ext': 'mp4', 'height': 480, 'format_note': 'HLS', 'preference': -10},
  524. '95': {'ext': 'mp4', 'height': 720, 'format_note': 'HLS', 'preference': -10},
  525. '96': {'ext': 'mp4', 'height': 1080, 'format_note': 'HLS', 'preference': -10},
  526. '132': {'ext': 'mp4', 'height': 240, 'format_note': 'HLS', 'preference': -10},
  527. '151': {'ext': 'mp4', 'height': 72, 'format_note': 'HLS', 'preference': -10},
  528.  
  529. // DASH mp4 video
  530. '133': {'ext': 'mp4', 'height': 240, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  531. '134': {'ext': 'mp4', 'height': 360, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  532. '135': {'ext': 'mp4', 'height': 480, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  533. '136': {'ext': 'mp4', 'height': 720, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  534. '137': {'ext': 'mp4', 'height': 1080, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  535. '138': {'ext': 'mp4', 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40}, // Height can vary (https://github.com/rg3/youtube-dl/issues/4559)
  536. '160': {'ext': 'mp4', 'height': 144, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  537. '264': {'ext': 'mp4', 'height': 1440, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  538. '298': {
  539. 'ext': 'mp4',
  540. 'height': 720,
  541. 'format_note': 'DASH video',
  542. 'acodec': 'none',
  543. 'preference': -40,
  544. 'fps': 60,
  545. 'vcodec': 'h264'
  546. },
  547. '299': {
  548. 'ext': 'mp4',
  549. 'height': 1080,
  550. 'format_note': 'DASH video',
  551. 'acodec': 'none',
  552. 'preference': -40,
  553. 'fps': 60,
  554. 'vcodec': 'h264'
  555. },
  556. '266': {
  557. 'ext': 'mp4',
  558. 'height': 2160,
  559. 'format_note': 'DASH video',
  560. 'acodec': 'none',
  561. 'preference': -40,
  562. 'vcodec': 'h264'
  563. },
  564.  
  565. // Dash mp4 audio
  566. '139': {
  567. 'ext': 'm4a',
  568. 'format_note': 'DASH audio',
  569. 'acodec': 'aac',
  570. 'vcodec': 'none',
  571. 'abr': 48,
  572. 'preference': -50,
  573. 'container': 'm4a_dash'
  574. },
  575. '140': {
  576. 'ext': 'm4a',
  577. 'format_note': 'DASH audio',
  578. 'acodec': 'aac',
  579. 'vcodec': 'none',
  580. 'abr': 128,
  581. 'preference': -50,
  582. 'container': 'm4a_dash'
  583. },
  584. '141': {
  585. 'ext': 'm4a',
  586. 'format_note': 'DASH audio',
  587. 'acodec': 'aac',
  588. 'vcodec': 'none',
  589. 'abr': 256,
  590. 'preference': -50,
  591. 'container': 'm4a_dash'
  592. },
  593.  
  594. // Dash webm
  595. '167': {
  596. 'ext': 'webm',
  597. 'height': 360,
  598. 'width': 640,
  599. 'format_note': 'DASH video',
  600. 'acodec': 'none',
  601. 'container': 'webm',
  602. 'vcodec': 'VP8',
  603. 'preference': -40
  604. },
  605. '168': {
  606. 'ext': 'webm',
  607. 'height': 480,
  608. 'width': 854,
  609. 'format_note': 'DASH video',
  610. 'acodec': 'none',
  611. 'container': 'webm',
  612. 'vcodec': 'VP8',
  613. 'preference': -40
  614. },
  615. '169': {
  616. 'ext': 'webm',
  617. 'height': 720,
  618. 'width': 1280,
  619. 'format_note': 'DASH video',
  620. 'acodec': 'none',
  621. 'container': 'webm',
  622. 'vcodec': 'VP8',
  623. 'preference': -40
  624. },
  625. '170': {
  626. 'ext': 'webm',
  627. 'height': 1080,
  628. 'width': 1920,
  629. 'format_note': 'DASH video',
  630. 'acodec': 'none',
  631. 'container': 'webm',
  632. 'vcodec': 'VP8',
  633. 'preference': -40
  634. },
  635. '218': {
  636. 'ext': 'webm',
  637. 'height': 480,
  638. 'width': 854,
  639. 'format_note': 'DASH video',
  640. 'acodec': 'none',
  641. 'container': 'webm',
  642. 'vcodec': 'VP8',
  643. 'preference': -40
  644. },
  645. '219': {
  646. 'ext': 'webm',
  647. 'height': 480,
  648. 'width': 854,
  649. 'format_note': 'DASH video',
  650. 'acodec': 'none',
  651. 'container': 'webm',
  652. 'vcodec': 'VP8',
  653. 'preference': -40
  654. },
  655. '278': {
  656. 'ext': 'webm',
  657. 'height': 144,
  658. 'format_note': 'DASH video',
  659. 'acodec': 'none',
  660. 'preference': -40,
  661. 'container': 'webm',
  662. 'vcodec': 'VP9'
  663. },
  664. '242': {'ext': 'webm', 'height': 240, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  665. '243': {'ext': 'webm', 'height': 360, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  666. '244': {'ext': 'webm', 'height': 480, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  667. '245': {'ext': 'webm', 'height': 480, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  668. '246': {'ext': 'webm', 'height': 480, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  669. '247': {'ext': 'webm', 'height': 720, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  670. '248': {'ext': 'webm', 'height': 1080, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  671. '271': {'ext': 'webm', 'height': 1440, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  672. '272': {'ext': 'webm', 'height': 2160, 'format_note': 'DASH video', 'acodec': 'none', 'preference': -40},
  673. '302': {
  674. 'ext': 'webm',
  675. 'height': 720,
  676. 'format_note': 'DASH video',
  677. 'acodec': 'none',
  678. 'preference': -40,
  679. 'fps': 60,
  680. 'vcodec': 'VP9'
  681. },
  682. '303': {
  683. 'ext': 'webm',
  684. 'height': 1080,
  685. 'format_note': 'DASH video',
  686. 'acodec': 'none',
  687. 'preference': -40,
  688. 'fps': 60,
  689. 'vcodec': 'VP9'
  690. },
  691. '308': {
  692. 'ext': 'webm',
  693. 'height': 1440,
  694. 'format_note': 'DASH video',
  695. 'acodec': 'none',
  696. 'preference': -40,
  697. 'fps': 60,
  698. 'vcodec': 'VP9'
  699. },
  700. '313': {
  701. 'ext': 'webm',
  702. 'height': 2160,
  703. 'format_note': 'DASH video',
  704. 'acodec': 'none',
  705. 'preference': -40,
  706. 'vcodec': 'VP9'
  707. },
  708. '315': {
  709. 'ext': 'webm',
  710. 'height': 2160,
  711. 'format_note': 'DASH video',
  712. 'acodec': 'none',
  713. 'preference': -40,
  714. 'fps': 60,
  715. 'vcodec': 'VP9'
  716. },
  717.  
  718. // Dash webm audio
  719. '171': {'ext': 'webm', 'vcodec': 'none', 'format_note': 'DASH audio', 'abr': 128, 'preference': -50},
  720. '172': {'ext': 'webm', 'vcodec': 'none', 'format_note': 'DASH audio', 'abr': 256, 'preference': -50},
  721.  
  722. // Dash webm audio with opus inside
  723. '249': {
  724. 'ext': 'webm',
  725. 'vcodec': 'none',
  726. 'format_note': 'DASH audio',
  727. 'acodec': 'opus',
  728. 'abr': 50,
  729. 'preference': -50
  730. },
  731. '250': {
  732. 'ext': 'webm',
  733. 'vcodec': 'none',
  734. 'format_note': 'DASH audio',
  735. 'acodec': 'opus',
  736. 'abr': 70,
  737. 'preference': -50
  738. },
  739. '251': {
  740. 'ext': 'webm',
  741. 'vcodec': 'none',
  742. 'format_note': 'DASH audio',
  743. 'acodec': 'opus',
  744. 'abr': 160,
  745. 'preference': -50
  746. },
  747.  
  748. // RTMP (unnamed)
  749. '_rtmp': {'protocol': 'rtmp'},
  750. }
  751.  
  752. // QueryString - begin
  753.  
  754. // This is public domain code written in 2011 by Jan Wolter and distributed
  755. // for free at http://unixpapa.com/js/querystring.html
  756. //
  757. // Query String Parser
  758. //
  759. // qs= new QueryString()
  760. // qs= new QueryString(string)
  761. //
  762. // Create a query string object based on the given query string. If
  763. // no string is given, we use the one from the current page by default.
  764. //
  765. // qs.value(key)
  766. //
  767. // Return a value for the named key. If the key was not defined,
  768. // it will return undefined. If the key was multiply defined it will
  769. // return the last value set. If it was defined without a value, it
  770. // will return an empty string.
  771. //
  772. // qs.values(key)
  773. //
  774. // Return an array of values for the named key. If the key was not
  775. // defined, an empty array will be returned. If the key was multiply
  776. // defined, the values will be given in the order they appeared on
  777. // in the query string.
  778. //
  779. // qs.keys()
  780. //
  781. // Return an array of unique keys in the query string. The order will
  782. // not necessarily be the same as in the original query, and repeated
  783. // keys will only be listed once.
  784. //
  785. // QueryString.decode(string)
  786. //
  787. // This static method is an error tolerant version of the builtin
  788. // function decodeURIComponent(), modified to also change pluses into
  789. // spaces, so that it is suitable for query string decoding. You
  790. // shouldn't usually need to call this yourself as the value(),
  791. // values(), and keys() methods already decode everything they return.
  792. //
  793. // Note: W3C recommends that ; be accepted as an alternative to & for
  794. // separating query string fields. To support that, simply insert a semicolon
  795. // immediately after each ampersand in the regular expression in the first
  796. // function below.
  797.  
  798. function QueryString(qs) {
  799. this.dict = {};
  800.  
  801. // If no query string was passed in use the one from the current page
  802. if (!qs) qs = location.search;
  803.  
  804. // Delete leading question mark, if there is one
  805. if (qs.charAt(0) == '?') qs = qs.substring(1);
  806.  
  807. // Parse it
  808. var re = /([^=&]+)(=([^&]*))?/g;
  809. while (match = re.exec(qs)) {
  810. var key = decodeURIComponent(match[1].replace(/\+/g, ' '));
  811. var value = match[3] ? QueryString.decode(match[3]) : '';
  812. if (this.dict[key])
  813. this.dict[key].push(value);
  814. else
  815. this.dict[key] = [value];
  816. }
  817. }
  818.  
  819. QueryString.decode = function (s) {
  820. s = s.replace(/\+/g, ' ');
  821. s = s.replace(/%([EF][0-9A-F])%([89AB][0-9A-F])%([89AB][0-9A-F])/gi,
  822. function (code, hex1, hex2, hex3) {
  823. var n1 = parseInt(hex1, 16) - 0xE0;
  824. var n2 = parseInt(hex2, 16) - 0x80;
  825. if (n1 == 0 && n2 < 32) return code;
  826. var n3 = parseInt(hex3, 16) - 0x80;
  827. var n = (n1 << 12) + (n2 << 6) + n3;
  828. if (n > 0xFFFF) return code;
  829. return String.fromCharCode(n);
  830. });
  831. s = s.replace(/%([CD][0-9A-F])%([89AB][0-9A-F])/gi,
  832. function (code, hex1, hex2) {
  833. var n1 = parseInt(hex1, 16) - 0xC0;
  834. if (n1 < 2) return code;
  835. var n2 = parseInt(hex2, 16) - 0x80;
  836. return String.fromCharCode((n1 << 6) + n2);
  837. });
  838. s = s.replace(/%([0-7][0-9A-F])/gi,
  839. function (code, hex) {
  840. return String.fromCharCode(parseInt(hex, 16));
  841. });
  842. return s;
  843. };
  844.  
  845. QueryString.prototype.value = function (key) {
  846. var a = this.dict[key];
  847. return a ? a[a.length - 1] : undefined;
  848. };
  849.  
  850. QueryString.prototype.values = function (key) {
  851. var a = this.dict[key];
  852. return a ? a : [];
  853. };
  854.  
  855. QueryString.prototype.keys = function () {
  856. var a = [];
  857. for (var key in this.dict)
  858. a.push(key);
  859. return a;
  860. };
  861.  
  862. // QueryString - end
  863.  
  864. var Queue = function () {
  865. var previous = new $.Deferred().resolve();
  866.  
  867. return function (fn, fail) {
  868. return previous = previous.then(fn, fail || fn);
  869. };
  870. };
  871.  
  872. var queue = Queue(); // lower case for idiomatic use
  873.  
  874. var LAST_PLAYER_URL = null;
  875. var LAST_FUNC = null;
  876.  
  877. function log(s) {
  878. try {
  879. console.log(s);
  880. } catch (ignore) {
  881. }
  882. }
  883.  
  884. function download(url) {
  885. log('Downloading webpage ' + url);
  886.  
  887. var deferred = $.Deferred();
  888.  
  889. //var userAgent = navigator.userAgent;
  890. var userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36';
  891.  
  892. $.get('http://query.yahooapis.com/v1/public/yql', {
  893. q: 'select * from xClient where url="' + url + '" and ua="' + userAgent + '"',
  894. format: 'json',
  895. env: 'store://datatables.org/alltableswithkeys',
  896. callback: ''
  897. }).done(function (data) {
  898. try {
  899. deferred.resolve(data.query.results.resources.content);
  900. } catch (e) {
  901. log(e);
  902. deferred.resolve(null);
  903. }
  904. });
  905.  
  906. return deferred.promise();
  907. }
  908.  
  909. function extractId(url) {
  910. var r = /^http(s?):\/\/www\.youtube\.com\/watch\?v=(.+)/.exec(url);
  911. return r !== null ? r[2] : null;
  912. }
  913.  
  914. function searchRegex(regex, string, defaultValue) {
  915. var r = regex.exec(string);
  916.  
  917. if (r !== null) {
  918. return r[1];
  919. } else {
  920. return defaultValue;
  921. }
  922. }
  923.  
  924. function parseQS(s) {
  925. var qs = new QueryString(s);
  926.  
  927. var obj = {};
  928.  
  929. var keys = qs.keys();
  930. var size = keys.length;
  931.  
  932. for (var i = 0; i < size; i++) {
  933. var k = keys[i];
  934. obj[k] = qs.values(k);
  935. }
  936.  
  937. return obj;
  938. }
  939.  
  940. function decryptSignature(s, playerUrl) {
  941. var deferred = $.Deferred();
  942.  
  943. if (playerUrl === null) {
  944. log('Cannot decrypt signature without player_url');
  945. deferred.resolve(null);
  946. }
  947.  
  948. if (playerUrl.indexOf('//') === 0) {
  949. playerUrl = 'https:' + playerUrl;
  950. }
  951.  
  952. if (LAST_PLAYER_URL === playerUrl && LAST_FUNC !== null) {
  953. var func = LAST_FUNC;
  954. var signature = func(s);
  955. deferred.resolve(signature);
  956. } else {
  957. download(playerUrl).done(function (jscode) {
  958. var func = null;
  959.  
  960. if (LAST_PLAYER_URL === playerUrl && LAST_FUNC !== null) {
  961. func = LAST_FUNC;
  962. } else {
  963.  
  964. var r = /\.sig\|\|([a-zA-Z0-9$]+)\(/.exec(jscode);
  965. if (r === null) {
  966. log("Couldn't find the signature code with regex");
  967. }
  968.  
  969. var funcname = r[1];
  970.  
  971. function shortcut(jscode) {
  972. var p = jscode.split('function ' + funcname + '(');
  973. if (p.length !== 2) {
  974. return null;
  975. }
  976.  
  977. var i1 = p[0].lastIndexOf('};var ');
  978. if (i1 === -1) {
  979. return null;
  980. }
  981.  
  982. var p1 = p[0].substr(i1 + 2);
  983.  
  984. var i2 = p[1].indexOf('};');
  985. if (i2 === -1) {
  986. return null;
  987. }
  988.  
  989. var p2 = p[1].substr(0, i2 + 2);
  990.  
  991. return p1 + 'function ' + funcname + '(' + p2;
  992. }
  993.  
  994. var temp = shortcut(jscode);
  995. if (temp !== null) {
  996. jscode = temp;
  997. }
  998.  
  999. var ast = esprima.parse(jscode);
  1000.  
  1001. function traverse(object, level, visitor) {
  1002. var key, child;
  1003.  
  1004. if (visitor.call(null, object) === false) {
  1005. return;
  1006. }
  1007.  
  1008. if (level > 8) {
  1009. return;
  1010. }
  1011.  
  1012. for (key in object) {
  1013. if (object.hasOwnProperty(key)) {
  1014. child = object[key];
  1015. if (typeof child === 'object' && child !== null) {
  1016. traverse(child, level + 1, visitor);
  1017. }
  1018. }
  1019. }
  1020. }
  1021.  
  1022. traverse(ast, 0, function (node) {
  1023. if (node.type === 'FunctionDeclaration' && node.id.name == funcname) {
  1024. func = eval('(' + escodegen.generate(node) + ')');
  1025. }
  1026.  
  1027. if (node.type === 'VariableDeclarator') {
  1028. try {
  1029. eval(escodegen.generate(node));
  1030. } catch (ignore) {
  1031. }
  1032. }
  1033. });
  1034.  
  1035. LAST_PLAYER_URL = playerUrl;
  1036. LAST_FUNC = func;
  1037. }
  1038.  
  1039. var signature = func(s);
  1040. deferred.resolve(signature);
  1041. });
  1042. }
  1043.  
  1044. return deferred.promise();
  1045. }
  1046.  
  1047. function parseDashManifest(video_id, dash_manifest_url, player_url, age_gate) {
  1048. var deferred = $.Deferred();
  1049.  
  1050. var r = /\/s\/([a-fA-F0-9\.]+)/.exec(dash_manifest_url);
  1051.  
  1052. if (r !== null) {
  1053. var s = r[1];
  1054.  
  1055. var formats = [];
  1056.  
  1057. decryptSignature(s, player_url).done(function (dec_s) {
  1058. dash_manifest_url = dash_manifest_url.replace(new RegExp('/s/' + s), '/signature/' + dec_s);
  1059.  
  1060. download(dash_manifest_url).done(function (dash_doc) {
  1061. dash_doc = $.parseXML(dash_doc);
  1062.  
  1063. $(dash_doc).find('AdaptationSet').each(function (index, elemSet) {
  1064. var mimeType = $(elemSet).attr('mimeType');
  1065.  
  1066. $(elemSet).find('Representation').each(function (index, elemRep) {
  1067. var url_el = $(elemRep).find('BaseURL');
  1068.  
  1069. if (mimeType.indexOf('audio/') === 0 || mimeType.indexOf('video/') === 0) {
  1070.  
  1071. var format_id = $(elemRep).attr('id');
  1072. var video_url = $(url_el).text();
  1073. var filesize = parseInt($(url_el).attr('yt:contentLength'));
  1074.  
  1075. var f = {
  1076. format_id: format_id,
  1077. url: video_url,
  1078. widt: parseInt($(elemRep).attr('width')),
  1079. height: parseInt($(elemRep).attr('height')),
  1080. filesize: filesize
  1081. }
  1082.  
  1083. formats.push(f);
  1084. }
  1085. });
  1086. });
  1087.  
  1088. deferred.resolve({
  1089. dash_manifest_url: dash_manifest_url,
  1090. formats: formats
  1091. });
  1092. });
  1093. });
  1094. } else {
  1095. deferred.resolve(null);
  1096. }
  1097.  
  1098. return deferred.promise();
  1099. }
  1100.  
  1101. function getSubtitles(videoId) {
  1102. var deferred = $.Deferred();
  1103.  
  1104. download('https://video.google.com/timedtext?hl=en&type=list&v=' + videoId).done(function (subsDoc) {
  1105. subsDoc = $.parseXML(subsDoc);
  1106.  
  1107. var subLangList = {};
  1108.  
  1109. $(subsDoc).find('track').each(function (index, track) {
  1110. var lang = $(track).attr('lang_code');
  1111. if (subLangList.hasOwnProperty(lang)) {
  1112. return;
  1113. }
  1114.  
  1115. var subFormats = [];
  1116.  
  1117. ['sbv', 'vtt', 'srt'].forEach(function (ext) {
  1118. var params = $.param({
  1119. lang: lang,
  1120. v: videoId,
  1121. fmt: ext,
  1122. name: $(track).attr('name'),
  1123. });
  1124.  
  1125. subFormats.push({
  1126. 'url': 'https://www.youtube.com/api/timedtext?' + params,
  1127. 'ext': ext,
  1128. });
  1129. });
  1130.  
  1131. subLangList[lang] = subFormats;
  1132. });
  1133.  
  1134. deferred.resolve(subLangList);
  1135. }).fail(function () {
  1136. deferred.resolve(null);
  1137. });
  1138.  
  1139. return deferred.promise();
  1140. }
  1141.  
  1142. function extractSupport(video_id, video_webpage, age_gate, embed_webpage, video_info) {
  1143. var deferred = $.Deferred();
  1144.  
  1145. function fail(s) {
  1146. log(s);
  1147. deferred.resolve(null);
  1148. return deferred.promise();
  1149. }
  1150.  
  1151. if (!video_info.hasOwnProperty('token')) {
  1152. if (video_info.hasOwnProperty('reason')) {
  1153. return fail('YouTube said: ' + video_info['reason'][0]);
  1154. }
  1155. else {
  1156. return fail('"token" parameter not in video info for unknown reason');
  1157. }
  1158. }
  1159.  
  1160. var view_count = 0;
  1161. if (video_info.hasOwnProperty('view_count')) {
  1162. view_count = parseInt(video_info['view_count'][0]);
  1163. }
  1164.  
  1165. // Check for "rental" videos
  1166. if (video_info.hasOwnProperty('ypc_video_rental_bar_text') && !video_info.hasOwnProperty('author')) {
  1167. return fail('"rental" videos not supported');
  1168. }
  1169.  
  1170. //Start extracting information
  1171. //self.report_information_extraction(video_id)
  1172.  
  1173. // uploader
  1174. if (!video_info.hasOwnProperty('author')) {
  1175. return fail('Unable to extract uploader name');
  1176. }
  1177.  
  1178. var video_uploader = decodeURIComponent(video_info['author'][0]);
  1179.  
  1180. // uploader_id
  1181. var video_uploader_id = null;
  1182.  
  1183. var mobj = /<link itemprop="url" href="http:\/\/www.youtube.com\/(?:user|channel)\/([^"]+)">/.exec(video_webpage);
  1184. if (mobj !== null) {
  1185. video_uploader_id = mobj[1];
  1186. }
  1187. else {
  1188. //return fail('unable to extract uploader nickname');
  1189. log('unable to extract uploader nickname');
  1190. }
  1191.  
  1192. // title
  1193. var video_title = '_';
  1194. if (video_info.hasOwnProperty('title')) {
  1195. video_title = video_info['title'][0];
  1196. }
  1197. else {
  1198. return fail('Unable to extract video title');
  1199. }
  1200.  
  1201. // upload date
  1202. var upload_date = null;
  1203. mobj = /id="eow-date.*?>(.*?)<\/span>/.exec(video_webpage);
  1204. if (mobj === null) {
  1205. mobj = /id="watch-uploader-info".*?>.*?(?:Published|Uploaded|Streamed live) on (.*?)<\/strong>/.exec(video_webpage);
  1206. }
  1207. if (mobj !== null) {
  1208. upload_date = new Date(mobj[1]);
  1209. //upload_date = ' '.join(re.sub(r'[/,-]', r' ', mobj.group(1)).split())
  1210. //upload_date = unified_strdate(upload_date)
  1211. }
  1212.  
  1213. // TODO: categories
  1214.  
  1215. // description
  1216. // TODO:
  1217.  
  1218. // subtitles
  1219. var videoSubtitles = null;
  1220. queue(function () {
  1221. return getSubtitles(video_id).done(function (subs) {
  1222. videoSubtitles = subs;
  1223. });
  1224. });
  1225. // TODO:
  1226. //automatic_captions = self.extract_automatic_captions(video_id, video_webpage)
  1227.  
  1228. var video_duration = null;
  1229. if (!video_info.hasOwnProperty('length_seconds')) {
  1230. return fail('unable to extract video duration');
  1231. }
  1232. else {
  1233. video_duration = parseInt(decodeURIComponent(video_info['length_seconds'][0]));
  1234. }
  1235.  
  1236. // TODO:
  1237. // annotations
  1238. //video_annotations = None
  1239. //if self._downloader.params.get('writeannotations', False):
  1240. // video_annotations = self._extract_annotations(video_id)
  1241.  
  1242. var formats = [];
  1243.  
  1244. if (video_info.hasOwnProperty('conn') && video_info['conn'][0].startswith('rtmp')) {
  1245. return fail('RTMP not supported');
  1246. } else if (video_info.hasOwnProperty('url_encoded_fmt_stream_map') || video_info.hasOwnProperty('adaptive_fmts')) {
  1247. var encodedUrlMap = '';
  1248. if (video_info.hasOwnProperty('url_encoded_fmt_stream_map')) {
  1249. encodedUrlMap = encodedUrlMap + ',' + video_info['url_encoded_fmt_stream_map'][0];
  1250. }
  1251. if (video_info.hasOwnProperty('adaptive_fmts')) {
  1252. encodedUrlMap = encodedUrlMap + ',' + video_info['adaptive_fmts'][0];
  1253. }
  1254. if (encodedUrlMap.indexOf('rtmpe%3Dyes') !== -1) {
  1255. return fail('rtmpe downloads are not supported');
  1256. }
  1257.  
  1258. var arr = encodedUrlMap.split(',');
  1259. var size = arr.length;
  1260.  
  1261. for (var i = 0; i < size; i++) {
  1262. if (arr[i].length == 0) {
  1263. continue;
  1264. }
  1265.  
  1266. var urlData = parseQS(arr[i]);
  1267.  
  1268. if (!urlData.hasOwnProperty('itag') || !urlData.hasOwnProperty('url')) {
  1269. continue;
  1270. }
  1271.  
  1272. var formatId = urlData['itag'][0];
  1273. var url = urlData['url'][0];
  1274.  
  1275. if (url.indexOf('ratebypass') === -1) {
  1276. url += '&ratebypass=yes';
  1277. }
  1278.  
  1279. if (urlData.hasOwnProperty('sig')) {
  1280. url += '&signature=' + urlData['sig'][0];
  1281. formats.push({
  1282. format_id: formatId,
  1283. url: url
  1284. });
  1285. } else if (urlData.hasOwnProperty('s')) {
  1286. var encrypted_sig = urlData['s'][0];
  1287. var ASSETS_RE = /"assets":.+?"js":\s*("[^"]+")/;
  1288.  
  1289. var jsplayer_url_json = searchRegex(ASSETS_RE, age_gate ? embed_webpage : video_webpage);
  1290.  
  1291. // TODO:
  1292. /*
  1293. if not jsplayer_url_json and not age_gate:
  1294. # We need the embed website after all
  1295. if embed_webpage is None:
  1296. embed_url = proto + '://www.youtube.com/embed/%s' % video_id
  1297. embed_webpage = self._download(
  1298. embed_url, video_id, 'Downloading embed webpage')
  1299. jsplayer_url_json = self._searchRegex(
  1300. ASSETS_RE, embed_webpage, 'JS player URL')
  1301. */
  1302.  
  1303. var playerUrl = JSON.parse(jsplayer_url_json);
  1304.  
  1305. (function (encrypted_sig, playerUrl, formatId, url) {
  1306. queue(function () {
  1307. return decryptSignature(encrypted_sig, playerUrl).done(function (signature) {
  1308. url += '&signature=' + signature;
  1309. formats.push({
  1310. format_id: formatId,
  1311. url: url
  1312. });
  1313. });
  1314. });
  1315. })(encrypted_sig, playerUrl, formatId, url);
  1316. } else if (url.indexOf('signature') !== -1) { // already decrypted
  1317. formats.push({
  1318. format_id: formatId,
  1319. url: url
  1320. });
  1321. }
  1322. }
  1323. } else if (video_info.hasOwnProperty('hlsvp')) {
  1324. return fail('HLS not supported');
  1325. } else {
  1326. return fail('no conn, hlsvp or url_encoded_fmt_stream_map information found in video info');
  1327. }
  1328.  
  1329. var dashManifestUrl = null;
  1330.  
  1331. function buildResult(formats) {
  1332. var size = formats.length;
  1333.  
  1334. for (var i = 0; i < size; i++) {
  1335. var fmt = formats[i];
  1336. var master = YT_FORMATS[fmt['format_id']];
  1337.  
  1338. $.extend(fmt, master);
  1339. }
  1340.  
  1341. return {
  1342. 'id': video_id,
  1343. 'uploader': video_uploader,
  1344. 'uploader_id': video_uploader_id,
  1345. 'upload_date': upload_date,
  1346. 'title': video_title,
  1347. 'thumbnail': 'https://i.ytimg.com/vi/' + video_id + '/hqdefault.jpg',
  1348. //'description': video_description,
  1349. //'categories': video_categories,
  1350. subtitles: videoSubtitles,
  1351. //'automatic_captions': automatic_captions,
  1352. 'duration': video_duration,
  1353. 'age_limit': age_gate ? 18 : 0,
  1354. //'annotations': video_annotations,
  1355. 'webpage_url': 'https://www.youtube.com/watch?v=' + video_id,
  1356. 'view_count': view_count,
  1357. //'average_rating': float_or_none(video_info.get('avg_rating', [None])[0]),
  1358. 'formats': formats,
  1359. dash_manifest_url: dashManifestUrl
  1360. }
  1361. }
  1362.  
  1363. // Look for the DASH manifest
  1364. if (video_info.hasOwnProperty('dashmpd')) {
  1365. dashManifestUrl = video_info['dashmpd'][0];
  1366.  
  1367. queue(function () {
  1368. return parseDashManifest(video_id, dashManifestUrl, playerUrl, age_gate).done(function (dash) {
  1369. if (dash != null) {
  1370. dashManifestUrl = dash.dash_manifest_url;
  1371. }
  1372. deferred.resolve(buildResult(dash && dash.formats ? formats.concat(dash.formats) : formats));
  1373. });
  1374. });
  1375. }
  1376.  
  1377. return deferred.promise();
  1378. }
  1379.  
  1380. function extract(url) {
  1381.  
  1382. var deferred = $.Deferred();
  1383.  
  1384. var video_id = extractId(url);
  1385.  
  1386. // Get video webpage
  1387. url = 'https://www.youtube.com/watch?v=' + video_id + '&gl=US&hl=en&has_verified=1&bpctr=9999999999';
  1388.  
  1389. download(url).done(function (video_webpage) {
  1390. var age_gate = false;
  1391.  
  1392. if (/player-age-gate-content">/i.test(video_webpage)) {
  1393. age_gate = true;
  1394. // We simulate the access to the video from www.youtube.com/v/{video_id}
  1395. // this can be viewed without login into Youtube
  1396. url = 'https://www.youtube.com/embed/' + video_id;
  1397. download(url).done(function (embed_webpage) {
  1398. var sts = searchRegex(/"sts"\s*:\s*(\d+)/, embed_webpage);
  1399. var videoInfoUrl = 'https://www.youtube.com/get_video_info?video_id=' + video_id + '&eurl=' + encodeURIComponent('https://youtube.googleapis.com/v/' + video_id) + '&sts=' + sts;
  1400. download(videoInfoUrl).done(function (video_info_webpage) {
  1401. var video_info = parseQS(video_info_webpage);
  1402. extractSupport(video_id, video_webpage, age_gate, embed_webpage, video_info).done(function (result) {
  1403. deferred.resolve(result);
  1404. });
  1405. });
  1406. });
  1407. } else {
  1408. age_gate = false;
  1409. var videoInfoUrl = 'https://www.youtube.com/get_video_info?&video_id=' + video_id + '&el=detailpage&ps=default&eurl=&gl=US&hl=en'
  1410. download(videoInfoUrl).done(function (video_info_webpage) {
  1411. var videoInfo = parseQS(video_info_webpage);
  1412. extractSupport(video_id, video_webpage, age_gate, '', videoInfo).done(function (result) {
  1413. deferred.resolve(result);
  1414. });
  1415. }).fail(function () {
  1416. deferred.resolve(null);
  1417. });
  1418. }
  1419. });
  1420.  
  1421. return deferred.promise();
  1422. }
  1423.  
  1424. function search(q) {
  1425.  
  1426. var deferred = $.Deferred();
  1427.  
  1428. var url = 'http://www.youtube.com/results?search_query=' + encodeURIComponent(q) + '&hl=en';
  1429.  
  1430. download(url).done(function (html) {
  1431. var re = /<h3 class="yt-lockup-title"><a href="\/watch\?v=(.*?)".*? title="(.*?)".*? Duration: (.*?)\.<\/span>.*?by <a href="\/user\/(.*?)".*?<li>([\d,]*) views<\/li>/ig;
  1432. var m = null;
  1433.  
  1434. var results = [];
  1435.  
  1436. while (m = re.exec(html)) {
  1437. var videoId = m[1];
  1438.  
  1439. var r = {
  1440. id: videoId,
  1441. url: 'https://www.youtube.com/watch?v=' + videoId,
  1442. title: m[2],
  1443. duration: m[3],
  1444. user: m[4],
  1445. views: parseInt(m[5].replace(/,/g, ''), 10),
  1446. thumbnail: 'https://i.ytimg.com/vi/' + videoId + '/mqdefault.jpg',
  1447. };
  1448.  
  1449. results.push(r);
  1450. }
  1451.  
  1452. deferred.resolve(results);
  1453. });
  1454.  
  1455. return deferred.promise();
  1456. }
  1457.  
  1458. function ytAutocompleteSource(request, response) {
  1459.  
  1460. // setup global object
  1461. if (typeof google === 'undefined') {
  1462. google = {
  1463. sbox: {
  1464. p50: function (data) {
  1465. data = data[1];
  1466. var result = [];
  1467. var size = data.length;
  1468. for (var i = 0; i < size; i++) {
  1469. result.push(data[i][0]);
  1470. }
  1471. google.sbox.response(result);
  1472. },
  1473. response: function (data) {
  1474. log(data)
  1475. }
  1476. }
  1477. }
  1478. }
  1479.  
  1480. // set global response
  1481. google.sbox.response = response;
  1482.  
  1483. $.ajax({
  1484. url: 'https://clients1.google.com/complete/search?client=youtube&hl=en&gl=us&gs_rn=23&gs_ri=youtube&ds=yt&cp=2&gs_id=8',
  1485. dataType: 'script',
  1486. data: {
  1487. q: request.term,
  1488. callback: 'google.sbox.p50'
  1489. },
  1490. success: function (data) {
  1491. // ignore
  1492. }
  1493. });
  1494. }
  1495. // END YT-LINKS CODE //
  1496.  
  1497. // START WAITFORKEYELEMENTS CODE //
  1498. /*--- waitForKeyElements(): A utility function, for Greasemonkey scripts,
  1499. that detects and handles AJAXed content.
  1500.  
  1501. Usage example:
  1502.  
  1503. waitForKeyElements (
  1504. "div.comments"
  1505. , commentCallbackFunction
  1506. );
  1507.  
  1508. //--- Page-specific function to do what we want when the node is found.
  1509. function commentCallbackFunction (jNode) {
  1510. jNode.text ("This comment changed by waitForKeyElements().");
  1511. }
  1512.  
  1513. IMPORTANT: This function requires your script to have loaded jQuery.
  1514. */
  1515. function waitForKeyElements (
  1516. selectorTxt, /* Required: The jQuery selector string that
  1517. specifies the desired element(s).
  1518. */
  1519. actionFunction, /* Required: The code to run when elements are
  1520. found. It is passed a jNode to the matched
  1521. element.
  1522. */
  1523. bWaitOnce, /* Optional: If false, will continue to scan for
  1524. new elements even after the first match is
  1525. found.
  1526. */
  1527. iframeSelector /* Optional: If set, identifies the iframe to
  1528. search.
  1529. */
  1530. ) {
  1531. var targetNodes, btargetsFound;
  1532.  
  1533. if (typeof iframeSelector == "undefined")
  1534. targetNodes = $(selectorTxt);
  1535. else
  1536. targetNodes = $(iframeSelector).contents ()
  1537. .find (selectorTxt);
  1538.  
  1539. if (targetNodes && targetNodes.length > 0) {
  1540. btargetsFound = true;
  1541. /*--- Found target node(s). Go through each and act if they
  1542. are new.
  1543. */
  1544. targetNodes.each ( function () {
  1545. var jThis = $(this);
  1546. var alreadyFound = jThis.data ('alreadyFound') || false;
  1547.  
  1548. if (!alreadyFound) {
  1549. //--- Call the payload function.
  1550. var cancelFound = actionFunction (jThis);
  1551. if (cancelFound)
  1552. btargetsFound = false;
  1553. else
  1554. jThis.data ('alreadyFound', true);
  1555. }
  1556. } );
  1557. }
  1558. else {
  1559. btargetsFound = false;
  1560. }
  1561.  
  1562. //--- Get the timer-control variable for this selector.
  1563. var controlObj = waitForKeyElements.controlObj || {};
  1564. var controlKey = selectorTxt.replace (/[^\w]/g, "_");
  1565. var timeControl = controlObj [controlKey];
  1566.  
  1567. //--- Now set or clear the timer as appropriate.
  1568. if (btargetsFound && bWaitOnce && timeControl) {
  1569. //--- The only condition where we need to clear the timer.
  1570. clearInterval (timeControl);
  1571. delete controlObj [controlKey]
  1572. }
  1573. else {
  1574. //--- Set a timer, if needed.
  1575. if ( ! timeControl) {
  1576. timeControl = setInterval ( function () {
  1577. waitForKeyElements ( selectorTxt,
  1578. actionFunction,
  1579. bWaitOnce,
  1580. iframeSelector
  1581. );
  1582. },
  1583. 300
  1584. );
  1585. controlObj [controlKey] = timeControl;
  1586. }
  1587. }
  1588. waitForKeyElements.controlObj = controlObj;
  1589. }
  1590. // END WAITFORKEYELEMENTS CODE //
  1591.