Youtube Downloader By Jeffery

Download every YouTube video you want and you can download them as Full-HD MP4, FLV, 3GP, MP3 128kbps and 192kbps, M4A and AAC formats.

  1. // ==UserScript==
  2. // @name Youtube Downloader By Jeffery
  3. // @description Download every YouTube video you want and you can download them as Full-HD MP4, FLV, 3GP, MP3 128kbps and 192kbps, M4A and AAC formats.
  4. // @author Jeffery
  5. // @version 1.7
  6. // @namespace Jeffery
  7. // @include http://www.youtube.com/*
  8. // @include https://www.youtube.com/*
  9. // @exclude http://www.youtube.com/embed/*
  10. // @exclude https://www.youtube.com/embed/*
  11. // @match http://www.youtube.com/*
  12. // @match https://www.youtube.com/*
  13. // @match http://manifest.googlevideo.com/*
  14. // @match https://manifest.googlevideo.com/*
  15. // @match http://*.googlevideo.com/videoplayback*
  16. // @match https://*.googlevideo.com/videoplayback*
  17. // @match http://*.youtube.com/videoplayback*
  18. // @match https://*.youtube.com/videoplayback*
  19. // @connect googlevideo.com
  20. // @connect bvd2.nl
  21. // @connect ytimg.com
  22. // @grant GM_xmlhttpRequest
  23. // @grant GM_getValu
  24. // @grant GM_setValue
  25. // @run-at document-end
  26. // @license MIT License
  27. // ==/UserScript==
  28. alert("The download button is below the video.-Jeffery")
  29.  
  30. (function() {
  31. var FORMAT_LABEL = {
  32. '18': 'MP4 360p',
  33. '22': 'MP4 720p',
  34. '43': 'WebM 360p',
  35. '44': 'WebM 480p',
  36. '45': 'WebM 720p',
  37. '46': 'WebM 1080p',
  38. '135': 'MP4 480p - no audio',
  39. '137': 'MP4 1080p - no audio',
  40. '138': 'MP4 2160p - no audio',
  41. '140': 'M4A 128kbps - audio',
  42. '264': 'MP4 1440p - no audio',
  43. '266': 'MP4 2160p - no audio',
  44. '298': 'MP4 720p60 - no audio',
  45. '13': '3GP',
  46. '17': '3GP 144p',
  47. '36': '3GP 240p',
  48. '5': 'FLV 240p',
  49. '34': 'FLV 360p',
  50. '35': 'FLV 480p',
  51. '299': 'MP4 1080p60 - no audio'
  52. };
  53. var FORMAT_TYPE = {
  54. '5': 'flv',
  55. '34': 'flv',
  56. '35': 'flv',
  57. '13': '3gp',
  58. '17': '3gp',
  59. '36': '3gp',
  60. '18': 'mp4',
  61. '22': 'mp4',
  62. '43': 'webm',
  63. '44': 'webm',
  64. '45': 'webm',
  65. '46': 'webm',
  66. '135': 'mp4',
  67. '137': 'mp4',
  68. '138': 'mp4',
  69. '140': 'm4a',
  70. '264': 'mp4',
  71. '266': 'mp4',
  72. '298': 'mp4',
  73. '299': 'mp4'
  74. };
  75. var FORMAT_ORDER = ['5', '13', '17', '34', '35', '36', '18', '43', '135', '44', '22', '298', '45', '137', '299', '46', '264', '138', '266', '140'];
  76. var FORMAT_RULE = {
  77. 'flv': 'all',
  78. '3gp': 'all',
  79. 'mp4': 'all',
  80. 'webm': 'none',
  81. 'm4a': 'max'
  82. };
  83. var SHOW_DASH_FORMATS = false;
  84. var BUTTON_TOOLTIP = {
  85. 'ar': 'تنزيل هذا الفيديو',
  86. 'cs': 'Stáhnout toto video',
  87. 'de': 'Dieses Video herunterladen',
  88. 'en': 'Download this video',
  89. 'nl': 'Download deze video',
  90. 'es': 'Descargar este vídeo',
  91. 'fr': 'Télécharger cette vidéo',
  92. 'hi': 'वीडियो डाउनलोड करें',
  93. 'hu': 'Videó letöltése',
  94. 'id': 'Unduh video ini',
  95. 'it': 'Scarica questo video',
  96. 'ja': 'このビデオをダウンロードする',
  97. 'ko': '이 비디오를 내려받기',
  98. 'pl': 'Pobierz plik wideo',
  99. 'pt': 'Baixar este vídeo',
  100. 'ro': 'Descărcați acest videoclip',
  101. 'ru': 'Скачать это видео',
  102. 'tr': 'Bu videoyu indir',
  103. 'zh': '下载此视频'
  104. };
  105. var DECODE_RULE = [];
  106. var RANDOM = 4789239175;
  107. var CONTAINER_ID = 'download-youtube-video' + RANDOM;
  108. var LISTITEM_ID = 'download-youtube-video-fmt' + RANDOM;
  109. var BUTTON_ID = 'download-youtube-video-button' + RANDOM;
  110. var DEBUG_ID = 'download-youtube-video-debug-info';
  111. var STORAGE_URL = 'download-youtube-script-url';
  112. var STORAGE_CODE = 'download-youtube-signature-code';
  113. var STORAGE_DASH = 'download-youtube-dash-enabled';
  114. var isDecodeRuleUpdated = false;
  115. var version = '7.70';
  116.  
  117. start();
  118. document.addEventListener("spfdone", start, false);
  119. function start() {
  120. //CHECK NEW DESIGN
  121. function isMaterial() {
  122. var temp;
  123. temp = document.querySelector("ytd-app, [src*='polymer'],link[href*='polymer']");
  124. if (temp && !document.getElementById("material-notice")) {
  125. temp = document.createElement("template");
  126. temp.innerHTML = //
  127. `<div id='material-notice' style='border-radius:2px;color:#FFF;padding:10px;background-color:#ff0000;box-shadow:0 0 3px rgba(0,0,0,.5);font-size:12px;position:fixed;bottom:20px;right:50px;z-index:99999'>
  128. <strong><ins>WARNING : </ins></strong>'Best Video Downloader 2' is not compatible with the experimental YouTube Material Layout<br/> which is under BETA testing.<br><br>
  129. <a href='https://bvd2.nl/newdesign' target='_blank' style='color:#FFF;font-weight:bold;'>Click here</a> for instructions on how to continue using the video downloading features.<br>This addon will get migrated to the new layout if Youtube makes the BETA design as default.
  130. </div>`;
  131. document.documentElement.appendChild(temp.content.firstChild);
  132. document.documentElement.removeAttribute("data-user_settings");
  133. return true;
  134. }
  135. }
  136. isMaterial();
  137. //END
  138. var pagecontainer = document.getElementById('page-container');
  139. if (!pagecontainer) return;
  140. if (/^https?:\/\/www\.youtube.com\/watch\?/.test(window.location.href)) run();
  141. var isAjax = /class[\w\s"'-=]+spf\-link/.test(pagecontainer.innerHTML);
  142. var logocontainer = document.getElementById('logo-container');
  143. if (logocontainer && !isAjax) {
  144. isAjax = (' ' + logocontainer.className + ' ').indexOf(' spf-link ') >= 0;
  145. }
  146. var content = document.getElementById('content');
  147. if (isAjax && content) {
  148. var mo = window.MutationObserver || window.WebKitMutationObserver;
  149. if (typeof mo !== 'undefined') {
  150. var observer = new mo(function(mutations) {
  151. mutations.forEach(function(mutation) {
  152. if (mutation.addedNodes !== null) {
  153. for (var i = 0; i < mutation.addedNodes.length; i++) {
  154. if (mutation.addedNodes[i].id == 'watch7-container' ||
  155. mutation.addedNodes[i].id == 'watch7-main-container') {
  156. run();
  157. break;
  158. }
  159. }
  160. }
  161. });
  162. });
  163. observer.observe(content, {
  164. childList: true,
  165. subtree: true
  166. });
  167. } else {
  168. pagecontainer.addEventListener('DOMNodeInserted', onNodeInserted, false);
  169. }
  170. }
  171. }
  172.  
  173. function onNodeInserted(e) {
  174. if (e && e.target && (e.target.id == 'watch7-container' ||
  175. e.target.id == 'watch7-main-container')) {
  176. run();
  177. }
  178. }
  179.  
  180. function run() {
  181. if (document.getElementById(CONTAINER_ID)) return;
  182. if (document.getElementById('p') && document.getElementById('vo')) return;
  183.  
  184. var videoID, videoFormats, videoAdaptFormats, videoManifestURL, scriptURL = null;
  185. var isSignatureUpdatingStarted = false;
  186. var operaTable = new Array();
  187. var language = document.documentElement.getAttribute('lang');
  188. var textDirection = 'left';
  189. if (document.body.getAttribute('dir') == 'rtl') {
  190. textDirection = 'right';
  191. }
  192. if (document.getElementById('watch7-action-buttons')) {
  193. fixTranslations(language, textDirection);
  194. }
  195.  
  196. var args = null;
  197. var usw = (typeof this.unsafeWindow !== 'undefined') ? this.unsafeWindow : window;
  198. if (usw.ytplayer && usw.ytplayer.config && usw.ytplayer.config.args) {
  199. args = usw.ytplayer.config.args;
  200. }
  201. if (args) {
  202. videoID = args['video_id'];
  203. videoFormats = args['url_encoded_fmt_stream_map'];
  204. videoAdaptFormats = args['adaptive_fmts'];
  205. videoManifestURL = args['dashmpd'];
  206. debug('DYVAM - Info: Standard mode. videoID ' + (videoID ? videoID : 'none') + '; ');
  207. }
  208. if (usw.ytplayer && usw.ytplayer.config && usw.ytplayer.config.assets) {
  209. scriptURL = usw.ytplayer.config.assets.js;
  210. }
  211.  
  212. if (videoID == null) {
  213. var buffer = document.getElementById(DEBUG_ID + '2');
  214. if (buffer) {
  215. while (buffer.firstChild) {
  216. buffer.removeChild(buffer.firstChild);
  217. }
  218. } else {
  219. buffer = createHiddenElem('pre', DEBUG_ID + '2');
  220. }
  221. injectScript('if(ytplayer&&ytplayer.config&&ytplayer.config.args){document.getElementById("' + DEBUG_ID + '2").appendChild(document.createTextNode(\'"video_id":"\'+ytplayer.config.args.video_id+\'", "js":"\'+ytplayer.config.assets.js+\'", "dashmpd":"\'+ytplayer.config.args.dashmpd+\'", "url_encoded_fmt_stream_map":"\'+ytplayer.config.args.url_encoded_fmt_stream_map+\'", "adaptive_fmts":"\'+ytplayer.config.args.adaptive_fmts+\'"\'));}');
  222. var code = buffer.innerHTML;
  223. if (code) {
  224. videoID = findMatch(code, /\"video_id\":\s*\"([^\"]+)\"/);
  225. videoFormats = findMatch(code, /\"url_encoded_fmt_stream_map\":\s*\"([^\"]+)\"/);
  226. videoFormats = videoFormats.replace(/&amp;/g, '\\u0026');
  227. videoAdaptFormats = findMatch(code, /\"adaptive_fmts\":\s*\"([^\"]+)\"/);
  228. videoAdaptFormats = videoAdaptFormats.replace(/&amp;/g, '\\u0026');
  229. videoManifestURL = findMatch(code, /\"dashmpd\":\s*\"([^\"]+)\"/);
  230. scriptURL = findMatch(code, /\"js\":\s*\"([^\"]+)\"/);
  231. }
  232. debug('DYVAM - Info: Injection mode. videoID ' + (videoID ? videoID : 'none') + '; ');
  233. }
  234.  
  235. if (videoID == null) {
  236. var bodyContent = document.body.innerHTML;
  237. if (bodyContent != null) {
  238. videoID = findMatch(bodyContent, /\"video_id\":\s*\"([^\"]+)\"/);
  239. videoFormats = findMatch(bodyContent, /\"url_encoded_fmt_stream_map\":\s*\"([^\"]+)\"/);
  240. videoAdaptFormats = findMatch(bodyContent, /\"adaptive_fmts\":\s*\"([^\"]+)\"/);
  241. videoManifestURL = findMatch(bodyContent, /\"dashmpd\":\s*\"([^\"]+)\"/);
  242. if (scriptURL == null) {
  243. scriptURL = findMatch(bodyContent, /\"js\":\s*\"([^\"]+)\"/);
  244. if (scriptURL) {
  245. scriptURL = scriptURL.replace(/\\/g, '');
  246. }
  247. }
  248. }
  249. debug('DYVAM - Info: Brute mode. videoID ' + (videoID ? videoID : 'none') + '; ');
  250. }
  251.  
  252. debug('DYVAM - Info: url ' + window.location.href + '; useragent ' + window.navigator.userAgent);
  253.  
  254. if (videoID == null || videoFormats == null || videoID.length == 0 || videoFormats.length == 0) {
  255. debug('DYVAM - Error: No config information found. YouTube must have changed the code.');
  256. return;
  257. }
  258. if (typeof window.opera !== 'undefined' && window.opera && typeof opera.extension !== 'undefined') {
  259. opera.extension.onmessage = function(event) {
  260. var index = findMatch(event.data.action, /xhr\-([0-9]+)\-response/);
  261. if (index && operaTable[parseInt(index, 10)]) {
  262. index = parseInt(index, 10);
  263. var trigger = (operaTable[index])['onload'];
  264. if (typeof trigger === 'function' && event.data.readyState == 4) {
  265. if (trigger) {
  266. trigger(event.data);
  267. }
  268. }
  269. }
  270. }
  271. }
  272.  
  273. if (!isDecodeRuleUpdated) {
  274. DECODE_RULE = getDecodeRules(DECODE_RULE);
  275. isDecodeRuleUpdated = true;
  276. }
  277. if (scriptURL) {
  278. scriptURL = absoluteURL(scriptURL);
  279. fetchSignatureScript(scriptURL);
  280. }
  281. var videoTitle = document.title || 'video';
  282. videoTitle = videoTitle.replace(/\s*\-\s*YouTube$/i, '').replace(/'/g, '\'').replace(/^\s+|\s+$/g, '').replace(/\.+$/g, '');
  283. videoTitle = videoTitle.replace(/[:"\?\*]/g, '').replace(/[\|\\\/]/g, '_');
  284. if (((window.navigator.userAgent || '').toLowerCase()).indexOf('windows') >= 0) {
  285. videoTitle = videoTitle.replace(/#/g, '').replace(/&/g, '_');
  286. } else {
  287. videoTitle = videoTitle.replace(/#/g, '%23').replace(/&/g, '%26');
  288. }
  289. var sep1 = '%2C',
  290. sep2 = '%26',
  291. sep3 = '%3D';
  292. if (videoFormats.indexOf(',') > -1) {
  293. sep1 = ',';
  294. sep2 = (videoFormats.indexOf('&') > -1) ? '&' : '\\u0026';
  295. sep3 = '=';
  296. }
  297. var videoURL = new Array();
  298. var videoSignature = new Array();
  299. if (videoAdaptFormats) {
  300. videoFormats = videoFormats + sep1 + videoAdaptFormats;
  301. }
  302. var videoFormatsGroup = videoFormats.split(sep1);
  303. for (var i = 0; i < videoFormatsGroup.length; i++) {
  304. var videoFormatsElem = videoFormatsGroup[i].split(sep2);
  305. var videoFormatsPair = new Array();
  306. for (var j = 0; j < videoFormatsElem.length; j++) {
  307. var pair = videoFormatsElem[j].split(sep3);
  308. if (pair.length == 2) {
  309. videoFormatsPair[pair[0]] = pair[1];
  310. }
  311. }
  312. if (videoFormatsPair['url'] == null) continue;
  313. var url = unescape(unescape(videoFormatsPair['url'])).replace(/\\\//g, '/').replace(/\\u0026/g, '&');
  314. if (videoFormatsPair['itag'] == null) continue;
  315. var itag = videoFormatsPair['itag'];
  316. var sig = videoFormatsPair['sig'] || videoFormatsPair['signature'];
  317. if (sig) {
  318. url = url + '&signature=' + sig;
  319. videoSignature[itag] = null;
  320. } else if (videoFormatsPair['s']) {
  321. url = url + '&signature=' + decryptSignature(videoFormatsPair['s']);
  322. videoSignature[itag] = videoFormatsPair['s'];
  323. }
  324. if (url.toLowerCase().indexOf('ratebypass') == -1) {
  325. url = url + '&ratebypass=yes';
  326. }
  327. if (url.toLowerCase().indexOf('http') == 0) {
  328. videoURL[itag] = url + '&title=' + videoTitle;
  329. }
  330. }
  331.  
  332. var showFormat = new Array();
  333. for (var category in FORMAT_RULE) {
  334. var rule = FORMAT_RULE[category];
  335. for (var index in FORMAT_TYPE) {
  336. if (FORMAT_TYPE[index] == category) {
  337. showFormat[index] = (rule == 'all');
  338. }
  339. }
  340. if (rule == 'max') {
  341. for (var i = FORMAT_ORDER.length - 1; i >= 0; i--) {
  342. var format = FORMAT_ORDER[i];
  343. if (FORMAT_TYPE[format] == category && videoURL[format] != undefined) {
  344. showFormat[format] = true;
  345. break;
  346. }
  347. }
  348. }
  349. }
  350.  
  351. var dashPref = getPref(STORAGE_DASH);
  352. if (dashPref == '1') {
  353. SHOW_DASH_FORMATS = true;
  354. } else if (dashPref != '0') {
  355. setPref(STORAGE_DASH, '0');
  356. }
  357.  
  358. var downloadCodeList = [];
  359. for (var i = 0; i < FORMAT_ORDER.length; i++) {
  360. var format = FORMAT_ORDER[i];
  361. if (format == '37' && videoURL[format] == undefined) {
  362. if (videoURL['137']) {
  363. format = '137';
  364.  
  365. }
  366.  
  367. showFormat[format] = showFormat['37'];
  368. } else if (format == '38' && videoURL[format] == undefined) {
  369. if (videoURL['138'] && !videoURL['266']) {
  370. format = '138';
  371. }
  372. showFormat[format] = showFormat['38'];
  373. }
  374. if (!SHOW_DASH_FORMATS && format.length > 2) continue;
  375. if (videoURL[format] != undefined && FORMAT_LABEL[format] != undefined && showFormat[format]) {
  376. downloadCodeList.push({
  377. url: videoURL[format],
  378. sig: videoSignature[format],
  379. format: format,
  380. label: FORMAT_LABEL[format]
  381. });
  382. debug('DYVAM - Info: itag' + format + ' url:' + videoURL[format]);
  383. }
  384. }
  385.  
  386. if (downloadCodeList.length == 0) {
  387. debug('DYVAM - Error: No download URL found. Probably YouTube uses encrypted streams.');
  388. return;
  389. }
  390. var newWatchPage = false;
  391. var parentElement = document.getElementById('watch7-action-buttons');
  392. if (parentElement == null) {
  393. parentElement = document.getElementById('watch8-secondary-actions');
  394. if (parentElement == null) {
  395. debug('DYVAM Error - No container for adding the download button. YouTube must have changed the code.');
  396. return;
  397. } else {
  398. newWatchPage = true;
  399. }
  400. }
  401.  
  402. var buttonLabel = (BUTTON_TOOLTIP[language]) ? BUTTON_TOOLTIP[language] : BUTTON_TOOLTIP['en'];
  403. var mainSpan = document.createElement('span');
  404.  
  405. if (newWatchPage) {
  406. var spanIcon = document.createElement('span');
  407. spanIcon.setAttribute('class', 'yt-uix-button-content');
  408. var imageIcon = document.createElement('img');
  409. imageIcon.setAttribute('src', '//s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif');
  410. imageIcon.setAttribute('class', 'yt-uix-button-icon');
  411. imageIcon.setAttribute('src', 'data:image/false;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAeCAIAAABc0ozeAAAACXBIWXMAAAsTAAALEwEAmpwYAAA57GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxMzggNzkuMTU5ODI0LCAyMDE2LzA5LzE0LTAxOjA5OjAxICAgICAgICAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICAgICAgICAgIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNyAoV2luZG93cyk8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHhtcDpDcmVhdGVEYXRlPjIwMTctMDMtMjZUMDQ6MDI6MTgrMDI6MDA8L3htcDpDcmVhdGVEYXRlPgogICAgICAgICA8eG1wOk1ldGFkYXRhRGF0ZT4yMDE3LTAzLTI2VDA0OjAyOjE4KzAyOjAwPC94bXA6TWV0YWRhdGFEYXRlPgogICAgICAgICA8eG1wOk1vZGlmeURhdGU+MjAxNy0wMy0yNlQwNDowMjoxOCswMjowMDwveG1wOk1vZGlmeURhdGU+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6Yzc2YTExOWMtYjQxYi0yMjQ0LWI3MWMtYTg0NDhkMzgwNmRhPC94bXBNTTpJbnN0YW5jZUlEPgogICAgICAgICA8eG1wTU06RG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpwaG90b3Nob3A6MzkyYTcwOGQtMTFjOC0xMWU3LWFhNGMtZDdlYjlhNmQ0NjJiPC94bXBNTTpEb2N1bWVudElEPgogICAgICAgICA8eG1wTU06T3JpZ2luYWxEb2N1bWVudElEPnhtcC5kaWQ6MjEwNDBjYzktMDcyNS03NDRiLWJlZWItZmFlY2Y3ZGQzZWUyPC94bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpIaXN0b3J5PgogICAgICAgICAgICA8cmRmOlNlcT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+Y3JlYXRlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOjIxMDQwY2M5LTA3MjUtNzQ0Yi1iZWViLWZhZWNmN2RkM2VlMjwvc3RFdnQ6aW5zdGFuY2VJRD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OndoZW4+MjAxNy0wMy0yNlQwNDowMjoxOCswMjowMDwvc3RFdnQ6d2hlbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnNvZnR3YXJlQWdlbnQ+QWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpPC9zdEV2dDpzb2Z0d2FyZUFnZW50PgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+c2F2ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0Omluc3RhbmNlSUQ+eG1wLmlpZDpjNzZhMTE5Yy1iNDFiLTIyNDQtYjcxYy1hODQ0OGQzODA2ZGE8L3N0RXZ0Omluc3RhbmNlSUQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDp3aGVuPjIwMTctMDMtMjZUMDQ6MDI6MTgrMDI6MDA8L3N0RXZ0OndoZW4+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpzb2Z0d2FyZUFnZW50PkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE3IChXaW5kb3dzKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOlNlcT4KICAgICAgICAgPC94bXBNTTpIaXN0b3J5PgogICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3BuZzwvZGM6Zm9ybWF0PgogICAgICAgICA8cGhvdG9zaG9wOkNvbG9yTW9kZT4zPC9waG90b3Nob3A6Q29sb3JNb2RlPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpYUmVzb2x1dGlvbj43MjAwMDAvMTAwMDA8L3RpZmY6WFJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOllSZXNvbHV0aW9uPjcyMDAwMC8xMDAwMDwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPGV4aWY6Q29sb3JTcGFjZT42NTUzNTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+OTY8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+MzA8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/Pq4YhDcAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAABP5JREFUeNrsmlFMU1cYx/+FXqCt0EvT6kWj1YSQtgg0IyPFuKHBZDUxpptLKpmEyktLgml5WAbzZQ9TcUuERqNlD67GEeHFGV2y+kAUyEZjwtKugVYgsRdDqdB0F8rl1nZt9zBFAip1ajLN/b/dk/M/555fvvOd755cAcuydt/FsYX7C2wYvJ5KKqEqSPWJ3Rah3Xex79HvY0RBSlTEc1lRbor1hYcB5G75XHknJ5MSCHgoq5URCCI5QkWcyVlcDvN0nquUQLDIPcrhQbxcPCAe0OtJ+KqGH/f2mjYBABO9XHxvgI+gl4jgt9j/VNaaHzJ7zf/dX/F9pv6k9S1tsSwX0C2TPHlIMp7IdYN3gH6/c5C16rSlkABAip60kIV6/956AOFo3/7x0bWG5Lht4JQdOz7ZdcRR2uyuTpSMDr/PgOwTQ4Y9jftWpx1CoSIQXxqyrafzTNO3H3TtE50O7jh4STTcwkG5vdVVVqsiALDB+VuG0RHLHrspfVPk7gd0v+4/oWOvFt9zAfo79Y3UnNUttRvS3qCoSksAqXnXxLcH6ciq8Su7apotMkUBEE/SzrFzLeEIIDdXfdVZspXEKouo/ufqY4ZNeQAbWEoCzJvOQZxrv3cokFobJu2jPbc3stLjdABy1WZAdOyGqpaK3dw3+IV2zA/Z0b4KRWcsVCApNQOQ1aryQUoqjQCoShURck9FAJCSrcGJDsHg+b6EQr/9iHLVyE3VZps0ecPXIRg872DllnKzFcCu1u4Sqed+h8DV0R4T60vNVsBaYTTkz3Z7rILfrnogfjtJOtKjnxh/9smfpB3eU3YuS7OEkgClVVpMOu71D3LwPuz6JsqoZPqdM6EgodDLUKdUUozXLVSaKCgVCooLOTkAYBZcnz6cBuduiIaQLzc8G7PeRJLByOWGmWlw7jbviIcoPVoGRK6b/ugyPZgGps/O0gxBalFvKJQEo1fbwhHEhhsWIm/rFKPpUzr/OAMgFXJ6v255hYnYMAsASCdXEF9JLEMo1kZHAo8Vqm2VliJpgPnOzZKqErWtcGt4aWQwizoj/rf/aYzPMsk8Mh+IQbfT7NH3ZvS9GbWGXN/zTecged3mUmqF5OOBzlnoHg+5hDoj9bQxveCe87/onFJqlCpE7s4BRUAOsWJqyhMjPR+G27nY2Fd4FHmzd2m0gbZsMeqEbGDGvdGLJQEUCNWAHwBEJSSBeBJ1Vc026bLT13F8ZhrKk3+pybU93zSgI44PPlatbdSshHo8hYLckNP15fHneHc0aRo7tynD844WDpjyeqiDlhqjy9fPyFrbZWRw7kI/gEjIodaolob0HEBPBrYf0GGyc+O6YMDJfOaUN1/bdr4hKjlTUatNTbYHQFUTSCfC3DIKP7pUoiSxAAzciBm7ZY1d1Lk2Vn1NKs8+Sb9+HcSGE9gpWh/+mm59b/e/ddDcZYN3GAC4nwwB0lV2+G7dYYANzvcZvH4AoKcCZRoqNkQD4G55uAPa9FRHFnNfGe3R1jRbKs5kgHiSdvgunAUwfstUY2yvsbcjEWBmGYhJGey+fl210aa125AIMBEmP9vlCQ5dP/TLBneJZr9+fQSt0Ysi6N3WIW4xmwjqUbt6+OsOXjwgHhAPiAfEA3r3ABWJqdxMhgexXrmZTJGYyqksVpcn4zyj9XTKk1yVTCM8sdsC4E/Gv8j/vLBKUglVKf+wtdz8zwBtOQxheHlkawAAAABJRU5ErkJggg==');
  412. spanIcon.appendChild(imageIcon);
  413. mainSpan.appendChild(spanIcon);
  414. }
  415.  
  416. var spanButton = document.createElement('span');
  417. spanButton.setAttribute('class', 'yt-uix-button-content');
  418. mainSpan.appendChild(spanButton);
  419.  
  420. if (!newWatchPage) {
  421. var imgButton = document.createElement('img');
  422. imgButton.setAttribute('class', 'yt-uix-button-arrow');
  423. imgButton.setAttribute('src', '//s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif');
  424. mainSpan.appendChild(imgButton);
  425. }
  426. var listItems = document.createElement('ol');
  427. listItems.setAttribute('style', 'display:none;');
  428. listItems.setAttribute('class', 'yt-uix-button-menu');
  429. for (var i = 0; i < downloadCodeList.length; i++) {
  430. var listItem = document.createElement('li');
  431. var listLink = document.createElement('a');
  432. listLink.setAttribute('style', 'text-decoration:none;');
  433. listLink.setAttribute('href', downloadCodeList[i].url);
  434. listLink.setAttribute('download', videoTitle + '.' + FORMAT_TYPE[downloadCodeList[i].format]);
  435. var listButton = document.createElement('span');
  436. listButton.setAttribute('class', 'yt-uix-button-menu-item');
  437. listButton.setAttribute('loop', i + '');
  438. listButton.setAttribute('id', LISTITEM_ID + downloadCodeList[i].format);
  439. if (downloadCodeList[i].format == '137') {
  440. listButton.onclick = function() {
  441. window.open('https://bvd2.nl/download/direct/1080p.php?url=' + videoID);
  442. }
  443. }
  444. listButton.appendChild(document.createTextNode(downloadCodeList[i].label));
  445. listLink.appendChild(listButton);
  446. listItem.appendChild(listLink);
  447. listItems.appendChild(listItem);
  448. }
  449. if (videoURL['137'] != undefined) {
  450. //console.log('Inside Full-HD :' + format);
  451. var listItem = document.createElement('li');
  452. var listLink = document.createElement('a');
  453. listLink.setAttribute('style', 'text-decoration:none;');
  454. listLink.setAttribute('href', 'javascript:void(0);');
  455. var listSpan = document.createElement('span');
  456. listSpan.setAttribute('class', 'yt-uix-button-menu-item');
  457. listSpan.setAttribute('id', LISTITEM_ID + '-1080p3');
  458. listSpan.onclick = function () {
  459. window.open('https://bvd2.nl/download/direct/1080p.php?url=' + videoID);
  460.  
  461. return false;
  462. };
  463.  
  464. listSpan.appendChild(document.createTextNode('MP4 1080p (Full-HD)'));
  465. listLink.appendChild(listSpan);
  466. listItem.appendChild(listLink);
  467. listItems.appendChild(listItem);
  468.  
  469. }
  470. var listItem = document.createElement('li');
  471. var listLink = document.createElement('a');
  472. listLink.setAttribute('style', 'text-decoration:none;');
  473. listLink.setAttribute('href', 'https://bvd2.nl/download/direct/aac.php?url=' + videoID);
  474. listLink.setAttribute('target', '_blank');
  475. var listSpan = document.createElement('span');
  476. listSpan.setAttribute('class', 'yt-uix-button-menu-item');
  477. listSpan.setAttribute('id', LISTITEM_ID + '-aac');
  478. listSpan.appendChild(document.createTextNode('AAC'));
  479. listLink.appendChild(listSpan);
  480. listItem.appendChild(listLink);
  481. listItems.appendChild(listItem);
  482. var listItem = document.createElement('li');
  483. var listLink = document.createElement('a');
  484. listLink.setAttribute('style', 'text-decoration:none;');
  485. listLink.setAttribute('href', 'https://bvd2.nl/download/direct/mp3.php?url=' + videoID);
  486. listLink.setAttribute('target', '_blank');
  487. var listSpan = document.createElement('span');
  488. listSpan.setAttribute('class', 'yt-uix-button-menu-item');
  489. listSpan.setAttribute('id', LISTITEM_ID + '-mp3');
  490. listSpan.appendChild(document.createTextNode('MP3 (128 Kbps)'));
  491. listLink.appendChild(listSpan);
  492. listItem.appendChild(listLink);
  493. listItems.appendChild(listItem);
  494. var listItem = document.createElement('li');
  495. var listLink = document.createElement('a');
  496. listLink.setAttribute('style', 'text-decoration:none;');
  497. listLink.setAttribute('href', 'https://bvd2.nl/download/direct/mp3hq.php?url=' + videoID);
  498. listLink.setAttribute('target', '_blank');
  499. var listSpan = document.createElement('span');
  500. listSpan.setAttribute('class', 'yt-uix-button-menu-item');
  501. listSpan.setAttribute('id', LISTITEM_ID + '-mp3hq');
  502. listSpan.appendChild(document.createTextNode('MP3 (192 Kbps)'));
  503. listLink.appendChild(listSpan);
  504. listItem.appendChild(listLink);
  505. listItems.appendChild(listItem);
  506. var listItem = document.createElement('li');
  507. var listLink = document.createElement('a');
  508. listLink.setAttribute('style', 'text-decoration:none;');
  509. listLink.setAttribute('href', 'https://bvd2.nl/download/direct/m4a.php?url=' + videoID);
  510. listLink.setAttribute('target', '_blank');
  511. var listSpan = document.createElement('span');
  512. listSpan.setAttribute('class', 'yt-uix-button-menu-item');
  513. listSpan.setAttribute('id', LISTITEM_ID + '-m4a');
  514. listSpan.appendChild(document.createTextNode('M4A (Best Quality)'));
  515. listLink.appendChild(listSpan);
  516. listItem.appendChild(listLink);
  517. listItems.appendChild(listItem);
  518. var listItem = document.createElement('li');
  519. var listLink = document.createElement('a');
  520. listLink.setAttribute('style', 'text-decoration:none;');
  521. var thumbID = 'vi/' + videoID + '/hqdefault.jpg';
  522. listLink.setAttribute('href', 'https://img.youtube.com/' + thumbID);
  523. listLink.setAttribute('target', '_blank');
  524. listLink.setAttribute('download', 'https://img.youtube.com/' + thumbID);
  525. var listSpan = document.createElement('span');
  526. listSpan.setAttribute('class', 'yt-uix-button-menu-item');
  527. listSpan.setAttribute('id', LISTITEM_ID + '-thumbnail');
  528. listSpan.setAttribute('title', 'Contact to get support, Bug Report or Suggestion');
  529. listSpan.appendChild(document.createTextNode('Thumbnail'));
  530. listLink.appendChild(listSpan);
  531. listItem.appendChild(listLink);
  532. listItems.appendChild(listItem);
  533. var listItem = document.createElement('li');
  534. var listLink = document.createElement('a');
  535. listLink.setAttribute('style', 'text-decoration:none;');
  536. listLink.setAttribute('href', 'https://bvd2.nl/download/direct/subtitle.php?url=' + videoID);
  537. listLink.setAttribute('target', '_blank');
  538. var listSpan = document.createElement('span');
  539. listSpan.setAttribute('class', 'yt-uix-button-menu-item');
  540. listSpan.setAttribute('id', LISTITEM_ID + '-sub');
  541. listSpan.appendChild(document.createTextNode('Subtitle'));
  542. listLink.appendChild(listSpan);
  543. listItem.appendChild(listLink);
  544. listItems.appendChild(listItem);
  545. var listItem = document.createElement('li');
  546. var listLink = document.createElement('a');
  547. listLink.setAttribute('style', 'text-decoration: underline overline; margin-left: 1px; color: #1b7fcc;');
  548. listLink.setAttribute('href', 'https://bvd2.nl/support?ver=' + version);
  549. listLink.setAttribute('target', '_blank');
  550. var listSpan = document.createElement('span');
  551. listSpan.setAttribute('class', 'yt-uix-button-menu-item');
  552. listSpan.setAttribute('id', LISTITEM_ID + '-support');
  553. listSpan.setAttribute('title', 'Contact to get support, Bug Report or Suggestion');
  554. listSpan.appendChild(document.createTextNode('Contact/Help/Donate'));
  555. listLink.appendChild(listSpan);
  556. listItem.appendChild(listLink);
  557. listItems.appendChild(listItem);
  558. mainSpan.appendChild(listItems);
  559. var buttonElement = document.createElement('button');
  560. buttonElement.setAttribute('id', BUTTON_ID);
  561. if (newWatchPage) {
  562. buttonElement.setAttribute('class', 'yt-uix-button yt-uix-button-size-default yt-uix-button-opacity yt-uix-tooltip yt-uix-button-active');
  563. } else {
  564. buttonElement.setAttribute('class', 'yt-uix-button yt-uix-tooltip yt-uix-button-empty yt-uix-button-text');
  565. buttonElement.setAttribute('style', 'margin-top:4px; margin-left:' + ((textDirection == 'left') ? 5 : 10) + 'px;');
  566. }
  567. buttonElement.setAttribute('data-tooltip-text', buttonLabel);
  568. buttonElement.setAttribute('type', 'button');
  569. buttonElement.setAttribute('role', 'button');
  570. buttonElement.addEventListener('click', function() {
  571. var frm_div = document.getElementById('EXT_DIV');
  572. if (frm_div) {
  573. frm_div.parentElement.removeChild(frm_div);
  574. }
  575. return false;
  576. }, false);
  577. buttonElement.appendChild(mainSpan);
  578. var containerSpan = document.createElement('span');
  579. containerSpan.setAttribute('id', CONTAINER_ID);
  580. containerSpan.appendChild(document.createTextNode(' '));
  581. containerSpan.appendChild(buttonElement);
  582. if (!newWatchPage) {
  583. parentElement.appendChild(containerSpan);
  584. } else {
  585. parentElement.insertBefore(containerSpan, parentElement.firstChild);
  586. }
  587. for (var i = 0; i < downloadCodeList.length; i++) {
  588. addFileSize(downloadCodeList[i].url, downloadCodeList[i].format);
  589. }
  590.  
  591. if (typeof GM_download !== 'undefined') {
  592. for (var i = 0; i < downloadCodeList.length; i++) {
  593. var downloadFMT = document.getElementById(LISTITEM_ID + downloadCodeList[i].format);
  594. var url = (downloadCodeList[i].url).toLowerCase();
  595. if (url.indexOf('clen=') > 0 && url.indexOf('dur=') > 0 && url.indexOf('gir=') > 0 &&
  596. url.indexOf('lmt=') > 0) {
  597. downloadFMT.addEventListener('click', downloadVideoNatively, false);
  598. }
  599. }
  600. }
  601.  
  602. addFromManifest();
  603.  
  604. function downloadVideoNatively(e) {
  605. var elem = e.currentTarget;
  606. e.returnValue = false;
  607. if (e.preventDefault) {
  608. e.preventDefault();
  609. }
  610. var loop = elem.getAttribute('loop');
  611. if (loop) {
  612. GM_download(downloadCodeList[loop].url, videoTitle + '.' + FORMAT_TYPE[downloadCodeList[loop].format]);
  613. }
  614. return false;
  615. }
  616.  
  617. function addFromManifest() { // add Dash URLs from manifest file
  618. var formats = ['137', '138', '140']; // 137=1080p, 138=4k, 140=m4a
  619. var isNecessary = true;
  620. for (var i = 0; i < formats.length; i++) {
  621. if (videoURL[formats[i]]) {
  622. isNecessary = false;
  623. break;
  624. }
  625. }
  626. if (videoManifestURL && SHOW_DASH_FORMATS && isNecessary) {
  627. var matchSig = findMatch(videoManifestURL, /\/s\/([a-zA-Z0-9\.]+)\//i);
  628. if (matchSig) {
  629. var decryptedSig = decryptSignature(matchSig);
  630. if (decryptedSig) {
  631. videoManifestURL = videoManifestURL.replace('/s/' + matchSig + '/', '/signature/' + decryptedSig + '/');
  632. }
  633. }
  634. if (videoManifestURL.indexOf('//') == 0) {
  635. var protocol = (document.location.protocol == 'http:') ? 'http:' : 'https:';
  636. videoManifestURL = protocol + videoManifestURL;
  637. }
  638. debug('DYVAM - Info: manifestURL ' + videoManifestURL);
  639. crossXmlHttpRequest({
  640. method: 'GET',
  641. url: videoManifestURL, // check if URL exists
  642. onload: function(response) {
  643. if (response.readyState === 4 && response.status === 200 && response.responseText) {
  644. debug('DYVAM - Info: maniestFileContents ' + response.responseText);
  645. var lastFormatFromList = downloadCodeList[downloadCodeList.length - 1].format;
  646. debug('DYVAM - Info: lastformat: ' + lastFormatFromList);
  647. for (var i = 0; i < formats.length; i++) {
  648. k = formats[i];
  649. if (videoURL[k] || showFormat[k] == false) continue;
  650. var regexp = new RegExp('<BaseURL>(http[^<]+itag\\/' + k + '[^<]+)<\\/BaseURL>', 'i');
  651. var matchURL = findMatch(response.responseText, regexp);
  652. debug('DYVAM - Info: matchURL itag= ' + k + ' url= ' + matchURL);
  653. if (!matchURL) continue;
  654. matchURL = matchURL.replace(/&amp\;/g, '&');
  655. // ...
  656. downloadCodeList.push({
  657. url: matchURL,
  658. sig: videoSignature[k],
  659. format: k,
  660. label: FORMAT_LABEL[k]
  661. });
  662. var downloadFMT = document.getElementById(LISTITEM_ID + lastFormatFromList);
  663. var clone = downloadFMT.parentNode.parentNode.cloneNode(true);
  664. clone.firstChild.firstChild.setAttribute('id', LISTITEM_ID + k);
  665. clone.firstChild.setAttribute('href', matchURL);
  666. downloadFMT.parentNode.parentNode.parentNode.appendChild(clone);
  667. downloadFMT = document.getElementById(LISTITEM_ID + k);
  668. downloadFMT.firstChild.nodeValue = FORMAT_LABEL[k];
  669. addFileSize(matchURL, k);
  670. lastFormatFromList = k;
  671. }
  672. }
  673. }
  674. });
  675. }
  676. }
  677.  
  678. function injectStyle(code) {
  679. var style = document.createElement('style');
  680. style.type = 'text/css';
  681. style.appendChild(document.createTextNode(code));
  682. document.getElementsByTagName('head')[0].appendChild(style);
  683. }
  684.  
  685. function injectScript(code) {
  686. var script = document.createElement('script');
  687. script.type = 'application/javascript';
  688. script.textContent = code;
  689. document.body.appendChild(script);
  690. document.body.removeChild(script);
  691. }
  692.  
  693. function debug(str) {
  694. var debugElem = document.getElementById(DEBUG_ID);
  695. if (!debugElem) {
  696. debugElem = createHiddenElem('div', DEBUG_ID);
  697.  
  698. }
  699. debugElem.appendChild(document.createTextNode(str + ' '));
  700. }
  701.  
  702. function createHiddenElem(tag, id) {
  703. var elem = document.createElement(tag);
  704. elem.setAttribute('id', id);
  705. elem.setAttribute('style', 'display:none;');
  706. document.body.appendChild(elem);
  707. return elem;
  708. }
  709.  
  710. function fixTranslations(language, textDirection) {
  711. if (/^af|bg|bn|ca|cs|de|el|es|et|eu|fa|fi|fil|fr|gl|hi|hr|hu|id|it|iw|kn|lv|lt|ml|mr|ms|nl|pl|ro|ru|sl|sk|sr|sw|ta|te|th|uk|ur|vi|zu$/.test(language)) {
  712. var likeButton = document.getElementById('watch-like');
  713. if (likeButton) {
  714. var spanElements = likeButton.getElementsByClassName('yt-uix-button-content');
  715. if (spanElements) {
  716. spanElements[0].style.display = 'none';
  717. }
  718. }
  719. var marginPixels = 10;
  720. if (/^bg|ca|cs|el|eu|hr|it|ml|ms|pl|sl|sw|te$/.test(language)) {
  721. marginPixels = 1;
  722. }
  723. injectStyle('#watch7-secondary-actions .yt-uix-button{margin-' + textDirection + ':' + marginPixels + 'px!important}');
  724. }
  725. }
  726.  
  727. function findMatch(text, regexp) {
  728. var matches = text.match(regexp);
  729. return (matches) ? matches[1] : null;
  730. }
  731.  
  732. function isString(s) {
  733. return (typeof s === 'string' || s instanceof String);
  734. }
  735.  
  736. function isInteger(n) {
  737. return (typeof n === 'number' && n % 1 == 0);
  738. }
  739.  
  740. function absoluteURL(url) {
  741. var link = document.createElement('a');
  742. link.href = url;
  743. return link.href;
  744. }
  745.  
  746. function getPref(name) {
  747. var a = '',
  748. b = '';
  749. try {
  750. a = typeof GM_getValue.toString;
  751. b = GM_getValue.toString()
  752. } catch (e) {}
  753. if (typeof GM_getValue === 'function' &&
  754. (a === 'undefined' || b.indexOf('not supported') === -1)) {
  755. return GM_getValue(name, null);
  756. } else {
  757. var ls = null;
  758. try {
  759. ls = window.localStorage || null
  760. } catch (e) {}
  761. if (ls) {
  762. return ls.getItem(name);
  763. }
  764. }
  765. return;
  766. }
  767.  
  768. function setPref(name, value) {
  769. var a = '',
  770. b = '';
  771. try {
  772. a = typeof GM_setValue.toString;
  773. b = GM_setValue.toString()
  774. } catch (e) {}
  775. if (typeof GM_setValue === 'function' &&
  776. (a === 'undefined' || b.indexOf('not supported') === -1)) {
  777. GM_setValue(name, value);
  778. } else {
  779. var ls = null;
  780. try {
  781. ls = window.localStorage || null
  782. } catch (e) {}
  783. if (ls) {
  784. return ls.setItem(name, value);
  785. }
  786. }
  787. }
  788.  
  789. function crossXmlHttpRequest(details) {
  790. if (typeof GM_xmlhttpRequest === 'function') {
  791. GM_xmlhttpRequest(details);
  792. } else if (typeof window.opera !== 'undefined' && window.opera && typeof opera.extension !== 'undefined' &&
  793. typeof opera.extension.postMessage !== 'undefined') {
  794. var index = operaTable.length;
  795. opera.extension.postMessage({
  796. 'action': 'xhr-' + index,
  797. 'url': details.url,
  798. 'method': details.method
  799. });
  800. operaTable[index] = details;
  801. } else if (typeof window.opera === 'undefined' && typeof XMLHttpRequest === 'function') {
  802. var xhr = new XMLHttpRequest();
  803. xhr.onreadystatechange = function() {
  804. if (xhr.readyState == 4) {
  805. if (details['onload']) {
  806. details['onload'](xhr);
  807. }
  808. }
  809. }
  810. xhr.open(details.method, details.url, true);
  811. xhr.send();
  812. }
  813. }
  814.  
  815. function addFileSize(url, format) {
  816.  
  817. function updateVideoLabel(size, format) {
  818. var elem = document.getElementById(LISTITEM_ID + format);
  819. if (elem) {
  820. size = parseInt(size, 10);
  821. if (size >= 1073741824) {
  822. size = parseFloat((size / 1073741824).toFixed(1)) + ' GB';
  823. } else if (size >= 1048576) {
  824. size = parseFloat((size / 1048576).toFixed(1)) + ' MB';
  825. } else {
  826. size = parseFloat((size / 1024).toFixed(1)) + ' KB';
  827. }
  828. if (elem.childNodes.length > 1) {
  829. elem.lastChild.nodeValue = ' (' + size + ')';
  830. } else if (elem.childNodes.length == 1) {
  831. elem.appendChild(document.createTextNode(' (' + size + ')'));
  832. }
  833. }
  834. }
  835.  
  836. var matchSize = findMatch(url, /[&\?]clen=([0-9]+)&/i);
  837. if (matchSize) {
  838. updateVideoLabel(matchSize, format);
  839. } else {
  840. try {
  841. crossXmlHttpRequest({
  842. method: 'HEAD',
  843. url: url,
  844. onload: function(response) {
  845. if (response.readyState == 4 && response.status == 200) {
  846. var size = 0;
  847. if (typeof response.getResponseHeader === 'function') {
  848. size = response.getResponseHeader('Content-length');
  849. } else if (response.responseHeaders) {
  850. var regexp = new RegExp('^Content\-length: (.*)$', 'im');
  851. var match = regexp.exec(response.responseHeaders);
  852. if (match) {
  853. size = match[1];
  854. }
  855. }
  856. if (size) {
  857. updateVideoLabel(size, format);
  858. }
  859. }
  860. }
  861. });
  862. } catch (e) {}
  863. }
  864. }
  865.  
  866. function findSignatureCode(sourceCode) {
  867. debug('DYVAM - Info: signature start ' + getPref(STORAGE_CODE));
  868. var signatureFunctionName =
  869. findMatch(sourceCode,
  870. /\.set\s*\("signature"\s*,\s*([a-zA-Z0-9_$][\w$]*)\(/) ||
  871. findMatch(sourceCode,
  872. /\.sig\s*\|\|\s*([a-zA-Z0-9_$][\w$]*)\(/) ||
  873. findMatch(sourceCode,
  874. /\.signature\s*=\s*([a-zA-Z_$][\w$]*)\([a-zA-Z_$][\w$]*\)/);
  875. if (signatureFunctionName == null) return setPref(STORAGE_CODE, 'error');
  876. signatureFunctionName = signatureFunctionName.replace('$', '\\$');
  877. var regCode = new RegExp(signatureFunctionName + '\\s*=\\s*function' +
  878. '\\s*\\([\\w$]*\\)\\s*{[\\w$]*=[\\w$]*\\.split\\(""\\);\n*(.+);return [\\w$]*\\.join');
  879. var regCode2 = new RegExp('function \\s*' + signatureFunctionName +
  880. '\\s*\\([\\w$]*\\)\\s*{[\\w$]*=[\\w$]*\\.split\\(""\\);\n*(.+);return [\\w$]*\\.join');
  881. var functionCode = findMatch(sourceCode, regCode) || findMatch(sourceCode, regCode2);
  882. debug('DYVAM - Info: signaturefunction ' + signatureFunctionName + ' -- ' + functionCode);
  883. if (functionCode == null) return setPref(STORAGE_CODE, 'error');
  884.  
  885. var reverseFunctionName = findMatch(sourceCode,
  886. /([\w$]*)\s*:\s*function\s*\(\s*[\w$]*\s*\)\s*{\s*(?:return\s*)?[\w$]*\.reverse\s*\(\s*\)\s*}/);
  887. debug('DYVAM - Info: reversefunction ' + reverseFunctionName);
  888. if (reverseFunctionName) reverseFunctionName = reverseFunctionName.replace('$', '\\$');
  889. var sliceFunctionName = findMatch(sourceCode,
  890. /([\w$]*)\s*:\s*function\s*\(\s*[\w$]*\s*,\s*[\w$]*\s*\)\s*{\s*(?:return\s*)?[\w$]*\.(?:slice|splice)\(.+\)\s*}/);
  891. debug('DYVAM - Info: slicefunction ' + sliceFunctionName);
  892. if (sliceFunctionName) sliceFunctionName = sliceFunctionName.replace('$', '\\$');
  893.  
  894. var regSlice = new RegExp('\\.(?:' + 'slice' + (sliceFunctionName ? '|' + sliceFunctionName : '') +
  895. ')\\s*\\(\\s*(?:[a-zA-Z_$][\\w$]*\\s*,)?\\s*([0-9]+)\\s*\\)');
  896. var regReverse = new RegExp('\\.(?:' + 'reverse' + (reverseFunctionName ? '|' + reverseFunctionName : '') +
  897. ')\\s*\\([^\\)]*\\)');
  898. var regSwap = new RegExp('[\\w$]+\\s*\\(\\s*[\\w$]+\\s*,\\s*([0-9]+)\\s*\\)');
  899. var regInline = new RegExp('[\\w$]+\\[0\\]\\s*=\\s*[\\w$]+\\[([0-9]+)\\s*%\\s*[\\w$]+\\.length\\]');
  900. var functionCodePieces = functionCode.split(';');
  901. var decodeArray = [];
  902. for (var i = 0; i < functionCodePieces.length; i++) {
  903. functionCodePieces[i] = functionCodePieces[i].trim();
  904. var codeLine = functionCodePieces[i];
  905. if (codeLine.length > 0) {
  906. var arrSlice = codeLine.match(regSlice);
  907. var arrReverse = codeLine.match(regReverse);
  908. debug(i + ': ' + codeLine + ' --' + (arrSlice ? ' slice length ' + arrSlice.length : '') + ' ' + (arrReverse ? 'reverse' : ''));
  909. if (arrSlice && arrSlice.length >= 2) {
  910. var slice = parseInt(arrSlice[1], 10);
  911. if (isInteger(slice)) {
  912. decodeArray.push(-slice);
  913. } else return setPref(STORAGE_CODE, 'error');
  914. } else if (arrReverse && arrReverse.length >= 1) {
  915. decodeArray.push(0);
  916. } else if (codeLine.indexOf('[0]') >= 0) {
  917. if (i + 2 < functionCodePieces.length &&
  918. functionCodePieces[i + 1].indexOf('.length') >= 0 &&
  919. functionCodePieces[i + 1].indexOf('[0]') >= 0) {
  920. var inline = findMatch(functionCodePieces[i + 1], regInline);
  921. inline = parseInt(inline, 10);
  922. decodeArray.push(inline);
  923. i += 2;
  924. } else return setPref(STORAGE_CODE, 'error');
  925. } else if (codeLine.indexOf(',') >= 0) {
  926. var swap = findMatch(codeLine, regSwap);
  927. swap = parseInt(swap, 10);
  928. if (isInteger(swap) && swap > 0) {
  929. decodeArray.push(swap);
  930. } else return setPref(STORAGE_CODE, 'error');
  931. } else return setPref(STORAGE_CODE, 'error');
  932. }
  933. }
  934.  
  935. if (decodeArray) {
  936. setPref(STORAGE_URL, scriptURL);
  937. setPref(STORAGE_CODE, decodeArray.toString());
  938. DECODE_RULE = decodeArray;
  939. debug('DYVAM - Info: signature ' + decodeArray.toString() + ' ' + scriptURL);
  940. for (var i = 0; i < downloadCodeList.length; i++) {
  941. var elem = document.getElementById(LISTITEM_ID + downloadCodeList[i].format);
  942. var url = downloadCodeList[i].url;
  943. var sig = downloadCodeList[i].sig;
  944. if (elem && url && sig) {
  945. url = url.replace(/\&signature=[\w\.]+/, '&signature=' + decryptSignature(sig));
  946. elem.parentNode.setAttribute('href', url);
  947. addFileSize(url, downloadCodeList[i].format);
  948. }
  949. }
  950. }
  951. }
  952.  
  953. function isValidSignatureCode(arr) {
  954. if (!arr) return false;
  955. if (arr == 'error') return true;
  956. arr = arr.split(',');
  957. for (var i = 0; i < arr.length; i++) {
  958. if (!isInteger(parseInt(arr[i], 10))) return false;
  959. }
  960. return true;
  961. }
  962.  
  963. function fetchSignatureScript(scriptURL) {
  964. var storageURL = getPref(STORAGE_URL);
  965. var storageCode = getPref(STORAGE_CODE);
  966. if (!(/,0,|^0,|,0$|\-/.test(storageCode))) storageCode = null;
  967. if (storageCode && isValidSignatureCode(storageCode) && storageURL &&
  968. scriptURL == absoluteURL(storageURL)) return;
  969. try {
  970. debug('DYVAM fetch ' + scriptURL);
  971. isSignatureUpdatingStarted = true;
  972. crossXmlHttpRequest({
  973. method: 'GET',
  974. url: scriptURL,
  975. onload: function(response) {
  976. debug('DYVAM fetch status ' + response.status);
  977. if (response.readyState === 4 && response.status === 200 && response.responseText) {
  978. findSignatureCode(response.responseText);
  979. }
  980. }
  981. });
  982. } catch (e) {}
  983. }
  984.  
  985. function getDecodeRules(rules) {
  986. var storageCode = getPref(STORAGE_CODE);
  987. if (storageCode && storageCode != 'error' && isValidSignatureCode(storageCode)) {
  988. var arr = storageCode.split(',');
  989. for (var i = 0; i < arr.length; i++) {
  990. arr[i] = parseInt(arr[i], 10);
  991. }
  992. rules = arr;
  993. debug('DYVAM - Info: signature ' + arr.toString() + ' ' + scriptURL);
  994. }
  995. return rules;
  996. }
  997.  
  998. function decryptSignature(sig) {
  999. function swap(a, b) {
  1000. var c = a[0];
  1001. a[0] = a[b % a.length];
  1002. a[b] = c;
  1003. return a
  1004. };
  1005.  
  1006. function decode(sig, arr) {
  1007. if (!isString(sig)) return null;
  1008. var sigA = sig.split('');
  1009. for (var i = 0; i < arr.length; i++) {
  1010. var act = arr[i];
  1011. if (!isInteger(act)) return null;
  1012. sigA = (act > 0) ? swap(sigA, act) : ((act == 0) ? sigA.reverse() : sigA.slice(-act));
  1013. }
  1014. var result = sigA.join('');
  1015. return result;
  1016. }
  1017.  
  1018. if (sig == null) return '';
  1019. var arr = DECODE_RULE;
  1020. if (arr) {
  1021. var sig2 = decode(sig, arr);
  1022. if (sig2) return sig2;
  1023. } else {
  1024. setPref(STORAGE_URL, '');
  1025. setPref(STORAGE_CODE, '');
  1026. }
  1027. return sig;
  1028. }
  1029.  
  1030. }
  1031.  
  1032. })();