B站自动点赞

B站自动点赞脚本,支持普通视频、视频合集、稍后再看、专栏。

// ==UserScript==
// @name         B站自动点赞
// @namespace    http://tampermonkey.net/
// @version      0.1.0
// @description  B站自动点赞脚本,支持普通视频、视频合集、稍后再看、专栏。
// @author       redmh
// @match        https://www.bilibili.com/video/*
// @match        https://www.bilibili.com/list/watchlater*
// @match        https://www.bilibili.com/opus/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=bilibili.com
// @grant        none
// @license      GPLv3
// ==/UserScript==

(function() {
    'use strict';

    // 是否开启DEBUG输出
    const DEBUG = false;
    // 每INTERVAL(ms)检查是否需要点赞
    const INTERVAL = 5000;
    // 尝试点赞CHECK_DELAY(ms)后检查是否需要清除定时器
    const CHECK_DELAY = 1000;
    // MAX_MISS次找不到点赞按钮和视频后清除定时器
    const MAX_MISS = 3;
    // 普通视频、视频合集 document.querySelector("#arc_toolbar_report .video-like")
    // 稍后再看 document.querySelector("#playlistToolbar .video-like")
    // 专栏 document.querySelector("#app .like")
    function getLikeButton() {
        return document.querySelector("#arc_toolbar_report > div.video-toolbar-left > div > div:nth-child(1) > div") ||
            document.querySelector("#playlistToolbar > div.video-toolbar-left > div > div:nth-child(1) > div") ||
            document.querySelector("#app > div.opus-detail > div.right-sidebar-wrap > div.side-toolbar.transition > div.side-toolbar__box > div.side-toolbar__action.like");
    }
    // 视频链接 document.querySelector("#bilibili-player video")
    function getVideoUrl() {
        return document.querySelector("#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-video-perch > div > video");
    }
    // 点赞报错
    function getLikeError() {
        return document.querySelector("body > div.van-message.van-message-error");
    }
    // 视频、专栏
    function isLiked(element) {
        const liked = ["on", "is-active"];
        return liked.some(className => element.classList.contains(className));
    }
    // 视频状态 document.querySelector("#bilibili-player .bpx-player-loading-panel").className
    function isVideoLoaded() {
        const videoState = document.querySelector("#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-loading-panel");
        if(videoState) return videoState.className === "bpx-player-loading-panel"
        else return false;
    }

    // 统一管理日志输出
    function log(logContent) {
        if (DEBUG) console.log(logContent);
    }
    // 弹出警告
    function showAlert(alertContent) {
        const el = document.createElement('div');
        el.textContent = alertContent;
        el.style = 'position:fixed;top:10px;left:0;right:0;margin:auto;padding:8px;background:black;text-align:center;width:300px;z-index:9999;font-size:16px;';
        document.body.appendChild(el);
        setTimeout(() => el.remove(), 3000);
    }
    // 清除定时器ID为null
    const indexSet = new Set();
    function clearIntervalToNull(index) {
        const url = location.href;
        indexSet.add(index);
        if ((!url.includes("/opus/") && indexSet.size >= 2) ||
           (url.includes("/opus/") && indexSet.size >= 1)) {
            log("清除定时!");
            clearInterval(intervalId);
            intervalId = null;
        }
    }

    // missedLikeButtonCount次找不到点赞按钮
    let missedLikeButtonCount = 0;
    // missedVideoCount次找不到视频
    let missedVideoCount = 0;
    // setInterval
    let intervalId = null;
    // MutationObserver
    let observer = null;

    function tryLike() {
        // 初始化计数
        missedLikeButtonCount = 0;
        missedVideoCount = 0;
        indexSet.clear();

        if (intervalId) {
            log("清除旧定时!");
            clearInterval(intervalId);
            intervalId = null;
        }

        intervalId = setInterval(() => {
            const url = location.href;

            if (url.includes("/opus/")) {
                log("专栏页面,跳过寻找视频!");
            }
            else if (!isVideoLoaded()) {
                log("视频未加载完成!");
                return;
            }

            const likeButton = getLikeButton();

            if (likeButton) {
                log("找到点赞按钮!");

                if (!isLiked(likeButton)) {
                    log("尝试点赞!");
                    likeButton.click();
                }

                setTimeout(() => {
                    if (isLiked(likeButton)) {
                        log("已经点赞!");
                        clearIntervalToNull(1);
                    }
                    else if (getLikeError()) {
                        log("点赞错误,请手动点赞!");
                        showAlert("点赞错误,请手动点赞!");
                        clearIntervalToNull(1);
                    }
                }, CHECK_DELAY);
            }
            else {
                log(`没找到点赞按钮${missedLikeButtonCount+1}次!`);
                if (++missedLikeButtonCount >= MAX_MISS) {
                    log("寻找点赞按钮超时!");
                    clearIntervalToNull(1);
                }
            }

            // 专栏页面,跳过寻找视频!
            if (url.includes("/opus/")) {
                return;
            }

            const videoUrl = getVideoUrl();

            if (videoUrl) {
                log("找到视频!");
                clearIntervalToNull(2);

                if (!observer) {
                    log("启动BOM监控!");
                    observer = new MutationObserver(mutations => {
                        const url = mutations[mutations.length - 1]?.target.src;
                        if (url) {
                            log("视频变化!");
                            tryLike();
                        }
                    });
                    observer.observe(videoUrl, { attributes: true, attributeFilter: ['src'] });
                }
            }
            else {
                log(`没找到视频${missedVideoCount+1}次!`);
                if (++missedVideoCount >= MAX_MISS) {
                    log("寻找视频超时!");
                    clearIntervalToNull(2);
                }
            }
        }, INTERVAL);
    }

    log("B站自动点赞脚本启动!");
    tryLike();
})();