Bilibili Mobile

view bilibili mobile page recommended video directly

目前為 2023-06-13 提交的版本,檢視 最新版本

// ==UserScript==
// @name               Bilibili Mobile
// @name:zh-CN         bilibili 移动端
// @namespace          https://github.com/jk278/bilibili-mobile
// @version            2.1
// @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;
        console.log('Execute Video! 获取 bvId:', bvId);
        onResult(bvId);
      } else {
        console.error("获取bvId时出错:");
        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("获得的bvId:", bvId);
          videoUrl = `https://m.bilibili.com/video/${bvId}`; // 在回调内更新 videoUrl 的值
        } else {
          console.error("获取bvId时出错:", error);
        }
      };
      try {
        getIdByTitle(keyword, callback);
      } catch (error) {
        console.log('Execute Error!', error);
      }

      anchor.addEventListener('click', async (event) => {
        event.preventDefault();
        event.stopImmediatePropagation();
        console.log('Execute test!');

        // 如果 videoUrl 为空(尚未设置),不进行导航
        if (!videoUrl) {
          console.log('Exrcute! 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 transparentTargetElementWithCSS() {
    const targetClassName = 'v-dialog';
    const css = `.${targetClassName}, .${targetClassName} * { opacity: 0 !important; }`;
    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 runVideo() {

    const player = document.querySelector('.player-icon');
    const play = document.querySelector('.play-icon');
    if (play) {
      play.click();
    } else if (player) {
      player.click();
    }

    let timer = setInterval(function () {
      const dialog = document.querySelector('.dialog');
      if (dialog) {
        clearInterval(timer);
        dialog.lastChild.click();
      }
    }, 50);

    observeCardBox();

    console.log('Execute Video!');
  }

  function runHome() {
    const aTags = document.querySelectorAll('a.v-card');

    aTags.forEach(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);
    });

    console.log('Execute Home!');
  }

  // 针对 VIA 浏览器优化,判断 DOM 状态
  function executeAfterDOMContentLoaded(callback) {
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', () => callback());
    } else {
      callback();
    }
  }

  transparentTargetElementWithCSS();
  executeAfterDOMContentLoaded(() => {
    let pathname = window.location.pathname;
    if (pathname.startsWith('/video')) {
      runVideo();
    } else if (pathname === '/' || pathname === '') {
      runHome();
    }
  });

})();

QingJ © 2025

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