bilibili copy comment link

b站评论留档链接生成

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         bilibili copy comment link
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  b站评论留档链接生成
// @author       Rain
// @match        https://t.bilibili.com/*
// @license      GNU General Public License v3.0
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none

// ==/UserScript==

window.addEventListener('load', () => {
    console.log("test")
    var url = window.location.href;
    //console.log(url)
    var reg1 =new RegExp("https://t.bilibili.com/[0-9].*")  //dynamic
    var reg2 = new RegExp("https://www.bilibili.com/video/.*") 
    const DEBUG = true;
    function debug(description = '', msg = '', force = false) {
        if (DEBUG || force) {
          console.log(`${description}`, msg)
        }
      }
    function attachEl(item) {
      let injectWrap = item.querySelector('.con .info');

         if(url.match(reg2)) injectWrap = item.querySelector('.root-reply-container .content-warp .root-reply .reply-info') 
         if(url.match(reg2)) console.log("NULL")
    
        // .text - comment content
        // .text-con - reply content
        //let content = item.querySelector('.con .text') || item.querySelector('.reply-con .text-con');
        //let id = item.dataset.id;
    
        // Simple way to attach element on replies initially loaded with comment
        // which wouldn't trigger mutation inside observeComments
        let replies = item.querySelectorAll('.con .reply-box .reply-item');
        if (replies.length > 0) {
          [...replies].map(reply => {
            attachEl(reply);
          });
        }
        
        if (injectWrap.querySelector('.asoulcnki')) {
          debug('already loaded for this comment');
        } else {
                // Insert asoulcnki check button
                let copyButton = document.createElement('span');

                copyButton.classList.add('asoulcnki', 'btn-hover', 'btn-highlight');
                copyButton.innerHTML = '复制链接';
                let oid = ""
                let root = ""
                //prepare url
                  var pageType = "17"
                  if(url.match(reg1)) {
                    let mrShow = item.getAttribute('mr-show')
                    //let obj = eval(mrShow
                    let jsonTmp = JSON.stringify(mrShow) //convert to string
                    if(mrShow) console.log(jsonTmp)
                    var index = jsonTmp.indexOf("oid")
                    console.log(index)
                    for(var i = index+ 8;i < jsonTmp.length; i ++) {
                      if(isNaN(jsonTmp[i])) break
                      oid += jsonTmp[i]
                    }
                    console.log(oid) 
                    // let reg = /\d+/
                    // var o = reg.exec(url)
                    // console.log(o[0])
                    //oid = o[0]
                    root = item.getAttribute('data-id')
                    console.log("root in reg1")
                    
                } else if(url.match(reg2)) {
                  // refer to https://www.zhihu.com/question/381784377/answer/1099438784
                  var regUrl = new RegExp("https://www.bilibili.com/video/BV(.*)/.*") 
                  var o = regUrl.exec(url)
                 // oid = 0[0]
                  
                    const bv2av = bv => {
                      if (!bv) return;
                      
                      const pos = [11, 10, 3, 8, 4, 6];
                      const base = 'fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF';
                      const table = {};
                      for (let i = 0; i < base.length; i++) table[base[i]] = i;

                      let r = 0;
                      for (let i = 0; i < pos.length; i++) r += table[bv[pos[i]]] * 58 ** i;
                      return (r - 8728348608) ^ 177451812;
                  };
                  
                  let tmp = item.querySelector('.root-reply-container .root-reply-avatar')
                  root = tmp.getAttribute('data-root-reply-id')
                  oid = bv2av(o[0])
                  console.log("av: ",oid)
                  pageType = "1"
                }
                copyButton.addEventListener('click', e => {
                

                var commentUrl = "https://www.bilibili.com/h5/comment/sub?oid=" + oid + "&pageType="+pageType + "&root="+root
                navigator.clipboard.writeText(commentUrl)
            })
            //if(url.match(reg1))
            if(url.match(reg1)) injectWrap.querySelector('.operation').before(copyButton);
            else if(url.match(reg2))injectWrap.querySelector('.reply-operation-warp').before(copyButton);

        }
    }

    function observeComments(wrapper) {
        // .comment-list - general list for video, zhuanlan, and dongtai
        // .reply-box - replies attached to specific comment
        let commentLists = wrapper ? wrapper.querySelectorAll('.comment-list, .reply-list') : document.querySelectorAll('.comment-list, .reply-list');
    
        if (commentLists) {
    
          [...commentLists].map(commentList => {
    
            // Directly attach elements for pure static server side rendered comments
            // and replies list. Used by zhuanlan posts with reply hash in URL.
            // TODO: need a better solution
            [...commentList.querySelectorAll('.list-item, .reply-item')].map(item => {  //list item
              attachEl(item);
              //console.log(item)
            });
    
            const observer = new MutationObserver((mutationsList, observer) => {
    
              for (const mutation of mutationsList) {
    
                if (mutation.type === 'childList') {
    
                  //('observed mutations', [...mutation.addedNodes].length);
    
                  [...mutation.addedNodes].map(item => {
                    attachEl(item);
    
                    // Check if the comment has replies
                    // I check replies here to make sure I can disable subtree option for
                    // MutationObserver to get better performance.
                    let replies = item.querySelectorAll('.con .reply-box .reply-item');
    
                    if (replies.length > 0) {
                      observeComments(item)
                     // debug(item.dataset.id + ' has rendered reply(ies)', replies.length);
                    }
                  })
                }
              }
            });
            observer.observe(commentList, { attributes: false, childList: true, subtree: false });
          });
        }
      }
      observeComments();
    const wrapperObserver = new MutationObserver((mutationsList, observer) => {

        for (const mutation of mutationsList) {
    
          if (mutation.type === 'childList') {
    
            [...mutation.addedNodes].map(item => {
              //debug('mutation wrapper added', item);
    
              if (item.classList?.contains('bb-comment')) {
                //debug('mutation wrapper added (found target)', item);
    
                observeComments(item);
    
                // Stop observing
                // TODO: when observer stops it won't work for dynamic homepage ie. https://space.bilibili.com/703007996/dynamic
                // so disable it here. This may have some performance impact on low-end machines.
                // wrapperObserver.disconnect();
              }
            })
          }
        }
      });
      wrapperObserver.observe(document.body, { attributes: false, childList: true, subtree: true });


}, false);