leathan

Hacked script (Download off youtube [mp4/mp3])

May 22nd, 2016
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name Download YouTube Videos as MP4
  3. // @description Adds a button that lets you download YouTube videos.
  4. // @homepageURL https://github.com/gantt/downloadyoutube
  5. // @author Gantt
  6. // @version 1.8.7
  7. // @date 2016-03-19
  8. // @namespace http://googlesystem.blogspot.com
  9. // @include http://www.youtube.com/*
  10. // @include https://www.youtube.com/*
  11. // @exclude http://www.youtube.com/embed/*
  12. // @exclude https://www.youtube.com/embed/*
  13. // @match http://www.youtube.com/*
  14. // @match https://www.youtube.com/*
  15. // @match http://s.ytimg.com/yts/jsbin/html5player*
  16. // @match https://s.ytimg.com/yts/jsbin/html5player*
  17. // @match http://manifest.googlevideo.com/*
  18. // @match https://manifest.googlevideo.com/*
  19. // @match http://*.googlevideo.com/videoplayback*
  20. // @match https://*.googlevideo.com/videoplayback*
  21. // @match http://*.youtube.com/videoplayback*
  22. // @match https://*.youtube.com/videoplayback*
  23. // @connect googlevideo.com
  24. // @connect ytimg.com
  25. // @grant GM_xmlhttpRequest
  26. // @grant GM_getValue
  27. // @grant GM_setValue
  28. // @run-at document-end
  29. // @require http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js
  30. // @license MIT License
  31. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAB3RJTUUH2wMOCgIoGUYEAQAAAAlwSFlzAAALEgAACxIB0t1+/AAAAARnQU1BAACxjwv8YQUAAAGSUExURfi/JO/v797e3sbGxq2traWlpZSUlJycnNbW1oyEhIRaWow5OZQhIZwYGKUQEKUICK0ICJQxMYxKSoxzc4x7e4RCQpQYGKUAAK0AALUAAL0AAK0QEIxra5QpKa0YGIxSUsYAAKUhIZR7e87Ozr0ICJRSUr29vYxjY6U5OaUpKa0hIb21tZwAALUICO/Ozu/GxqUxMZSEhLUYGO/W1r0YGKVCQpQQEL0pKffe3vfW1pxra5Q5OcZCQvfn585CQr2trZx7e8ZSUs5SUq05Oc5jY9ZjY84AAKWMjM5zc957e60pKdaMjOelpbWcnLWUlLVCQsYYGMYICNbOzpQICMYhIbV7e5xaWt6cnPfv79bGxt6lpe+9vc5KSs6lpb0xMc6EhM69vbUxMbUhIb1aWs61tcZaWuecnMYxMb1KSsZjY96UlNa1td7W1r17e9a9vZwQEN6trb1jY8YQENZra+fOzr1zc85aWufe3t6MjMY5OdZaWt61tdZ7e+/n5+e9vc6MjMZra+/e3ue1tdalpd7GxrUpKalL4aAAAAABdFJOUwBA5thmAAACxklEQVR42uXX/1/SQBgH8NuAoEQ2ijgbBivJLznBAiUUKiyJSgOVAk0tKZKw75mRRt/7v4MBY8ezjW39Vs8v8rqHz/u1jbvbidC/XL8KmcpOqVT6nSjXjooGw8WfFd+QWGfE4oLbtbr++PdMOy0BDYLjEj/0xevfWIyVAI7b/aIj/9WHsRrA8Yf9bqSexVgD4Lic9kWE/LgPwPGfNfJHDO4P8Iuq+S2M9QD8oUp+nxEAcFCtfgIA/14x/9ElAKDQbNQAwN9VAiYEABy0OgsAWAnB/AcBAtVWawkAfJ4CD0BQADZavYcQgI9h3CCQjpD5PcEgwG+SwLRhIL0vz78SjAPEU3hrHODfyX4I6rUJIP0G3oExoNwFXpoB+HwXmDEFpF9IwKA5YK+Tp9fMAdUOsC6YA553gKcmgdTfAhV1oMQqADndQDmJ0AZLAsFnCIV3VYDHJLAjDkZKciAaFz/lCeBJB1glgXBrNLndBWLJ9uZGAI+keTBLANL8SnWAzWRniAC2pG+6lQF0hfjTqCIBrEvjDwiggFSLuIUoLY0vEwAbUcsnc/LlnO02HGvEz+hXEeJ5Yj+4L2vNkxOJDSnlQzliIq2synr3embiUBjmw0FyU83KX04Ob+9aAK/Ppd5deZloz4HFlCHzt3sX0x2a6LcvQb4ab8r7i+DVdqvnCq/D5ZzqdhfAcr5B9wD0PNwPEu0ZnLwK9oPgNfCQJ2fhhhITJ3E8BjeUOXA+QNQlBh5xLjemVCgKjzgzNIJFjWF4yJoKhafgIWt6VHGmjgR0HvMuTipPdWQJ6AImbBRSE8aY/sC4er5xFx5vHyB4YRRpFWUf0AL4c+dHkHZRFo9TDeB9Aa3Llwjr8FlFwB+wO/rHm0VbPae9mPini/O5h/XGxatw2I6fGHAOuhiGZVxO98lTdgutP94yaIvVdqxZdpvFYTT9X9UfqQQlTXlm8wkAAAAASUVORK5CYII=
  32. // ==/UserScript==
  33.  
  34.  
  35.  
  36.        
  37.  
  38. (function () {
  39.   var FORMAT_LABEL={'5':'FLV 240p','18':'MP4 360p','22':'MP4 720p','34':'FLV 360p','35':'FLV 480p','37':'MP4 1080p','38':'MP4 2160p','43':'WebM 360p','44':'WebM 480p','45':'WebM 720p','46':'WebM 1080p','135':'MP4 480p - no audio','137':'MP4 1080p - no audio','138':'MP4 2160p - no audio','139':'M4A 48kbps - audio','140':'M4A 128kbps - audio','141':'M4A 256kbps - audio','264':'MP4 1440p - no audio','266':'MP4 2160p - no audio','298':'MP4 720p60 - no audio','299':'MP4 1080p60 - no audio'};
  40.   var FORMAT_TYPE={'5':'flv','18':'mp4','22':'mp4','34':'flv','35':'flv','37':'mp4','38':'mp4','43':'webm','44':'webm','45':'webm','46':'webm','135':'mp4','137':'mp4','138':'mp4','139':'m4a','140':'m4a','141':'m4a','264':'mp4','266':'mp4','298':'mp4','299':'mp4'};
  41.   var FORMAT_ORDER=['5','18','34','43','35','135','44','22','298','45','37','299','46','264','38','266','139','140','141'];
  42.   var FORMAT_RULE={'flv':'max','mp4':'all','webm':'none','m4a':'max'};
  43.   // all=display all versions, max=only highest quality version, none=no version  
  44.   // the default settings show all MP4 videos, the highest quality FLV and no WebM
  45.   var SHOW_DASH_FORMATS=false;
  46.   var BUTTON_TEXT={'ar':'تنزيل','cs':'Stáhnout','de':'Herunterladen','en':'Download','es':'Descargar','fr':'Télécharger','hi':'डाउनलोड','hu':'Letöltés','id':'Unduh','it':'Scarica','ja':'ダウンロード','ko':'내려받기','pl':'Pobierz','pt':'Baixar','ro':'Descărcați','ru':'Скачать','tr':'İndir','zh':'下载','zh-TW':'下載'};
  47.   var BUTTON_TOOLTIP={'ar':'تنزيل هذا الفيديو','cs':'Stáhnout toto video','de':'Dieses Video herunterladen','en':'Download this video','es':'Descargar este vídeo','fr':'Télécharger cette vidéo','hi':'वीडियो डाउनलोड करें','hu':'Videó letöltése','id':'Unduh video ini','it':'Scarica questo video','ja':'このビデオをダウンロードする','ko':'이 비디오를 내려받기','pl':'Pobierz plik wideo','pt':'Baixar este vídeo','ro':'Descărcați acest videoclip','ru':'Скачать это видео','tr': 'Bu videoyu indir','zh':'下载此视频','zh-TW':'下載此影片'};
  48.   var DECODE_RULE=[];
  49.   var RANDOM=7489235179; // Math.floor(Math.random()*1234567890);
  50.   var CONTAINER_ID='download-youtube-video'+RANDOM;
  51.   var LISTITEM_ID='download-youtube-video-fmt'+RANDOM;
  52.   var BUTTON_ID='download-youtube-video-button'+RANDOM;
  53.   var DEBUG_ID='download-youtube-video-debug-info';
  54.   var STORAGE_URL='download-youtube-script-url';
  55.   var STORAGE_CODE='download-youtube-signature-code';
  56.   var STORAGE_DASH='download-youtube-dash-enabled';
  57.   var isDecodeRuleUpdated=false;
  58.  
  59.   start();
  60.  
  61. function start() {
  62.   var pagecontainer=document.getElementById('page-container');
  63.   if (!pagecontainer) return;
  64.   if (/^https?:\/\/www\.youtube.com\/watch\?/.test(window.location.href)) run();
  65.   var isAjax=/class[\w\s"'-=]+spf\-link/.test(pagecontainer.innerHTML);
  66.   var logocontainer=document.getElementById('logo-container');
  67.   if (logocontainer && !isAjax) { // fix for blocked videos
  68.     isAjax=(' '+logocontainer.className+' ').indexOf(' spf-link ')>=0;
  69.   }
  70.   var content=document.getElementById('content');
  71.   if (isAjax && content) { // Ajax UI
  72.       var mo=window.MutationObserver||window.WebKitMutationObserver;
  73.       if(typeof mo!=='undefined') {
  74.         var observer=new mo(function(mutations) {
  75.           mutations.forEach(function(mutation) {
  76.               if(mutation.addedNodes!==null) {
  77.                 for (var i=0; i<mutation.addedNodes.length; i++) {
  78.                     if (mutation.addedNodes[i].id=='watch7-container' ||
  79.                         mutation.addedNodes[i].id=='watch7-main-container') { // old value: movie_player
  80.                       run();
  81.                       break;
  82.                     }
  83.                 }
  84.               }
  85.           });
  86.         });
  87.         observer.observe(content, {childList: true, subtree: true}); // old value: pagecontainer
  88.       } else { // MutationObserver fallback for old browsers
  89.         pagecontainer.addEventListener('DOMNodeInserted', onNodeInserted, false);
  90.       }
  91.   }
  92. }
  93.  
  94. function onNodeInserted(e) {
  95.     if (e && e.target && (e.target.id=='watch7-container' ||
  96.         e.target.id=='watch7-main-container')) { // old value: movie_player
  97.       run();
  98.   }
  99. }
  100.  
  101. function run() {
  102.  
  103.   // Add persistant "MP3 Download" option.
  104.   var linkPath ='http://youtubeinmp3.com/fetch/?video='+encodeURIComponent(document.URL)+"&hq=1"; // MP3 Download direct link.
  105.   $('<a id="youtube2mp3" class="yt-uix-button yt-uix-button-default" a target="_blank" href="'+linkPath+'" style="margin-left: 8px; height: 26px; padding: 0 22px; /* background-color: #e62117; */"><img src="http://youtubeinmp3.com/icon/download.png" style="vertical-align:middle;color: white;"> <span class="yt-uix-button-content" style="line-height: 25px; /* font-variant: small-caps; */ font-size: 12px; /* color: #fefefe; */">MP3 Download</span></a>').insertAfter( "#watch7-subscription-container" );  
  106.   window.close(); //Close the download tab.
  107.  
  108.     if (document.getElementById(CONTAINER_ID)) return; // check download container
  109.   if (document.getElementById('p') && document.getElementById('vo')) return; // Feather not supported
  110.  
  111.   var videoID, videoFormats, videoAdaptFormats, videoManifestURL, scriptURL=null;
  112.   var isSignatureUpdatingStarted=false;
  113.   var operaTable=new Array();
  114.   var language=document.documentElement.getAttribute('lang');
  115.   var textDirection='left';
  116.   if (document.body.getAttribute('dir')=='rtl') {
  117.     textDirection='right';
  118.   }
  119.   if (document.getElementById('watch7-action-buttons')) {  // old UI
  120.     fixTranslations(language, textDirection);
  121.   }
  122.  
  123.   // obtain video ID, formats map
  124.  
  125.   var args=null;
  126.   var usw=(typeof this.unsafeWindow !== 'undefined')?this.unsafeWindow:window; // Firefox, Opera<15
  127.   if (usw.ytplayer && usw.ytplayer.config && usw.ytplayer.config.args) {
  128.     args=usw.ytplayer.config.args;
  129.   }
  130.   if (args) {
  131.     videoID=args['video_id'];
  132.     videoFormats=args['url_encoded_fmt_stream_map'];
  133.     videoAdaptFormats=args['adaptive_fmts'];
  134.     videoManifestURL=args['dashmpd'];
  135.     debug('DYVAM - Info: Standard mode. videoID '+(videoID?videoID:'none')+'; ');
  136.   }
  137.   if (usw.ytplayer && usw.ytplayer.config && usw.ytplayer.config.assets) {
  138.     scriptURL=usw.ytplayer.config.assets.js;
  139.   }
  140.  
  141.   if (videoID==null) { // unsafeWindow workaround (Chrome, Opera 15+)
  142.     var buffer=document.getElementById(DEBUG_ID+'2');
  143.     if (buffer) {
  144.       while (buffer.firstChild) {
  145.         buffer.removeChild(buffer.firstChild);
  146.       }
  147.     } else {
  148.       buffer=createHiddenElem('pre', DEBUG_ID+'2');
  149.     }
  150.     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+\'"\'));}');
  151.     var code=buffer.innerHTML;
  152.     if (code) {
  153.       videoID=findMatch(code, /\"video_id\":\s*\"([^\"]+)\"/);
  154.      videoFormats=findMatch(code, /\"url_encoded_fmt_stream_map\":\s*\"([^\"]+)\"/);
  155.      videoFormats=videoFormats.replace(/&amp;/g,'\\u0026');
  156.      videoAdaptFormats=findMatch(code, /\"adaptive_fmts\":\s*\"([^\"]+)\"/);
  157.      videoAdaptFormats=videoAdaptFormats.replace(/&amp;/g,'\\u0026');
  158.      videoManifestURL=findMatch(code, /\"dashmpd\":\s*\"([^\"]+)\"/);
  159.      scriptURL=findMatch(code, /\"js\":\s*\"([^\"]+)\"/);
  160.    }
  161.    debug('DYVAM - Info: Injection mode. videoID '+(videoID?videoID:'none')+'; ');
  162.  }
  163.  
  164.  if (videoID==null) { // if all else fails
  165.    var bodyContent=document.body.innerHTML;
  166.    if (bodyContent!=null) {
  167.      videoID=findMatch(bodyContent, /\"video_id\":\s*\"([^\"]+)\"/);
  168.      videoFormats=findMatch(bodyContent, /\"url_encoded_fmt_stream_map\":\s*\"([^\"]+)\"/);
  169.      videoAdaptFormats=findMatch(bodyContent, /\"adaptive_fmts\":\s*\"([^\"]+)\"/);
  170.      videoManifestURL=findMatch(bodyContent, /\"dashmpd\":\s*\"([^\"]+)\"/);
  171.      if (scriptURL==null) {
  172.        scriptURL=findMatch(bodyContent, /\"js\":\s*\"([^\"]+)\"/);
  173.        if (scriptURL) {
  174.          scriptURL=scriptURL.replace(/\\/g,'');
  175.        }
  176.      }
  177.    }
  178.    debug('DYVAM - Info: Brute mode. videoID '+(videoID?videoID:'none')+'; ');
  179.  }
  180.  
  181.  debug('DYVAM - Info: url '+window.location.href+'; useragent '+window.navigator.userAgent);
  182.  
  183.  if (videoID==null || videoFormats==null || videoID.length==0 || videoFormats.length==0) {
  184.   debug('DYVAM - Error: No config information found. YouTube must have changed the code.');
  185.   return;
  186.  }
  187.  
  188.  // Opera 12 extension message handler
  189.  if (typeof window.opera !== 'undefined' && window.opera && typeof opera.extension !== 'undefined') {
  190.    opera.extension.onmessage = function(event) {
  191.      var index=findMatch(event.data.action, /xhr\-([0-9]+)\-response/);
  192.      if (index && operaTable[parseInt(index,10)]) {
  193.        index=parseInt(index,10);
  194.        var trigger=(operaTable[index])['onload'];
  195.        if (typeof trigger === 'function' && event.data.readyState == 4) {
  196.          if (trigger) {
  197.              trigger(event.data);
  198.          }
  199.        }
  200.      }
  201.    }
  202.  }
  203.  
  204.  if (!isDecodeRuleUpdated) {
  205.    DECODE_RULE=getDecodeRules(DECODE_RULE);
  206.    isDecodeRuleUpdated=true;
  207.  }
  208.  if (scriptURL) {
  209.    if (scriptURL.indexOf('//')==0) {
  210.      var protocol=(document.location.protocol=='http:')?'http:':'https:';
  211.      scriptURL=protocol+scriptURL;
  212.    }
  213.    fetchSignatureScript(scriptURL);
  214.  }
  215.  
  216.   // video title
  217.   var videoTitle=document.title || 'video';
  218.   videoTitle=videoTitle.replace(/\s*\-\s*YouTube$/i, '').replace(/'/g, '\'').replace(/^\s+|\s+$/g, '').replace(/\.+$/g, '');
  219.   videoTitle=videoTitle.replace(/[:"\?\*]/g, '').replace(/[\|\\\/]/g, '_'); // Mac, Linux, Windows
  220.    if (((window.navigator.userAgent || '').toLowerCase()).indexOf('windows') >= 0) {
  221.       videoTitle=videoTitle.replace(/#/g, '').replace(/&/g, '_'); // Windows
  222.    } else {
  223.       videoTitle=videoTitle.replace(/#/g, '%23').replace(/&/g, '%26'); //  Mac, Linux
  224.    }
  225.  
  226.   // parse the formats map
  227.   var sep1='%2C', sep2='%26', sep3='%3D';
  228.   if (videoFormats.indexOf(',')>-1) {
  229.     sep1=',';
  230.     sep2=(videoFormats.indexOf('&')>-1)?'&':'\\u0026';
  231.     sep3='=';
  232.   }
  233.   var videoURL=new Array();
  234.   var videoSignature=new Array();
  235.   if (videoAdaptFormats) {
  236.     videoFormats=videoFormats+sep1+videoAdaptFormats;
  237.   }
  238.   var videoFormatsGroup=videoFormats.split(sep1);
  239.   for (var i=0;i<videoFormatsGroup.length;i++) {
  240.     var videoFormatsElem=videoFormatsGroup[i].split(sep2);
  241.     var videoFormatsPair=new Array();
  242.     for (var j=0;j<videoFormatsElem.length;j++) {
  243.       var pair=videoFormatsElem[j].split(sep3);
  244.       if (pair.length==2) {
  245.         videoFormatsPair[pair[0]]=pair[1];
  246.       }
  247.     }
  248.     if (videoFormatsPair['url']==null) continue;
  249.     var url=unescape(unescape(videoFormatsPair['url'])).replace(/\\\//g,'/').replace(/\\u0026/g,'&');
  250.     if (videoFormatsPair['itag']==null) continue;
  251.     var itag=videoFormatsPair['itag'];
  252.     var sig=videoFormatsPair['sig']||videoFormatsPair['signature'];
  253.     if (sig) {
  254.       url=url+'&signature='+sig;
  255.       videoSignature[itag]=null;
  256.     } else if (videoFormatsPair['s']) {
  257.       url=url+'&signature='+decryptSignature(videoFormatsPair['s']);
  258.       videoSignature[itag]=videoFormatsPair['s'];
  259.     }
  260.     if (url.toLowerCase().indexOf('ratebypass')==-1) { // speed up download for dash
  261.       url=url+'&ratebypass=yes';
  262.     }
  263.     if (url.toLowerCase().indexOf('http')==0) { // validate URL
  264.       videoURL[itag]=url+'&title='+videoTitle;
  265.     }
  266.   }
  267.  
  268.   var showFormat=new Array();
  269.   for (var category in FORMAT_RULE) {
  270.     var rule=FORMAT_RULE[category];
  271.     for (var index in FORMAT_TYPE){
  272.       if (FORMAT_TYPE[index]==category) {
  273.         showFormat[index]=(rule=='all');
  274.       }
  275.     }
  276.     if (rule=='max') {
  277.       for (var i=FORMAT_ORDER.length-1;i>=0;i--) {
  278.         var format=FORMAT_ORDER[i];
  279.         if (FORMAT_TYPE[format]==category && videoURL[format]!=undefined) {
  280.           showFormat[format]=true;
  281.           break;
  282.         }
  283.       }
  284.     }
  285.   }
  286.  
  287.   var dashPref=getPref(STORAGE_DASH);
  288.   if (dashPref=='1') {
  289.     SHOW_DASH_FORMATS=true;
  290.   } else if (dashPref!='0') {
  291.     setPref(STORAGE_DASH,'0');
  292.   }
  293.  
  294.   var downloadCodeList=[];
  295.   for (var i=0;i<FORMAT_ORDER.length;i++) {
  296.     var format=FORMAT_ORDER[i];
  297.     if (format=='37' && videoURL[format]==undefined) { // hack for dash 1080p
  298.       if (videoURL['137']) {
  299.        format='137';
  300.       }
  301.       showFormat[format]=showFormat['37'];
  302.     } else if (format=='38' && videoURL[format]==undefined) { // hack for dash 4K
  303.       if (videoURL['138'] && !videoURL['266']) {
  304.        format='138';
  305.       }
  306.       showFormat[format]=showFormat['38'];
  307.     }
  308.     if (!SHOW_DASH_FORMATS && format.length>2) continue;
  309.     if (videoURL[format]!=undefined && FORMAT_LABEL[format]!=undefined && showFormat[format]) {
  310.       downloadCodeList.push({url:videoURL[format],sig:videoSignature[format],format:format,label:FORMAT_LABEL[format]});
  311.       debug('DYVAM - Info: itag'+format+' url:'+videoURL[format]);
  312.     }
  313.   }
  314.  
  315.   if (downloadCodeList.length==0) {
  316.     debug('DYVAM - Error: No download URL found. Probably YouTube uses encrypted streams.');
  317.     return; // no format
  318.   }
  319.  
  320.   // find parent container
  321.   var newWatchPage=false;
  322.   var parentElement=document.getElementById('watch7-action-buttons');
  323.   if (parentElement==null) {
  324.     parentElement=document.getElementById('watch8-secondary-actions');
  325.     if (parentElement==null) {
  326.       debug('DYVAM Error - No container for adding the download button. YouTube must have changed the code.');
  327.       return;
  328.     } else {
  329.       newWatchPage=true;
  330.     }
  331.   }
  332.  
  333.   // get button labels
  334.   var buttonText=(BUTTON_TEXT[language])?BUTTON_TEXT[language]:BUTTON_TEXT['en'];
  335.   var buttonLabel=(BUTTON_TOOLTIP[language])?BUTTON_TOOLTIP[language]:BUTTON_TOOLTIP['en'];
  336.  
  337.   // generate download code for regular interface
  338.   var mainSpan=document.createElement('span');
  339.  
  340.   if (newWatchPage) {
  341.     var spanIcon=document.createElement('span');
  342.     spanIcon.setAttribute('class', 'yt-uix-button-icon-wrapper');
  343.     var imageIcon=document.createElement('img');
  344.     imageIcon.setAttribute('src', '//s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif');
  345.     imageIcon.setAttribute('class', 'yt-uix-button-icon');
  346.     imageIcon.setAttribute('style', 'width:20px;height:20px;background-size:20px 20px;background-repeat:no-repeat;background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABG0lEQVRYR+2W0Q3CMAxE2wkYAdiEEWADmIxuACMwCmzABpCTEmRSO7YTQX+ChECV43t2nF7GYeHPuLD+0AKwC/DnWMAp/N5qimkBuAfBdRTF/+2/AV6ZYFUxVYuicAfoHegd6B3oHfhZB+ByF+JyV8FkrAB74pqH3DU5L3iGoBURhdVODIQF4EjEkWLmmhYALOQgNIBcHHke4buhxXAAaFnaAhqbQ5QAOHHkwhZ8balkx1ICCiEBWNZ+CivdB7REHIC2ZjZK2oWklDDdB1NSdCd/Js2PqQMpSIKYVcM8kE6QCwDBNRCqOBJrW0CL8kCYxL0A1k6YxWsANAiXeC2ABOEWbwHAWrwxpzgkmA/JtIqnxTOElmPnjlkc4A3FykAhA42AxwAAAABJRU5ErkJggg==);');
  347.     spanIcon.appendChild(imageIcon);
  348.     mainSpan.appendChild(spanIcon);
  349.   }
  350.  
  351.   var spanButton=document.createElement('span');
  352.   spanButton.setAttribute('class', 'yt-uix-button-content');
  353.   spanButton.appendChild(document.createTextNode(buttonText+' '));
  354.   mainSpan.appendChild(spanButton);
  355.  
  356.   if (!newWatchPage) { // old UI
  357.     var imgButton=document.createElement('img');
  358.     imgButton.setAttribute('class', 'yt-uix-button-arrow');
  359.     imgButton.setAttribute('src', '//s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif');
  360.     mainSpan.appendChild(imgButton);
  361.   }
  362.  
  363.   var listItems=document.createElement('ol');
  364.   listItems.setAttribute('style', 'display:none;');
  365.   listItems.setAttribute('class', 'yt-uix-button-menu');
  366.   for (var i=0;i<downloadCodeList.length;i++) {
  367.     var listItem=document.createElement('li');
  368.     var listLink=document.createElement('a');
  369.     listLink.setAttribute('style', 'text-decoration:none;');
  370.     listLink.setAttribute('href', downloadCodeList[i].url);
  371.     listLink.setAttribute('download', videoTitle+'.'+FORMAT_TYPE[downloadCodeList[i].format]);
  372.     var listButton=document.createElement('span');
  373.     listButton.setAttribute('class', 'yt-uix-button-menu-item');
  374.     listButton.setAttribute('loop', i+'');
  375.     listButton.setAttribute('id', LISTITEM_ID+downloadCodeList[i].format);
  376.     listButton.appendChild(document.createTextNode(downloadCodeList[i].label));
  377.     listLink.appendChild(listButton);
  378.     listItem.appendChild(listLink);
  379.     listItems.appendChild(listItem);
  380.   }
  381.   mainSpan.appendChild(listItems);
  382.   var buttonElement=document.createElement('button');
  383.   buttonElement.setAttribute('id', BUTTON_ID);
  384.   if (newWatchPage) {
  385.     buttonElement.setAttribute('class', 'yt-uix-button  yt-uix-button-size-default yt-uix-button-opacity yt-uix-tooltip');
  386.   } else { // old UI
  387.     buttonElement.setAttribute('class', 'yt-uix-button yt-uix-tooltip yt-uix-button-empty yt-uix-button-text');
  388.     buttonElement.setAttribute('style', 'margin-top:4px; margin-left:'+((textDirection=='left')?5:10)+'px;');
  389.   }
  390.   buttonElement.setAttribute('data-tooltip-text', buttonLabel);  
  391.   buttonElement.setAttribute('type', 'button');
  392.   buttonElement.setAttribute('role', 'button');
  393.   buttonElement.addEventListener('click', function(){return false;}, false);
  394.   buttonElement.appendChild(mainSpan);
  395.   var containerSpan=document.createElement('span');
  396.   containerSpan.setAttribute('id', CONTAINER_ID);
  397.   containerSpan.appendChild(document.createTextNode(' '));
  398.   containerSpan.appendChild(buttonElement);
  399.  
  400.   // add the button
  401.   if (!newWatchPage) { // watch7
  402.     parentElement.appendChild(containerSpan);
  403.   } else { // watch8
  404.     parentElement.insertBefore(containerSpan, parentElement.firstChild);
  405.   }
  406.    
  407.   // REPLACEWITH if (!isSignatureUpdatingStarted) {
  408.     for (var i=0;i<downloadCodeList.length;i++) {
  409.       addFileSize(downloadCodeList[i].url, downloadCodeList[i].format);
  410.     }
  411.   // }
  412.  
  413.   if (typeof GM_download !== 'undefined') {
  414.     for (var i=0;i<downloadCodeList.length;i++) {
  415.       var downloadFMT=document.getElementById(LISTITEM_ID+downloadCodeList[i].format);
  416.       var url=(downloadCodeList[i].url).toLowerCase();
  417.       if (url.indexOf('clen=')>0 && url.indexOf('dur=')>0 && url.indexOf('gir=')>0
  418.           && url.indexOf('lmt=')>0) {
  419.         downloadFMT.addEventListener('click', downloadVideoNatively, false);
  420.       }
  421.     }
  422.   }
  423.  
  424.   addFromManifest('140', '141'); // replace fmt140 with fmt141 if found in manifest
  425.  
  426.   function downloadVideoNatively(e) {
  427.     var elem=e.currentTarget;
  428.     e.returnValue=false;    
  429.     if (e.preventDefault) {
  430.       e.preventDefault();
  431.     }
  432.     var loop=elem.getAttribute('loop');
  433.     if (loop) {
  434.       GM_download(downloadCodeList[loop].url, videoTitle+'.'+FORMAT_TYPE[downloadCodeList[loop].format]);
  435.     }
  436.     return false;
  437.   }
  438.  
  439.   function addFromManifest(oldFormat, newFormat) { // find newFormat URL in manifest
  440.     if (videoManifestURL && videoURL[newFormat]==undefined && SHOW_DASH_FORMATS && FORMAT_RULE['m4a']!='none') {
  441.       var matchSig=findMatch(videoManifestURL, /\/s\/([a-zA-Z0-9\.]+)\//i);
  442.       if (matchSig) {
  443.         var decryptedSig=decryptSignature(matchSig);
  444.         if (decryptedSig) {
  445.           videoManifestURL=videoManifestURL.replace('/s/'+matchSig+'/','/signature/'+decryptedSig+'/');
  446.         }
  447.       }
  448.       if (videoManifestURL.indexOf('//')==0) {
  449.         var protocol=(document.location.protocol=='http:')?'http:':'https:';
  450.         videoManifestURL=protocol+videoManifestURL;
  451.       }
  452.       debug('DYVAM - Info: manifestURL '+videoManifestURL);
  453.       crossXmlHttpRequest({
  454.           method:'GET',
  455.           url:videoManifestURL, // check if URL exists
  456.           onload:function(response) {
  457.             if (response.readyState === 4 && response.status === 200 && response.responseText) {
  458.               var regexp = new RegExp('<BaseURL.+>(http[^<]+itag='+newFormat+'[^<]+)<\\/BaseURL>','i');
  459.               var matchURL=findMatch(response.responseText, regexp);
  460.               debug('DYVAM - Info: matchURL '+matchURL);
  461.               if (!matchURL) return;
  462.               matchURL=matchURL.replace(/&amp\;/g,'&');
  463.               if (FORMAT_RULE['m4a']=='max') {
  464.                 for (var i=0;i<downloadCodeList.length;i++) {
  465.                   if (downloadCodeList[i].format==oldFormat) {
  466.                     downloadCodeList[i].format==newFormat;
  467.                     var downloadFMT=document.getElementById(LISTITEM_ID+oldFormat);
  468.                     downloadFMT.setAttribute('id', LISTITEM_ID+newFormat);
  469.                     downloadFMT.parentNode.setAttribute('href', matchURL);
  470.                     downloadCodeList[i].url=matchURL;
  471.                     downloadFMT.firstChild.nodeValue=FORMAT_LABEL[newFormat];
  472.                     addFileSize(matchURL, newFormat);
  473.                   }
  474.                 }
  475.               } else if (FORMAT_RULE['m4a']=='all') {
  476.                 downloadCodeList.push(
  477.                   {url:matchURL,sig:videoSignature[newFormat],format:newFormat,label:FORMAT_LABEL[newFormat]});
  478.                 var downloadFMT=document.getElementById(LISTITEM_ID+oldFormat);
  479.                 var clone=downloadFMT.parentNode.parentNode.cloneNode(true);
  480.                 clone.firstChild.firstChild.setAttribute('id', LISTITEM_ID+newFormat);
  481.                 clone.firstChild.setAttribute('href', matchURL);
  482.                 downloadFMT.parentNode.parentNode.parentNode.appendChild(clone);
  483.                 downloadFMT=document.getElementById(LISTITEM_ID+newFormat);
  484.                 downloadFMT.firstChild.nodeValue=FORMAT_LABEL[newFormat];
  485.                 addFileSize(matchURL, newFormat);
  486.               }
  487.             }
  488.           }
  489.         });
  490.     }  
  491.   }
  492.  
  493.   function injectStyle(code) {
  494.     var style=document.createElement('style');
  495.     style.type='text/css';
  496.     style.appendChild(document.createTextNode(code));
  497.     document.getElementsByTagName('head')[0].appendChild(style);
  498.   }
  499.  
  500.   function injectScript(code) {
  501.     var script=document.createElement('script');
  502.     script.type='application/javascript';
  503.     script.textContent=code;
  504.     document.body.appendChild(script);
  505.     document.body.removeChild(script);
  506.   }    
  507.  
  508.   function debug(str) {
  509.     var debugElem=document.getElementById(DEBUG_ID);
  510.     if (!debugElem) {
  511.       debugElem=createHiddenElem('div', DEBUG_ID);
  512.     }
  513.     debugElem.appendChild(document.createTextNode(str+' '));
  514.   }
  515.  
  516.   function createHiddenElem(tag, id) {
  517.     var elem=document.createElement(tag);
  518.     elem.setAttribute('id', id);
  519.     elem.setAttribute('style', 'display:none;');
  520.     document.body.appendChild(elem);
  521.     return elem;
  522.   }
  523.  
  524.   function fixTranslations(language, textDirection) {  
  525.     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)) { // fix international UI
  526.       var likeButton=document.getElementById('watch-like');
  527.       if (likeButton) {
  528.         var spanElements=likeButton.getElementsByClassName('yt-uix-button-content');
  529.         if (spanElements) {
  530.           spanElements[0].style.display='none'; // hide like text
  531.         }
  532.       }
  533.       var marginPixels=10;
  534.       if (/^bg|ca|cs|el|eu|hr|it|ml|ms|pl|sl|sw|te$/.test(language)) {
  535.         marginPixels=1;
  536.       }
  537.       injectStyle('#watch7-secondary-actions .yt-uix-button{margin-'+textDirection+':'+marginPixels+'px!important}');
  538.     }
  539.   }
  540.  
  541.   function findMatch(text, regexp) {
  542.     var matches=text.match(regexp);
  543.     return (matches)?matches[1]:null;
  544.   }
  545.  
  546.   function isString(s) {
  547.     return (typeof s==='string' || s instanceof String);
  548.   }
  549.    
  550.   function isInteger(n) {
  551.     return (typeof n==='number' && n%1==0);
  552.   }
  553.  
  554.   function getPref(name) { // cross-browser GM_getValue
  555.     var a='', b='';
  556.     try {a=typeof GM_getValue.toString; b=GM_getValue.toString()} catch(e){}    
  557.     if (typeof GM_getValue === 'function' &&
  558.     (a === 'undefined' || b.indexOf('not supported') === -1)) {
  559.       return GM_getValue(name, null); // Greasemonkey, Tampermonkey, Firefox extension
  560.     } else {
  561.         var ls=null;
  562.         try {ls=window.localStorage||null} catch(e){}
  563.         if (ls) {
  564.           return ls.getItem(name); // Chrome script, Opera extensions
  565.         }
  566.     }
  567.     return;
  568.   }
  569.  
  570.   function setPref(name, value) { //  cross-browser GM_setValue
  571.     var a='', b='';
  572.     try {a=typeof GM_setValue.toString; b=GM_setValue.toString()} catch(e){}    
  573.     if (typeof GM_setValue === 'function' &&
  574.     (a === 'undefined' || b.indexOf('not supported') === -1)) {
  575.       GM_setValue(name, value); // Greasemonkey, Tampermonkey, Firefox extension
  576.     } else {
  577.         var ls=null;
  578.         try {ls=window.localStorage||null} catch(e){}
  579.         if (ls) {
  580.           return ls.setItem(name, value); // Chrome script, Opera extensions
  581.         }
  582.     }
  583.   }
  584.  
  585.   function crossXmlHttpRequest(details) { // cross-browser GM_xmlhttpRequest
  586.     if (typeof GM_xmlhttpRequest === 'function') { // Greasemonkey, Tampermonkey, Firefox extension, Chrome script
  587.       GM_xmlhttpRequest(details);
  588.     } else if (typeof window.opera !== 'undefined' && window.opera && typeof opera.extension !== 'undefined' &&
  589.                typeof opera.extension.postMessage !== 'undefined') { // Opera 12 extension
  590.         var index=operaTable.length;
  591.         opera.extension.postMessage({'action':'xhr-'+index, 'url':details.url, 'method':details.method});
  592.         operaTable[index]=details;
  593.     } else if (typeof window.opera === 'undefined' && typeof XMLHttpRequest === 'function') { // Opera 15+ extension
  594.         var xhr=new XMLHttpRequest();
  595.         xhr.onreadystatechange = function() {
  596.           if (xhr.readyState == 4) {
  597.             if (details['onload']) {
  598.               details['onload'](xhr);
  599.             }
  600.           }
  601.         }
  602.         xhr.open(details.method, details.url, true);
  603.         xhr.send();
  604.     }
  605.   }
  606.    
  607.   function addFileSize(url, format) {
  608.  
  609.     function updateVideoLabel(size, format) {
  610.       var elem=document.getElementById(LISTITEM_ID+format);
  611.       if (elem) {
  612.         size=parseInt(size,10);
  613.         if (size>=1073741824) {
  614.           size=parseFloat((size/1073741824).toFixed(1))+' GB';
  615.         } else if (size>=1048576) {
  616.           size=parseFloat((size/1048576).toFixed(1))+' MB';
  617.         } else {
  618.           size=parseFloat((size/1024).toFixed(1))+' KB';
  619.         }
  620.         if (elem.childNodes.length>1) {
  621.             elem.lastChild.nodeValue=' ('+size+')';
  622.         } else if (elem.childNodes.length==1) {
  623.             elem.appendChild(document.createTextNode(' ('+size+')'));
  624.         }
  625.       }
  626.     }
  627.        
  628.     var matchSize=findMatch(url, /[&\?]clen=([0-9]+)&/i);
  629.     if (matchSize) {
  630.       updateVideoLabel(matchSize, format);
  631.     } else {
  632.       try {
  633.         crossXmlHttpRequest({
  634.           method:'HEAD',
  635.           url:url,
  636.           onload:function(response) {
  637.             if (response.readyState == 4 && response.status == 200) { // add size
  638.               var size=0;
  639.               if (typeof response.getResponseHeader === 'function') {
  640.                 size=response.getResponseHeader('Content-length');
  641.               } else if (response.responseHeaders) {
  642.                   var regexp = new RegExp('^Content\-length: (.*)$','im');
  643.                   var match = regexp.exec(response.responseHeaders);
  644.                   if (match) {
  645.                     size=match[1];
  646.                   }
  647.               }
  648.               if (size) {
  649.                 updateVideoLabel(size, format);
  650.               }
  651.             }
  652.           }
  653.         });
  654.       } catch(e) { }
  655.     }
  656.   }
  657.  
  658.   function findSignatureCode(sourceCode) {
  659.     debug('DYVAM - Info: signature start '+getPref(STORAGE_CODE));
  660.     var signatureFunctionName =
  661.     findMatch(sourceCode,
  662.     /\.set\s*\("signature"\s*,\s*([a-zA-Z0-9_$][\w$]*)\(/)
  663.     || findMatch(sourceCode,
  664.     /\.sig\s*\|\|\s*([a-zA-Z0-9_$][\w$]*)\(/)
  665.     || findMatch(sourceCode,
  666.     /\.signature\s*=\s*([a-zA-Z_$][\w$]*)\([a-zA-Z_$][\w$]*\)/); //old
  667.     if (signatureFunctionName == null) return setPref(STORAGE_CODE, 'error');
  668.     signatureFunctionName=signatureFunctionName.replace('$','\\$');    
  669.     var regCode = new RegExp(signatureFunctionName + '\\s*=\\s*function' +
  670.     '\\s*\\([\\w$]*\\)\\s*{[\\w$]*=[\\w$]*\\.split\\(""\\);\n*(.+);return [\\w$]*\\.join');
  671.     var regCode2 = new RegExp('function \\s*' + signatureFunctionName +
  672.     '\\s*\\([\\w$]*\\)\\s*{[\\w$]*=[\\w$]*\\.split\\(""\\);\n*(.+);return [\\w$]*\\.join');    
  673.     var functionCode = findMatch(sourceCode, regCode) || findMatch(sourceCode, regCode2);
  674.     debug('DYVAM - Info: signaturefunction ' + signatureFunctionName + ' -- ' + functionCode);            
  675.     if (functionCode == null) return setPref(STORAGE_CODE, 'error');
  676.    
  677.     var reverseFunctionName = findMatch(sourceCode,
  678.     /([\w$]*)\s*:\s*function\s*\(\s*[\w$]*\s*\)\s*{\s*(?:return\s*)?[\w$]*\.reverse\s*\(\s*\)\s*}/);
  679.     debug('DYVAM - Info: reversefunction ' + reverseFunctionName);
  680.     if (reverseFunctionName) reverseFunctionName=reverseFunctionName.replace('$','\\$');        
  681.     var sliceFunctionName = findMatch(sourceCode,
  682.     /([\w$]*)\s*:\s*function\s*\(\s*[\w$]*\s*,\s*[\w$]*\s*\)\s*{\s*(?:return\s*)?[\w$]*\.(?:slice|splice)\(.+\)\s*}/);
  683.     debug('DYVAM - Info: slicefunction ' + sliceFunctionName);
  684.     if (sliceFunctionName) sliceFunctionName=sliceFunctionName.replace('$','\\$');    
  685.    
  686.     var regSlice = new RegExp('\\.(?:'+'slice'+(sliceFunctionName?'|'+sliceFunctionName:'')+
  687.     ')\\s*\\(\\s*(?:[a-zA-Z_$][\\w$]*\\s*,)?\\s*([0-9]+)\\s*\\)'); // .slice(5) sau .Hf(a,5)
  688.     var regReverse = new RegExp('\\.(?:'+'reverse'+(reverseFunctionName?'|'+reverseFunctionName:'')+
  689.     ')\\s*\\([^\\)]*\\)');  // .reverse() sau .Gf(a,45)
  690.     var regSwap = new RegExp('[\\w$]+\\s*\\(\\s*[\\w$]+\\s*,\\s*([0-9]+)\\s*\\)');
  691.     var regInline = new RegExp('[\\w$]+\\[0\\]\\s*=\\s*[\\w$]+\\[([0-9]+)\\s*%\\s*[\\w$]+\\.length\\]');
  692.     var functionCodePieces=functionCode.split(';');
  693.     var decodeArray=[];
  694.     for (var i=0; i<functionCodePieces.length; i++) {
  695.       functionCodePieces[i]=functionCodePieces[i].trim();
  696.       var codeLine=functionCodePieces[i];
  697.       if (codeLine.length>0) {
  698.         var arrSlice=codeLine.match(regSlice);
  699.         var arrReverse=codeLine.match(regReverse);
  700.         debug(i+': '+codeLine+' --'+(arrSlice?' slice length '+arrSlice.length:'') +' '+(arrReverse?'reverse':''));
  701.         if (arrSlice && arrSlice.length >= 2) { // slice
  702.         var slice=parseInt(arrSlice[1], 10);
  703.         if (isInteger(slice)){
  704.           decodeArray.push(-slice);
  705.         } else return setPref(STORAGE_CODE, 'error');
  706.       } else if (arrReverse && arrReverse.length >= 1) { // reverse
  707.         decodeArray.push(0);
  708.       } else if (codeLine.indexOf('[0]') >= 0) { // inline swap
  709.           if (i+2<functionCodePieces.length &&
  710.           functionCodePieces[i+1].indexOf('.length') >= 0 &&
  711.           functionCodePieces[i+1].indexOf('[0]') >= 0) {
  712.             var inline=findMatch(functionCodePieces[i+1], regInline);
  713.             inline=parseInt(inline, 10);
  714.             decodeArray.push(inline);
  715.             i+=2;
  716.           } else return setPref(STORAGE_CODE, 'error');
  717.       } else if (codeLine.indexOf(',') >= 0) { // swap
  718.         var swap=findMatch(codeLine, regSwap);      
  719.         swap=parseInt(swap, 10);
  720.         if (isInteger(swap) && swap>0){
  721.           decodeArray.push(swap);
  722.         } else return setPref(STORAGE_CODE, 'error');
  723.       } else return setPref(STORAGE_CODE, 'error');
  724.       }
  725.     }
  726.    
  727.     if (decodeArray) {
  728.       setPref(STORAGE_URL, scriptURL);
  729.       setPref(STORAGE_CODE, decodeArray.toString());
  730.       DECODE_RULE=decodeArray;
  731.       debug('DYVAM - Info: signature '+decodeArray.toString()+' '+scriptURL);
  732.       // update download links and add file sizes
  733.       for (var i=0;i<downloadCodeList.length;i++) {        
  734.         var elem=document.getElementById(LISTITEM_ID+downloadCodeList[i].format);
  735.         var url=downloadCodeList[i].url;
  736.         var sig=downloadCodeList[i].sig;
  737.         if (elem && url && sig) {
  738.           url=url.replace(/\&signature=[\w\.]+/, '&signature='+decryptSignature(sig));
  739.           elem.parentNode.setAttribute('href', url);
  740.           addFileSize(url, downloadCodeList[i].format);
  741.         }
  742.       }
  743.     }
  744.   }
  745.  
  746.   function isValidSignatureCode(arr) { // valid values: '5,-3,0,2,5', 'error'
  747.     if (!arr) return false;
  748.     if (arr=='error') return true;
  749.     arr=arr.split(',');
  750.     for (var i=0;i<arr.length;i++) {
  751.       if (!isInteger(parseInt(arr[i],10))) return false;
  752.     }
  753.     return true;
  754.   }
  755.  
  756.   function fetchSignatureScript(scriptURL) {
  757.     var storageURL=getPref(STORAGE_URL);
  758.     var storageCode=getPref(STORAGE_CODE);
  759.     if (!(/,0,|^0,|,0$|\-/.test(storageCode))) storageCode=null; // hack for only positive items
  760.     if (storageCode && isValidSignatureCode(storageCode) && storageURL &&
  761.         scriptURL.replace(/^https?/i,'')==storageURL.replace(/^https?/i,'')) return;
  762.     try {
  763.       debug('DYVAM fetch '+scriptURL);
  764.       isSignatureUpdatingStarted=true;    
  765.       crossXmlHttpRequest({
  766.         method:'GET',
  767.         url:scriptURL,
  768.         onload:function(response) {
  769.           debug('DYVAM fetch status '+response.status);
  770.           if (response.readyState === 4 && response.status === 200 && response.responseText) {
  771.             findSignatureCode(response.responseText);
  772.           }
  773.         }
  774.       });
  775.     } catch(e) { }
  776.   }
  777.  
  778.   function getDecodeRules(rules) {
  779.     var storageCode=getPref(STORAGE_CODE);    
  780.     if (storageCode && storageCode!='error' && isValidSignatureCode(storageCode)) {
  781.       var arr=storageCode.split(',');
  782.       for (var i=0; i<arr.length; i++) {
  783.         arr[i]=parseInt(arr[i], 10);
  784.       }
  785.       rules=arr;
  786.       debug('DYVAM - Info: signature '+arr.toString()+' '+scriptURL);
  787.     }
  788.     return rules;
  789.   }
  790.  
  791.   function decryptSignature(sig) {
  792.     function swap(a,b){var c=a[0];a[0]=a[b%a.length];a[b]=c;return a};
  793.     function decode(sig, arr) { // encoded decryption
  794.       if (!isString(sig)) return null;
  795.       var sigA=sig.split('');
  796.       for (var i=0;i<arr.length;i++) {
  797.         var act=arr[i];
  798.         if (!isInteger(act)) return null;
  799.         sigA=(act>0)?swap(sigA, act):((act==0)?sigA.reverse():sigA.slice(-act));
  800.       }
  801.       var result=sigA.join('');
  802.       return result;
  803.     }
  804.    
  805.     if (sig==null) return '';    
  806.     var arr=DECODE_RULE;
  807.     if (arr) {
  808.       var sig2=decode(sig, arr);
  809.       if (sig2) return sig2;
  810.     } else {
  811.       setPref(STORAGE_URL, '');
  812.       setPref(STORAGE_CODE, '');
  813.     }
  814.     return sig;
  815.   }  
  816.      
  817.   }
  818.  
  819. })();
Add Comment
Please, Sign In to add comment