bilibili copy comment link

b站评论留档链接生成

// ==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);