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