Download MP3 & Video for YouTube

Add a download button for YouTube!

当前为 2017-11-15 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Download MP3 & Video for YouTube
  3. // @description Add a download button for YouTube!
  4. // @namespace https://greasyfork.org/
  5. // @homepageURL https://greasyfork.org/scripts/34613
  6. // @supportURL https://greasyfork.org/scripts/34613/feedback
  7. // @author Punisher
  8. // @version 1.4
  9. // @date 2017-11-15
  10. // @compatible chrome
  11. // @compatible firefox
  12. // @compatible opera
  13. // @compatible safari
  14. // @license GNU GPL v3.0 or later. http://www.gnu.org/copyleft/gpl.html
  15. // @include http://www.youtube.com/*
  16. // @include https://www.youtube.com/*
  17. // @exclude http://www.youtube.com/embed/*
  18. // @exclude https://www.youtube.com/embed/*
  19. // @match http://www.youtube.com/*
  20. // @match https://www.youtube.com/*
  21. // @match http://s.ytimg.com/yts/jsbin/html5player*
  22. // @match https://s.ytimg.com/yts/jsbin/html5player*
  23. // @match http://manifest.googlevideo.com/*
  24. // @match https://manifest.googlevideo.com/*
  25. // @match http://*.googlevideo.com/videoplayback*
  26. // @match https://*.googlevideo.com/videoplayback*
  27. // @match http://*.youtube.com/videoplayback*
  28. // @match https://*.youtube.com/videoplayback*
  29. // ==/UserScript==
  30.  
  31.  
  32. (function () {
  33. var FORMAT_TYPE={'mp3':'mp3'};
  34. var FORMAT_ORDER=[];
  35. var BUTTON_TEXT={'bg':'Изтегляне','cs':'Stáhnout','de':'Herunterladen','en':'Download','es':'Descargar','fr':'Télécharger','hu':'Letöltés','id':'Unduh','it':'Scarica','ja':'ダウンロード','pl':'Pobierz','pt':'Baixar','ru':'Загрузить','ro':'Descărcare','sk':'Prenesi','sv':'Ladda ner','zh':'下载','zh-TW':'下载'};
  36. var BUTTON_TOOLTIP={'bg':'Изтегляне','cs':'Stáhnout','de':'Herunterladen','en':'Download','es':'Descargar','fr':'Télécharger','hu':'Letöltés','id':'Unduh','it':'Scarica','ja':'ダウンロード','pl':'Pobierz','pt':'Baixar','ru':'Загрузить','ro':'Descărcare','sk':'Prenesi','sv':'Ladda ner','zh':'下载','zh-TW':'下载'};
  37. var RANDOM=7489235179;
  38. var CONTAINER_ID='download-youtube-video'+RANDOM;
  39. var LISTITEM_ID='download-youtube-video-fmt'+RANDOM;
  40. var BUTTON_ID='download-youtube-video-button'+RANDOM;
  41.  
  42. start();
  43.  
  44. function start() {
  45. var pagecontainer=document.getElementById('page-container');
  46. if (/^https?:\/\/www\.youtube.com\/watch\?/.test(window.location.href)) run();
  47.  
  48. var content=document.getElementById('content');
  49. var mo=window.MutationObserver||window.WebKitMutationObserver;
  50. if(typeof mo!=='undefined') {
  51. var observer=new mo(function(mutations) {
  52. mutations.forEach(function(mutation) {
  53. if(mutation.addedNodes!==null) {
  54. for (var i=0; i<mutation.addedNodes.length; i++) {
  55. if (mutation.addedNodes[i].id=='watch7-container' ||
  56. mutation.addedNodes[i].id=='watch7-main-container') {
  57. run();
  58. break;
  59. }
  60. }
  61. }
  62. });
  63. });
  64. observer.observe(content, {childList: true, subtree: true});
  65. }
  66. }
  67.  
  68. function onNodeInserted(e) {
  69. if (e && e.target && (e.target.id=='watch7-container' ||
  70. e.target.id=='watch7-main-container')) {
  71. run();
  72. }
  73. }
  74.  
  75. function run() {
  76. var operaTable=new Array();
  77. var language=document.documentElement.getAttribute('lang');
  78. var textDirection='left';
  79. if (document.body.getAttribute('dir')=='rtl') {
  80. textDirection='right';
  81. }
  82. if (document.getElementById('watch7-action-buttons')) {
  83. fixTranslations(language, textDirection);
  84. }
  85.  
  86. var args=null;
  87. var usw=(typeof this.unsafeWindow !== 'undefined')?this.unsafeWindow:window;
  88. if (typeof window.opera !== 'undefined' && window.opera && typeof opera.extension !== 'undefined') {
  89. opera.extension.onmessage = function(event) {
  90. var index=findMatch(event.data.action, /xhr\-([0-9]+)\-response/);
  91. if (index && operaTable[parseInt(index,10)]) {
  92. index=parseInt(index,10);
  93. var trigger=(operaTable[index])['onload'];
  94. if (typeof trigger === 'function' && event.data.readyState == 4) {
  95. if (trigger) {
  96. trigger(event.data);
  97. }
  98. }
  99. }
  100. }
  101. }
  102.  
  103. var downloadCodeList=[];
  104. for (var i=0;i<FORMAT_ORDER.length;i++) {
  105. var format=FORMAT_ORDER[i];
  106. if (!SHOW_DASH_FORMATS && format.length>2) continue;
  107. if (videoURL[format]!=undefined && FORMAT_LABEL[format]!=undefined && showFormat[format]) {
  108. downloadCodeList.push({url:videoURL[format],sig:videoSignature[format],format:format,label:FORMAT_LABEL[format]});
  109. }
  110. }
  111.  
  112. downloadCodeList.push({
  113. 'url': 'http://api.yt-mp3.com/watch?v=' + encodeURIComponent(location.href),
  114. 'format': 'mp3',
  115. 'label': 'MP3 or VIDEO',
  116. 'popup': true
  117. });
  118.  
  119. var newWatchPage=false;
  120. var parentElement=document.getElementById('watch7-action-buttons');
  121. if (parentElement==null) {
  122. parentElement=document.getElementById('watch8-secondary-actions');
  123. if (parentElement==null) {
  124. return;
  125. } else {
  126. newWatchPage=true;
  127. }
  128. }
  129.  
  130. var buttonText=(BUTTON_TEXT[language])?BUTTON_TEXT[language]:BUTTON_TEXT['en'];
  131. var buttonLabel=(BUTTON_TOOLTIP[language])?BUTTON_TOOLTIP[language]:BUTTON_TOOLTIP['en'];
  132. var mainSpan=document.createElement('span');
  133. if (newWatchPage) {
  134. var spanIcon=document.createElement('span');
  135. spanIcon.setAttribute('class', 'yt-uix-button-icon-wrapper');
  136. var imageIcon=document.createElement('img');
  137. imageIcon.setAttribute('src', '//s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif');
  138. imageIcon.setAttribute('class', 'yt-uix-button-icon');
  139. 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==);');
  140. spanIcon.appendChild(imageIcon);
  141. mainSpan.appendChild(spanIcon);
  142. }
  143.  
  144. var spanButton=document.createElement('span');
  145. spanButton.setAttribute('class', 'yt-uix-button-content');
  146. spanButton.appendChild(document.createTextNode(buttonText+' '));
  147. mainSpan.appendChild(spanButton);
  148. if (!newWatchPage) {
  149. var imgButton=document.createElement('img');
  150. imgButton.setAttribute('class', 'yt-uix-button-arrow');
  151. imgButton.setAttribute('src', '//s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif');
  152. mainSpan.appendChild(imgButton);
  153. }
  154.  
  155. var listItems=document.createElement('ol');
  156. listItems.setAttribute('style', 'display:none;');
  157. listItems.setAttribute('class', 'yt-uix-button-menu');
  158. for (var i=0;i<downloadCodeList.length;i++) {
  159. var listItem=document.createElement('li');
  160. var listLink=document.createElement('a');
  161. listLink.setAttribute('style', 'text-decoration:none;');
  162. listLink.setAttribute('href', downloadCodeList[i].url);
  163.  
  164. if (downloadCodeList[i].popup) {
  165. listLink.onclick = (function (href, e) {
  166. e.preventDefault();
  167. window.open(href,href,'height=327,width=954,location=yes,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no');
  168. }).bind(null, downloadCodeList[i].url);
  169. } else {
  170. listLink.setAttribute('download', videoTitle+'.'+FORMAT_TYPE[downloadCodeList[i].format]);
  171. }
  172.  
  173. var listButton=document.createElement('span');
  174. listButton.setAttribute('class', 'yt-uix-button-menu-item');
  175. listButton.setAttribute('loop', i+'');
  176. listButton.setAttribute('id', LISTITEM_ID+downloadCodeList[i].format);
  177. listButton.appendChild(document.createTextNode(downloadCodeList[i].label));
  178. listLink.appendChild(listButton);
  179. listItem.appendChild(listLink);
  180. listItems.appendChild(listItem);
  181. }
  182. mainSpan.appendChild(listItems);
  183.  
  184. var buttonElement=document.createElement('button');
  185. buttonElement.setAttribute('id', BUTTON_ID);
  186. if (newWatchPage) {
  187. buttonElement.setAttribute('class', 'yt-uix-button yt-uix-button-size-default yt-uix-button-opacity yt-uix-tooltip');
  188. } else {
  189. buttonElement.setAttribute('class', 'yt-uix-button yt-uix-tooltip yt-uix-button-empty yt-uix-button-text');
  190. buttonElement.setAttribute('style', 'margin-top:4px; margin-left:'+((textDirection=='left')?5:10)+'px;');
  191. }
  192.  
  193. buttonElement.setAttribute('data-tooltip-text', buttonLabel);
  194. buttonElement.setAttribute('type', 'button');
  195. buttonElement.setAttribute('role', 'button');
  196. buttonElement.addEventListener('click', function(){return false;}, false);
  197. buttonElement.appendChild(mainSpan);
  198.  
  199. var containerSpan=document.createElement('span');
  200. containerSpan.setAttribute('id', CONTAINER_ID);
  201. containerSpan.appendChild(document.createTextNode(' '));
  202. containerSpan.appendChild(buttonElement);
  203. if (!newWatchPage) {
  204. parentElement.appendChild(containerSpan);
  205. } else {
  206. parentElement.insertBefore(containerSpan, parentElement.firstChild);
  207. }
  208.  
  209. function createHiddenElem(tag, id) {
  210. var elem=document.createElement(tag);
  211. document.body.appendChild(elem);
  212. }
  213.  
  214. function fixTranslations(language, textDirection) {
  215. var likeButton=document.getElementById('watch-like');
  216. if (likeButton) {
  217. var spanElements=likeButton.getElementsByClassName('yt-uix-button-content');
  218. if (spanElements) {
  219. spanElements[0].style.display='none';
  220. }
  221. }
  222.  
  223. var marginPixels=10, marginPixels=1;
  224. injectStyle('#watch7-secondary-actions .yt-uix-button{margin-'+textDirection+':'+marginPixels+'px!important}');
  225. }
  226.  
  227. function crossXmlHttpRequest(details) {
  228. if (typeof GM_xmlhttpRequest === 'function') {
  229. GM_xmlhttpRequest(details);
  230. } else if (typeof window.opera !== 'undefined' && window.opera && typeof opera.extension !== 'undefined' &&
  231. typeof opera.extension.postMessage !== 'undefined') {
  232. var index=operaTable.length;
  233. opera.extension.postMessage({'action':'xhr-'+index, 'url':details.url, 'method':details.method});
  234. operaTable[index]=details;
  235. } else if (typeof window.opera === 'undefined' && typeof XMLHttpRequest === 'function') {
  236. var xhr=new XMLHttpRequest();
  237. xhr.onreadystatechange = function() {
  238. if (xhr.readyState == 4) {
  239. if (details['onload']) {
  240. details['onload'](xhr);
  241. }
  242. }
  243. }
  244. xhr.open(details.method, details.url, true);
  245. xhr.send();
  246. }
  247. }
  248. }
  249. })();