您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
增加bilibili网页视频简介文字的交互,部分网页链接、社交平台跳转、邮箱跳转、视频时间跳转、微信号和群号可扫二维码录入手机、百度盘4位密码点击复制
当前为
// ==UserScript== // @name bilibili网页视频简介中的链接可以点击 // @namespace http://tampermonkey.net/ // @version 2.2 // @description 增加bilibili网页视频简介文字的交互,部分网页链接、社交平台跳转、邮箱跳转、视频时间跳转、微信号和群号可扫二维码录入手机、百度盘4位密码点击复制 // @description:en black to blue! // @description:zh-CN 增加bilibili网页视频简介文字的交互,部分网页链接、社交平台跳转、邮箱跳转、视频时间跳转、微信号和群号可扫二维码录入手机、百度盘4位密码点击复制 // @author beibeibeibei // @match *.bilibili.com/video/* // @grant GM_setClipboard // @require https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js // @require https://cdn.jsdelivr.net/npm/kjua/dist/kjua.min.js // ==/UserScript== (function () { 'use strict'; let $ = jQuery.noConflict(); // line09 https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js let QR = kjua; //////////////// line10 https://cdn.jsdelivr.net/npm/kjua/dist/kjua.min.js ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////22到190行都是识别规则//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //可以点击 /* 0A*/ let URLreg = /([hH][tT]{2}[pP]([sS]?):\/\/|[wW]{3}.|[wW][aA][pP].|[fF][tT][pP].|[fF][iI][lL][eE].|[bB]{2}[sS].|[nN][eE][wW][sS].|[bB][lL][oO][gG].)[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/; function url2URL(url) { return '<a target="_blank" href="' + url + '">' + url + '</a>'; } /* 0B*/ let baidupanlink = /pan.baidu.com\/s\/[\-0-9a-zA-Z_]{8,27}/; function url2URL2(url) { return '<a target="_blank" href="https://' + url + '">' + url + '</a>'; } /* 1A*/ let BVlink = /(?<![hH][tT]{2}[pP][sS]?:\/\/www.bilibili.com\/video\/)(bv|BV)[A-Za-z0-9]{10}/; function BVnum2BVlink(BVnum) { return '<a target="_blank" href="//www.bilibili.com/video/' + BVnum + '">' + BVnum + '</a>'; } /* 1B*/ let avlink = /(?<![hH][tT]{2}[pP][sS]?:\/\/www.bilibili.com\/video\/)av[0-9]+/; function avnum2avlink(AVnum) { return '<a target="_blank" href="//www.bilibili.com/video/' + AVnum + '">' + AVnum + '</a>'; } /* 1C*/ let cvlink = /(?<![hH][tT]{2}[pP][sS]?:\/\/www.bilibili.com\/read\/)cv[1-9][0-9]*/; function cvnum2cvlink(cvnum) { return '<a target="_blank" href="//www.bilibili.com/read/' + cvnum + '/">' + cvnum + '</a>'; } /* 1D*/ let smlink = /(?<![hH][tT]{2}[pP][sS]?:\/\/www.nicovideo.jp\/watch\/)sm[0-9]+/; function smnum2smlink(smnum) { return '<a target="_blank" href="http://acg.tv/' + smnum + '/">' + smnum + '</a>'; } /* 2A*/ let weibo1 = /((新浪)?(微|官)博(已更名为|名)?|围脖)(@|@|@ | @|:|:@|: @)[\-0-9A-Z_a-z\u4e00-\u9fa5]{2,30}/; function wbstr2wblink1(wbstr) { let wb = wbstr.match(/(?<=((新浪)?(微|官)博(已更名为|名)?|围脖)(@|@|@ | @|:|:@|: @))[\-0-9A-Z_a-z\u4e00-\u9fa5]{2,30}/)[0]; return '<a target="_blank" href="https://s.weibo.com/user?q=' + wb + '&Refer=weibo_user">' + wbstr + '</a>'; } /* 2B*/ let weibo2 = /(微博【)[\-0-9A-Z_a-z\u4e00-\u9fa5]{2,30}(】)/; function wbstr2wblink2(wbstr) { let wb = wbstr.match(/(?<=微博【)[\-0-9A-Z_a-z\u4e00-\u9fa5]{2,30}(?=】)/)[0]; return '<a target="_blank" href="https://s.weibo.com/user?q=' + wb + '&Refer=weibo_user">' + wbstr + '</a>'; } /* 2C*/ let weibo3 = /(@|@|:|:@)[\-0-9A-Z_a-z\u4e00-\u9fa5]{3,30}( 的微博)/; function wbstr2wblink3(wbstr) { let wb = wbstr.match(/(?<=(@|@|:|:@))[\-0-9A-Z_a-z\u4e00-\u9fa5]{3,30}(?= 的微博)/)[0]; return '<a target="_blank" href="https://s.weibo.com/user?q=' + wb + '&Refer=weibo_user">' + wbstr + '</a>'; } /* 3 */ let youtube = /(youtube|YouTube|Youtube)(频道| ID)?[:|:| ] ?(?!快手)[\-0-9A-Z_a-z\u4e00-\u9fa5【】']+/; function ytb2ytblink(ytbstr) { let ytb = ytbstr.match(/(?<=(youtube|YouTube|Youtube)(频道| ID)?[:|:| ] ?)[\u4e00-\u9fa5【】']+/)[0]; return '<a target="_blank" href="https://www.youtube.com/results?search_query=' + ytb + '">' + ytbstr + '</a>'; } //显示二维码,将字符串扫入手机 /* 4A*/ let WeChat1 = /联系微信[0-9A-Za-z\u4e00-\u9fa5]+|微信搜一搜:[0-9A-Za-z\u4e00-\u9fa5]+/; function wechat2qr1(wechatstr) { let wechat = wechatstr.match(/(?<=微信)[0-9A-Za-z\u4e00-\u9fa5]+|(?<=微信搜一搜:)[0-9A-Za-z\u4e00-\u9fa5]+/)[0]; return '<a class="qrtampermonkey" value="' + wechat + '">' + wechatstr + '</a>'; } /* 4B*/ let WeChat2 = /【联系微信:[0-9A-Za-z\u4e00-\u9fa5]+,非诚勿扰】/; let WeChat2QR = /(?<=【联系微信:)[0-9A-Za-z\u4e00-\u9fa5]+(?=,非诚勿扰】)/; function wechat2qr2(wechatstr) { let wechat = wechatstr.match(/(?<=【联系微信:)[0-9A-Za-z\u4e00-\u9fa5]+(?=,非诚勿扰】)/)[0]; return '<a class="qrtampermonkey" value="' + wechat + '">' + wechatstr + '</a>'; } /* 4C*/ let WeChatOfficial1 = /(微信)?公众号(:|:|: )[0-9A-Za-z\u4e00-\u9fa5]{4,30}/; function WeChatOfficial2qr1(WeChatOfficialstr) { let WeChatOfficial = WeChatOfficialstr.match(/(?<=(微信)?公众号(:|:|: ))[0-9A-Za-z\u4e00-\u9fa5]{4,30}/)[0]; return '<a class="qrtampermonkey" value="' + WeChatOfficial + '">' + WeChatOfficialstr + '</a>'; } /* 4D*/ let WeChatOfficial2 = /(微信)?公众号【[0-9A-Za-z\u4e00-\u9fa5]{4,30}】/; function WeChatOfficial2qr2(WeChatOfficialstr) { let WeChatOfficial = WeChatOfficialstr.match(/(?<=(微信)?公众号【)[0-9A-Za-z\u4e00-\u9fa5]{4,30}(?=】)/)[0]; return '<a class="qrtampermonkey" value="' + WeChatOfficial + '">' + WeChatOfficialstr + '</a>'; } /* 5 */ let qqgroup = /[qQ][qQ]?(交流)?群(号)?(:|~)?[0-9]+|搜索QQ群:[\u4e00-\u9fa5]+|(?<![0-9qQ])群(号|号码)?(:|: |:| )?[0-9]+(?!:)|群([0-9]+|⑧|⑨|⑩):[0-9]+|[0-9]+群:[0-9]+/; function qqgroupstr2qr(qqgroupstr) { let qqgroupnum = qqgroupstr.match(/(?<=([qQ][qQ]?(交流)?群(号)?(:|~)?))[0-9]+|(?<=搜索QQ群:)[\u4e00-\u9fa5]+|(?<=((?<![0-9qQ])群(号|号码)?(:|: |:| )?))[0-9]+(?!:)|(?<=(群([0-9]+|⑧|⑨|⑩):))[0-9]+|(?<=([0-9]+群:))[0-9]+/)[0]; return '<a class="qrtampermonkey" value="' + qqgroupnum + '">' + qqgroupstr + '</a>'; } //其他 //邮箱链接 let mailaddress = /[0-9A-Za-z_\-]+@(qq|163|126|gmail|outlook|foxmail|aliyun|rd.netease|global-link-m|bigdongdong).com/; /* 6 */ let mail = RegExp(/(商务)?(合作)?(联系)?邮箱(:|:|::| |:\n)?/.source + mailaddress.source + /|/.source + /商务/.source + mailaddress.source); function mailstr2mail(mailaddressstr) { let mail = mailaddressstr.match(RegExp(/(?<=(商务)?(合作)?(联系)?邮箱(:|:|::| )?)/.source + mailaddress.source + /|/.source + /(?<=商务)/.source + mailaddress.source))[0]; return '<a href="mailto:' + mail + '">' + mailaddressstr + '</a>'; } //时间跳转 /* 7 */ let videotime1 = /[0-9]+:[0-9]{2}(?![0-9])/; //时间数字串,修改视频进度条 //暂时还不支持3个冒号的??? function changevideotime1(time){ let text = time.split(":"); let value = text[0] * 60 + text[1] * 1; return '<a class="timetampermonkey" value="' + value + '">' + time + '</a>'; } /* 8 */ let videotime2 = /[0-9]{1,2}分[0-9]{1,2}秒|[0-9]{1,2}分|[0-9]{1,2}秒/; //时间数字文字组合串,修改视频进度条 function changevideotime2(time) { let timetest_m_s = time.split(/[分秒]/); let timetest_m = time.split(/[分]/); let timetest_s = time.split(/[秒]/); let value = 0; if (timetest_m_s.toString() == timetest_m.toString()) { // 例子:2分 value = timetest_m[0] * 60; } else if (timetest_m_s.toString() == timetest_s.toString()) { // 例子:2秒 value = timetest_s[0] * 1; } else { // 剩下的就是分秒都有 例子:1分01秒 value = timetest_m_s[0] * 60 + timetest_m_s[1] * 1; } return '<a class="timetampermonkey" value="' + value + '">' + time + '</a>'; } //密码点击复制 /* 9 */ let four_digit_password = /密码(:|: )[0-9a-z]{4}/; function copy_password(text) { let password = text.match(/(?<=密码(:|: ))[0-9a-z]{4}/)[0]; return '<a class="copytampermonkey" title="点击复制" value="' + password + '">' + text + '</a>'; } //删除重复文字 //修复up主口吃的问题 /* 10A*/ let repeatWORD1 = /(三连|三连啊|求三连|三连我!|关注|求关注|关注我!|评论我!|不要白嫖!|不要白嫖!!!!|一件三连叭~~~)\1+/; function Norepeat1(repeatstr) { repeatstr.match(new RegExp(repeatWORD1)); return RegExp.$1; } /* 10B*/ let repeatWORD2 = /(三)\1+(连)/; function Norepeat2(repeatstr) { repeatstr.match(new RegExp(repeatWORD2)); return RegExp.$1 + RegExp.$2; } /* 10C*/ let repeatWORD3 = /(关)\1+(注)(?!注)/; function Norepeat3(repeatstr) { repeatstr.match(new RegExp(repeatWORD3)); return RegExp.$1 + RegExp.$2; } /* 10D*/ let repeatWORD4 = /(关)\1+(注)\2+/; function Norepeat4(repeatstr) { repeatstr.match(new RegExp(repeatWORD3)); return RegExp.$1 + RegExp.$2; } /* 10E*/ let repeatWORD5 = /(三连一定|一键三连哦|关注)(!)\2+/; function Norepeat5(repeatstr) { repeatstr.match(new RegExp(repeatWORD3)); return RegExp.$1 + RegExp.$2; } let R = [ /* 0A*/[URLreg, url2URL], /* 0B*/[baidupanlink, url2URL2], /* 1A*/[BVlink, BVnum2BVlink], /* 1B*/[avlink, avnum2avlink], /* 1C*/[cvlink, cvnum2cvlink], /* 1D*/[smlink, smnum2smlink], /* 2A*/[weibo1, wbstr2wblink1], /* 2B*/[weibo2, wbstr2wblink2], /* 2C*/[weibo3, wbstr2wblink3], /* 3 */[youtube, ytb2ytblink], /* 4A*/[WeChat1, wechat2qr1], /* 4B*/[WeChat2, wechat2qr2], /* 4C*/[WeChatOfficial1, WeChatOfficial2qr1], /* 4D*/[WeChatOfficial2, WeChatOfficial2qr2], /* 5 */[qqgroup, qqgroupstr2qr], /* 6 */[mail, mailstr2mail], /* 7 */[videotime1, changevideotime1], /* 8 */[videotime2, changevideotime2], /* 9 */[four_digit_password, copy_password], /* 10A*/[repeatWORD1, Norepeat1], /* 10B*/[repeatWORD2, Norepeat2], /* 10C*/[repeatWORD3, Norepeat3], /* 10D*/[repeatWORD4, Norepeat4], /* 10E*/[repeatWORD5, Norepeat5], ]; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////190行//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * @description 在字符串中搜索符合正则的所有位置 * @param text {string} 字符串 * @param reg {RegExp} 正则表达式 * @param shift {number} 开头或结尾的数字可能需要偏移 * @example split_text("example",/e/) * @return {Array} [['命中的字符串', '正则', '命中的字符串的开头', '命中的字符串的位置结尾']] */ function split_text(text, reg, shift = 0) { let R = new RegExp(reg, 'g'); let A = []; let result; while ((result = R.exec(text))) { //console.log("匹配文本 = " + result[0] + " index = " + result.index + " lastIndex = " + R.lastIndex); if (A.length != 0) { let i = A[A.length - 1][3]; // 最后一个结果组中的结尾数字 if (i != result.index) { A.push([text.substring(i, result.index), -1, i, result.index]); } } A.push([result[0], reg, result.index, R.lastIndex]); } if (A.length != 0) { let i1 = A[0][2]; // 第一个结果组中的开头数字 if (i1 != 0) { A.unshift([text.substring(0, i1), -1, 0, i1]); } let i2 = A[A.length - 1][3]; // 最后一个结果组中的结尾数字 if (i2 != text.length) { A.push([text.substring(i2, text.length), -1, i2, text.length]); } } if (shift != 0) { for (let i = 0, l = A.length; i < l; i++) { A[i] = [A[i][0], A[i][1], A[i][2] + shift, A[i][3] + shift]; } } if (A.length == 0) { A = [[text, -1, 0 + shift, text.length + shift]]; } return A; } /** * @description 分割字符串 * @param text {string} 字符串 * @param REG_array {array} 正则表达式数组 * @example get_split_array("example",[/e/,/x/]) * @return {Array} [['命中的字符串', '正则', '命中的字符串的开头', '命中的字符串的位置结尾']] */ function get_split_array(text, REG_array) { let A = [[text, -1, 0, text.length]]; for (let I = 0, L = REG_array.length; I < L; I++) { for (let i = A.length - 1, l = -1; i > l; i--) { if (A[i][1] == -1) { let B = split_text(A[i][0], REG_array[I][0], A[i][2]); for (let j = B.length - 1, le = -1; j > le; j--) { A.splice(i + 1, 0, B[j]); if (j == 0) { A.splice(i, 1); } } } } } return A; } /** * @description 字符串数组添加元素内容 * @param arr {array} 字符串数组 * @param REG_array {array} 正则表达式数组 */ function array_add_element(arr, REG_array) { for (let i = 0, l = arr.length; i < l; i++) { if (arr[i][1] == -1) { arr[i][4] = arr[i][0]; } else { for (let j = 0, lR = REG_array.length; j < lR; j++) { if (arr[i][1].source == (REG_array[j][0]).source) { arr[i][4] = REG_array[j][1](arr[i][0]); break; } } } } } /** * @description 从字符串数组中获取元素内容 * @param arr {array} 字符串数组 */ function array_get_element(arr) { let infotampermonkey = ""; for (let i = 0, l = arr.length; i < l; i++) { infotampermonkey = infotampermonkey + arr[i][4]; } return infotampermonkey; } function main() { //获取原简介内容 let text = $("#v_desc > div.info").text(); let text_array = get_split_array(text, R); array_add_element(text_array, R); // console.table(text_array); let infotampermonkey = array_get_element(text_array); //添加a标签的颜色样式和鼠标悬浮颜色样式 let infotampermonkeystyle = "<style>" + ".video-desc .infotampermonkey a {color: #00a1d6}" + ".video-desc .infotampermonkey a:hover {color: #f25d8e}" + "</style>"; //准备一个div用于存放二维码图片 let qrcode_div = '<div id="qrcodetampermonkey" style="z-index: 1001; position: absolute; top: 0px; left: 0px;"></div>'; //在旧简介div后添加一个新的简介div if ($("#v_desc > div.infotampermonkey").length == 0) { $("#v_desc > div.info").after('<div class="infotampermonkey" style="white-space: pre-line; overflow: hidden;">' + infotampermonkeystyle + qrcode_div + infotampermonkey + '</div>'); } //隐藏旧简介div $("#v_desc > div.info").hide(); //新简介使用和旧简介一样的元素高度 $("#v_desc > div.infotampermonkey").css("height", $("#v_desc > div.info").css("height")); $("#v_desc > div.infotampermonkey").css("width", $("#v_desc > div.info").css("width")); //给需要显示二维码的元素添加鼠标悬浮显示二维码的效果 $(".qrtampermonkey").hover(function () { let qrtext = $(this).attr("value"); $("#qrcodetampermonkey").append(QR({ text: qrtext, fill: '#00a1d6', size: 100, ecLevel: 'L', rounded: 40 })); $("#qrcodetampermonkey").css({ "top": $(this).position().top + $(this).height(), "left": $(this).position().left + $(this).width() }); $("#qrcodetampermonkey").show(); }, function () { $("#qrcodetampermonkey").hide(); $("#qrcodetampermonkey").empty(); }); //给需要修改视频时间的元素添加点击事件 $(document).on("click", ".timetampermonkey", function () { let time = $(this).attr("value"); $("video")[0].currentTime = time; }); //给需要触发复制的元素添加点击事件 $(document).on("click", ".copytampermonkey", function () { let copy_text = $(this).attr("value"); GM_setClipboard(copy_text); $(this).after('<a id="alert_after_copy" style="color:black;">(已复制)</a>'); setTimeout(function () { $("#alert_after_copy").remove(); }, 2500) }); } function debounce(fn, delay) { delay = delay || 10; let handle; return function (e) { clearTimeout(handle); handle = setTimeout(() => { fn(e); }, delay); } } $(document).on("DOMNodeInserted", "#v_desc > div.info", debounce(main)); //给"展开更多"、"收起"按钮添加点击事件,让按钮可以像控制旧简介div高度一样控制新简介div高度 let flag = true;//显示"展开更多"就是true,默认就是true $(document).on("click", "#v_desc > div.btn", function () { if (flag) { $("#v_desc > div.infotampermonkey").css("height", "auto"); flag = false; } else { $("#v_desc > div.infotampermonkey").css("height", "63px"); flag = true; } }); })(); //搜索框占行 //搜索...: □ .* □ Aa 查找下一个 查找上一个 关闭