YouTube去广告

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

目前为 2023-11-16 提交的版本。查看 最新版本

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

QingJ © 2025

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