source: main/trunk/model-sites-dev/respooled/user-script/Popup_Videos_Respooled.user.js@ 29984

Last change on this file since 29984 was 29984, checked in by davidb, 9 years ago

The Respooled User-script for transfering a selected YouTube video to the DL, along with the YouTube Downloader script it was based on

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