b 站移动端网页推荐视频直接看
当前为
// ==UserScript==
// @name Bilibili Mobile
// @name:zh-CN bilibili 移动端
// @namespace https://github.com/jk278/bilibili-mobile
// @version 2.2.0
// @description view bilibili mobile page recommended video directly
// @description:zh-CN b 站移动端网页推荐视频直接看
// @author jk278
// @match *://m.bilibili.com
// @match *://m.bilibili.com/video/*
// @grant none
// @run-at document-start
// @icon https://www.bilibili.com/favicon.ico
// ==/UserScript==
(function () {
'use strict';
function getIdByTitle(keyword, onResult) {
// 禁止使用 const encodedKeyword = encodeURIComponent(keyword);
// 生成一个唯一的回调函数名称
const callbackName = `jsonp_callback_${Date.now()}_${Math.floor(Math.random() * 100000)}`;
// 将回调函数挂载到 window 对象上
window[callbackName] = function (responseData) {
console.log('test data: ', responseData.data.result[11].data[0]); // 这里会打印 JSON 数据
if (responseData.data.result[11].data[0]) {
const bvId = responseData.data.result[11].data[0].bvid;
onResult(bvId);
} else {
onResult(null, "Error occurred while getting bvId.");
}
};
const script = document.createElement('script');
script.src = `https://api.bilibili.com/x/web-interface/search/all/v2?page=1&keyword=${keyword}&jsonp=jsonp&callback=${callbackName}`;
document.body.appendChild(script);
}
function addTargetElementListener(targetElement) {
if (targetElement) {
const anchor = targetElement.firstChild;
const h2Element = anchor.lastChild;
const keyword = encodeURIComponent(h2Element.innerHTML);
let videoUrl = null; // 初始化 videoUrl 为 null
const callback = (bvId, error) => {
if (bvId) {
console.log("test bvId: ", bvId);
videoUrl = `https://m.bilibili.com/video/${bvId}`; // 在回调内更新 videoUrl 的值
} else {
console.error("test bvId wrong: ", error);
}
};
try {
getIdByTitle(keyword, callback);
} catch (error) {
console.log('Test getIdByTitle Error!', error);
}
console.log('test anchor: ', anchor);
anchor.addEventListener('click', async (event) => { // 这个时灵时不灵
event.preventDefault();
event.stopImmediatePropagation();
console.log('Execute test!');
// 如果 videoUrl 为空(尚未设置),不进行导航
if (!videoUrl) {
console.log('Test null! Skip navigation as videoUrl is not set yet.');
return;
} else {
console.log('test videoUrl: ', videoUrl);
}
// 使用setTimeout将当前操作放在事件队列的末尾以确保正确执行
await new Promise((resolve) => setTimeout(resolve, 0));
window.location.href = videoUrl;
}, true);
}
console.log('Execute Video! 添加监听器');
}
function observeCardBox() {
const cardBox = document.querySelector('.card-box');
const targetElements = cardBox.children;
// 为初始子元素添加监听器
Array.from(targetElements).forEach(addTargetElementListener);
// 创建 MutationObserver 以监听子元素的变化
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach((addedNode) => {
addTargetElementListener(addedNode);
});
}
});
});
// 配置观察选项
const observerConfig = {
childList: true,
};
// 开始观察
observer.observe(cardBox, observerConfig);
}
function changeTargetElementWithCSS(css) {
const style = document.createElement('style');
style.textContent = css;
// 如果 document.documentElement 可用,将样式添加到文档
if (document.documentElement) {
document.documentElement.appendChild(style);
} else {
// 如果 document.documentElement 不可用,监听 readyStateChange 事件
document.addEventListener('readystatechange', () => {
if (!style.isConnected && document.readyState !== 'loading') {
document.documentElement.appendChild(style);
}
});
}
}
function customElementStyle() {
// transparentElement // 调试时要注释掉
const css1 = `.v-dialog, .v-dialog * { opacity: 0 !important; }`;
// bigImgElement
const css2 = `.main-cover { width: 100% !important; border-radius: 0 !important; }
.natural-main-video { padding: 0 !important; }`;
const css = `${css1}\n${css2}`;
changeTargetElementWithCSS(css);
}
function runVideo() {
const player = document.querySelector('.player-icon');
console.log('test player: ', player);
const play = document.querySelector('.play-icon');
console.log('test player: ', play);
if (play) {
play.click();
} else if (player) {
player.click();
}
const timer = setInterval(function () {
const dialog = document.querySelector('.dialog');
if (dialog) {
clearInterval(timer);
dialog.lastChild.click();
}
}, 50);
observeCardBox();
console.log('Execute Video!');
}
function addHomeTargetElementListener(tag) {
tag.addEventListener('click', async (event) => { // 异步,然后放到 js 末尾执行
event.preventDefault(); // 阻止默认行为
// event.stopPropagation(); // 阻止事件冒泡
event.stopImmediatePropagation(); // 阻止其他事件监听器的执行
console.log("test href: ", tag.getAttribute("href"));
// 等待下一个事件循环迭代
await new Promise((resolve) => setTimeout(resolve, 0)); // THIS!
window.location.href = tag.getAttribute("href");
// 在此处执行您所需的操作,例如更新页面状态、导航等。
history.pushState(null, '', href); // 使用 pushState 更新浏览器的 URL
}, true);
}
function runHome() {
// observeHomeCardBox
const cardBox = document.querySelector('.card-box');
const aTags = cardBox.children;
Array.from(aTags).forEach(addHomeTargetElementListener);
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach((addedNode) => {
addHomeTargetElementListener(addedNode);
});
}
});
});
const observerConfig = {
childList: true,
};
observer.observe(cardBox, observerConfig);
console.log('Execute Home!');
}
// 针对 VIA 浏览器优化,判断 DOM 状态
function executeAfterDOMContentLoaded(callback) {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => callback());
} else {
callback();
}
}
customElementStyle();
executeAfterDOMContentLoaded(() => {
let pathname = window.location.pathname;
if (pathname.startsWith('/video')) {
runVideo();
} else if (pathname === '/' || pathname === '') {
runHome();
}
});
})();