Bilibili 笔记功能扩展

恢复Bilibili笔记中被隐藏的功能

当前为 2022-03-15 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Bilibili 笔记功能扩展
// @namespace    http://tampermonkey.net/
// @version      0.2.0
// @description  恢复Bilibili笔记中被隐藏的功能
// @author       as042971
// @include      *://www.bilibili.com/video/av*
// @include      *://www.bilibili.com/video/BV*
// @icon         https://experiments.sparanoid.net/favicons/v2/www.bilibili.com.ico
// @license      MIT
// @grant        none
// ==/UserScript==

class XMLHttp {
    request = function (param) { };
    response = function (param) { };
    filterData = function(args, data) { return data };
}
//拦截XMLHttpRequest
(function() {
    'use strict';
    const initXMLHttpRequest = function(http) {
        let open = XMLHttpRequest.prototype.open;
        XMLHttpRequest.prototype.open = function (...args) {
            let send = this.send;
            let _this = this;
            let post_data = [];
            this.send = function (...data) {
                post_data = http.filterData(args, data);
                return send.apply(_this, data);
            };
            // 请求前拦截
            http.request(args);

            this.addEventListener(
                "readystatechange",
                function () {
                    if (this.readyState === 4) {
                        let config = {
                            url: args[1],
                            status: this.status,
                            method: args[0],
                            data: post_data,
                        };
                        // 请求后拦截
                        http.response({ config, response: this.response });
                    }
                },
                false
            );
            return open.apply(this, args);
        };
    }

    const injectPostMsg = function(raw_str, abstract) {
        let params = new URLSearchParams(raw_str);
        params.set('summary', abstract);
        console.log(params.toString());
        return params.toString();
    }

    const inject = function(toolbar) {
        let quill = document.querySelector('.ql-container').__quill;
        let icons = quill.constructor.import('ui/icons');
        // Align
        let alignIcons = icons.align;
        let span = document.createElement('select');
        span.setAttribute('class', 'ql-align ql-bar');
        span.setAttribute('labeltooltip','对齐方式');
        [false, 'center', 'right', 'justify'].forEach(value => {
            const option = document.createElement('option');
            if (value === false) {
                option.setAttribute('selected', 'selected');
            } else {
                option.setAttribute('value', value);
            }
            span.appendChild(option);
        });
        toolbar.insertBefore(span, toolbar.childNodes[toolbar.childNodes.length-2]);
        let Picker = quill.constructor.import('ui/icon-picker');
        let picker = new Picker(span, alignIcons);
        picker.update();
        quill.theme.pickers.push(picker);
        quill.getModule('toolbar').attach(span);

        // Buttons
        let exButtons = [
            {id: 'link', icon: icons.link, tooltip: '标记为链接'},
            {id: 'video', icon: icons.video, tooltip: '嵌入视频'},
            {id: 'code-block', icon: icons.code, tooltip: '标记为代码块'}
        ];
        exButtons.forEach(input =>{
            let button = document.createElement('button');
            button.setAttribute('class', 'ql-' + input.id + ' ql-bar');
            button.setAttribute('type', 'button');
            button.setAttribute('labeltooltip', input.tooltip);
            button.innerHTML = input.icon;
            toolbar.insertBefore(button, toolbar.childNodes[toolbar.childNodes.length-1]);
            quill.getModule("toolbar").attach(button);
        });

        // abstract
        let noteAbstract = document.createElement('textarea');
        noteAbstract.setAttribute('rows', '3');
        noteAbstract.setAttribute('placeholder', '自定义笔记发布时评论区显示的内容...');
        noteAbstract.setAttribute('style', 'margin:0 10px 10px');
        toolbar.parentNode.insertBefore(noteAbstract, toolbar.nextSibling);

        // inject message
        let http = new XMLHttp();
        http.filterData = (args, data) => {
            if (args[0]=='POST' && args[1]=='//api.bilibili.com/x/note/add' && noteAbstract.value != '') {
                data[0] = injectPostMsg(data[0], noteAbstract.value);
            }
            return data;
        }
        initXMLHttpRequest(http);
    };
    let app = document.getElementById('app');
    let observerOptions = {
      childList: true,
      attributes: false,
      subtree: false
    };
    let observer = new MutationObserver((mutation_records) => {
        let toolbar = document.querySelector('.ql-toolbar');
        if (toolbar) {
            inject(toolbar);
            observer.disconnect();
        }
    });
    observer.observe(app, observerOptions);
})();