B站动态操作栏跟随

B站浏览动态优化

// ==UserScript==
// @name         B站动态操作栏跟随
// @namespace    http://tampermonkey.net/
// @version      2024-07-03-1
// @description  B站浏览动态优化
// @author       Liuhl1mx
// @match        https://t.bilibili.com/*
// @match        https://space.bilibili.com/*
// @match        https://www.bilibili.com/v/topic/detail/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=bilibili.com
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    class DynamicLoad {
        dynamicLoaderObserver;

        constructor(node, deep=false) {
            this.#updataObserver(node, deep);
        }

        get items() {
            return null;
        }

        close() {
            this.dynamicLoaderObserver.disconnect();
        }

        #updataObserver(node, deep) {
            this.dynamicLoaderObserver = new MutationObserver((mutation_records) => {
                const append_dynamic_list = mutation_records.reduce((acc, curr) => {
                    acc.push(...Array.from(curr.addedNodes));
                    return acc;
                }, []);
                window.dispatchEvent(new CustomEvent('dynamicUpdate', {
                    detail: append_dynamic_list
                }))
            });
            this.dynamicLoaderObserver.observe(node, { childList: true, subtree: deep });
        }
    }

    function waitForElement(selector, callback) {
        const interval = setInterval(()=>{
            const element = document.querySelector(selector);
            if (element instanceof Node) {
                clearInterval(interval);
                callback(element)
            }
        }, 100)
        }

    // B站个人动态
    function main1() {
        waitForElement('.bili-dyn-list__items', (element) => {
            const section_load = new DynamicLoad(element.parentNode.parentNode);
            let dyn_load = new DynamicLoad(element);
            if (element) {
                GM_addStyle(`
    .bili-dyn-item__footer {
    padding: 0 40px 0 88px;
    position: sticky;
    top: 64px;
    z-index: 5;
    background-color: white;
    }`)
            }
            window.addEventListener('dynamicUpdate', (e) => {
                const append_list = e.detail;
                // console.log('append_list: ', append_list);
                append_list.forEach((item) => {
                    // 动态切换时,切换监听当前动态列
                    if(item instanceof Element && item.classList.contains('bili-dyn-list')) {
                        //console.log('切换动态: ', item);
                        if (dyn_load) dyn_load.close();
                        dyn_load = new DynamicLoad(item.querySelector('.bili-dyn-list__items'));
                    }
                    // 动态内容更新时,修改动态
                    if(item instanceof Element && item.classList.contains('bili-dyn-list__item')) {
                        //console.log('修改动态: ', item);
                        const footer = item.querySelector('.bili-dyn-item__footer');
                        const mm = item.querySelector('.bili-dyn-item__main')
                        const dyn = item.querySelector('.bili-dyn-item');
                        if (footer && mm && dyn) {
                            dyn.insertBefore(footer, mm);
                            dyn.insertBefore(mm, footer);
                            // 左键和右键自动滚动到对应动态主体
                            const comment_btn = footer.querySelector('.bili-dyn-action.comment');
                            if (comment_btn) {
                                footer.querySelector('.bili-dyn-action.comment').addEventListener('contextmenu', function(event) {
                                    event.preventDefault();
                                    if (dyn.querySelector('.bili-dyn-item__panel')) {
                                        mm.scrollIntoView({ behavior: 'smooth', block: 'start'});
                                    }
                                });
                                footer.querySelector('.bili-dyn-action.comment').addEventListener('click', function(event) {
                                    if (dyn.querySelector('.bili-dyn-item__panel')) {
                                        mm.scrollIntoView({ behavior: 'instant', block: 'start'});
                                    }
                                });
                            }
                        }
                    }
                })
            })
            //console.log('动态已修改');
        })
    }

    //console.log('用户动态界面');
    function main2() {
        let dyn_load;
        // 动态界面直接出现
        if (window.location.href.indexOf('dynamic') !== -1) {
            waitForElement('.bili-dyn-list__items', (element) => {
                dyn_load = new DynamicLoad(element);
                if (element) {
                    GM_addStyle(`
    .bili-dyn-item__footer {
    padding: 0 40px 0 88px;
    position: sticky;
    top: 64px;
    z-index: 5;
    background-color: white;
    }`)
                }
                window.addEventListener('dynamicUpdate', (e) => {
                    const append_list = e.detail;
                    // console.log('append_list: ', append_list);
                    append_list.forEach((item) => {
                        // 动态内容更新时,修改动态
                        const footer = item.querySelector('.bili-dyn-item__footer');
                        const mm = item.querySelector('.bili-dyn-item__main')
                        const dyn = item.querySelector('.bili-dyn-item');
                        if (footer && mm && dyn) {
                            dyn.insertBefore(footer, mm);
                            dyn.insertBefore(mm, footer);
                            // 左键和右键自动滚动到对应动态主体
                            const comment_btn = footer.querySelector('.bili-dyn-action.comment');
                            if (comment_btn) {
                                footer.querySelector('.bili-dyn-action.comment').addEventListener('contextmenu', function(event) {
                                    event.preventDefault();
                                    if (dyn.querySelector('.bili-dyn-item__panel')) {
                                        mm.scrollIntoView({ behavior: 'smooth', block: 'start'});
                                    }
                                });
                                footer.querySelector('.bili-dyn-action.comment').addEventListener('click', function(event) {
                                    if (dyn.querySelector('.bili-dyn-item__panel')) {
                                        mm.scrollIntoView({ behavior: 'instant', block: 'start'});
                                    }
                                });
                            }
                        }

                    })
                })
                //console.log('动态已修改');
            })
        }
        // 点击切换动态界面
        let originPush = history.pushState;
        history.pushState = function (...arg) {
            //console.log("改变了路由", arg[2]);
            if (arg[2].indexOf('dynamic') !== -1) {
                waitForElement('.bili-dyn-list__items', (element) => {
                    dyn_load = new DynamicLoad(element);
                    if (element) {
                        GM_addStyle(`
    .bili-dyn-item__footer {
    padding: 0 40px 0 88px;
    position: sticky;
    top: 64px;
    z-index: 5;
    background-color: white;
    }`)
                    }
                    window.addEventListener('dynamicUpdate', (e) => {
                        const append_list = e.detail;
                        // console.log('append_list: ', append_list);
                        append_list.forEach((item) => {
                            // 动态内容更新时,修改动态
                            const footer = item.querySelector('.bili-dyn-item__footer');
                            const mm = item.querySelector('.bili-dyn-item__main')
                            const dyn = item.querySelector('.bili-dyn-item');
                            if (footer && mm && dyn) {
                                dyn.insertBefore(footer, mm);
                                dyn.insertBefore(mm, footer);
                                // 左键和右键自动滚动到对应动态主体
                                const comment_btn = footer.querySelector('.bili-dyn-action.comment');
                                if (comment_btn) {
                                    footer.querySelector('.bili-dyn-action.comment').addEventListener('contextmenu', function(event) {
                                        event.preventDefault();
                                        if (dyn.querySelector('.bili-dyn-item__panel')) {
                                            mm.scrollIntoView({ behavior: 'smooth', block: 'start'});
                                        }
                                    });
                                    footer.querySelector('.bili-dyn-action.comment').addEventListener('click', function(event) {
                                        if (dyn.querySelector('.bili-dyn-item__panel')) {
                                            mm.scrollIntoView({ behavior: 'instant', block: 'start'});
                                        }
                                    });
                                }
                            }

                        })
                    })
                    //console.log('动态已修改');
                })
            } else if (dyn_load){
                dyn_load.close();
                //console.log('监听器释放');
            }
            return originPush.call(this, ...arg);
        };
    }

    // 话题界面
    function main3() {
        waitForElement('div.topic-list__flow-list > div', (element) => {
            const processItem = (item) => {
                    // 动态内容更新时,修改动态
                    if(item instanceof Element && item.classList.contains('list__topic-card')) {
                        // console.log('修改动态: ', item);
                        const footer = item.querySelector('.bili-dyn-item__footer');
                        const mm = item.querySelector('.bili-dyn-item__main')
                        const dyn = item.querySelector('.bili-dyn-item');
                        if (footer && mm && dyn) {
                            dyn.insertBefore(footer, mm);
                            dyn.insertBefore(mm, footer);
                            // 左键和右键自动滚动到对应动态主体
                            const comment_btn = footer.querySelector('.bili-dyn-action.comment');
                            if (comment_btn) {
                                footer.querySelector('.bili-dyn-action.comment').addEventListener('contextmenu', function(event) {
                                    event.preventDefault();
                                    if (dyn.querySelector('.bili-dyn-item__panel')) {
                                        mm.scrollIntoView({ behavior: 'smooth', block: 'start'});
                                    }
                                });
                                footer.querySelector('.bili-dyn-action.comment').addEventListener('click', function(event) {
                                    if (dyn.querySelector('.bili-dyn-item__panel')) {
                                        mm.scrollIntoView({ behavior: 'instant', block: 'start'});
                                    }
                                });
                            }
                        }
                    }
                }
            element.querySelectorAll('.list__topic-card').forEach(item => processItem(item));
            // console.log('element load: ', element.parentNode.parentNode);
            let dyn_load = new DynamicLoad(element.parentNode.parentNode, true);
            if (element) {
                GM_addStyle(`
    .bili-dyn-item__footer {
    padding: 0 40px 0 88px;
    position: sticky;
    top: 64px;
    z-index: 5;
    background-color: white;
    }`)
            }
            window.addEventListener('dynamicUpdate', (e) => {
                const append_list = e.detail;
                append_list.forEach(item => processItem(item))
            })
            //console.log('动态已修改');
        })
    }
    if (window.location.href.indexOf('t.bilibili.com') !== -1) {
        //console.log('个人动态界面');
        main1();
    }else if (window.location.href.indexOf('space.bilibili.com') !== -1) {
        //console.log('用户动态界面');
        main2();
    }else if (window.location.href.indexOf('www.bilibili.com/v/topic/detail') !== -1) {
        //console.log('话题界面');
        main3();
    }
})();