🏠 Home 

B站评论直达

为 bilibili 上的评论生成支持 web 端和手机 app 直达的链接


Installer dette script?
// ==UserScript==
// @name         B站评论直达
// @namespace    http://tampermonkey.net/
// @version      0.3.3
// @description  为 bilibili 上的评论生成支持 web 端和手机 app 直达的链接
// @author       5ec1cff
// @license      AGPL
// @match        *://*.bilibili.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=bilibili.com
// @grant        unsafeWindow
// @grant        GM_setClipboard
// @grant        GM_addStyle
// @run-at       document-start
// ==/UserScript==
(function(window) {
'use strict';
// 动态:1-转发 2-相簿 4-动态 8-视频 16-小视频 64-文章 256-音频 512-番剧
// 评论:1-视频,5-小视频,6-小黑屋,11-相簿,12-文章,14-音频,17-动态
const commentToDynamicTypeMap = {
11: 2,
1: 8,
12: 64,
14: 256
}
GM_addStyle(`
.selected-comment { background-color: pink; }
.my-message {
border-radius: 8px;
color: #fff;
font-size: 14px;
left: 50%;
overflow: hidden;
padding: 12px 24px;
position: fixed;
transform: translate(-50%,-50%);
transition: all .4s;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background-color: #47d279;
box-shadow: 0 .2em .1em .1em rgba(71,210,121,.2);
top: calc(50% - 0px);
z-index: 2004;
text-align: center;
white-space: nowrap;
}
`);
let is_new_comment = false;
// 判断是否为 new_comment
if (location.href.indexOf('www.bilibili.com/video') > 0 || location.href.indexOf('www.bilibili.com/opus') > 0) { // && (!getJumpId() || location.href.indexOf('old_comment=1') > 0)) {
/*
let origMatch = String.prototype.match;
let count = 0;
String.prototype.match = function (...args) {
let r = origMatch.call(this, ...args);
if (!r && this == location.href && args[0]?.source == '#reply([0-9]+)$') {
r = '00';
count++;
if (count >= 2) String.prototype.match = origMatch;
}
return r;
}*/
// window.history.replaceState({}, '', "?old_comment=1");
is_new_comment = true;
console.warn('use new comment');
}
let main_comment_classes = ["list-item", "reply-wrap"],
reply_classes = ["reply-item", "reply-wrap"],
bar_selector = 'div.info';
if (is_new_comment) {
main_comment_classes = ['reply-item'];
reply_classes = ['sub-reply-item'];
bar_selector = 'div.reply-info, div.sub-reply-info';
}
let update_selector = `${'.' + main_comment_classes.join('.')}, ${'.' + reply_classes.join('.')}`;
function getJumpId() {
let r = location.hash.match(/#reply(\d+)/);
return r && r[1];
}
let jumpId = getJumpId();
window.addEventListener('hashchange', function () {
jumpId = getJumpId();
// console.log('new jumpId:', jumpId);
document.querySelectorAll(update_selector).forEach(updateSelectedState);
})
function getCommentRpid(e) {
if (is_new_comment) {
if (classNameMatch(e, 'sub-reply-item')) {
return e.__vnode?.children[1].props.reply.rpid || WARN('Failed to get sub-reply-item rpid on', e);
}
// return e.__vnode?.props['mr-show']?.msg?.rpid;
return e?.__vueParentComponent?.props?.reply?.rpid;
} else {
return e.dataset?.id;
}
}
// 高亮选择的评论
function updateSelectedState(e) {
if (getCommentRpid(e) == jumpId && jumpId != null) {
e.classList.add('selected-comment');
} else {
e.classList.remove('selected-comment');
}
}
function showToast(content) {
let d = document.createElement('div');
d.classList.add('my-message');
d.textContent = content;
document.body.append(d);
setTimeout((e) => { d.remove() }, 2000);
}
let _isDetail = null;
// 视频页面、动态页面、专栏页面
function isDetailPage() {
if (_isDetail == null) {
_isDetail = Boolean(location.href.match(/www\.bilibili\.com\/(video|read|opus)\/|t\.bilibili\.com\/\d+/));
console.log('isDetail:', _isDetail);
}
return _isDetail;
}
function WARN(msg, append) {
// console.warn(msg, append);
// debugger
return null;
}
function getBaseUrl(type, oid) {
let url = null;
if (!isDetailPage() && type != null && oid != null) {
if (type in commentToDynamicTypeMap) {
url = new URL(`https://t.bilibili.com/${oid}?type=${commentToDynamicTypeMap[type]}`);
} else if (type == 17) {
url = new URL(`https://t.bilibili.com/${oid}`);
} else {
console.warn('unsupported comment type:', type, oid);
url = new URL(location.href);
}
} else {
url = new URL(location.href);
}
let params = new URLSearchParams(url.search);
for (let k of Array.from(params.keys())) {
if (k.match(/spm|vd_source/)) { params.delete(k); }
}
url.search = params.toString();
return url;
}
function getUrl(e) {
let p = e.parentElement, root_id = null, second_id = null, comment_on = null, comment_on_oid = null;
while (p != null) {
if (classNameMatch(p, "reply-item", "reply-wrap")) second_id = p.dataset.id;
if (classNameMatch(p, 'sub-reply-item')) second_id = p?.__vnode?.children[1]?.props?.reply?.rpid || WARN('Failed to get new comment second id on', p);
if (classNameMatch(p, ...main_comment_classes)) {
let data;
if (p.attributes['mr-show']) {
data = JSON.parse(p.attributes['mr-show'].value);
root_id = p.dataset.id;
comment_on = data.msg.type;
comment_on_oid = data.msg.oid;
} else if (is_new_comment) {
data = p.__vueParentComponent.props.reply;
root_id = data.rpid;
comment_on = data.type;
comment_on_oid = data.oid;
}
}
if (root_id != null) break;
p = p.parentElement;
}
// console.log(root_id, second_id, comment_on, comment_on_oid);
let u = getBaseUrl(comment_on, comment_on_oid);
let params = new URLSearchParams(u.search);
params.append('comment_on', 1);
params.append('comment_root_id', root_id);
if (second_id != null) params.append('comment_secondary_id', 'second_id');
u.search = params.toString();
u.hash = `#reply${second_id || root_id}`;
return [u.hash, u.toString()];
}
function classNameMatch(elem, ...classNames) {
if (!(elem instanceof Element)) return false;
for (let name of classNames) {
if (!elem.classList.contains(name)) return false;
}
return true;
}
document.addEventListener('DOMContentLoaded', function() {
let observer = new MutationObserver(function(mutationsList, observe) {
mutationsList.forEach(l => {
l.addedNodes?.forEach(e => {
if (classNameMatch(e, ...main_comment_classes) || classNameMatch(e, ...reply_classes)) {
e.querySelectorAll(bar_selector).forEach(info => {
let newSpan = document.createElement('a');
newSpan.textContent = "直达链接";
newSpan.className = "btn-hover btn-highlight";
newSpan.title = '点击复制';
newSpan.addEventListener('click', function (e) {
GM_setClipboard(e.target.dataset.url, 'text');
showToast('已复制');
if (!isDetailPage()) {
e.preventDefault();
return false;
}
});
if (is_new_comment) {
newSpan.style = 'margin-left: 19px;';
}
info.insertBefore(newSpan, info.querySelector('div'));
let [hash, url] = getUrl(newSpan);
newSpan.dataset.url = url;
newSpan.href = isDetailPage() ? hash : url;
});
updateSelectedState(e);
}
})
})
});
observer.observe(document.body, { 'childList': true, 'subtree': true })
});
console.log("b comment loaded");
})(unsafeWindow);