Greasy Fork 支持简体中文。

【自用】YoutubeTools

1.恢复页面布局,2.增加按钮,点击后复制一条命令行到剪切板(配合IDM使用)【受YouTube™ Multi Downloader启发,需配合Local YouTube Downloader使用】,3.增加按钮,一键重绘下载png格式的cover

目前為 2021-09-07 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @icon https://github.com/favicon.ico
  3. // @name 【自用】YoutubeTools
  4. // @namespace Violentmonkey Scripts
  5. // @match *://*.youtube.com/*
  6. // @grant none
  7. // @version 2021.09.07
  8. // @author heckles
  9. // @description 1.恢复页面布局,2.增加按钮,点击后复制一条命令行到剪切板(配合IDM使用)【受YouTube™ Multi Downloader启发,需配合Local YouTube Downloader使用】,3.增加按钮,一键重绘下载png格式的cover
  10. // @Homepage URL https://greasyfork.org/zh-CN/scripts/431488-%E8%87%AA%E7%94%A8-youtubetools
  11. // ==/UserScript==
  12.  
  13.  
  14. //1.设定加载条件
  15. if (document.getElementById("browser-app") || document.getElementById("masthead")) { //这两个元素,有一个是true,就往下执行
  16. var sx = setInterval(function () { //间隔执行
  17. console.log(">>>>>>>>>>> 【YoutubeTools】 interval开始 <<<<<<<<<<<");
  18. if (window.location.href.indexOf("watch?v=") < 0) { //如果网址不匹配
  19. return false; //就不执行 【这里只能匹配域名,然后筛,直接用watch的网址,从首页点进去会不触发】
  20. }else{
  21. if (document.getElementById("meta-contents") && document.getElementById("punisher") === null) { //网址匹配的话,punisher没有被添加
  22. StartJS(); //就执行函数,添加punisher
  23. console.log(">>>>>>>>>>> 【YoutubeTools】 已加载 <<<<<<<<<<<");
  24. clearInterval(sx);
  25. }
  26. }
  27. }, 3000); //间隔时间,毫秒
  28. //return;
  29. }
  30.  
  31. //2.条件触发后加载
  32. function StartJS() {
  33. //2.1新增按钮的样式
  34. const btncss = `
  35. color: #F97D00;
  36. font-weight: bold;
  37. /*text-transform: uppercase;*/
  38. padding: 0px 3px;
  39. background-color: transparent;
  40. border-color: transparent;
  41. `
  42. //2.2开始添加按钮
  43. var buttonDiv = document.createElement("span");
  44. buttonDiv.id = "punisher";
  45. buttonDiv.style.width = "100%";
  46. buttonDiv.style.marginTop = "3px";
  47. buttonDiv.style.padding = "1px 0";
  48. var addButtonV = document.createElement("button");
  49. var addButtonA = document.createElement("button");
  50. var addButtonM = document.createElement("button");
  51. var aCover = document.createElement("a");
  52. addButtonV.appendChild(document.createTextNode("Vcode"));
  53. addButtonA.appendChild(document.createTextNode("Acode"));
  54. addButtonM.appendChild(document.createTextNode("Merge"));
  55. aCover.appendChild(document.createTextNode("Cover"));
  56. addButtonV.style.cssText = btncss;
  57. addButtonA.style.cssText = btncss;
  58. addButtonM.style.cssText = btncss;
  59. aCover.style.cssText = btncss;
  60. buttonDiv.appendChild(addButtonV);
  61. buttonDiv.appendChild(addButtonA);
  62. buttonDiv.appendChild(addButtonM);
  63. buttonDiv.appendChild(aCover);
  64.  
  65. var aTitle = document.createElement("a");
  66. aTitle.appendChild(document.createTextNode("F-name"));
  67. aTitle.style.cssText = btncss;
  68. buttonDiv.appendChild(aTitle);
  69. //aTest.href = "https://w.wallhaven.cc/full/e7/wallhaven-e7ek7k.jpg";
  70. //aTest.download = "1.jpg";
  71. var targetElement = document.querySelectorAll("[id='info-text']"); //youtube故意的,很多元素id重复,这里够绝,直接全选中,然后按class筛,再加
  72. if (targetElement) {
  73. for (var i = 0; i < targetElement.length; i++) {
  74. if (targetElement[i].className.indexOf("style-scope ytd-video-primary-info-renderer") > -1) {
  75. targetElement[i].appendChild(buttonDiv);
  76. }
  77. }
  78. }
  79.  
  80. //3.创建一个input,但是不显示(通过移位),作为复制的中介
  81. var nMInput = document.createElement('input');
  82. nMInput.style.cssText = "position:absolute; top:-200px;"; //火狐实测隐藏的话不能选,oInput.style.display='none';
  83. document.body.appendChild(nMInput);
  84.  
  85. var refreshvar = function(){//设置全局变量,随时准备刷新
  86. //4.生成文件名
  87. nMo = document.querySelector("#container h1 yt-formatted-string").innerText;//获取视频名称,下面再把不能作为文件名的符号替换
  88. if(nMo.match(/[\uac00-\ud7ff]/gi)){
  89. nMo = "【名称包含韩文,根据视频编号自行修改】" +window.location.href.split("watch?v=")[1];
  90. }
  91. nM = nMo.replace(/[|\\|\/|\:|\*|\?|\"|\<|\>|\|]/g, function (a) {//每一个符号前面都加|\,/[]/g表示全文匹配
  92. switch (a) {
  93. case '\\':
  94. return ' ';
  95. case '/':
  96. return ' ';
  97. case ':':
  98. return ':';
  99. case '*':
  100. return '·';
  101. case '?':
  102. return ' ?';
  103. case '\"':
  104. return '\'';
  105. case '<':
  106. return '《';
  107. case '>':
  108. return '》';
  109. case '|':
  110. return '-';
  111. }
  112. });
  113. nM_V = '"' + nM + ' - DASH_V' + '"' + '.mp4';
  114. nM_A = '"' + nM + ' - DASH_A' + '"' + '.m4a';
  115. //5.生成封面图的地址和名称
  116. src_J = document.querySelector("#container div.ytp-cued-thumbnail-overlay-image").style.cssText.slice(23, -3);
  117. nM_J = document.querySelector("#container h1 yt-formatted-string").innerText + src_J.split("default")[1];
  118. }
  119. aCover.target = "_blank";
  120. //6.IDM下载命令行所需
  121. const ds1 = `"D:\\Programs\\Internet Download Manager"\\idman.exe /n /d "`
  122. const ds2 = `" /f `
  123. const mg1 = `"D:\\Programs\\视频编辑\\YouTube 音视频分离合并\\64 位\\ffmpeg" -i "D:\\下载\\IDM\\`
  124. const mg2 = ` - DASH_A".m4a -i "D:\\下载\\IDM\\`
  125. const mg3 = ` - DASH_V".mp4 -acodec copy -vcodec copy "D:\\下载\\IDM\\`
  126. const mg4 = `".mp4`
  127. //7.1视频
  128. addButtonV.onclick = function () {//按钮加event //shadowroot的mode必须是open,否则没有ShadowDOM
  129. refreshvar();//刷新全局变量
  130. var xroot = document.getElementById("hahahazijijiade");
  131. var linkss = xroot.shadowRoot.children[0].children[2].children[1].children[1];
  132. var ku = linkss.querySelectorAll("a");
  133. if (ku) {
  134. for (var i = 0; i < ku.length; i++) {
  135. if (linkss.children[i].innerText.indexOf("1080p") > -1 && linkss.children[i].innerText.indexOf("video/mp4") > -1 && linkss.children[i].innerText.indexOf("avc1.6") > -1) { //用=0就不行,用>-1就行...,如果没有,就是-1
  136. nMInput.value = ds1 + linkss.children[i].href + ds2 + nM_V;
  137. console.log(nMInput.value);
  138. }
  139. }
  140. }
  141. nMInput.select(); // 选择对象
  142. document.execCommand("Copy"); // 执行浏览器复制命令,火狐里面这个command只能是用户触发,不能自动
  143. };
  144. //7.2音频
  145. addButtonA.onclick = function () {//按钮加event //shadowroot的mode必须是open,否则没有ShadowDOM
  146. refreshvar();//刷新全局变量
  147. var xroot = document.getElementById("hahahazijijiade");
  148. var linkss = xroot.shadowRoot.children[0].children[2].children[1].children[1];
  149. var ku = linkss.querySelectorAll("a");
  150. if (ku) {
  151. for (var i = 0; i < ku.length; i++) {
  152. if (linkss.children[i].innerText.indexOf("audio/mp4") > -1) { //用=0就不行,用>-1就行...,如果没有,就是-1
  153. nMInput.value = ds1 + linkss.children[i].href + ds2 + nM_A;
  154. console.log(nMInput.value);
  155. }
  156. }
  157. }
  158. nMInput.select(); // 选择对象
  159. document.execCommand("Copy"); // 执行浏览器复制命令,火狐里面这个command只能是用户触发,不能自动
  160. };
  161. //7.3合并
  162. addButtonM.onclick = function () {//按钮加event //shadowroot的mode必须是open,否则没有ShadowDOM
  163. refreshvar();//刷新全局变量
  164. nMInput.value = mg1 + nM + mg2 + nM + mg3 + nM + mg4;
  165. nMInput.select(); // 选择对象
  166. document.execCommand("Copy"); // 执行浏览器复制命令,火狐里面这个command只能是用户触发,不能自动
  167. };
  168. //7.4封面
  169. //网上找的点击下载图片的,原理是canvas重绘
  170. aCover.onclick = function(){
  171. refreshvar();//刷新全局变量
  172. function dIamge(xhref, name) {
  173. var image = new Image();
  174. image.setAttribute('crossOrigin', 'anonymous'); // 解决跨域 Canvas 污染问题
  175. image.src = xhref;
  176. image.onload = function () {
  177. var canvas = document.createElement('canvas');
  178. canvas.width = image.width;
  179. canvas.height = image.height;
  180. var context = canvas.getContext('2d');
  181. context.drawImage(image, 0, 0, image.width, image.height);
  182. var url = canvas.toDataURL('image/png');
  183. var a = document.createElement('a'); // 生成一个a元素
  184. var event = new MouseEvent('click'); // 创建一个单击事件
  185. a.download = name || '下载图片名称'; // 将a的download属性设置为我们想要下载的图片名称,若name不存在则使用‘下载图片名称’作为默认名称
  186. a.href = url; // 将生成的URL设置为a.href属性
  187. a.dispatchEvent(event); // 触发a的单击事件
  188. }
  189. };
  190. dIamge(src_J, nM_J);
  191. };
  192. //7.5名称
  193. aTitle.onclick = function () {//按钮加event //shadowroot的mode必须是open,否则没有ShadowDOM
  194. refreshvar();//刷新全局变量
  195. nMInput.value = document.querySelector("#container h1 yt-formatted-string").innerText.replace(/[|\\|\/|\:|\*|\?|\"|\<|\>|\|]/g, function (a) {//每一个符号前面都加|\,/[]/g表示全文匹配
  196. switch (a) {
  197. case '\\':
  198. return ' ';
  199. case '/':
  200. return ' ';
  201. case ':':
  202. return ':';
  203. case '*':
  204. return '·';
  205. case '?':
  206. return ' ?';
  207. case '\"':
  208. return '\'';
  209. case '<':
  210. return '《';
  211. case '>':
  212. return '》';
  213. case '|':
  214. return '-';
  215. }
  216. });;
  217. nMInput.select(); // 选择对象
  218. document.execCommand("Copy"); // 执行浏览器复制命令,火狐里面这个command只能是用户触发,不能自动
  219. };
  220. }