YouTube去广告

这是一个去除YouTube广告的脚本,轻量且高效,它能丝滑的去除界面广告和视频广告,包括6s广告。

目前为 2023-12-10 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name YouTube去广告 YouTube AD Blocker
  3. // @name:zh-CN YouTube去广告
  4. // @name:zh-TW YouTube去廣告
  5. // @name:zh-HK YouTube去廣告
  6. // @name:zh-MO YouTube去廣告
  7. // @namespace https://github.com/iamfugui/YouTubeADB
  8. // @version 6.00
  9. // @description 这是一个去除YouTube广告的脚本,轻量且高效,它能丝滑的去除界面广告和视频广告,包括6s广告。This is a script that removes ads on YouTube, it's lightweight and efficient, capable of smoothly removing interface and video ads, including 6s ads.
  10. // @description:zh-CN 这是一个去除YouTube广告的脚本,轻量且高效,它能丝滑的去除界面广告和视频广告,包括6s广告。
  11. // @description:zh-TW 這是一個去除YouTube廣告的腳本,輕量且高效,它能絲滑地去除界面廣告和視頻廣告,包括6s廣告。
  12. // @description:zh-HK 這是一個去除YouTube廣告的腳本,輕量且高效,它能絲滑地去除界面廣告和視頻廣告,包括6s廣告。
  13. // @description:zh-MO 這是一個去除YouTube廣告的腳本,輕量且高效,它能絲滑地去除界面廣告和視頻廣告,包括6s廣告。
  14. // @author iamfugui
  15. // @match *://*.youtube.com/*
  16. // @icon https://www.google.com/s2/favicons?sz=64&domain=YouTube.com
  17. // @grant none
  18. // @license MIT
  19. // ==/UserScript==
  20. (function() {
  21. `use strict`;
  22.  
  23. //界面广告选择器
  24. const cssSeletorArr = [
  25. `#masthead-ad`,//首页顶部横幅广告.
  26. `ytd-rich-item-renderer.style-scope.ytd-rich-grid-row #content:has(.ytd-display-ad-renderer)`,//首页视频排版广告.
  27. `.video-ads.ytp-ad-module`,//播放器底部广告.
  28. `tp-yt-paper-dialog:has(yt-mealbar-promo-renderer)`,//播放页会员促销广告.
  29. `ytd-engagement-panel-section-list-renderer[target-id="engagement-panel-ads"]`,//播放页右上方推荐广告.
  30. `#related #player-ads`,//播放页评论区右侧推广广告.
  31. `#related ytd-ad-slot-renderer`,//播放页评论区右侧视频排版广告.
  32. `ytd-ad-slot-renderer`,//搜索页广告.
  33. `yt-mealbar-promo-renderer`,//播放页会员推荐广告.
  34. `ad-slot-renderer`,//M播放页第三方推荐广告
  35. `ytm-companion-ad-renderer`,//M可跳过的视频广告链接处
  36. ];
  37.  
  38. window.dev=true;//开发使用
  39.  
  40. /**
  41. * 将标准时间格式化
  42. * @param {Date} time 标准时间
  43. * @param {String} format 格式
  44. * @return {String}
  45. */
  46. function moment(time) {
  47. // 获取年⽉⽇时分秒
  48. let y = time.getFullYear()
  49. let m = (time.getMonth() + 1).toString().padStart(2, `0`)
  50. let d = time.getDate().toString().padStart(2, `0`)
  51. let h = time.getHours().toString().padStart(2, `0`)
  52. let min = time.getMinutes().toString().padStart(2, `0`)
  53. let s = time.getSeconds().toString().padStart(2, `0`)
  54. return `${y}-${m}-${d} ${h}:${min}:${s}`
  55. }
  56.  
  57. /**
  58. * 输出信息
  59. * @param {String} msg 信息
  60. * @return {undefined}
  61. */
  62. function log(msg) {
  63. if(!window.dev){
  64. return false;
  65. }
  66. console.log(window.location.href);
  67. console.log(`${moment(new Date())} ${msg}`);
  68. }
  69.  
  70. /**
  71. * 设置运行标志
  72. * @param {String} name
  73. * @return {undefined}
  74. */
  75. function setRunFlag(name){
  76. let style = document.createElement(`style`);
  77. style.id = name;
  78. (document.querySelector(`head`) || document.querySelector(`body`)).appendChild(style);//将节点附加到HTML.
  79. }
  80.  
  81. /**
  82. * 获取运行标志
  83. * @param {String} name
  84. * @return {undefined|Element}
  85. */
  86. function getRunFlag(name){
  87. return document.getElementById(name);
  88. }
  89.  
  90. /**
  91. * 检查是否设置了运行标志
  92. * @param {String} name
  93. * @return {Boolean}
  94. */
  95. function checkRunFlag(name){
  96. if(getRunFlag(name)){
  97. return true;
  98. }else{
  99. setRunFlag(name)
  100. return false;
  101. }
  102. }
  103.  
  104. /**
  105. * 生成去除广告的css元素style并附加到HTML节点上
  106. * @param {String} styles 样式文本
  107. * @return {undefined}
  108. */
  109. function generateRemoveADHTMLElement(styles) {
  110. //如果已经设置过,退出.
  111. if (checkRunFlag(`RemoveADHTMLElement`)) {
  112. log(`屏蔽页面广告节点已生成`);
  113. return false
  114. }
  115.  
  116. //设置移除广告样式.
  117. let style = document.createElement(`style`);//创建style元素.
  118. (document.querySelector(`head`) || document.querySelector(`body`)).appendChild(style);//将节点附加到HTML.
  119. style.appendChild(document.createTextNode(styles));//附加样式节点到元素节点.
  120. log(`生成屏蔽页面广告节点成功`);
  121. }
  122.  
  123. /**
  124. * 生成去除广告的css文本
  125. * @param {Array} cssSeletorArr 待设置css选择器数组
  126. * @return {String}
  127. */
  128. function generateRemoveADCssText(cssSeletorArr){
  129. cssSeletorArr.forEach((seletor,index)=>{
  130. cssSeletorArr[index]=`${seletor}{display:none!important}`;//遍历并设置样式.
  131. });
  132. return cssSeletorArr.join(` `);//拼接成字符串.
  133. }
  134.  
  135. /**
  136. * 触摸事件
  137. * @return {undefined}
  138. */
  139. function nativeTouch(){
  140. // 创建 Touch 对象
  141. let touch = new Touch({
  142. identifier: Date.now(),
  143. target: this,
  144. clientX: 12,
  145. clientY: 34,
  146. radiusX: 56,
  147. radiusY: 78,
  148. rotationAngle: 0,
  149. force: 1
  150. });
  151.  
  152. // 创建 TouchEvent 对象
  153. let touchStartEvent = new TouchEvent("touchstart", {
  154. bubbles: true,
  155. cancelable: true,
  156. view: window,
  157. touches: [touch],
  158. targetTouches: [touch],
  159. changedTouches: [touch]
  160. });
  161.  
  162. // 分派 touchstart 事件到目标元素
  163. this.dispatchEvent(touchStartEvent);
  164.  
  165. // 创建 TouchEvent 对象
  166. let touchEndEvent = new TouchEvent("touchend", {
  167. bubbles: true,
  168. cancelable: true,
  169. view: window,
  170. touches: [],
  171. targetTouches: [],
  172. changedTouches: [touch]
  173. });
  174.  
  175. // 分派 touchend 事件到目标元素
  176. this.dispatchEvent(touchEndEvent);
  177. }
  178.  
  179. /**
  180. * 跳过广告
  181. * @return {undefined}
  182. */
  183. function skipAd(mutationsList, observer) {
  184. let video = document.querySelector(`.ad-showing video`) || document.querySelector(`video`);//获取视频节点
  185. let skipButton = document.querySelector(`.ytp-ad-skip-button`) || document.querySelector(`.ytp-ad-skip-button-modern`);
  186. let shortAdMsg = document.querySelector(`.video-ads.ytp-ad-module .ytp-ad-player-overlay`);
  187.  
  188. if(skipButton){
  189. log(`总时长:`);
  190. log(`${video.duration}`)
  191. log(`当前时间:`);
  192. log(`${video.currentTime}`)
  193. skipButton.click();//PC
  194. nativeTouch.call(skipButton);//Phone
  195. log(`按钮跳过了该广告~~~~~~~~~~~~~`);
  196. }else if(shortAdMsg){
  197. log(`总时长:`);
  198. log(`${video.duration}`)
  199. log(`当前时间:`);
  200. log(`${video.currentTime}`)
  201. video.currentTime = video.duration;
  202. log(`强制结束了该广告~~~~~~~~~~~~~`);
  203. }else{
  204. log(`######广告不存在######`);
  205. }
  206. }
  207.  
  208. /**
  209. * 去除播放中的广告
  210. * @return {undefined}
  211. */
  212. function removePlayerAD(){
  213. //如果已经在运行,退出.
  214. if (checkRunFlag(`removePlayerAD`)) {
  215. log(`去除播放中的广告功能已在运行`);
  216. return false
  217. }
  218. let observer;//监听器
  219. let timerID;//定时器
  220.  
  221. //开始监听
  222. function startObserve(){
  223. //广告节点监听
  224. const targetNode = document.querySelector(`.video-ads.ytp-ad-module`);
  225. if(!targetNode){
  226. log(`正在寻找待监听的目标节点`);
  227. return false;
  228. }
  229. //监听视频中的广告并处理
  230. const config = {childList: true, subtree: true };// 监听目标节点本身与子树下节点的变动
  231. observer = new MutationObserver(skipAd);// 创建一个观察器实例并设置处理广告的回调函数
  232. observer.observe(targetNode, config);// 以上述配置开始观察广告节点
  233. timerID=setInterval(skipAd, 1000);//漏网鱼
  234. }
  235.  
  236. //轮询任务
  237. let startObserveID = setInterval(()=>{
  238. if(observer && timerID){
  239. clearInterval(startObserveID);
  240. }else{
  241. startObserve();
  242. }
  243. },16);
  244.  
  245. log(`运行去除播放中的广告功能成功`);
  246. }
  247.  
  248. /**
  249. * main函数
  250. */
  251. function main(){
  252. generateRemoveADHTMLElement(generateRemoveADCssText(cssSeletorArr));//移除界面中的广告.
  253. removePlayerAD();//移除播放中的广告.
  254. }
  255.  
  256. if (document.readyState === `loading`) {
  257. log(`YouTube去广告脚本即将调用:`);
  258. document.addEventListener(`DOMContentLoaded`, main);// 此时加载尚未完成
  259. } else {
  260. log(`YouTube去广告脚本快速调用:`);
  261. main();// 此时`DOMContentLoaded` 已经被触发
  262. }
  263.  
  264. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址