Bilibili 轴Man小助手

将评论区的轴转换至Bilibili的笔记,实现手机可点的特性

目前为 2022-01-27 提交的版本。查看 最新版本

// ==UserScript==
// @name         Bilibili 轴Man小助手
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  将评论区的轴转换至Bilibili的笔记,实现手机可点的特性
// @author       as042971
// @include      *://www.bilibili.com/video/av*
// @include      *://www.bilibili.com/video/BV*
// @license MIT
// @grant        none
// @esversion    8
// ==/UserScript==

(function() {
    'use strict';
    // 设置 useIndent = true 会在文本前增加缩进
    const useIndent = false;
    // 设置 useNewLine = true 会在文本后增加空行
    const useNewLine = false;

    const wait1s = function () {
        return new Promise(resolve => {
            setTimeout(() => {
                resolve();
            }, 1000);
        });
    };

    const waitforComponent = async function(name) {
        while (true) {
            let component = document.querySelector(name);
            if (component) {
                return component;
            }
            await wait1s();
        }
    }

    const markTime = async function (loc, time) {
        let comment = document.querySelector('.con ').childNodes[1];
        let seeker = document.createElement('a');
        seeker.className = 'video-seek';
        seeker.setAttribute('data-p', '-1');
        seeker.setAttribute('data-time', String(time));
        comment.appendChild(seeker);
        seeker.click();
        document.querySelector('.ql-tag-btn').click();
        await wait1s();

        // 人工将时间戳置底
        let editor = document.querySelector('.ql-editor');
        editor.appendChild(editor.childNodes[loc]);
        // 清除多出来的那一个
        editor.removeChild(editor.childNodes[loc]);
    };

    const insertText = function (text) {
        let editor = document.querySelector('.ql-editor');
        let insertItem = document.createElement('p');
        if (useIndent) {
            text = '        ' + text;
        }
        const insertTxt = document.createTextNode(text);
        insertItem.appendChild(insertTxt);
        editor.appendChild(insertItem);
    };

    const parseTime = function (timeStr) {
        const timePart = timeStr.split(":");
        if (timePart.length == 3) {
            return parseInt(timePart[0]) * 3600 + parseInt(timePart[1]) * 60 + parseInt(timePart[2]);
        } else {
            return parseInt(timePart[0]) * 60 + parseInt(timePart[1]);
        }
    };

    const handleTimeline = async function (inputStr) {
        let editor = document.querySelector('.ql-editor');
        const loc = editor.childNodes.length - 1;

        // h:mm:ss 型时间
        const timeRegex = /^(\d{1})\:([0-5]{1}\d{1})\:([0-5]{1}\d{1})$/;
        // mm:ss 型时间
        const timeRegex2 = /^([0-5]{1}\d{1})\:([0-5]{1}\d{1})$/;
        // 通过换行分隔
        const inputStrList = inputStr.split(/[(\r\n)\r\n]+/);
        for (let i = 0; i < inputStrList.length; i++) {
            let inputStrItem = inputStrList[i];
            let nonTimeStr = '';
            // 通过空格分隔
            const inputPart = inputStrItem.split(' ');
            for (let j = 0; j < inputPart.length; j++) {
                let part = inputPart[j];
                if (part) {
                    if (timeRegex.test(part) || timeRegex2.test(part)) {
                        // 这是一个时间戳
                        // 结束上一次的非时间戳内容
                        if (nonTimeStr != '') {
                            insertText(nonTimeStr);
                            if (useNewLine) {
                                insertText('');
                            }
                            nonTimeStr = '';
                        }
                        // 标记这个时间戳
                        const time = parseTime(part);
                        await markTime(loc, time);
                    } else {
                        if (nonTimeStr != '') {
                            nonTimeStr += ' ';
                        }
                        nonTimeStr += part;
                    }
                }
            }
            if (nonTimeStr != '') {
                insertText(nonTimeStr);
                if (useNewLine) {
                    insertText('');
                }
            }
        }
    };

    let app = document.getElementById('app');
    let observerOptions = {
      childList: true,
      attributes: false,
      subtree: false
    };
    let injected = false;
    let commentLoad = false;

    let observer = new MutationObserver(async (mutation_records) => {
      if (injected) {
        return;
      }
      for (let i = 0; i < mutation_records.length; i++) {
        const record = mutation_records[i];
        for (let j = 0; j < record.addedNodes.length; j++) {
          if (injected) {
            return;
          }
          const node = record.addedNodes[j];
          if (node.className == 'resizable-component bili-note active-note') {
            let rawTimeline = document.createElement('textarea');
            rawTimeline.setAttribute('id', 'inject-timeline');
            rawTimeline.setAttribute('rows', '1');
            rawTimeline.oninput = async function () {
                let data = rawTimeline.value;
                rawTimeline.value = "";
                rawTimeline.setAttribute('disabled', 'disabled');
                rawTimeline.setAttribute('placeholder', '处理中,请稍后...');
                await handleTimeline(data);
                rawTimeline.removeAttribute('disabled');
                rawTimeline.setAttribute('placeholder', '处理完毕,请换P或直接发表');
            };
            node.insertBefore(rawTimeline, node.childNodes[3]);
            rawTimeline.setAttribute('disabled', 'disabled');
            rawTimeline.setAttribute('placeholder', '请向下滑动加载评论区');
            await waitforComponent('.con ');
            commentLoad = true;
            rawTimeline.removeAttribute('disabled');
            rawTimeline.setAttribute('placeholder', '将光标移动至文末空行后,将轴粘贴至这里...');
            injected = true;
          }
        }
      }
    });
    observer.observe(app, observerOptions);
})();

QingJ © 2025

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