链滴社区优化

优化内容:1. 标记打赏用户和黑名单用户;2. 当前窗口打开链接;3.首页标签增加优选、最新回帖、代码片段、创造、新发布、EN等按钮;4.标签、最新、文档列表页显示文档数和分页分割线;5.链滴自动跳转;6. 聊天页面字体大小;7.聊天页面按日期增加分割线和;8.聊天页面右侧按日期增加跳转日期列表

// ==UserScript==
// @name         链滴社区优化
// @namespace    http://tampermonkey.net/
// @version      0.0.8
// @description  优化内容:1. 标记打赏用户和黑名单用户;2. 当前窗口打开链接;3.首页标签增加优选、最新回帖、代码片段、创造、新发布、EN等按钮;4.标签、最新、文档列表页显示文档数和分页分割线;5.链滴自动跳转;6. 聊天页面字体大小;7.聊天页面按日期增加分割线和;8.聊天页面右侧按日期增加跳转日期列表
// @author       Wilson
// @match        https://ld246.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=ld246.com
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 打赏用户列表(主要用于初始化),多个用英文逗号隔开即可,没有保持空即可,这个列表的用户头像上会有爱心标志
    var loveUsers = '';

    // 打赏用户列表(主要用于初始化),多个用英文逗号隔开即可,没有保持空即可(通常用于标记垃圾广告及骗子用户),这个用户的头像上会有红色x号
    var blackUsers = '';

    // 数组去重函数
    const uniqueArray = (array)=>[...new Set(array)];

    // 获取已存储用户信息
    const storeLoveUsers = GM_getValue('__love_users') || [];
    const storeBlackUsers = GM_getValue('__black_users') || [];

    // 打赏用户
    loveUsers = loveUsers.split(',').map(i=>i.trim()).filter(i=>i);
    loveUsers = uniqueArray([...storeLoveUsers, ...loveUsers].map(item=>item.trim()).filter(item=>item));
    GM_setValue('__love_users', loveUsers);

    // 链滴黑名单列表
    blackUsers = blackUsers.split(',').map(i=>i.trim()).filter(i=>i);
    blackUsers = uniqueArray([...storeBlackUsers, ...blackUsers].map(item=>item.trim()).filter(item=>item));
    GM_setValue('__black_users', blackUsers);

    addLoveBlackStyle(loveUsers, blackUsers);
    function addLoveBlackStyle(loveUsers, blackUsers) {
        var loveSelector = loveUsers.map(username => `[href$='/${username}'], [pjax-title^='${username} -']`).join(',\n');
        var blackSelector = blackUsers.map(username => `[href$='/${username}'], [pjax-title^='${username} -']`).join(',\n');
        addStyle(`
        /* 打赏用户 */
        a:is(
            ${loveSelector}
        ) {
           position: relative;
           &::before{
                content: "♥️";
                left: -3px;
                top: -3px;
                position: absolute;
                z-index: 10;
                color: green;
                pointer-events: none;
            }
            .user__info &.avatar-big::before {
                top: 0;
                left: 0;
            }
            .user-card &:has(.avatar-mid)::before{
                top: -40px;
            }
            .comment--perfect &::before{
                top: -12px;
                left: 0;
            }
            .article__meta &::before {
                left: -78px;
                top: 0;
            }
            .user__info &.avatar-big[style^="box-shadow"]::before{
                left:72px;
            }
            .user-card.user-card--bg & .avatar-mid{
                top: -65px!important;
            }
            .user-card.user-card--bg &::before{
                top: 0;
            }
        }
        /* 黑名单 */
        a:is(
            ${blackSelector}
        ) {
           position: relative;
           &::before{
                content: "❌";
                left: -3px;
                top: -3px;
                position: absolute;
                z-index: 10;
                color: red;
                pointer-events: none;
            }
            .user__info &.avatar-big::before {
                top: -12px;
                left: 0;
            }
            .user-card &:has(.avatar-mid)::before{
                top: -40px;
            }
            .comment--perfect &::before{
                top: 0;
                left: 0;
            }
            .article__meta &::before {
                left: -78px;
                top: 0;
            }
            .user__info &.avatar-big[style^="box-shadow"]::before{
                left:72px;
            }
            .user-card.user-card--bg & .avatar-mid{
                top: -65px!important;
            }
            .user-card.user-card--bg &::before{
                top: 0;
            }
        }
      `);
    }

    setTimeout(()=>{
        // 当前窗口打开
        var links = document.querySelectorAll('a[target="_blank"]');
        for (var i = 0; i < links.length; i++) {
            links[i].removeAttribute('target');
        }
        // 首页标签按钮
        var createButton = function(name, url, blank){
            var newSpan = document.createElement("span");
            newSpan.className = "tabs-sub__item tabs-sub__item"; // 注意这里可能有一个类名书写错误,实际使用中请检查你的类名定义
            newSpan.innerHTML = name;
            newSpan.onclick = function() {
                if(blank) window.open(url); else location.href = url;
            };
            // 获取目标元素
            var chatBtn = document.getElementById("chatBtn");
            // 检查是否存在父节点以便插入新元素
            if (chatBtn) {
                // 在#chatBtn之前插入新的span元素
                chatBtn.parentNode.insertBefore(newSpan, chatBtn);
            }
        }
        createButton('优选', 'https://ld246.com/recent/perfect');
        createButton('最新回帖', 'https://ld246.com/recent/reply');
        createButton('代码片段', 'https://ld246.com/tag/code-snippet');
        createButton('创造', 'https://ld246.com/tag/creation');
        createButton('新发布', 'https://github.com/siyuan-note/siyuan/releases', true);
        createButton('EN', 'https://liuyun.io/', true);
        // 标签列表页显示文档数和分页分割线
        if(location.href.indexOf("ld246.com/tag/")!==-1 || location.href.indexOf("ld246.com/recent")!==-1 || location.href.indexOf("ld246.com/qna")!==-1){
            GM_addStyle(`
                .listAjax li:nth-child(32n){border-bottom: 2px solid black;}
                .html--dark .listAjax li:nth-child(32n){border-bottom: 2px solid white;}
                .listAjax{counter-reset: item-counter;}
                .listAjax li::before {
                    content: counter(item-counter);
                    counter-increment: item-counter;
                    position: absolute;
                    left: 146px;
                    margin-top: 15px;
                    text-align: right;
                    color: var(--text-color);
                }
                .tabs-sub {
                    --before-left: 73px;
                }
                .tabs-sub::before {
                    content: attr(data-total);
                    position: absolute;
                    left: var(--before-left);
                    text-align: right;
                    color: var(--text-color);
                }
            `);
            function loadDocNums() {
                (async ()=>{
                    var pageSize = 32;
                    var result = await fetch(location.href + "?ajax=true&p=1");
                    result = await result.json();
                    var page1Length = document.querySelector(".listAjax").children.length;
                    if(page1Length < pageSize) document.querySelector(".tabs-sub").style.setProperty('--before-left', '146px');
                    document.querySelector(".tabs-sub").setAttribute('data-total', page1Length < pageSize ? page1Length : '~ ' + ((result.paginationPageCount+1) * pageSize +16)+' ±16');
                })();
            }
            loadDocNums();

            // 监控切换标签
            setTimeout(()=>{
                const parentEl = document.querySelector('#recent-pjax-container, #tag-pjax-container, #qna-pjax-container');
                const observer = new MutationObserver((mutations) => {
                    mutations.forEach(mutation => {
                        // 遍历新增的节点
                        mutation.addedNodes.forEach(node => {
                            //if (node.nodeType === 1) console.log(node)
                            // 确保是元素节点且符合选择器
                            if (node.nodeType === 1 && (node.matches('.module') || node.matches('.wrapper:has(.tabs-sub)'))) {
                                loadDocNums();
                            }
                        });
                    });
                });

                // 开始观察 body 的子元素变化
                observer.observe(parentEl, {
                    childList: true,  // 监听直接子元素变化
                    subtree: false    // 不监听深层子元素
                });
            }, 1000);
        }
    }, 1000);

    // 链滴自动跳转
    if (location.href.indexOf("ld246.com/forward")!==-1) {
        document.querySelector(".text button").click();
    }
    // 聊天页面字体大小
    if (location.href.indexOf("ld246.com/chats/")!==-1) {
        GM_addStyle(`.chats__content .ft-13{font-size: 16px;}.chats__content .ft__fade{font-size:14px;}`);
    }

    // 聊天界面添加分割线和右侧按日期跳转列表
    if (location.href.indexOf("ld246.com/chats/")!==-1) {
        // 生成日期列表
        generateDateList();

        // 监控新聊天消息生成
        const chatsList = document.querySelector('.chats__list');
        const observer = new MutationObserver((mutations) => {
            mutations.forEach(mutation => {
                // 遍历新增的节点
                mutation.addedNodes.forEach(node => {
                    //if (node.nodeType === 1) console.log(node)
                    // 确保是元素节点且符合选择器
                    if (node.nodeType === 1 && node.matches('.chats__item')) {
                        generateDateList();
                    }
                });
            });
        });
        // 开始观察 body 的子元素变化
        observer.observe(chatsList, {
            childList: true,  // 监听直接子元素变化
            subtree: false    // 不监听深层子元素
        });

        function generateDateList() {
             // ================= 原有分割线功能 =================
            GM_addStyle(`
    /* 分隔符样式 */
    .new-day-separator {
        border-top: 2px solid #ccc;
        padding-top: 10px;
        position: relative;
    }

    /* 新增悬浮列表样式 */
    #date-floating-list {
        position: fixed;
        right: 41px;
        top: 50%;
        transform: translateY(-50%);
        background-color: var(--background-color); /*rgba(255, 255, 255, 0.95);*/
        /*border: 1px solid #ddd;*/
        border: 1px solid var(--layer-border-color);
        border-radius: 3px;
        padding: 12px 16px;
        box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        max-height: 80vh;
        overflow-y: auto;
        z-index: 9999;
        font-family: Arial, sans-serif;
    }

    .date-item {
        padding: 6px 12px;
        margin: 4px 0;
        border-radius: 4px;
        cursor: pointer;
        transition: all 0.2s;
        font-size: 14px;
        color: var(--layer-color); /*#666;*/
        white-space: nowrap;
    }

    .date-item:hover {
        /*background: #f0f0f0;
        color: #333;*/
        background-color: var(--background-secondary-color);
        color: var(--toc-hover-color);
        transform: translateX(-4px);
    }

    .highlight {
        animation: highlight-fade 1s ease-out;
    }

    @keyframes highlight-fade {
        0% { background: rgba(255,235,59,0.3); }
        100% { background: transparent; }
    }
    `);

            // ================= 原有分割线逻辑 + 新增悬浮列表数据收集 =================
            const chatItems = document.querySelectorAll('.chats__list .chats__item');
            const dateMap = new Map();
            let previousDate = null;

            chatItems.forEach((item, index) => {
                // 原有分割线逻辑
                const timeElement = item.querySelector('.ft__smaller.ft__fade.fn__right');
                if (!timeElement) return;

                const timeString = timeElement.textContent.trim();
                const currentDate = new Date(timeString);
                currentDate.setHours(0, 0, 0, 0);

                // 收集日期数据用于悬浮列表
                const dateKey = currentDate.toISOString().split('T')[0];
                if (!dateMap.has(dateKey)) {
                    dateMap.set(dateKey, {
                        element: item,
                        dateStr: timeString.split(' ')[0]
                    });
                }

                // 原有日期比较逻辑
                if (index > 0 && !isSameDay(currentDate, previousDate)) {
                    item.classList.add('new-day-separator');
                }
                previousDate = currentDate;
            });

            // ================= 新增悬浮列表功能 =================
            const dateList = document.createElement('div');
            dateList.id = 'date-floating-list';

            // 按日期排序(从新到旧)
            const sortedDates = [...dateMap.entries()].sort((a, b) => new Date(b[0]) - new Date(a[0]));

            sortedDates.forEach(([dateKey, data]) => {
                const dateItem = document.createElement('div');
                dateItem.className = 'date-item';
                dateItem.textContent = data.dateStr;

                dateItem.addEventListener('click', () => {
                    data.element.scrollIntoView({
                        behavior: 'smooth',
                        block: 'start'
                    });
                    data.element.classList.add('highlight');
                    setTimeout(() => data.element.classList.remove('highlight'), 1000);
                });

                dateList.appendChild(dateItem);
            });

            document.body.appendChild(dateList);

            // ================= 原有辅助函数 =================
            function isSameDay(date1, date2) {
                if (!date1 || !date2) return false;
                return (
                    date1.getFullYear() === date2.getFullYear() &&
                    date1.getMonth() === date2.getMonth() &&
                    date1.getDate() === date2.getDate()
                );
            }
        }
    }

    function deleteArray(array, removeValue) {
        const index = array.indexOf(removeValue);
        if (index !== -1) {
            array.splice(index, 1); // 删除一个元素
        }
    }

    // 监控用户卡片出现
    const observer = new MutationObserver((mutations) => {
        mutations.forEach(mutation => {
            // 遍历新增的节点
            mutation.addedNodes.forEach(node => {
                //if (node.nodeType === 1) console.log(node)
                // 确保是元素节点且符合选择器
                if (node.nodeType === 1 && node.matches('div > .user-card')) {
                    const loveBtnHtml = `<button class="follow small" id="userCardLoveUser" title="添加到打赏者"> ♥️ </button>`;
                    const blackBtnHtml = `<button class="follow small" id="userCardBlackUser" title="添加到黑名单"> ❌ </button>`;
                    const shrink = node.querySelector('.fn__shrink');
                    if(shrink) {
                        shrink.insertAdjacentHTML('beforeend', loveBtnHtml);
                        shrink.insertAdjacentHTML('beforeend', blackBtnHtml);
                        const username = node.querySelector('.ft-gray b')?.textContent?.trim() || '';
                        if(!username) return;
                        const loveBtn = node.querySelector('#userCardLoveUser');
                        if(loveUsers.includes(username)) {loveBtn.setAttribute('title', '取消打赏者');}
                        const blackBtn = node.querySelector('#userCardBlackUser');
                        if(blackUsers.includes(username)) {blackBtn.setAttribute('title', '取消黑名单');}
                        loveBtn.onclick = () => {
                            if(!loveUsers.includes(username)){
                                loveUsers.push(username);
                                GM_setValue('__love_users', uniqueArray(loveUsers));
                                loveBtn.setAttribute('title', '取消打赏者');
                            } else {
                                deleteArray(loveUsers, username);
                                GM_setValue('__love_users', loveUsers);
                                loveBtn.setAttribute('title', '添加到打赏者');
                            }
                            addLoveBlackStyle(loveUsers, blackUsers);
                        };
                        blackBtn.onclick = () => {
                            if(!blackUsers.includes(username)){
                                blackUsers.push(username);
                                GM_setValue('__black_users', uniqueArray(blackUsers));
                                blackBtn.setAttribute('title', '取消黑名单');
                            } else {
                                deleteArray(blackUsers, username);
                                GM_setValue('__black_users', blackUsers);
                                blackBtn.setAttribute('title', '添加到黑名单');
                            }
                            addLoveBlackStyle(loveUsers, blackUsers);
                        };
                    }
                }
            });
        });
    });

    // 开始观察 body 的子元素变化
    observer.observe(document.body, {
        childList: true,  // 监听直接子元素变化
        subtree: true    // 不监听深层子元素
    });

    // 监听用户页面
    if(location.href.indexOf("ld246.com/member/")!==-1){
        setTimeout(()=> {
            const userInfo = document.querySelector('.user__info');
            const userBar = userInfo.querySelector('.fn__clear');
            if(!userBar) return;
            const loveBtnHtml = `<a href="javascript:;" id="userCardLoveUser" style="float:right" class="user__site vditor-tooltipped__n vditor-tooltipped" aria-label="添加到打赏者"> ♥️ </a>`;
            const blackBtnHtml = `<a href="javascript:;" id="userCardBlackUser" style="float:right" class="user__site vditor-tooltipped__n vditor-tooltipped" aria-label="添加到黑名单"> ❌ </a>`;
            userBar.insertAdjacentHTML('beforeend', blackBtnHtml);
            userBar.insertAdjacentHTML('beforeend', loveBtnHtml);
            const username = userInfo.querySelector('span.ft__gray.ft__smaller')?.textContent?.trim() || '';
            if(!username) return;
            const loveBtn = userInfo.querySelector('#userCardLoveUser');
            if(loveUsers.includes(username)) {loveBtn.setAttribute('aria-label', '取消打赏者');}
            const blackBtn = userInfo.querySelector('#userCardBlackUser');
            if(blackUsers.includes(username)) {blackBtn.setAttribute('aria-label', '取消黑名单');}
            loveBtn.onclick = () => {
                if(!loveUsers.includes(username)){
                    loveUsers.push(username);
                    GM_setValue('__love_users', uniqueArray(loveUsers));
                    loveBtn.setAttribute('aria-label', '取消打赏者');
                } else {
                    deleteArray(loveUsers, username);
                    GM_setValue('__love_users', loveUsers);
                    loveBtn.setAttribute('aria-label', '添加到打赏者');
                }
                addLoveBlackStyle(loveUsers, blackUsers);
            };
            blackBtn.onclick = () => {
                if(!blackUsers.includes(username)){
                    blackUsers.push(username);
                    GM_setValue('__black_users', uniqueArray(blackUsers));
                    blackBtn.setAttribute('aria-label', '取消黑名单');
                } else {
                    deleteArray(blackUsers, username);
                    GM_setValue('__black_users', blackUsers);
                    blackBtn.setAttribute('aria-label', '添加到黑名单');
                }
                addLoveBlackStyle(loveUsers, blackUsers);
            };
        }, 1000);
    }

    function addStyle(cssRules) {
        const styleId = 'ld246-user-white-black-style'; // 定义一个固定的 id 标记

        // 如果存在上一次添加的 <style> 元素,则移除它
        const existingStyle = document.getElementById(styleId);
        if (existingStyle && existingStyle.parentNode) {
            existingStyle.parentNode.removeChild(existingStyle);
        }

        // 创建一个新的 <style> 元素
        const styleElement = document.createElement('style');
        styleElement.id = styleId; // 设置 id
        styleElement.type = 'text/css';

        // 将 CSS 规则写入 <style> 元素
        if (styleElement.styleSheet) {
            // 针对旧版 IE 浏览器
            styleElement.styleSheet.cssText = cssRules;
        } else {
            // 现代浏览器
            styleElement.appendChild(document.createTextNode(cssRules));
        }

        // 将 <style> 元素添加到 <head> 中
        document.head.appendChild(styleElement);
    }

    function getUsers() {
        console.log('打赏者用户:');
        console.log(loveUsers.join(','));
        console.log('黑名单用户:');
        console.log(blackUsers.join(','));
    }
    // console.log(getUsers());
})();

QingJ © 2025

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