1 背景#
我习惯使用浏览器匿名模式来打开 Youtube 视频,避免 Youtube 的推荐算法给我总是推荐同一类的视频。
但有个问题: 匿名模式下,Youtube的播放器是默认自动播放的。
虽然我可以登录 Google 账号并关闭自动播放,但是每次我使用匿名模式来浏览,关闭窗口之后,所有的操作记录都会被清除了,自动播放设置也不会被保存。
所以我使用 TamperMonkey 给 Youtube写了一个关闭自动播放的脚本,打开 Youtube 播放器时,把自动播放按钮给关闭掉,避免我使用浏览器的匿名窗口打开 Youtube 之后,Youtube自动播放导致一直有声音。
脚本逻辑很简单:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| // ==UserScript==
// @name Disable YouTube Autoplay
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Automatically turn off YouTube autoplay
// @author ramsayliang
// @match https://*.youtube.com/*
// @grant none
// @icon https://www.youtube.com/favicon.ico
// ==/UserScript==
(function() {
'use strict';
// Function to disable autoplay
function disableAutoplay() {
console.log("disableAutoplay");
const autoplayToggle = document.querySelector('div[class="ytp-autonav-toggle-button"]');
if (autoplayToggle && autoplayToggle.getAttribute('aria-checked') === 'true') {
autoplayToggle.click();
console.log("Disable YouTube Autoplay");
}
}
console.log("Before loading");
// Run the function when the page loads
window.addEventListener('load', () => {
// Wait for a short delay to ensure the page fully loads
// setTimeout(disableAutoplay, 8000);
console.log("Loading page..");
disableAutoplay();
}, false);
})();
|
2 问题#
但是我发现这个脚本时灵不灵,甚至有一天晚上,睡着之后被自动播放的声音吵醒了。
我就在找能稳定复现这个问题的场景,花费半个小时,终于能稳定复现问题了。
- 打开 Chrome 的匿名模式
- 打开 Youtube 首页, 地址是: youtube.com, 脚本运行.
- 随意点击一个视频,进行播放:https://www.youtube.com/watch?v=-pKGaxoVhok ,脚本就不会运行了。
- 如果我在视频播放页刷新,脚本又会重新运行。
但分析了1个小时,都没有找到原因,我甚至怀疑是 Tampermonkey 有Bug(虽然主观感觉这个可能性较小)
3 分析#
结合 Tampermonkey 的表现,我觉得可能是 Tampermonkey 的执行机制有问题,可能是判断 youtube.com 和 youtube.com/watch?v=xxxx 是同一个页面,就不会运行两次。
在Stackoverflow上搜索了一下,发现果然如此:
原来这个是feature, 不是bug.
对于 Single Page Application, Tampermonkey 无法判断页面的 DOM 是否发生变化,是否访问到新的页面了,所以不会重复执行。
分析下来,之前脚本能直接生效的原因是, 我在Chrome正常模式下打开 Youtube 首页, 右键对想要看的视频,点击"Open link in incognito window", 因为页面是首次打开,所以就能正常运行。
但当通过Chrome 匿名模式打开 Youtube 首页,然后再点击视频播放,无法运行脚本。
因为在打开首页的时候,脚本已经运行过了,当点击跳转到指定的视频时,且 Youtube 是个 Single Page Application, 对脚本来说,页面就没有发生过变化,所以不会再运行。
如果手动刷新,页面重新加载,脚本就又会被加载。
4 解决方案#
最后通过 Stackoverflow 的建议,增加一个对 DOM 事件变化的监听来解决:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| // https://stackoverflow.com/questions/2844565/is-there-a-javascript-jquery-dom-change-listener/39508954#39508954
// Detect the url change for programmatic navigation
let lastUrl = location.href;
new MutationObserver(() => {
const url = location.href;
if (url !== lastUrl) {
lastUrl = url;
onUrlChange();
}
}).observe(document, {subtree: true, childList: true});
// callback when url change
function onUrlChange() {
console.log('URL changed!', location.href);
if(isYouTubeVideoURL(location.href)){
disableAutoplay();
}
}
|
这样就可以正常运行了。