// ==UserScript==
// @name Bilibili 轴Man小助手
// @namespace http://tampermonkey.net/
// @version 0.9.3
// @description 将评论区的轴转换至Bilibili的笔记,实现手机可点的特性
// @author as042971
// @include *://www.bilibili.com/video/av*
// @include *://www.bilibili.com/video/BV*
// @license MIT
// @grant none
// @esversion 8
// ==/UserScript==
(function() {
'use strict';
// 设置 useIndent = true 会在文本前增加缩进和引导线
const useIndent = true;
// 设置 useNewLine = true 会在文本后增加空行
const useNewLine = false;
const insertNewLine = function (quill) {
let currentPosition = quill.getSelection(true);
quill.insertText(currentPosition,'\n','silent');
};
const markTime = function (quill, index, seconds, cidCount, title) {
let currentPosition = quill.getSelection(true);
quill.insertEmbed(currentPosition, 'tag', {
'cid': window.cid,
'oid_type': 1,
'status': 0,
'index': index,
'seconds': seconds,
'cidCount': cidCount,
'key': (new Date).getTime(),
'title': title,
'epid': 0
}, 'silent');
currentPosition.index += 2;
quill.setSelection(currentPosition);
};
const insertText = function (quill, text, guide) {
let currentPosition = quill.getSelection(true);
if (useIndent) {
// 插入引导线
let guideStr = (guide)? " └─ " : '\n ';
quill.insertText(currentPosition, guideStr,{'color': '#cccccc'}, 'silent');
}
let mark = false;
if (text.charAt(text.length-1) == '*') {
text = text.substr(0, text.length - 1);
mark = true;
}
// 使用正则表达式分割链接
// 增加前后缀以避免BV在头尾出现
let exText = '*' + text + '*';
let textParts = exText.split(/BV[A-Za-z0-9]{10}/);
let bvParts = exText.match(/BV[A-Za-z0-9]{10}/);
for (let i = 0; i < textParts.length; i++) {
// 增加文本部分
let textPart = textParts[i];
if (i == 0) {
// 删去先导符号
textPart = textPart.substr(1, textPart.length - 1);
}
if (i == textParts.length - 1) {
// 删去结尾符号
textPart = textPart.substr(0, textPart.length - 1);
}
if (textPart) {
currentPosition = quill.getSelection(true);
if (mark) {
quill.insertText(currentPosition, textPart,{'color': '#ee230d', 'bold': true, 'link': null}, 'silent');
} else {
quill.insertText(currentPosition, textPart,{'color': null, 'link': null, 'bold': false}, 'silent');
}
}
// 增加链接部分
if (i != textParts.length - 1) {
currentPosition = quill.getSelection(true);
let bvPart = bvParts[i];
quill.insertText(currentPosition, '打开', {'color': '#0b84ed', 'link':'https://www.bilibili.com/video/'+ bvPart ,'bold': false }, 'silent');
}
}
};
const parseTime = function (timeStr) {
const timePart = timeStr.split(":");
if (timePart.length == 3) {
return parseInt(timePart[0]) * 3600 + parseInt(timePart[1]) * 60 + parseInt(timePart[2]);
} else {
return parseInt(timePart[0]) * 60 + parseInt(timePart[1]);
}
};
const handleTimeline = function (inputStr) {
// 获取分p信息
let pages = window.__INITIAL_STATE__.videoData.pages;
let cid = window.cid;
let cidCount = pages.length;
let index = 0;
let title = '';
for (index=0; index < pages.length; index++) {
if (pages[index].cid == cid) {
title = pages[index].part;
break;
}
}
index += 1;
title = 'P' + index;
let quill = document.querySelector('.ql-container').__quill;
// h:mm:ss 型时间
const timeRegex = /^(\d{1})\:([0-5]{1}\d{1})\:([0-5]{1}\d{1})$/;
// mm:ss 型时间
const timeRegex2 = /^([0-5]{1}\d{1})\:([0-5]{1}\d{1})$/;
// 通过换行分隔
const inputStrList = inputStr.split(/[\r\n]+/);
for (let i = 0; i < inputStrList.length; i++) {
let inputStrItem = inputStrList[i];
let nonTimeStr = '';
let time = 0;
// 通过空格分隔
const inputPart = inputStrItem.split(' ');
for (let j = 0; j < inputPart.length; j++) {
let part = inputPart[j];
if (part) {
if (timeRegex.test(part) || timeRegex2.test(part)) {
// 这是一个时间戳
// 结束上一次的非时间戳内容
if (nonTimeStr != '') {
if (time != 0) {
quill.setSelection(0, 5);
markTime(quill, index, time, cidCount, title);
insertText(quill, nonTimeStr, true);
time = 0;
} else {
insertText(quill, nonTimeStr, false);
}
if (useNewLine) {
insertNewLine(quill);
}
nonTimeStr = '';
}
// 标记这个时间戳
time = parseTime(part);
} else {
if (nonTimeStr != '') {
nonTimeStr += ' ';
}
nonTimeStr += part;
}
}
}
if (nonTimeStr != '') {
if (time != 0) {
markTime(quill, index, time, cidCount, title);
insertText(quill, nonTimeStr, true);
time = 0;
} else {
insertText(quill, nonTimeStr, false);
}
if (useNewLine) {
insertNewLine(quill);
}
}
}
// 必须进行一次user插入,否则无法正常保存
let currentPosition = quill.getSelection(true);
quill.insertText(currentPosition, '', 'user');
};
const inject = function(node) {
let rawTimeline = document.createElement('textarea');
rawTimeline.setAttribute('id', 'inject-timeline');
rawTimeline.setAttribute('class', 'ipt-txt');
rawTimeline.setAttribute('rows', '1');
rawTimeline.setAttribute('placeholder', '将轴粘贴至这里...');
rawTimeline.oninput = async function () {
let data = rawTimeline.value;
rawTimeline.value = "";
rawTimeline.setAttribute('disabled', 'disabled');
rawTimeline.setAttribute('placeholder', '处理中,请稍后...');
handleTimeline(data);
rawTimeline.removeAttribute('disabled');
rawTimeline.setAttribute('placeholder', '将轴粘贴至这里...');
};
node.insertBefore(rawTimeline, node.childNodes[3]);
};
let app = document.getElementById('app');
let observerOptions = {
childList: true,
attributes: false,
subtree: false
};
let observer = new MutationObserver((mutation_records) => {
let note = document.querySelector('.active-note');
if (note) {
inject(note);
observer.disconnect();
}
});
observer.observe(app, observerOptions);
})();