您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A real-time comment checker, Fuck YouTube’s opaque comment censorship
// ==UserScript== // @name youtube-comment-censor-detector // @name:zh-CN YouTube发评反诈 // @name:zh-TW YouTube發評反詐 // @namespace npm/vite-plugin-monkey // @version 2.0.0 // @author freedom-introvert // @description A real-time comment checker, Fuck YouTube’s opaque comment censorship // @description:zh-CN Fuck YouTube版“阿瓦隆系统”,实时检查评论状态,防止评论被儿童偷偷误食你还被蒙在鼓里 // @description:zh-TW Fuck YouTube版“阿瓦隆系統”,即時檢查評論狀態,防止評論被兒童偷偷誤食你還被蒙在鼓裡 // @license GPL // @icon https://raw.githubusercontent.com/freedom-introvert/youtube-comment-censor-detector/refs/heads/main/logo/logo_256x256.avif // @match *://*.youtube.com/* // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js // @require https://unpkg.com/vue-demi@latest/lib/index.iife.js // @require data:application/javascript,window.Vue%3DVue%3B // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/index.full.min.js // @resource element-plus/dist/index.css https://cdn.jsdelivr.net/npm/[email protected]/dist/index.css // @grant GM_addStyle // @grant GM_getResourceText // @grant GM_registerMenuCommand // @grant unsafeWindow // @run-at document-start // ==/UserScript== (e=>{if(typeof GM_addStyle=="function"){GM_addStyle(e);return}const a=document.createElement("style");a.textContent=e,document.head.append(a)})(" .el-message,.is-message-box{z-index:9999!important}.comment-checker[data-v-684910ce]{font-size:12px}.container[data-v-684910ce]{width:80%;margin:0 auto}.comment-checker[data-v-684910ce]{padding:15px 15px 11px;border-radius:8px;transition:background-color .3s}.title[data-v-684910ce]{font-weight:700;margin-bottom:6px}.message[data-v-684910ce]{margin-bottom:10px}.el-progress[data-v-684910ce]{margin-bottom:4px}.buttons[data-v-684910ce]>[data-v-684910ce]{display:inline-flex;align-items:center;padding:4px 8px;margin-left:-8px;color:#4b5e9d;border-radius:4px;transition:background-color .2s,color .2s;-webkit-user-select:none;user-select:none;margin-right:10px}.buttons[data-v-684910ce]>[data-v-684910ce]:hover{background-color:#0000000d}.buttons[data-v-684910ce]>[data-v-684910ce]:active{background-color:#0000001a}.comment-checker.not-check[data-v-684910ce]{background-color:#00f3}.comment-checker.normal[data-v-684910ce]{background-color:#0f03}.comment-checker.deleted[data-v-684910ce]{background-color:#f003}.comment-checker.shadow-ban[data-v-684910ce]{background-color:#ff03}.hot-ban-checker[data-v-e5341f8d]{background-color:#007bff1a;border:1px solid rgba(0,60,136,.4);border-radius:6px;padding:1rem;margin:10px 0}.title[data-v-e5341f8d]{font-weight:700;margin-bottom:6px}.message[data-v-e5341f8d]{margin-bottom:10px}.actions[data-v-e5341f8d]{margin-top:10px}.buttons[data-v-e5341f8d]>[data-v-e5341f8d]{display:inline-flex;align-items:center;padding:4px 8px;margin-left:-8px;color:#4b5e9d;border-radius:4px;transition:background-color .2s,color .2s;-webkit-user-select:none;user-select:none;margin-right:10px}.buttons[data-v-e5341f8d]>[data-v-e5341f8d]:hover{background-color:#0000000d}.buttons[data-v-e5341f8d]>[data-v-e5341f8d]:active{background-color:#0000001a}[data-v-ff4696c9] .dialog-body{height:calc(100% - 40px);display:flex;flex-direction:column}.pagination[data-v-ff4696c9]{margin-top:6px}.detail[data-v-ff4696c9]{margin-left:10px}.info-table td[data-v-ff4696c9]:nth-child(1){white-space:nowrap;vertical-align:top}.info-table td[data-v-ff4696c9]:nth-child(2){padding-left:16px}.comment-content[data-v-ff4696c9]{white-space:break-spaces}summary[data-v-ff4696c9]{cursor:pointer;margin-top:2px;-webkit-user-select:none;user-select:none}.locate-link[data-v-ff4696c9]{width:100%}[data-v-ff4696c9] .locate-link>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.post-locate-link[data-v-ff4696c9]{font-size:10px} "); (function (vue, ElementPlus) { 'use strict'; function sleep(time) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(); }, time); }); } function urlSafeBase64ToStandard(urlSafeBase64) { let standardBase64 = urlSafeBase64.replace(/%3D/g, "=").replace(/-/g, "+").replace(/_/g, "/"); return standardBase64; } function standardBase64ToUrlSafe(standardBase64) { let urlSafeBase64 = standardBase64.replace(/=/g, "%3D").replace(/\+/g, "-").replace(/\//g, "_"); return urlSafeBase64; } function createUrl(path) { return new URL(new URL(window.location.href).origin + path); } function formatSecondsToMMSS(seconds) { const sec = parseInt(seconds, 10); const minutes = Math.floor(sec / 60); const remainingSeconds = sec % 60; const formattedMinutes = String(minutes).padStart(2, "0"); const formattedSeconds = String(remainingSeconds).padStart(2, "0"); return `${formattedMinutes}:${formattedSeconds}`; } function formatTimestamp(timestamp) { if (!timestamp) { return "--:--:--"; } const date = new Date(timestamp); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); const hours = String(date.getHours()).padStart(2, "0"); const minutes = String(date.getMinutes()).padStart(2, "0"); const seconds = String(date.getSeconds()).padStart(2, "0"); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } function translateState(state) { switch (state) { case "NORMAL": return "正常"; case "DELETED": return "已删除"; case "SHADOW_BAN": return "仅自己可见"; case "NOT_CHECK": return "还未检查"; } } const _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const _hoisted_1$2 = { class: "title" }; const _hoisted_2$2 = { class: "message" }; const _hoisted_3$2 = { key: 0 }; const _hoisted_4$2 = { class: "message" }; const _hoisted_5$1 = { class: "buttons" }; const maxTimeSec = 120; const _sfc_main$2 = { __name: "CommentChecker", setup(__props) { const check2 = vue.inject("check"); const hotBanCheck2 = vue.inject("hotBanCheck"); const commentRecord = vue.inject("commentRecord"); const onClose = vue.inject("onClose"); const onUnblock = vue.inject("onUnblock"); const interval = vue.inject("interval"); const showCancelButton = vue.ref(true); const showConfirmButton = vue.ref(false); const showCloseButton = vue.ref(false); const showHotBanCheckButton = vue.ref(false); const showStopHotBanCheckButton = vue.ref(false); const showLetMeAccessButtton = vue.ref(false); const showHotBanChecker = vue.ref(false); const stateClass = vue.ref("not-check"); const title = vue.ref("等待检查中……"); const message = vue.ref(""); const messageByHotCheck = vue.ref("等待检查中……"); let completed = false; let netErr = false; let hotBanCheckerController = { isCancelled: false }; let skipHotBanCheckWait = false; const stripedFlow = vue.ref(false); const currentTimeSec = vue.ref(0); const percentage = vue.computed(() => { if (currentTimeSec.value < 0 || currentTimeSec.value > maxTimeSec) { return 100; } else { return currentTimeSec.value / maxTimeSec * 100; } }); function format() { if (currentTimeSec.value < 0) { return `--:-- / ${formatSecondsToMMSS(maxTimeSec)}`; } else { return `${formatSecondsToMMSS(currentTimeSec.value)} / ${formatSecondsToMMSS(maxTimeSec)}`; } } let shown = null; let startTime = Date.now() / 1e3; async function startCheck() { while (currentTimeSec.value < maxTimeSec || netErr) { if (!netErr) { for (let i = interval; i > 0; i--) { message.value = "等待 " + i + "s 后检查评论状态"; await sleep(1e3); currentTimeSec.value = Date.now() / 1e3 - startTime; if (completed) { onStateCheckComplete(); return; } } } else { currentTimeSec.value = Date.now() / 1e3 - startTime; if (completed) { onStateCheckComplete(); return; } } message.value = "检查评论状态中……"; stripedFlow.value = true; try { await check2(commentRecord); } catch (err) { netErr = true; title.value = "网络错误,获取当前状态失败"; showConfirmButton.value = false; showCloseButton.value = true; stripedFlow.value = false; console.error(err); continue; } netErr = false; showCancelButton.value = false; showCloseButton.value = false; stripedFlow.value = false; if (commentRecord.currentState == "NORMAL") { title.value = "当前状态:正常"; stateClass.value = "normal"; shown = commentRecord.currentState; } else if (commentRecord.currentState == "SHADOW_BAN") { title.value = "当前状态:仅自己可见"; stateClass.value = "shadow-ban"; shown = commentRecord.currentState; } else if (commentRecord.currentState == "DELETED") { title.value = "当前状态:已被删除"; stateClass.value = "deleted"; if (shown) { completed = true; message.value = `不用等了,你的评论检查到的状态先从『${shown == "NORMAL" ? "正常" : "仅自己可见"}』再到删除,系统偷偷删了无疑。如果不信,你可以尝试编辑评论或添加回复来求证`; onStateCheckComplete(); return; } } showConfirmButton.value = true; } onStateCheckComplete(); completed = true; message.value = "观察时间已足够,当前状态可信,检查完毕"; buttonText.value = "关闭"; } function onStateCheckComplete() { showConfirmButton.value = false; showCloseButton.value = true; if (commentRecord.currentState == "NORMAL") { showHotBanCheckButton.value = true; } else if (commentRecord.currentState == "DELETED") { onUnblock(commentRecord); } } startCheck(); function cancelCheck() { completed = true; onClose(commentRecord); } function confirmCurrentState() { completed = true; message.value = "您已确认当前状态,检查完毕"; } function close() { onClose(commentRecord); } async function checkHotBan() { if (commentRecord.commentId.indexOf(".") == -1) { try { await ElementPlus.ElMessageBox.confirm( "确认检查吗?该检查需要遍历热门评论区,请注意评论区的评论数量(总数大于3000的评论区慎重考虑)!数量太多将导致漫长的检查过程,同时频繁调用API可能会引发不可预料的后果!", "警告", { confirmButtonText: "确定", cancelButtonText: "取消" } ); } catch (err) { return; } } showCloseButton.value = false; showHotBanCheckButton.value = false; showHotBanChecker.value = true; showStopHotBanCheckButton.value = true; while (currentTimeSec.value < maxTimeSec && !hotBanCheckerController.isCancelled) { messageByHotCheck.value = `为避免检查误判,检查需要等待至状态可信任时开始,剩余 ${Math.floor(maxTimeSec - currentTimeSec.value)}s`; if (!skipHotBanCheckWait && currentTimeSec.value > 50) { showLetMeAccessButtton.value = true; } if (skipHotBanCheckWait) { break; } await sleep(1e3); if (hotBanCheckerController.isCancelled) { return; } currentTimeSec.value = Date.now() / 1e3 - startTime; } showLetMeAccessButtton.value = false; messageByHotCheck.value = "正在重新检查评论状态……"; await check2(commentRecord); if (commentRecord.currentState != "NORMAL") { if (commentRecord.currentState == "SHADOW_BAN") { title.value = "当前状态:仅自己可见"; stateClass.value = "shadow-ban"; messageByHotCheck.value = "评论已被ShadowBan,热门的屏蔽的检查已取消"; } else if (commentRecord.currentState == "DELETED") { title.value = "当前状态:已被删除"; stateClass.value = "deleted"; messageByHotCheck.value = "评论已被删除,热门的屏蔽的检查已取消"; } showStopHotBanCheckButton.value = false; showCloseButton.value = true; return; } messageByHotCheck.value = "评论状态正常,准备检查中……"; let observer = { onCountChange(c, p) { messageByHotCheck.value = `正在搜索热门列表,已搜寻至:第${c}个 第${p}页`; } }; if (await hotBanCheck2(commentRecord, observer, hotBanCheckerController)) { if (commentRecord.hotBan) { messageByHotCheck.value = "⚠ 你的评论未在热门列表找到,已被热门屏蔽,检查完成"; } else { messageByHotCheck.value = "✔ 你的评论已在热门列表找到,没有被热门屏蔽,检查完成"; } } showStopHotBanCheckButton.value = false; showCloseButton.value = true; } function stopHotBanCheck() { hotBanCheckerController.isCancelled = true; messageByHotCheck.value = "你已终止热门屏蔽的检查"; showStopHotBanCheckButton.value = false; showCloseButton.value = true; } function letMeAccess() { skipHotBanCheckWait = true; showLetMeAccessButtton.value = false; } return (_ctx, _cache) => { const _component_el_progress = vue.resolveComponent("el-progress"); return vue.openBlock(), vue.createElementBlock("div", { class: vue.normalizeClass(["comment-checker", stateClass.value]) }, [ vue.createElementVNode("div", _hoisted_1$2, vue.toDisplayString(title.value), 1), vue.createElementVNode("div", _hoisted_2$2, vue.toDisplayString(message.value), 1), vue.createVNode(_component_el_progress, { percentage: percentage.value, striped: "", format, "striped-flow": stripedFlow.value }, null, 8, ["percentage", "striped-flow"]), showHotBanChecker.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$2, [ _cache[0] || (_cache[0] = vue.createElementVNode("div", { class: "title" }, "热门屏蔽检查", -1)), vue.createElementVNode("div", _hoisted_4$2, vue.toDisplayString(messageByHotCheck.value), 1) ])) : vue.createCommentVNode("", true), vue.createElementVNode("div", _hoisted_5$1, [ showCancelButton.value ? (vue.openBlock(), vue.createElementBlock("span", { key: 0, onClick: cancelCheck }, "取消")) : vue.createCommentVNode("", true), showConfirmButton.value ? (vue.openBlock(), vue.createElementBlock("span", { key: 1, onClick: confirmCurrentState }, "确认当前状态")) : vue.createCommentVNode("", true), showCloseButton.value ? (vue.openBlock(), vue.createElementBlock("span", { key: 2, onClick: close }, "关闭")) : vue.createCommentVNode("", true), showHotBanCheckButton.value ? (vue.openBlock(), vue.createElementBlock("span", { key: 3, onClick: checkHotBan }, "热门屏蔽检查")) : vue.createCommentVNode("", true), showStopHotBanCheckButton.value ? (vue.openBlock(), vue.createElementBlock("span", { key: 4, onClick: stopHotBanCheck }, "终止检查")) : vue.createCommentVNode("", true), showLetMeAccessButtton.value ? (vue.openBlock(), vue.createElementBlock("span", { key: 5, onClick: letMeAccess }, "让我检查!")) : vue.createCommentVNode("", true) ]) ], 2); }; } }; const CommentChecker = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-684910ce"]]); var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {}; var indexMinimal = {}; var minimal$1 = {}; var aspromise; var hasRequiredAspromise; function requireAspromise() { if (hasRequiredAspromise) return aspromise; hasRequiredAspromise = 1; aspromise = asPromise; function asPromise(fn, ctx) { var params = new Array(arguments.length - 1), offset = 0, index = 2, pending = true; while (index < arguments.length) params[offset++] = arguments[index++]; return new Promise(function executor(resolve, reject) { params[offset] = function callback(err) { if (pending) { pending = false; if (err) reject(err); else { var params2 = new Array(arguments.length - 1), offset2 = 0; while (offset2 < params2.length) params2[offset2++] = arguments[offset2]; resolve.apply(null, params2); } } }; try { fn.apply(ctx || null, params); } catch (err) { if (pending) { pending = false; reject(err); } } }); } return aspromise; } var base64 = {}; var hasRequiredBase64; function requireBase64() { if (hasRequiredBase64) return base64; hasRequiredBase64 = 1; (function(exports) { var base642 = exports; base642.length = function length(string) { var p = string.length; if (!p) return 0; var n = 0; while (--p % 4 > 1 && string.charAt(p) === "=") ++n; return Math.ceil(string.length * 3) / 4 - n; }; var b64 = new Array(64); var s64 = new Array(123); for (var i = 0; i < 64; ) s64[b64[i] = i < 26 ? i + 65 : i < 52 ? i + 71 : i < 62 ? i - 4 : i - 59 | 43] = i++; base642.encode = function encode(buffer, start, end) { var parts = null, chunk = []; var i2 = 0, j = 0, t; while (start < end) { var b = buffer[start++]; switch (j) { case 0: chunk[i2++] = b64[b >> 2]; t = (b & 3) << 4; j = 1; break; case 1: chunk[i2++] = b64[t | b >> 4]; t = (b & 15) << 2; j = 2; break; case 2: chunk[i2++] = b64[t | b >> 6]; chunk[i2++] = b64[b & 63]; j = 0; break; } if (i2 > 8191) { (parts || (parts = [])).push(String.fromCharCode.apply(String, chunk)); i2 = 0; } } if (j) { chunk[i2++] = b64[t]; chunk[i2++] = 61; if (j === 1) chunk[i2++] = 61; } if (parts) { if (i2) parts.push(String.fromCharCode.apply(String, chunk.slice(0, i2))); return parts.join(""); } return String.fromCharCode.apply(String, chunk.slice(0, i2)); }; var invalidEncoding = "invalid encoding"; base642.decode = function decode(string, buffer, offset) { var start = offset; var j = 0, t; for (var i2 = 0; i2 < string.length; ) { var c = string.charCodeAt(i2++); if (c === 61 && j > 1) break; if ((c = s64[c]) === void 0) throw Error(invalidEncoding); switch (j) { case 0: t = c; j = 1; break; case 1: buffer[offset++] = t << 2 | (c & 48) >> 4; t = c; j = 2; break; case 2: buffer[offset++] = (t & 15) << 4 | (c & 60) >> 2; t = c; j = 3; break; case 3: buffer[offset++] = (t & 3) << 6 | c; j = 0; break; } } if (j === 1) throw Error(invalidEncoding); return offset - start; }; base642.test = function test(string) { return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(string); }; })(base64); return base64; } var eventemitter; var hasRequiredEventemitter; function requireEventemitter() { if (hasRequiredEventemitter) return eventemitter; hasRequiredEventemitter = 1; eventemitter = EventEmitter; function EventEmitter() { this._listeners = {}; } EventEmitter.prototype.on = function on(evt, fn, ctx) { (this._listeners[evt] || (this._listeners[evt] = [])).push({ fn, ctx: ctx || this }); return this; }; EventEmitter.prototype.off = function off(evt, fn) { if (evt === void 0) this._listeners = {}; else { if (fn === void 0) this._listeners[evt] = []; else { var listeners = this._listeners[evt]; for (var i = 0; i < listeners.length; ) if (listeners[i].fn === fn) listeners.splice(i, 1); else ++i; } } return this; }; EventEmitter.prototype.emit = function emit(evt) { var listeners = this._listeners[evt]; if (listeners) { var args = [], i = 1; for (; i < arguments.length; ) args.push(arguments[i++]); for (i = 0; i < listeners.length; ) listeners[i].fn.apply(listeners[i++].ctx, args); } return this; }; return eventemitter; } var float; var hasRequiredFloat; function requireFloat() { if (hasRequiredFloat) return float; hasRequiredFloat = 1; float = factory(factory); function factory(exports) { if (typeof Float32Array !== "undefined") (function() { var f32 = new Float32Array([-0]), f8b = new Uint8Array(f32.buffer), le = f8b[3] === 128; function writeFloat_f32_cpy(val, buf, pos) { f32[0] = val; buf[pos] = f8b[0]; buf[pos + 1] = f8b[1]; buf[pos + 2] = f8b[2]; buf[pos + 3] = f8b[3]; } function writeFloat_f32_rev(val, buf, pos) { f32[0] = val; buf[pos] = f8b[3]; buf[pos + 1] = f8b[2]; buf[pos + 2] = f8b[1]; buf[pos + 3] = f8b[0]; } exports.writeFloatLE = le ? writeFloat_f32_cpy : writeFloat_f32_rev; exports.writeFloatBE = le ? writeFloat_f32_rev : writeFloat_f32_cpy; function readFloat_f32_cpy(buf, pos) { f8b[0] = buf[pos]; f8b[1] = buf[pos + 1]; f8b[2] = buf[pos + 2]; f8b[3] = buf[pos + 3]; return f32[0]; } function readFloat_f32_rev(buf, pos) { f8b[3] = buf[pos]; f8b[2] = buf[pos + 1]; f8b[1] = buf[pos + 2]; f8b[0] = buf[pos + 3]; return f32[0]; } exports.readFloatLE = le ? readFloat_f32_cpy : readFloat_f32_rev; exports.readFloatBE = le ? readFloat_f32_rev : readFloat_f32_cpy; })(); else (function() { function writeFloat_ieee754(writeUint, val, buf, pos) { var sign = val < 0 ? 1 : 0; if (sign) val = -val; if (val === 0) writeUint(1 / val > 0 ? ( /* positive */ 0 ) : ( /* negative 0 */ 2147483648 ), buf, pos); else if (isNaN(val)) writeUint(2143289344, buf, pos); else if (val > 34028234663852886e22) writeUint((sign << 31 | 2139095040) >>> 0, buf, pos); else if (val < 11754943508222875e-54) writeUint((sign << 31 | Math.round(val / 1401298464324817e-60)) >>> 0, buf, pos); else { var exponent = Math.floor(Math.log(val) / Math.LN2), mantissa = Math.round(val * Math.pow(2, -exponent) * 8388608) & 8388607; writeUint((sign << 31 | exponent + 127 << 23 | mantissa) >>> 0, buf, pos); } } exports.writeFloatLE = writeFloat_ieee754.bind(null, writeUintLE); exports.writeFloatBE = writeFloat_ieee754.bind(null, writeUintBE); function readFloat_ieee754(readUint, buf, pos) { var uint = readUint(buf, pos), sign = (uint >> 31) * 2 + 1, exponent = uint >>> 23 & 255, mantissa = uint & 8388607; return exponent === 255 ? mantissa ? NaN : sign * Infinity : exponent === 0 ? sign * 1401298464324817e-60 * mantissa : sign * Math.pow(2, exponent - 150) * (mantissa + 8388608); } exports.readFloatLE = readFloat_ieee754.bind(null, readUintLE); exports.readFloatBE = readFloat_ieee754.bind(null, readUintBE); })(); if (typeof Float64Array !== "undefined") (function() { var f64 = new Float64Array([-0]), f8b = new Uint8Array(f64.buffer), le = f8b[7] === 128; function writeDouble_f64_cpy(val, buf, pos) { f64[0] = val; buf[pos] = f8b[0]; buf[pos + 1] = f8b[1]; buf[pos + 2] = f8b[2]; buf[pos + 3] = f8b[3]; buf[pos + 4] = f8b[4]; buf[pos + 5] = f8b[5]; buf[pos + 6] = f8b[6]; buf[pos + 7] = f8b[7]; } function writeDouble_f64_rev(val, buf, pos) { f64[0] = val; buf[pos] = f8b[7]; buf[pos + 1] = f8b[6]; buf[pos + 2] = f8b[5]; buf[pos + 3] = f8b[4]; buf[pos + 4] = f8b[3]; buf[pos + 5] = f8b[2]; buf[pos + 6] = f8b[1]; buf[pos + 7] = f8b[0]; } exports.writeDoubleLE = le ? writeDouble_f64_cpy : writeDouble_f64_rev; exports.writeDoubleBE = le ? writeDouble_f64_rev : writeDouble_f64_cpy; function readDouble_f64_cpy(buf, pos) { f8b[0] = buf[pos]; f8b[1] = buf[pos + 1]; f8b[2] = buf[pos + 2]; f8b[3] = buf[pos + 3]; f8b[4] = buf[pos + 4]; f8b[5] = buf[pos + 5]; f8b[6] = buf[pos + 6]; f8b[7] = buf[pos + 7]; return f64[0]; } function readDouble_f64_rev(buf, pos) { f8b[7] = buf[pos]; f8b[6] = buf[pos + 1]; f8b[5] = buf[pos + 2]; f8b[4] = buf[pos + 3]; f8b[3] = buf[pos + 4]; f8b[2] = buf[pos + 5]; f8b[1] = buf[pos + 6]; f8b[0] = buf[pos + 7]; return f64[0]; } exports.readDoubleLE = le ? readDouble_f64_cpy : readDouble_f64_rev; exports.readDoubleBE = le ? readDouble_f64_rev : readDouble_f64_cpy; })(); else (function() { function writeDouble_ieee754(writeUint, off0, off1, val, buf, pos) { var sign = val < 0 ? 1 : 0; if (sign) val = -val; if (val === 0) { writeUint(0, buf, pos + off0); writeUint(1 / val > 0 ? ( /* positive */ 0 ) : ( /* negative 0 */ 2147483648 ), buf, pos + off1); } else if (isNaN(val)) { writeUint(0, buf, pos + off0); writeUint(2146959360, buf, pos + off1); } else if (val > 17976931348623157e292) { writeUint(0, buf, pos + off0); writeUint((sign << 31 | 2146435072) >>> 0, buf, pos + off1); } else { var mantissa; if (val < 22250738585072014e-324) { mantissa = val / 5e-324; writeUint(mantissa >>> 0, buf, pos + off0); writeUint((sign << 31 | mantissa / 4294967296) >>> 0, buf, pos + off1); } else { var exponent = Math.floor(Math.log(val) / Math.LN2); if (exponent === 1024) exponent = 1023; mantissa = val * Math.pow(2, -exponent); writeUint(mantissa * 4503599627370496 >>> 0, buf, pos + off0); writeUint((sign << 31 | exponent + 1023 << 20 | mantissa * 1048576 & 1048575) >>> 0, buf, pos + off1); } } } exports.writeDoubleLE = writeDouble_ieee754.bind(null, writeUintLE, 0, 4); exports.writeDoubleBE = writeDouble_ieee754.bind(null, writeUintBE, 4, 0); function readDouble_ieee754(readUint, off0, off1, buf, pos) { var lo = readUint(buf, pos + off0), hi = readUint(buf, pos + off1); var sign = (hi >> 31) * 2 + 1, exponent = hi >>> 20 & 2047, mantissa = 4294967296 * (hi & 1048575) + lo; return exponent === 2047 ? mantissa ? NaN : sign * Infinity : exponent === 0 ? sign * 5e-324 * mantissa : sign * Math.pow(2, exponent - 1075) * (mantissa + 4503599627370496); } exports.readDoubleLE = readDouble_ieee754.bind(null, readUintLE, 0, 4); exports.readDoubleBE = readDouble_ieee754.bind(null, readUintBE, 4, 0); })(); return exports; } function writeUintLE(val, buf, pos) { buf[pos] = val & 255; buf[pos + 1] = val >>> 8 & 255; buf[pos + 2] = val >>> 16 & 255; buf[pos + 3] = val >>> 24; } function writeUintBE(val, buf, pos) { buf[pos] = val >>> 24; buf[pos + 1] = val >>> 16 & 255; buf[pos + 2] = val >>> 8 & 255; buf[pos + 3] = val & 255; } function readUintLE(buf, pos) { return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16 | buf[pos + 3] << 24) >>> 0; } function readUintBE(buf, pos) { return (buf[pos] << 24 | buf[pos + 1] << 16 | buf[pos + 2] << 8 | buf[pos + 3]) >>> 0; } return float; } var inquire_1; var hasRequiredInquire; function requireInquire() { if (hasRequiredInquire) return inquire_1; hasRequiredInquire = 1; inquire_1 = inquire; function inquire(moduleName) { try { var mod = eval("quire".replace(/^/, "re"))(moduleName); if (mod && (mod.length || Object.keys(mod).length)) return mod; } catch (e) { } return null; } return inquire_1; } var utf8 = {}; var hasRequiredUtf8; function requireUtf8() { if (hasRequiredUtf8) return utf8; hasRequiredUtf8 = 1; (function(exports) { var utf82 = exports; utf82.length = function utf8_length(string) { var len = 0, c = 0; for (var i = 0; i < string.length; ++i) { c = string.charCodeAt(i); if (c < 128) len += 1; else if (c < 2048) len += 2; else if ((c & 64512) === 55296 && (string.charCodeAt(i + 1) & 64512) === 56320) { ++i; len += 4; } else len += 3; } return len; }; utf82.read = function utf8_read(buffer, start, end) { var len = end - start; if (len < 1) return ""; var parts = null, chunk = [], i = 0, t; while (start < end) { t = buffer[start++]; if (t < 128) chunk[i++] = t; else if (t > 191 && t < 224) chunk[i++] = (t & 31) << 6 | buffer[start++] & 63; else if (t > 239 && t < 365) { t = ((t & 7) << 18 | (buffer[start++] & 63) << 12 | (buffer[start++] & 63) << 6 | buffer[start++] & 63) - 65536; chunk[i++] = 55296 + (t >> 10); chunk[i++] = 56320 + (t & 1023); } else chunk[i++] = (t & 15) << 12 | (buffer[start++] & 63) << 6 | buffer[start++] & 63; if (i > 8191) { (parts || (parts = [])).push(String.fromCharCode.apply(String, chunk)); i = 0; } } if (parts) { if (i) parts.push(String.fromCharCode.apply(String, chunk.slice(0, i))); return parts.join(""); } return String.fromCharCode.apply(String, chunk.slice(0, i)); }; utf82.write = function utf8_write(string, buffer, offset) { var start = offset, c1, c2; for (var i = 0; i < string.length; ++i) { c1 = string.charCodeAt(i); if (c1 < 128) { buffer[offset++] = c1; } else if (c1 < 2048) { buffer[offset++] = c1 >> 6 | 192; buffer[offset++] = c1 & 63 | 128; } else if ((c1 & 64512) === 55296 && ((c2 = string.charCodeAt(i + 1)) & 64512) === 56320) { c1 = 65536 + ((c1 & 1023) << 10) + (c2 & 1023); ++i; buffer[offset++] = c1 >> 18 | 240; buffer[offset++] = c1 >> 12 & 63 | 128; buffer[offset++] = c1 >> 6 & 63 | 128; buffer[offset++] = c1 & 63 | 128; } else { buffer[offset++] = c1 >> 12 | 224; buffer[offset++] = c1 >> 6 & 63 | 128; buffer[offset++] = c1 & 63 | 128; } } return offset - start; }; })(utf8); return utf8; } var pool_1; var hasRequiredPool; function requirePool() { if (hasRequiredPool) return pool_1; hasRequiredPool = 1; pool_1 = pool; function pool(alloc, slice, size) { var SIZE = size || 8192; var MAX = SIZE >>> 1; var slab = null; var offset = SIZE; return function pool_alloc(size2) { if (size2 < 1 || size2 > MAX) return alloc(size2); if (offset + size2 > SIZE) { slab = alloc(SIZE); offset = 0; } var buf = slice.call(slab, offset, offset += size2); if (offset & 7) offset = (offset | 7) + 1; return buf; }; } return pool_1; } var longbits; var hasRequiredLongbits; function requireLongbits() { if (hasRequiredLongbits) return longbits; hasRequiredLongbits = 1; longbits = LongBits; var util = requireMinimal$1(); function LongBits(lo, hi) { this.lo = lo >>> 0; this.hi = hi >>> 0; } var zero = LongBits.zero = new LongBits(0, 0); zero.toNumber = function() { return 0; }; zero.zzEncode = zero.zzDecode = function() { return this; }; zero.length = function() { return 1; }; var zeroHash = LongBits.zeroHash = "\0\0\0\0\0\0\0\0"; LongBits.fromNumber = function fromNumber(value) { if (value === 0) return zero; var sign = value < 0; if (sign) value = -value; var lo = value >>> 0, hi = (value - lo) / 4294967296 >>> 0; if (sign) { hi = ~hi >>> 0; lo = ~lo >>> 0; if (++lo > 4294967295) { lo = 0; if (++hi > 4294967295) hi = 0; } } return new LongBits(lo, hi); }; LongBits.from = function from(value) { if (typeof value === "number") return LongBits.fromNumber(value); if (util.isString(value)) { if (util.Long) value = util.Long.fromString(value); else return LongBits.fromNumber(parseInt(value, 10)); } return value.low || value.high ? new LongBits(value.low >>> 0, value.high >>> 0) : zero; }; LongBits.prototype.toNumber = function toNumber(unsigned) { if (!unsigned && this.hi >>> 31) { var lo = ~this.lo + 1 >>> 0, hi = ~this.hi >>> 0; if (!lo) hi = hi + 1 >>> 0; return -(lo + hi * 4294967296); } return this.lo + this.hi * 4294967296; }; LongBits.prototype.toLong = function toLong(unsigned) { return util.Long ? new util.Long(this.lo | 0, this.hi | 0, Boolean(unsigned)) : { low: this.lo | 0, high: this.hi | 0, unsigned: Boolean(unsigned) }; }; var charCodeAt = String.prototype.charCodeAt; LongBits.fromHash = function fromHash(hash) { if (hash === zeroHash) return zero; return new LongBits( (charCodeAt.call(hash, 0) | charCodeAt.call(hash, 1) << 8 | charCodeAt.call(hash, 2) << 16 | charCodeAt.call(hash, 3) << 24) >>> 0, (charCodeAt.call(hash, 4) | charCodeAt.call(hash, 5) << 8 | charCodeAt.call(hash, 6) << 16 | charCodeAt.call(hash, 7) << 24) >>> 0 ); }; LongBits.prototype.toHash = function toHash() { return String.fromCharCode( this.lo & 255, this.lo >>> 8 & 255, this.lo >>> 16 & 255, this.lo >>> 24, this.hi & 255, this.hi >>> 8 & 255, this.hi >>> 16 & 255, this.hi >>> 24 ); }; LongBits.prototype.zzEncode = function zzEncode() { var mask = this.hi >> 31; this.hi = ((this.hi << 1 | this.lo >>> 31) ^ mask) >>> 0; this.lo = (this.lo << 1 ^ mask) >>> 0; return this; }; LongBits.prototype.zzDecode = function zzDecode() { var mask = -(this.lo & 1); this.lo = ((this.lo >>> 1 | this.hi << 31) ^ mask) >>> 0; this.hi = (this.hi >>> 1 ^ mask) >>> 0; return this; }; LongBits.prototype.length = function length() { var part0 = this.lo, part1 = (this.lo >>> 28 | this.hi << 4) >>> 0, part2 = this.hi >>> 24; return part2 === 0 ? part1 === 0 ? part0 < 16384 ? part0 < 128 ? 1 : 2 : part0 < 2097152 ? 3 : 4 : part1 < 16384 ? part1 < 128 ? 5 : 6 : part1 < 2097152 ? 7 : 8 : part2 < 128 ? 9 : 10; }; return longbits; } var hasRequiredMinimal$1; function requireMinimal$1() { if (hasRequiredMinimal$1) return minimal$1; hasRequiredMinimal$1 = 1; (function(exports) { var util = exports; util.asPromise = requireAspromise(); util.base64 = requireBase64(); util.EventEmitter = requireEventemitter(); util.float = requireFloat(); util.inquire = requireInquire(); util.utf8 = requireUtf8(); util.pool = requirePool(); util.LongBits = requireLongbits(); util.isNode = Boolean(typeof commonjsGlobal !== "undefined" && commonjsGlobal && commonjsGlobal.process && commonjsGlobal.process.versions && commonjsGlobal.process.versions.node); util.global = util.isNode && commonjsGlobal || typeof window !== "undefined" && window || typeof self !== "undefined" && self || minimal$1; util.emptyArray = Object.freeze ? Object.freeze([]) : ( /* istanbul ignore next */ [] ); util.emptyObject = Object.freeze ? Object.freeze({}) : ( /* istanbul ignore next */ {} ); util.isInteger = Number.isInteger || /* istanbul ignore next */ function isInteger(value) { return typeof value === "number" && isFinite(value) && Math.floor(value) === value; }; util.isString = function isString(value) { return typeof value === "string" || value instanceof String; }; util.isObject = function isObject(value) { return value && typeof value === "object"; }; util.isset = /** * Checks if a property on a message is considered to be present. * @param {Object} obj Plain object or message instance * @param {string} prop Property name * @returns {boolean} `true` if considered to be present, otherwise `false` */ util.isSet = function isSet(obj, prop) { var value = obj[prop]; if (value != null && obj.hasOwnProperty(prop)) return typeof value !== "object" || (Array.isArray(value) ? value.length : Object.keys(value).length) > 0; return false; }; util.Buffer = function() { try { var Buffer = util.inquire("buffer").Buffer; return Buffer.prototype.utf8Write ? Buffer : ( /* istanbul ignore next */ null ); } catch (e) { return null; } }(); util._Buffer_from = null; util._Buffer_allocUnsafe = null; util.newBuffer = function newBuffer(sizeOrArray) { return typeof sizeOrArray === "number" ? util.Buffer ? util._Buffer_allocUnsafe(sizeOrArray) : new util.Array(sizeOrArray) : util.Buffer ? util._Buffer_from(sizeOrArray) : typeof Uint8Array === "undefined" ? sizeOrArray : new Uint8Array(sizeOrArray); }; util.Array = typeof Uint8Array !== "undefined" ? Uint8Array : Array; util.Long = /* istanbul ignore next */ util.global.dcodeIO && /* istanbul ignore next */ util.global.dcodeIO.Long || /* istanbul ignore next */ util.global.Long || util.inquire("long"); util.key2Re = /^true|false|0|1$/; util.key32Re = /^-?(?:0|[1-9][0-9]*)$/; util.key64Re = /^(?:[\\x00-\\xff]{8}|-?(?:0|[1-9][0-9]*))$/; util.longToHash = function longToHash(value) { return value ? util.LongBits.from(value).toHash() : util.LongBits.zeroHash; }; util.longFromHash = function longFromHash(hash, unsigned) { var bits = util.LongBits.fromHash(hash); if (util.Long) return util.Long.fromBits(bits.lo, bits.hi, unsigned); return bits.toNumber(Boolean(unsigned)); }; function merge(dst, src, ifNotSet) { for (var keys = Object.keys(src), i = 0; i < keys.length; ++i) if (dst[keys[i]] === void 0 || !ifNotSet) dst[keys[i]] = src[keys[i]]; return dst; } util.merge = merge; util.lcFirst = function lcFirst(str) { return str.charAt(0).toLowerCase() + str.substring(1); }; function newError(name) { function CustomError(message, properties) { if (!(this instanceof CustomError)) return new CustomError(message, properties); Object.defineProperty(this, "message", { get: function() { return message; } }); if (Error.captureStackTrace) Error.captureStackTrace(this, CustomError); else Object.defineProperty(this, "stack", { value: new Error().stack || "" }); if (properties) merge(this, properties); } CustomError.prototype = Object.create(Error.prototype, { constructor: { value: CustomError, writable: true, enumerable: false, configurable: true }, name: { get: function get() { return name; }, set: void 0, enumerable: false, // configurable: false would accurately preserve the behavior of // the original, but I'm guessing that was not intentional. // For an actual error subclass, this property would // be configurable. configurable: true }, toString: { value: function value() { return this.name + ": " + this.message; }, writable: true, enumerable: false, configurable: true } }); return CustomError; } util.newError = newError; util.ProtocolError = newError("ProtocolError"); util.oneOfGetter = function getOneOf(fieldNames) { var fieldMap = {}; for (var i = 0; i < fieldNames.length; ++i) fieldMap[fieldNames[i]] = 1; return function() { for (var keys = Object.keys(this), i2 = keys.length - 1; i2 > -1; --i2) if (fieldMap[keys[i2]] === 1 && this[keys[i2]] !== void 0 && this[keys[i2]] !== null) return keys[i2]; }; }; util.oneOfSetter = function setOneOf(fieldNames) { return function(name) { for (var i = 0; i < fieldNames.length; ++i) if (fieldNames[i] !== name) delete this[fieldNames[i]]; }; }; util.toJSONOptions = { longs: String, enums: String, bytes: String, json: true }; util._configure = function() { var Buffer = util.Buffer; if (!Buffer) { util._Buffer_from = util._Buffer_allocUnsafe = null; return; } util._Buffer_from = Buffer.from !== Uint8Array.from && Buffer.from || /* istanbul ignore next */ function Buffer_from(value, encoding) { return new Buffer(value, encoding); }; util._Buffer_allocUnsafe = Buffer.allocUnsafe || /* istanbul ignore next */ function Buffer_allocUnsafe(size) { return new Buffer(size); }; }; })(minimal$1); return minimal$1; } var writer; var hasRequiredWriter; function requireWriter() { if (hasRequiredWriter) return writer; hasRequiredWriter = 1; writer = Writer; var util = requireMinimal$1(); var BufferWriter; var LongBits = util.LongBits, base642 = util.base64, utf82 = util.utf8; function Op(fn, len, val) { this.fn = fn; this.len = len; this.next = void 0; this.val = val; } function noop() { } function State(writer2) { this.head = writer2.head; this.tail = writer2.tail; this.len = writer2.len; this.next = writer2.states; } function Writer() { this.len = 0; this.head = new Op(noop, 0, 0); this.tail = this.head; this.states = null; } var create = function create2() { return util.Buffer ? function create_buffer_setup() { return (Writer.create = function create_buffer() { return new BufferWriter(); })(); } : function create_array() { return new Writer(); }; }; Writer.create = create(); Writer.alloc = function alloc(size) { return new util.Array(size); }; if (util.Array !== Array) Writer.alloc = util.pool(Writer.alloc, util.Array.prototype.subarray); Writer.prototype._push = function push(fn, len, val) { this.tail = this.tail.next = new Op(fn, len, val); this.len += len; return this; }; function writeByte(val, buf, pos) { buf[pos] = val & 255; } function writeVarint32(val, buf, pos) { while (val > 127) { buf[pos++] = val & 127 | 128; val >>>= 7; } buf[pos] = val; } function VarintOp(len, val) { this.len = len; this.next = void 0; this.val = val; } VarintOp.prototype = Object.create(Op.prototype); VarintOp.prototype.fn = writeVarint32; Writer.prototype.uint32 = function write_uint32(value) { this.len += (this.tail = this.tail.next = new VarintOp( (value = value >>> 0) < 128 ? 1 : value < 16384 ? 2 : value < 2097152 ? 3 : value < 268435456 ? 4 : 5, value )).len; return this; }; Writer.prototype.int32 = function write_int32(value) { return value < 0 ? this._push(writeVarint64, 10, LongBits.fromNumber(value)) : this.uint32(value); }; Writer.prototype.sint32 = function write_sint32(value) { return this.uint32((value << 1 ^ value >> 31) >>> 0); }; function writeVarint64(val, buf, pos) { while (val.hi) { buf[pos++] = val.lo & 127 | 128; val.lo = (val.lo >>> 7 | val.hi << 25) >>> 0; val.hi >>>= 7; } while (val.lo > 127) { buf[pos++] = val.lo & 127 | 128; val.lo = val.lo >>> 7; } buf[pos++] = val.lo; } Writer.prototype.uint64 = function write_uint64(value) { var bits = LongBits.from(value); return this._push(writeVarint64, bits.length(), bits); }; Writer.prototype.int64 = Writer.prototype.uint64; Writer.prototype.sint64 = function write_sint64(value) { var bits = LongBits.from(value).zzEncode(); return this._push(writeVarint64, bits.length(), bits); }; Writer.prototype.bool = function write_bool(value) { return this._push(writeByte, 1, value ? 1 : 0); }; function writeFixed32(val, buf, pos) { buf[pos] = val & 255; buf[pos + 1] = val >>> 8 & 255; buf[pos + 2] = val >>> 16 & 255; buf[pos + 3] = val >>> 24; } Writer.prototype.fixed32 = function write_fixed32(value) { return this._push(writeFixed32, 4, value >>> 0); }; Writer.prototype.sfixed32 = Writer.prototype.fixed32; Writer.prototype.fixed64 = function write_fixed64(value) { var bits = LongBits.from(value); return this._push(writeFixed32, 4, bits.lo)._push(writeFixed32, 4, bits.hi); }; Writer.prototype.sfixed64 = Writer.prototype.fixed64; Writer.prototype.float = function write_float(value) { return this._push(util.float.writeFloatLE, 4, value); }; Writer.prototype.double = function write_double(value) { return this._push(util.float.writeDoubleLE, 8, value); }; var writeBytes = util.Array.prototype.set ? function writeBytes_set(val, buf, pos) { buf.set(val, pos); } : function writeBytes_for(val, buf, pos) { for (var i = 0; i < val.length; ++i) buf[pos + i] = val[i]; }; Writer.prototype.bytes = function write_bytes(value) { var len = value.length >>> 0; if (!len) return this._push(writeByte, 1, 0); if (util.isString(value)) { var buf = Writer.alloc(len = base642.length(value)); base642.decode(value, buf, 0); value = buf; } return this.uint32(len)._push(writeBytes, len, value); }; Writer.prototype.string = function write_string(value) { var len = utf82.length(value); return len ? this.uint32(len)._push(utf82.write, len, value) : this._push(writeByte, 1, 0); }; Writer.prototype.fork = function fork() { this.states = new State(this); this.head = this.tail = new Op(noop, 0, 0); this.len = 0; return this; }; Writer.prototype.reset = function reset() { if (this.states) { this.head = this.states.head; this.tail = this.states.tail; this.len = this.states.len; this.states = this.states.next; } else { this.head = this.tail = new Op(noop, 0, 0); this.len = 0; } return this; }; Writer.prototype.ldelim = function ldelim() { var head = this.head, tail = this.tail, len = this.len; this.reset().uint32(len); if (len) { this.tail.next = head.next; this.tail = tail; this.len += len; } return this; }; Writer.prototype.finish = function finish() { var head = this.head.next, buf = this.constructor.alloc(this.len), pos = 0; while (head) { head.fn(head.val, buf, pos); pos += head.len; head = head.next; } return buf; }; Writer._configure = function(BufferWriter_) { BufferWriter = BufferWriter_; Writer.create = create(); BufferWriter._configure(); }; return writer; } var writer_buffer; var hasRequiredWriter_buffer; function requireWriter_buffer() { if (hasRequiredWriter_buffer) return writer_buffer; hasRequiredWriter_buffer = 1; writer_buffer = BufferWriter; var Writer = requireWriter(); (BufferWriter.prototype = Object.create(Writer.prototype)).constructor = BufferWriter; var util = requireMinimal$1(); function BufferWriter() { Writer.call(this); } BufferWriter._configure = function() { BufferWriter.alloc = util._Buffer_allocUnsafe; BufferWriter.writeBytesBuffer = util.Buffer && util.Buffer.prototype instanceof Uint8Array && util.Buffer.prototype.set.name === "set" ? function writeBytesBuffer_set(val, buf, pos) { buf.set(val, pos); } : function writeBytesBuffer_copy(val, buf, pos) { if (val.copy) val.copy(buf, pos, 0, val.length); else for (var i = 0; i < val.length; ) buf[pos++] = val[i++]; }; }; BufferWriter.prototype.bytes = function write_bytes_buffer(value) { if (util.isString(value)) value = util._Buffer_from(value, "base64"); var len = value.length >>> 0; this.uint32(len); if (len) this._push(BufferWriter.writeBytesBuffer, len, value); return this; }; function writeStringBuffer(val, buf, pos) { if (val.length < 40) util.utf8.write(val, buf, pos); else if (buf.utf8Write) buf.utf8Write(val, pos); else buf.write(val, pos); } BufferWriter.prototype.string = function write_string_buffer(value) { var len = util.Buffer.byteLength(value); this.uint32(len); if (len) this._push(writeStringBuffer, len, value); return this; }; BufferWriter._configure(); return writer_buffer; } var reader; var hasRequiredReader; function requireReader() { if (hasRequiredReader) return reader; hasRequiredReader = 1; reader = Reader; var util = requireMinimal$1(); var BufferReader; var LongBits = util.LongBits, utf82 = util.utf8; function indexOutOfRange(reader2, writeLength) { return RangeError("index out of range: " + reader2.pos + " + " + (writeLength || 1) + " > " + reader2.len); } function Reader(buffer) { this.buf = buffer; this.pos = 0; this.len = buffer.length; } var create_array = typeof Uint8Array !== "undefined" ? function create_typed_array(buffer) { if (buffer instanceof Uint8Array || Array.isArray(buffer)) return new Reader(buffer); throw Error("illegal buffer"); } : function create_array2(buffer) { if (Array.isArray(buffer)) return new Reader(buffer); throw Error("illegal buffer"); }; var create = function create2() { return util.Buffer ? function create_buffer_setup(buffer) { return (Reader.create = function create_buffer(buffer2) { return util.Buffer.isBuffer(buffer2) ? new BufferReader(buffer2) : create_array(buffer2); })(buffer); } : create_array; }; Reader.create = create(); Reader.prototype._slice = util.Array.prototype.subarray || /* istanbul ignore next */ util.Array.prototype.slice; Reader.prototype.uint32 = /* @__PURE__ */ function read_uint32_setup() { var value = 4294967295; return function read_uint32() { value = (this.buf[this.pos] & 127) >>> 0; if (this.buf[this.pos++] < 128) return value; value = (value | (this.buf[this.pos] & 127) << 7) >>> 0; if (this.buf[this.pos++] < 128) return value; value = (value | (this.buf[this.pos] & 127) << 14) >>> 0; if (this.buf[this.pos++] < 128) return value; value = (value | (this.buf[this.pos] & 127) << 21) >>> 0; if (this.buf[this.pos++] < 128) return value; value = (value | (this.buf[this.pos] & 15) << 28) >>> 0; if (this.buf[this.pos++] < 128) return value; if ((this.pos += 5) > this.len) { this.pos = this.len; throw indexOutOfRange(this, 10); } return value; }; }(); Reader.prototype.int32 = function read_int32() { return this.uint32() | 0; }; Reader.prototype.sint32 = function read_sint32() { var value = this.uint32(); return value >>> 1 ^ -(value & 1) | 0; }; function readLongVarint() { var bits = new LongBits(0, 0); var i = 0; if (this.len - this.pos > 4) { for (; i < 4; ++i) { bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0; if (this.buf[this.pos++] < 128) return bits; } bits.lo = (bits.lo | (this.buf[this.pos] & 127) << 28) >>> 0; bits.hi = (bits.hi | (this.buf[this.pos] & 127) >> 4) >>> 0; if (this.buf[this.pos++] < 128) return bits; i = 0; } else { for (; i < 3; ++i) { if (this.pos >= this.len) throw indexOutOfRange(this); bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0; if (this.buf[this.pos++] < 128) return bits; } bits.lo = (bits.lo | (this.buf[this.pos++] & 127) << i * 7) >>> 0; return bits; } if (this.len - this.pos > 4) { for (; i < 5; ++i) { bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0; if (this.buf[this.pos++] < 128) return bits; } } else { for (; i < 5; ++i) { if (this.pos >= this.len) throw indexOutOfRange(this); bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0; if (this.buf[this.pos++] < 128) return bits; } } throw Error("invalid varint encoding"); } Reader.prototype.bool = function read_bool() { return this.uint32() !== 0; }; function readFixed32_end(buf, end) { return (buf[end - 4] | buf[end - 3] << 8 | buf[end - 2] << 16 | buf[end - 1] << 24) >>> 0; } Reader.prototype.fixed32 = function read_fixed32() { if (this.pos + 4 > this.len) throw indexOutOfRange(this, 4); return readFixed32_end(this.buf, this.pos += 4); }; Reader.prototype.sfixed32 = function read_sfixed32() { if (this.pos + 4 > this.len) throw indexOutOfRange(this, 4); return readFixed32_end(this.buf, this.pos += 4) | 0; }; function readFixed64() { if (this.pos + 8 > this.len) throw indexOutOfRange(this, 8); return new LongBits(readFixed32_end(this.buf, this.pos += 4), readFixed32_end(this.buf, this.pos += 4)); } Reader.prototype.float = function read_float() { if (this.pos + 4 > this.len) throw indexOutOfRange(this, 4); var value = util.float.readFloatLE(this.buf, this.pos); this.pos += 4; return value; }; Reader.prototype.double = function read_double() { if (this.pos + 8 > this.len) throw indexOutOfRange(this, 4); var value = util.float.readDoubleLE(this.buf, this.pos); this.pos += 8; return value; }; Reader.prototype.bytes = function read_bytes() { var length = this.uint32(), start = this.pos, end = this.pos + length; if (end > this.len) throw indexOutOfRange(this, length); this.pos += length; if (Array.isArray(this.buf)) return this.buf.slice(start, end); if (start === end) { var nativeBuffer = util.Buffer; return nativeBuffer ? nativeBuffer.alloc(0) : new this.buf.constructor(0); } return this._slice.call(this.buf, start, end); }; Reader.prototype.string = function read_string() { var bytes = this.bytes(); return utf82.read(bytes, 0, bytes.length); }; Reader.prototype.skip = function skip(length) { if (typeof length === "number") { if (this.pos + length > this.len) throw indexOutOfRange(this, length); this.pos += length; } else { do { if (this.pos >= this.len) throw indexOutOfRange(this); } while (this.buf[this.pos++] & 128); } return this; }; Reader.prototype.skipType = function(wireType) { switch (wireType) { case 0: this.skip(); break; case 1: this.skip(8); break; case 2: this.skip(this.uint32()); break; case 3: while ((wireType = this.uint32() & 7) !== 4) { this.skipType(wireType); } break; case 5: this.skip(4); break; /* istanbul ignore next */ default: throw Error("invalid wire type " + wireType + " at offset " + this.pos); } return this; }; Reader._configure = function(BufferReader_) { BufferReader = BufferReader_; Reader.create = create(); BufferReader._configure(); var fn = util.Long ? "toLong" : ( /* istanbul ignore next */ "toNumber" ); util.merge(Reader.prototype, { int64: function read_int64() { return readLongVarint.call(this)[fn](false); }, uint64: function read_uint64() { return readLongVarint.call(this)[fn](true); }, sint64: function read_sint64() { return readLongVarint.call(this).zzDecode()[fn](false); }, fixed64: function read_fixed64() { return readFixed64.call(this)[fn](true); }, sfixed64: function read_sfixed64() { return readFixed64.call(this)[fn](false); } }); }; return reader; } var reader_buffer; var hasRequiredReader_buffer; function requireReader_buffer() { if (hasRequiredReader_buffer) return reader_buffer; hasRequiredReader_buffer = 1; reader_buffer = BufferReader; var Reader = requireReader(); (BufferReader.prototype = Object.create(Reader.prototype)).constructor = BufferReader; var util = requireMinimal$1(); function BufferReader(buffer) { Reader.call(this, buffer); } BufferReader._configure = function() { if (util.Buffer) BufferReader.prototype._slice = util.Buffer.prototype.slice; }; BufferReader.prototype.string = function read_string_buffer() { var len = this.uint32(); return this.buf.utf8Slice ? this.buf.utf8Slice(this.pos, this.pos = Math.min(this.pos + len, this.len)) : this.buf.toString("utf-8", this.pos, this.pos = Math.min(this.pos + len, this.len)); }; BufferReader._configure(); return reader_buffer; } var rpc = {}; var service; var hasRequiredService; function requireService() { if (hasRequiredService) return service; hasRequiredService = 1; service = Service; var util = requireMinimal$1(); (Service.prototype = Object.create(util.EventEmitter.prototype)).constructor = Service; function Service(rpcImpl, requestDelimited, responseDelimited) { if (typeof rpcImpl !== "function") throw TypeError("rpcImpl must be a function"); util.EventEmitter.call(this); this.rpcImpl = rpcImpl; this.requestDelimited = Boolean(requestDelimited); this.responseDelimited = Boolean(responseDelimited); } Service.prototype.rpcCall = function rpcCall(method, requestCtor, responseCtor, request, callback) { if (!request) throw TypeError("request must be specified"); var self2 = this; if (!callback) return util.asPromise(rpcCall, self2, method, requestCtor, responseCtor, request); if (!self2.rpcImpl) { setTimeout(function() { callback(Error("already ended")); }, 0); return void 0; } try { return self2.rpcImpl( method, requestCtor[self2.requestDelimited ? "encodeDelimited" : "encode"](request).finish(), function rpcCallback(err, response) { if (err) { self2.emit("error", err, method); return callback(err); } if (response === null) { self2.end( /* endedByRPC */ true ); return void 0; } if (!(response instanceof responseCtor)) { try { response = responseCtor[self2.responseDelimited ? "decodeDelimited" : "decode"](response); } catch (err2) { self2.emit("error", err2, method); return callback(err2); } } self2.emit("data", response, method); return callback(null, response); } ); } catch (err) { self2.emit("error", err, method); setTimeout(function() { callback(err); }, 0); return void 0; } }; Service.prototype.end = function end(endedByRPC) { if (this.rpcImpl) { if (!endedByRPC) this.rpcImpl(null, null, null); this.rpcImpl = null; this.emit("end").off(); } return this; }; return service; } var hasRequiredRpc; function requireRpc() { if (hasRequiredRpc) return rpc; hasRequiredRpc = 1; (function(exports) { var rpc2 = exports; rpc2.Service = requireService(); })(rpc); return rpc; } var roots; var hasRequiredRoots; function requireRoots() { if (hasRequiredRoots) return roots; hasRequiredRoots = 1; roots = {}; return roots; } var hasRequiredIndexMinimal; function requireIndexMinimal() { if (hasRequiredIndexMinimal) return indexMinimal; hasRequiredIndexMinimal = 1; (function(exports) { var protobuf = exports; protobuf.build = "minimal"; protobuf.Writer = requireWriter(); protobuf.BufferWriter = requireWriter_buffer(); protobuf.Reader = requireReader(); protobuf.BufferReader = requireReader_buffer(); protobuf.util = requireMinimal$1(); protobuf.rpc = requireRpc(); protobuf.roots = requireRoots(); protobuf.configure = configure; function configure() { protobuf.util._configure(); protobuf.Writer._configure(protobuf.BufferWriter); protobuf.Reader._configure(protobuf.BufferReader); } configure(); })(indexMinimal); return indexMinimal; } var minimal; var hasRequiredMinimal; function requireMinimal() { if (hasRequiredMinimal) return minimal; hasRequiredMinimal = 1; minimal = requireIndexMinimal(); return minimal; } var minimalExports = requireMinimal(); const $Writer = minimalExports.Writer; const $root$2 = minimalExports.roots["default"] || (minimalExports.roots["default"] = {}); const NextContinuation = $root$2.NextContinuation = (() => { function NextContinuation2(p) { if (p) { for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) if (p[ks[i]] != null) this[ks[i]] = p[ks[i]]; } } NextContinuation2.prototype.commentAreaWrapper = null; NextContinuation2.prototype.uField3 = 0; NextContinuation2.prototype.mainCommentRequest = null; NextContinuation2.encode = function encode(m, w) { if (!w) w = $Writer.create(); if (m.commentAreaWrapper != null && Object.hasOwnProperty.call(m, "commentAreaWrapper")) $root$2.CommentAreaWrapper.encode(m.commentAreaWrapper, w.uint32(18).fork()).ldelim(); if (m.uField3 != null && Object.hasOwnProperty.call(m, "uField3")) w.uint32(24).int32(m.uField3); if (m.mainCommentRequest != null && Object.hasOwnProperty.call(m, "mainCommentRequest")) $root$2.MainCommentRequest.encode(m.mainCommentRequest, w.uint32(50).fork()).ldelim(); return w; }; return NextContinuation2; })(); $root$2.CommentAreaWrapper = (() => { function CommentAreaWrapper(p) { if (p) { for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) if (p[ks[i]] != null) this[ks[i]] = p[ks[i]]; } } CommentAreaWrapper.prototype.videoId = ""; CommentAreaWrapper.encode = function encode(m, w) { if (!w) w = $Writer.create(); if (m.videoId != null && Object.hasOwnProperty.call(m, "videoId")) w.uint32(18).string(m.videoId); return w; }; return CommentAreaWrapper; })(); $root$2.MainCommentRequest = (() => { function MainCommentRequest(p) { if (p) { for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) if (p[ks[i]] != null) this[ks[i]] = p[ks[i]]; } } MainCommentRequest.prototype.commentParameters = null; MainCommentRequest.prototype.commentReplyParameters = null; MainCommentRequest.prototype.sectionIdentifier = ""; MainCommentRequest.encode = function encode(m, w) { if (!w) w = $Writer.create(); if (m.commentReplyParameters != null && Object.hasOwnProperty.call(m, "commentReplyParameters")) $root$2.CommentReplyParameters.encode(m.commentReplyParameters, w.uint32(26).fork()).ldelim(); if (m.commentParameters != null && Object.hasOwnProperty.call(m, "commentParameters")) $root$2.CommentParameters.encode(m.commentParameters, w.uint32(34).fork()).ldelim(); if (m.sectionIdentifier != null && Object.hasOwnProperty.call(m, "sectionIdentifier")) w.uint32(66).string(m.sectionIdentifier); return w; }; return MainCommentRequest; })(); $root$2.CommentParameters = (() => { function CommentParameters(p) { if (p) { for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) if (p[ks[i]] != null) this[ks[i]] = p[ks[i]]; } } CommentParameters.prototype.videoId = ""; CommentParameters.prototype.postId = ""; CommentParameters.prototype.channelId = ""; CommentParameters.prototype.sortType = 0; CommentParameters.prototype.targetCommentId = ""; CommentParameters.encode = function encode(m, w) { if (!w) w = $Writer.create(); if (m.videoId != null && Object.hasOwnProperty.call(m, "videoId")) w.uint32(34).string(m.videoId); if (m.sortType != null && Object.hasOwnProperty.call(m, "sortType")) w.uint32(48).int32(m.sortType); if (m.targetCommentId != null && Object.hasOwnProperty.call(m, "targetCommentId")) w.uint32(130).string(m.targetCommentId); if (m.postId != null && Object.hasOwnProperty.call(m, "postId")) w.uint32(234).string(m.postId); if (m.channelId != null && Object.hasOwnProperty.call(m, "channelId")) w.uint32(242).string(m.channelId); return w; }; CommentParameters.SortType = function() { const valuesById = {}, values = Object.create(valuesById); values[valuesById[0] = "HOT"] = 0; values[valuesById[1] = "LATEST"] = 1; return values; }(); return CommentParameters; })(); $root$2.CommentReplyParameters = (() => { function CommentReplyParameters(p) { if (p) { for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) if (p[ks[i]] != null) this[ks[i]] = p[ks[i]]; } } CommentReplyParameters.prototype.rootCommentId = ""; CommentReplyParameters.prototype.channelId = ""; CommentReplyParameters.prototype.videoId = ""; CommentReplyParameters.prototype.postId = ""; CommentReplyParameters.prototype.pageSize = 0; CommentReplyParameters.prototype.sortParam = null; CommentReplyParameters.encode = function encode(m, w) { if (!w) w = $Writer.create(); if (m.rootCommentId != null && Object.hasOwnProperty.call(m, "rootCommentId")) w.uint32(18).string(m.rootCommentId); if (m.channelId != null && Object.hasOwnProperty.call(m, "channelId")) w.uint32(42).string(m.channelId); if (m.videoId != null && Object.hasOwnProperty.call(m, "videoId")) w.uint32(50).string(m.videoId); if (m.pageSize != null && Object.hasOwnProperty.call(m, "pageSize")) w.uint32(72).int32(m.pageSize); if (m.postId != null && Object.hasOwnProperty.call(m, "postId")) w.uint32(122).string(m.postId); if (m.sortParam != null && Object.hasOwnProperty.call(m, "sortParam")) $root$2.CommentReplyParameters.SortParam.encode(m.sortParam, w.uint32(130).fork()).ldelim(); return w; }; CommentReplyParameters.SortParam = function() { function SortParam(p) { if (p) { for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) if (p[ks[i]] != null) this[ks[i]] = p[ks[i]]; } } SortParam.prototype.sortType = 0; SortParam.encode = function encode(m, w) { if (!w) w = $Writer.create(); if (m.sortType != null && Object.hasOwnProperty.call(m, "sortType")) w.uint32(8).int32(m.sortType); return w; }; SortParam.SortType = function() { const valuesById = {}, values = Object.create(valuesById); values[valuesById[0] = "DEFAULT"] = 0; values[valuesById[1] = "HOT"] = 1; values[valuesById[2] = "LATEST"] = 2; return values; }(); return SortParam; }(); return CommentReplyParameters; })(); const BrowserContinuation = $root$2.BrowserContinuation = (() => { function BrowserContinuation2(p) { if (p) { for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) if (p[ks[i]] != null) this[ks[i]] = p[ks[i]]; } } BrowserContinuation2.prototype.request = null; BrowserContinuation2.encode = function encode(m, w) { if (!w) w = $Writer.create(); if (m.request != null && Object.hasOwnProperty.call(m, "request")) $root$2.BrowserContinuation.Request.encode(m.request, w.uint32(641815778).fork()).ldelim(); return w; }; BrowserContinuation2.Request = function() { function Request(p) { if (p) { for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) if (p[ks[i]] != null) this[ks[i]] = p[ks[i]]; } } Request.prototype.description = ""; Request.prototype.continuationBase64 = ""; Request.encode = function encode(m, w) { if (!w) w = $Writer.create(); if (m.description != null && Object.hasOwnProperty.call(m, "description")) w.uint32(18).string(m.description); if (m.continuationBase64 != null && Object.hasOwnProperty.call(m, "continuationBase64")) w.uint32(26).string(m.continuationBase64); return w; }; return Request; }(); return BrowserContinuation2; })(); const BrowserCommentListContinuation = $root$2.BrowserCommentListContinuation = (() => { function BrowserCommentListContinuation2(p) { if (p) { for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) if (p[ks[i]] != null) this[ks[i]] = p[ks[i]]; } } BrowserCommentListContinuation2.prototype.description = ""; BrowserCommentListContinuation2.prototype.mainCommentRequest = null; BrowserCommentListContinuation2.encode = function encode(m, w) { if (!w) w = $Writer.create(); if (m.description != null && Object.hasOwnProperty.call(m, "description")) w.uint32(18).string(m.description); if (m.mainCommentRequest != null && Object.hasOwnProperty.call(m, "mainCommentRequest")) $root$2.MainCommentRequest.encode(m.mainCommentRequest, w.uint32(426).fork()).ldelim(); return w; }; return BrowserCommentListContinuation2; })(); const $Reader$1 = minimalExports.Reader; const $root$1 = minimalExports.roots["default"] || (minimalExports.roots["default"] = {}); const CommentAction = $root$1.CommentAction = (() => { function CommentAction2(p) { if (p) { for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) if (p[ks[i]] != null) this[ks[i]] = p[ks[i]]; } } CommentAction2.prototype.action = 0; CommentAction2.prototype.commentId = ""; CommentAction2.decode = function decode(r, l, e) { if (!(r instanceof $Reader$1)) r = $Reader$1.create(r); var c = l === void 0 ? r.len : r.pos + l, m = new $root$1.CommentAction(); while (r.pos < c) { var t = r.uint32(); if (t === e) break; switch (t >>> 3) { case 1: { m.action = r.int32(); break; } case 3: { m.commentId = r.string(); break; } default: r.skipType(t & 7); break; } } return m; }; return CommentAction2; })(); $root$1.Action = (() => { const valuesById = {}, values = Object.create(valuesById); values[valuesById[0] = "DEFAULT"] = 0; values[valuesById[5] = "LIKE"] = 5; values[valuesById[6] = "DELETE"] = 6; return values; })(); const $Reader = minimalExports.Reader; const $root = minimalExports.roots["default"] || (minimalExports.roots["default"] = {}); const UpdateCommentParams = $root.UpdateCommentParams = (() => { function UpdateCommentParams2(p) { if (p) { for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) if (p[ks[i]] != null) this[ks[i]] = p[ks[i]]; } } UpdateCommentParams2.prototype.commentId = ""; UpdateCommentParams2.decode = function decode(r, l, e) { if (!(r instanceof $Reader)) r = $Reader.create(r); var c = l === void 0 ? r.len : r.pos + l, m = new $root.UpdateCommentParams(); while (r.pos < c) { var t = r.uint32(); if (t === e) break; switch (t >>> 3) { case 1: { m.commentId = r.string(); break; } default: r.skipType(t & 7); break; } } return m; }; return UpdateCommentParams2; })(); var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)(); var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)(); const cssLoader = (e) => { const t = GM_getResourceText(e); return GM_addStyle(t), t; }; cssLoader("element-plus/dist/index.css"); const _hoisted_1$1 = { key: 0, class: "hot-ban-checker" }; const _hoisted_2$1 = { class: "message" }; const _hoisted_3$1 = { class: "buttons" }; const _hoisted_4$1 = { class: "actions" }; const _sfc_main$1 = { __name: "CommentActions", props: ["comment"], emits: ["delete", "checkHotBan"], setup(__props, { emit: __emit }) { const props = __props; const emit = __emit; const comment = props.comment; const check2 = vue.inject("check"); const hotBanCheck2 = vue.inject("hotBanCheck"); const updating = vue.ref(false); const showHotBanChecker = vue.ref(false); const hotBanCheckerMessage = vue.ref("等待检查中……"); let hotBanCheckerController = vue.reactive({ isCancelled: false }); function updateState() { updating.value = true; check2(comment).then(() => { updating.value = false; ElementPlus.ElMessage({ type: comment.currentState == "NORMAL" ? "success" : "warning", message: "更新成功,当前状态:" + translateState(comment.currentState) }); }).catch((err) => { updating.value = false; let msg = err.message; if (msg == "COMMENT_AREA_CLOSED") { msg = "评论区已关闭"; } ElementPlus.ElMessage.error("更新失败,因为:" + msg); }); } function copyComment(commentText) { if (navigator.clipboard) { navigator.clipboard.writeText(commentText).then(() => { ElementPlus.ElMessage({ message: "评论已复制到剪贴板", type: "success" }); }).catch((err) => { ElementPlus.ElMessage.error("无法复制文本,因为: " + err); }); } else { const textArea = document.createElement("textarea"); textArea.value = commentText; document.body.appendChild(textArea); textArea.select(); try { document.execCommand("copy"); ElementPlus.ElMessage({ message: "评论已复制到剪贴板", type: "success" }); } catch (err) { ElementPlus.ElMessage.error("无法复制文本,因为: " + err); } document.body.removeChild(textArea); } } function askDelete() { ElementPlus.ElMessageBox.confirm("确定要删除这条记录吗(这不会删除你在YouTube上发布的评论)?删除操作无法撤销!").then(() => { emit("delete"); }).catch(() => { }); } async function toHotBanCheck() { if (Date.now() - comment.recordedTime < 120 * 1e3) { ElementPlus.ElMessage.warning(`当前时间距评论记录时间不足2分钟,状态不可信,请到 ${formatTimestamp(comment.recordedTime + 120 * 1e3)} 来检查`); return; } if (comment.commentId.indexOf(".") == -1) { try { await ElementPlus.ElMessageBox.confirm( "确认检查吗?该检查需要遍历热门评论区,请注意评论区的评论数量(总数大于3000的评论区慎重考虑)!数量太多将导致漫长的检查过程,同时频繁调用API可能会引发不可预料的后果!", "警告", { confirmButtonText: "确定", cancelButtonText: "取消" } ); } catch (err) { return; } } hotBanCheckerMessage.value = "正在重新检查评论状态……"; hotBanCheckerController.isCancelled = false; showHotBanChecker.value = true; try { await check2(comment); if (comment.currentState != "NORMAL") { ElementPlus.ElMessage.error(`评论状态重新检查后为${translateState(comment.currentState)},无法继续进行检查`); showHotBanChecker.value = false; return; } } catch (err) { let msg = err.message; if (msg == "COMMENT_AREA_CLOSED") { msg = "评论区已关闭"; } ElementPlus.ElMessage.error("检查失败,因为" + msg); showHotBanChecker.value = false; return; } let observer = { onCountChange(c, p) { hotBanCheckerMessage.value = `正在搜索热门列表,已搜寻至:第${c}个 第${p}页`; } }; let notCancelled; try { notCancelled = await hotBanCheck2(comment, observer, hotBanCheckerController); } catch (err) { showHotBanChecker.value = false; ElementPlus.ElMessage.error(err.message); return; } if (notCancelled) { if (comment.hotBan) { ElementPlus.ElMessage.warning("你的评论未在热门列表找到,已被热门屏蔽,检查完成"); } else { ElementPlus.ElMessage.success("你的评论已在热门列表找到,没有被热门屏蔽,检查完成"); } } showHotBanChecker.value = false; } return (_ctx, _cache) => { const _component_el_button = vue.resolveComponent("el-button"); return vue.openBlock(), vue.createElementBlock("div", null, [ showHotBanChecker.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [ _cache[2] || (_cache[2] = vue.createElementVNode("div", { class: "title" }, "热门屏蔽检查", -1)), vue.createElementVNode("div", _hoisted_2$1, vue.toDisplayString(hotBanCheckerMessage.value), 1), vue.createElementVNode("div", _hoisted_3$1, [ vue.createElementVNode("span", { onClick: _cache[0] || (_cache[0] = ($event) => vue.unref(hotBanCheckerController).isCancelled = true) }, "终止检查") ]) ])) : vue.createCommentVNode("", true), vue.createElementVNode("div", _hoisted_4$1, [ vue.unref(comment).isUserDelete == false ? (vue.openBlock(), vue.createBlock(_component_el_button, { key: 0, type: "primary", plain: "", onClick: updateState, loading: updating.value }, { default: vue.withCtx(() => _cache[3] || (_cache[3] = [ vue.createTextVNode("更新状态") ])), _: 1, __: [3] }, 8, ["loading"])) : vue.createCommentVNode("", true), vue.unref(comment).currentState == "NORMAL" ? (vue.openBlock(), vue.createBlock(_component_el_button, { key: 1, type: "primary", plain: "", onClick: toHotBanCheck }, { default: vue.withCtx(() => _cache[4] || (_cache[4] = [ vue.createTextVNode("热门屏蔽检查") ])), _: 1, __: [4] })) : vue.createCommentVNode("", true), vue.createVNode(_component_el_button, { type: "primary", plain: "", onClick: _cache[1] || (_cache[1] = ($event) => copyComment(vue.unref(comment).content)) }, { default: vue.withCtx(() => _cache[5] || (_cache[5] = [ vue.createTextVNode("复制") ])), _: 1, __: [5] }), vue.createVNode(_component_el_button, { type: "danger", plain: "", onClick: askDelete }, { default: vue.withCtx(() => _cache[6] || (_cache[6] = [ vue.createTextVNode("删除记录") ])), _: 1, __: [6] }) ]) ]); }; } }; const CommentActions = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-e5341f8d"]]); const _hoisted_1 = { class: "detail" }; const _hoisted_2 = { class: "info-table" }; const _hoisted_3 = { class: "comment-content" }; const _hoisted_4 = { key: 0 }; const _hoisted_5 = { key: 3 }; const _hoisted_6 = { class: "comment-content" }; const _hoisted_7 = { class: "pagination" }; const pageSize = 20; const _sfc_main = { __name: "App", setup(__props) { const dialogVisible = vue.ref(false); const menuListener = vue.inject("menuListener"); const deleteComment2 = vue.inject("deleteComment"); const db2 = vue.inject("db"); const comments = vue.reactive([]); const loadingComments = vue.ref(false); const prevTime = vue.ref(null); const nextTime = vue.ref(null); var prevStack = [null]; function loadComments(direction = "next") { loadingComments.value = true; comments.length = 0; let time = null; if (direction == "next") { time = nextTime.value; prevStack.push(time ? time : -1); prevTime.value = prevStack[prevStack.length - 2]; } else if (direction == "prev") { time = prevStack[prevStack.length - 2]; time = time == -1 ? null : time; prevStack.pop(); prevTime.value = prevStack[prevStack.length - 2]; } db2.transaction("comments").objectStore("comments").index("recordedTime").openCursor(time ? IDBKeyRange.upperBound(time) : null, "prev").onsuccess = (event) => { var cursor = event.target.result; if (cursor) { if (comments.length < pageSize) { comments.push(cursor.value); cursor.continue(); } else { nextTime.value = cursor.value.recordedTime; loadingComments.value = false; } } else { nextTime.value = null; loadingComments.value = false; } }; } menuListener.onOpenHistory = () => { dialogVisible.value = true; nextTime.value = null; prevStack = [null]; loadComments(); }; function formatStateDesc(comment) { switch (comment.currentState) { case "NORMAL": if (comment.hotBan === true) { return "热门屏蔽"; } else if (comment.hotBan === false) { return "完全正常"; } else { return "正常"; } case "DELETED": if (comment.isUserDelete) { return "用户删除"; } else { return "已删除"; } case "SHADOW_BAN": return "仅自己可见"; case "NOT_CHECK": return "还未检查"; } } function formatCommentArea(comment, needEmojiHead) { var commentAreaInfo = comment.commentAreaInfo; switch (comment.webPageType) { case "WEB_PAGE_TYPE_WATCH": return "📺 " + commentAreaInfo.videoId; case "WEB_PAGE_TYPE_BROWSE": return "📰" + commentAreaInfo.postId; } } function formatHotBan(hotBan) { if (hotBan == null) { return "未检查"; } return hotBan ? "是" : "否"; } function deleteCommentItem(comment) { deleteComment2(comment.commentId).then(() => { const index = comments.findIndex((item) => item.commentId == comment.commentId); if (index !== -1) { comments.splice(index, 1); ElementPlus.ElMessage.success("评论删除成功"); } }).catch((err) => { ElementPlus.ElMessage.error("评论删除失败"); console.error("delete comment from database failed", err); }); } return (_ctx, _cache) => { const _component_el_table_column = vue.resolveComponent("el-table-column"); const _component_el_link = vue.resolveComponent("el-link"); const _component_el_table = vue.resolveComponent("el-table"); const _component_el_button = vue.resolveComponent("el-button"); const _component_el_dialog = vue.resolveComponent("el-dialog"); return vue.openBlock(), vue.createElementBlock("div", null, [ vue.createVNode(_component_el_dialog, { modelValue: dialogVisible.value, "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => dialogVisible.value = $event), "z-index": 3e3, title: "历史评论列表", width: "80%", style: { "height": "92vh" }, "body-class": "dialog-body", "align-center": "" }, { default: vue.withCtx(() => [ vue.createVNode(_component_el_table, { data: comments, "row-key": "commentId", height: "100%", class: "comment-list" }, { default: vue.withCtx(() => [ vue.createVNode(_component_el_table_column, { prop: "content", label: "评论内容", align: "left", "show-overflow-tooltip": "" }), vue.createVNode(_component_el_table_column, { prop: "state", label: "当前状态", align: "center", width: "136", formatter: formatStateDesc }), vue.createVNode(_component_el_table_column, { prop: "recordedTime", label: "记录时间", align: "center", width: "160", formatter: (comment) => vue.unref(formatTimestamp)(comment.recordedTime) }, null, 8, ["formatter"]), vue.createVNode(_component_el_table_column, { prop: "area", label: "所在评论区", align: "center", width: "240" }, { default: vue.withCtx(({ row }) => [ vue.createElementVNode("div", null, [ vue.createVNode(_component_el_link, { type: "primary", href: row.url, class: vue.normalizeClass(["locate-link", { "post-locate-link": row.webPageType == "WEB_PAGE_TYPE_BROWSE" }]) }, { default: vue.withCtx(() => [ vue.createTextVNode(vue.toDisplayString(formatCommentArea(row)), 1) ]), _: 2 }, 1032, ["href", "class"]) ]) ]), _: 1 }), vue.createVNode(_component_el_table_column, { type: "expand" }, { default: vue.withCtx(({ row }) => [ vue.createElementVNode("div", _hoisted_1, [ vue.createElementVNode("table", _hoisted_2, [ vue.createElementVNode("tbody", null, [ vue.createElementVNode("tr", null, [ _cache[3] || (_cache[3] = vue.createElementVNode("td", null, "评论内容", -1)), vue.createElementVNode("td", _hoisted_3, vue.toDisplayString(row.content), 1) ]), vue.createElementVNode("tr", null, [ _cache[4] || (_cache[4] = vue.createElementVNode("td", null, "当前状态", -1)), vue.createElementVNode("td", null, vue.toDisplayString(vue.unref(translateState)(row.currentState)), 1) ]), row.currentState == "DELETED" ? (vue.openBlock(), vue.createElementBlock("tr", _hoisted_4, [ _cache[5] || (_cache[5] = vue.createElementVNode("td", null, "用户删除", -1)), vue.createElementVNode("td", null, vue.toDisplayString(row.isUserDelete ? "是" : "否"), 1) ])) : vue.createCommentVNode("", true), vue.createElementVNode("tr", null, [ _cache[6] || (_cache[6] = vue.createElementVNode("td", null, "热门屏蔽", -1)), vue.createElementVNode("td", null, vue.toDisplayString(formatHotBan(row.hotBan)), 1) ]), vue.createElementVNode("tr", null, [ _cache[7] || (_cache[7] = vue.createElementVNode("td", null, "发送者", -1)), vue.createElementVNode("td", null, vue.toDisplayString(row.displayName), 1) ]), vue.createElementVNode("tr", null, [ _cache[8] || (_cache[8] = vue.createElementVNode("td", null, "评论ID", -1)), vue.createElementVNode("td", null, vue.toDisplayString(row.commentId), 1) ]), row.webPageType == "WEB_PAGE_TYPE_WATCH" ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [ _cache[10] || (_cache[10] = vue.createElementVNode("tr", null, [ vue.createElementVNode("td", null, "评论区类型"), vue.createElementVNode("td", null, "视频") ], -1)), vue.createElementVNode("tr", null, [ _cache[9] || (_cache[9] = vue.createElementVNode("td", null, "视频ID", -1)), vue.createElementVNode("td", null, vue.toDisplayString(row.commentAreaInfo.videoId), 1) ]) ], 64)) : row.webPageType == "WEB_PAGE_TYPE_BROWSE" ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 2 }, [ _cache[13] || (_cache[13] = vue.createElementVNode("tr", null, [ vue.createElementVNode("td", null, "评论区类型"), vue.createElementVNode("td", null, "帖子") ], -1)), vue.createElementVNode("tr", null, [ _cache[11] || (_cache[11] = vue.createElementVNode("td", null, "帖子所属频道ID", -1)), vue.createElementVNode("td", null, vue.toDisplayString(row.commentAreaInfo.channelId), 1) ]), vue.createElementVNode("tr", null, [ _cache[12] || (_cache[12] = vue.createElementVNode("td", null, "帖子ID", -1)), vue.createElementVNode("td", null, vue.toDisplayString(row.commentAreaInfo.postId), 1) ]) ], 64)) : vue.createCommentVNode("", true), vue.createElementVNode("tr", null, [ _cache[14] || (_cache[14] = vue.createElementVNode("td", null, "点赞数", -1)), vue.createElementVNode("td", null, vue.toDisplayString(row.likeCount), 1) ]), row.commentId.indexOf(".") == -1 ? (vue.openBlock(), vue.createElementBlock("tr", _hoisted_5, [ _cache[15] || (_cache[15] = vue.createElementVNode("td", null, "回复数", -1)), vue.createElementVNode("td", null, vue.toDisplayString(row.replyCount), 1) ])) : vue.createCommentVNode("", true), vue.createElementVNode("tr", null, [ _cache[16] || (_cache[16] = vue.createElementVNode("td", null, "记录时间", -1)), vue.createElementVNode("td", null, vue.toDisplayString(vue.unref(formatTimestamp)(row.recordedTime)), 1) ]), vue.createElementVNode("tr", null, [ _cache[17] || (_cache[17] = vue.createElementVNode("td", null, "更新时间", -1)), vue.createElementVNode("td", null, vue.toDisplayString(vue.unref(formatTimestamp)(row.updatedTime)), 1) ]) ]) ]), vue.createElementVNode("details", null, [ _cache[18] || (_cache[18] = vue.createElementVNode("summary", null, "历史检查记录", -1)), vue.createVNode(_component_el_table, { data: row.histories, style: { "width": "100%" } }, { default: vue.withCtx(() => [ vue.createVNode(_component_el_table_column, { prop: "time", label: "时间戳", width: "160", formatter: (history) => vue.unref(formatTimestamp)(history.time) }, null, 8, ["formatter"]), vue.createVNode(_component_el_table_column, { prop: "state", label: "状态", width: "136", formatter: (history) => vue.unref(translateState)(history.state) }, null, 8, ["formatter"]), vue.createVNode(_component_el_table_column, { prop: "hotBan", label: "热门屏蔽", width: "120", formatter: (history) => formatHotBan(history.hotBan) }, null, 8, ["formatter"]), vue.createVNode(_component_el_table_column, { prop: "content", label: "评论内容", "show-overflow-tooltip": "" }), vue.createVNode(_component_el_table_column, { type: "expand" }, { default: vue.withCtx(({ row: row2 }) => [ vue.createElementVNode("div", _hoisted_6, vue.toDisplayString(row2.content), 1) ]), _: 2 }, 1024) ]), _: 2 }, 1032, ["data"]) ]), vue.createVNode(CommentActions, { comment: row, onDelete: ($event) => deleteCommentItem(row) }, null, 8, ["comment", "onDelete"]) ]) ]), _: 1 }) ]), _: 1 }, 8, ["data"]), vue.createElementVNode("div", _hoisted_7, [ prevTime.value ? (vue.openBlock(), vue.createBlock(_component_el_button, { key: 0, onClick: _cache[0] || (_cache[0] = ($event) => loadComments("prev")), disabled: loadingComments.value }, { default: vue.withCtx(() => [ vue.createTextVNode("< " + vue.toDisplayString(prevTime.value == -1 ? "NOW" : vue.unref(formatTimestamp)(prevTime.value)), 1) ]), _: 1 }, 8, ["disabled"])) : vue.createCommentVNode("", true), nextTime.value ? (vue.openBlock(), vue.createBlock(_component_el_button, { key: 1, onClick: _cache[1] || (_cache[1] = ($event) => loadComments("next")), disabled: loadingComments.value }, { default: vue.withCtx(() => [ vue.createTextVNode(vue.toDisplayString(vue.unref(formatTimestamp)(nextTime.value)) + " >", 1) ]), _: 1 }, 8, ["disabled"])) : vue.createCommentVNode("", true) ]) ]), _: 1 }, 8, ["modelValue"]) ]); }; } }; const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-ff4696c9"]]); const originalFetch = _unsafeWindow.fetch; var authorizationCache = null; var contextCache = null; var trueLoaded = false; var db = null; const checkingCommentIdSet = /* @__PURE__ */ new Set(); function waitForElement(observeSelector, targetSelector) { return new Promise((resolve) => { const parent = document.querySelector(observeSelector); if (!parent) return; const found = parent.querySelector(targetSelector); if (found) { resolve(found); return; } const observer = new MutationObserver(() => { const el = parent.querySelector(targetSelector); if (el) { observer.disconnect(); resolve(el); } }); observer.observe(parent, { childList: true, subtree: true }); }); } async function findComment(commentRecord, isLogin = true) { let continuation; let requestUrl; if (commentRecord.webPageType == "WEB_PAGE_TYPE_WATCH") { let payload = { uField3: 6, commentAreaWrapper: { videoId: commentRecord.commentAreaInfo.videoId }, mainCommentRequest: { sectionIdentifier: "comments-section", commentParameters: { videoId: commentRecord.commentAreaInfo.videoId, targetCommentId: commentRecord.commentId } } }; let encoded = NextContinuation.encode(payload); let buffer = encoded.finish(); continuation = btoa(String.fromCharCode(...buffer)); continuation = standardBase64ToUrlSafe(continuation); requestUrl = "https://www.youtube.com/youtubei/v1/next?prettyPrint=false"; } else if (commentRecord.webPageType == "WEB_PAGE_TYPE_BROWSE") { let payload = { description: "community", mainCommentRequest: { sectionIdentifier: "comments-section", commentParameters: { channelId: commentRecord.commentAreaInfo.channelId, postId: commentRecord.commentAreaInfo.postId, targetCommentId: commentRecord.commentId } } }; let encoded = BrowserCommentListContinuation.encode(payload); let buffer = encoded.finish(); continuation = btoa(String.fromCharCode(...buffer)); continuation = standardBase64ToUrlSafe(continuation); payload = { request: { description: "FEcomment_post_detail_page_web_top_level", continuationBase64: continuation } }; encoded = BrowserContinuation.encode(payload); buffer = encoded.finish(); continuation = btoa(String.fromCharCode(...buffer)); continuation = standardBase64ToUrlSafe(continuation); requestUrl = "https://www.youtube.com/youtubei/v1/browse?prettyPrint=false"; } else { throw new Error("Unsupported webPageType : " + commentRecord.webPageType); } let data = { context: contextCache, continuation }; let headers = {}; if (isLogin) { headers.authorization = authorizationCache; } let options = { method: "POST", body: JSON.stringify(data), headers }; let response = await (await originalFetch(requestUrl, options)).json(); let loggedOut = response.responseContext.mainAppWebResponseContext.loggedOut; if (loggedOut == isLogin) { console.warn("登录(不可用)状态不符,需要的:" + isLogin + " API返回的:" + !loggedOut); } if (!response.frameworkUpdates) { throw new Error("COMMENT_AREA_CLOSED"); } let mutations = response.frameworkUpdates.entityBatchUpdate.mutations; for (let i = 0; i < mutations.length; i++) { let mutation = mutations[i]; if (mutation.payload.commentEntityPayload) { let entity = mutation.payload.commentEntityPayload; let commentId = entity.properties.commentId; if (commentId == commentRecord.commentId) { let likeCount = parseInt(entity.toolbar.likeCountNotliked); likeCount = likeCount ? likeCount : 0; let replyCount = parseInt(entity.toolbar.replyCount); replyCount = replyCount ? replyCount : 0; return { content: entity.properties.content.content, commentId, likeCount, replyCount }; } } } } async function insertComment() { } async function updateComment() { } async function selectComment() { } async function deleteComment() { } function appendHistory(commentRecord) { let histories = commentRecord.histories; let needPush = false; if (histories.length == 0) { needPush = true; } else { let lastHistory = histories[histories.length - 1]; needPush = lastHistory.state != commentRecord.currentState || lastHistory.content != commentRecord.content || lastHistory.hotBan != commentRecord.hotBan; } if (needPush) { histories.push({ time: commentRecord.updatedTime, content: commentRecord.content, state: commentRecord.currentState, hotBan: commentRecord.hotBan }); } } function updateRecord(commentRecord, state, result) { commentRecord.updatedTime = Date.now(); if (state) { commentRecord.currentState = state; } if (result) { commentRecord.likeCount = result.likeCount; commentRecord.replyCount = result.replyCount; commentRecord.content = result.content; } appendHistory(commentRecord); updateComment(commentRecord); } async function check(commentRecord) { let loggedOutResult = await findComment(commentRecord, false); if (loggedOutResult) { updateRecord(commentRecord, "NORMAL", loggedOutResult); return; } let loggedInResult = await findComment(commentRecord, true); if (loggedInResult) { updateRecord(commentRecord, "SHADOW_BAN", loggedInResult); } else { updateRecord(commentRecord, "DELETED"); } } async function toCheck(commentRecord) { checkingCommentIdSet.add(commentRecord.commentId); let selector; if (window.location.pathname.startsWith("/channel")) { selector = "ytd-item-section-renderer#sections"; } else { selector = "#comments"; } let element = (await waitForElement(selector, `a[href='${commentRecord.url}']`)).parentNode.parentNode.parentNode.parentNode; let div = document.createElement("div"); div.style.marginTop = "8px"; div.id = "checker"; element.append(div); let app = vue.createApp(CommentChecker); app.use(ElementPlus); app.provide("check", check); app.provide("hotBanCheck", hotBanCheck); app.provide("commentRecord", commentRecord); app.provide("interval", 5); app.provide("onUnblock", (commentRecord2) => { checkingCommentIdSet.delete(commentRecord2.commentId); }); app.provide("onClose", (commentRecord2) => { checkingCommentIdSet.delete(commentRecord2.commentId); console.log("评论检查完成", commentRecord2); div.remove(); }); app.mount(div); } function createCommentListRequest(commentRecord, isLatestSort) { let api; let continuation; if (commentRecord.webPageType == "WEB_PAGE_TYPE_WATCH") { api = "https://www.youtube.com/youtubei/v1/next?prettyPrint=false"; if (commentRecord.commentId.indexOf(".") != -1) { let rootCommentId = commentRecord.commentId.split(".")[0]; let payload = { uField3: 6, commentAreaWrapper: { videoId: commentRecord.commentAreaInfo.videoId }, mainCommentRequest: { sectionIdentifier: `comment-replies-item-${rootCommentId}`, commentReplyParameters: { rootCommentId, channelId: commentRecord.commentAreaInfo.channelId, videoId: commentRecord.commentAreaInfo.videoId, pageSize: 10, sortParam: { sortType: 1 } } } }; let encoded = NextContinuation.encode(payload); let buffer = encoded.finish(); continuation = btoa(String.fromCharCode(...buffer)); continuation = standardBase64ToUrlSafe(continuation); } else { let payload = { uField3: 6, commentAreaWrapper: { videoId: commentRecord.commentAreaInfo.videoId }, mainCommentRequest: { sectionIdentifier: "comments-section", commentParameters: { videoId: commentRecord.commentAreaInfo.videoId, sortType: 0 } } }; let encoded = NextContinuation.encode(payload); let buffer = encoded.finish(); continuation = btoa(String.fromCharCode(...buffer)); continuation = standardBase64ToUrlSafe(continuation); } } else if (commentRecord.webPageType == "WEB_PAGE_TYPE_BROWSE") { api = "https://www.youtube.com/youtubei/v1/browse?prettyPrint=false"; if (commentRecord.commentId.indexOf(".") != -1) { let rootCommentId = commentRecord.commentId.split(".")[0]; let payload = { description: "community", mainCommentRequest: { sectionIdentifier: `comment-replies-item-${rootCommentId}`, commentReplyParameters: { rootCommentId, channelId: commentRecord.commentAreaInfo.channelId, postId: commentRecord.commentAreaInfo.postId, pageSize: 10, sortParam: { sortType: 1 } } } }; let encoded = BrowserCommentListContinuation.encode(payload); let buffer = encoded.finish(); continuation = btoa(String.fromCharCode(...buffer)); continuation = standardBase64ToUrlSafe(continuation); payload = { request: { description: "FEcomment_post_detail_page_web_replies_page", continuationBase64: continuation } }; encoded = BrowserContinuation.encode(payload); buffer = encoded.finish(); continuation = btoa(String.fromCharCode(...buffer)); continuation = standardBase64ToUrlSafe(continuation); } else { let payload = { description: "community", mainCommentRequest: { sectionIdentifier: "comments-section", commentParameters: { channelId: commentRecord.commentAreaInfo.channelId, postId: commentRecord.commentAreaInfo.postId, sortType: 0 } } }; let encoded = BrowserCommentListContinuation.encode(payload); let buffer = encoded.finish(); continuation = btoa(String.fromCharCode(...buffer)); continuation = standardBase64ToUrlSafe(continuation); payload = { request: { description: "FEcomment_post_detail_page_web_top_level", continuationBase64: continuation } }; encoded = BrowserContinuation.encode(payload); buffer = encoded.finish(); continuation = btoa(String.fromCharCode(...buffer)); continuation = standardBase64ToUrlSafe(continuation); } } return { api, continuation }; } async function hotBanCheck(commentRecord, observer, controller) { var _a, _b, _c, _d, _e; if (!observer) { observer = { onCountChange(c, p) { } }; } if (!controller) { controller = { isCancelled: false }; } let pageCpunt = 0; let commentCount = 0; let { api, continuation } = createCommentListRequest(commentRecord); while (continuation) { if (controller.isCancelled) { return false; } let data = { context: contextCache, continuation }; let options = { method: "POST", body: JSON.stringify(data) }; let response = await (await originalFetch(api, options)).json(); pageCpunt++; if (!response.frameworkUpdates) { commentRecord.hotBan = true; updateRecord(commentRecord); return true; } for (let mutation of response.frameworkUpdates.entityBatchUpdate.mutations) { let entity = mutation.payload.commentEntityPayload; if (entity) { let commentId = entity.properties.commentId; commentCount++; observer.onCountChange(commentCount, pageCpunt); if (commentId == commentRecord.commentId) { commentRecord.hotBan = false; updateRecord(commentRecord); return true; } } } continuation = null; for (const endpoint of response.onResponseReceivedEndpoints) { const items = ((_a = endpoint.appendContinuationItemsAction) == null ? void 0 : _a.continuationItems) || ((_b = endpoint.reloadContinuationItemsCommand) == null ? void 0 : _b.continuationItems); if (!items) continue; for (const item of items) { const token = (_e = (_d = (_c = item.continuationItemRenderer) == null ? void 0 : _c.continuationEndpoint) == null ? void 0 : _d.continuationCommand) == null ? void 0 : _e.token; if (token) { continuation = token; break; } } if (continuation) break; } } commentRecord.hotBan = true; updateRecord(commentRecord); return true; } async function handlerYoutubei(request) { let requsetClone = request.clone(); let requestBody = await requsetClone.json(); if (requestBody && requestBody.context) { contextCache = requestBody.context; if (!trueLoaded) { console.log("fetch已成功劫持"); _GM_registerMenuCommand("✅ 脚本已完全加载"); trueLoaded = true; } } if (request.url.startsWith("https://www.youtube.com/youtubei/v1/comment/create_comment")) { let response = await originalFetch(request); if (response.status != 200) { return response; } let responseClone = response.clone(); try { let json = await responseClone.json(); if (json.frameworkUpdates.entityBatchUpdate.mutations.length == 1) { return response; } let entity = json.frameworkUpdates.entityBatchUpdate.mutations[0].payload.commentEntityPayload; let innertubeCommand = json.frameworkUpdates.entityBatchUpdate.mutations[1].payload.commentSurfaceEntityPayload.publishedTimeCommand.innertubeCommand; let webCommandMetadata = innertubeCommand.commandMetadata.webCommandMetadata; let webPageType = webCommandMetadata.webPageType; let url = webCommandMetadata.url; let commentAreaInfo = {}; if (webPageType == "WEB_PAGE_TYPE_WATCH") { commentAreaInfo.videoId = innertubeCommand.watchEndpoint.videoId; commentAreaInfo.channelId = json.actions[0].runAttestationCommand.ids[2].externalChannelId; } else if (webPageType == "WEB_PAGE_TYPE_BROWSE") { commentAreaInfo.channelId = url.split("/")[2]; commentAreaInfo.postId = createUrl(url).searchParams.get("lb"); } let author = entity.author; let properties = entity.properties; let content = properties.content.content; let recordedTime = Date.now(); let commentRecord = { //评论ID commentId: properties.commentId, //@发送者 displayName: author.displayName, //频道ID,类似UID channelId: author.channelId, //评论内容 content, //webPageType 评论区类型 视频 or 帖子 webPageType, //URL 点击可跳转“所要查看的评论” 例如 /watch?v=${视频ID}&lc=${评论ID} url, //评论区信息,视频{视频ID},帖子{频道ID,帖子ID} commentAreaInfo, //当前状态 默认从SHADOW_BAN开始,到NORMAL或DELETED currentState: "NOT_CHECK", //是否在热门排序中被禁止显示(搜索整个热门评论区来检查),前提条件currentState = "NORMAL",值:null | false | true //此状态不会因为修改评论内容而解除,但会因为修改评论内容而赋予 hotBan: null, //历史记录,时间 内容 状态 是否热门屏蔽 histories: [], //{ time: recordedTime, state: "SHADOW_BAN", content, hotBan: null } //点赞与回复数,不记录历史 likeCount: 0, replyCount: 0, //记录的时间,用的是系统当前时间,约等于评论的发布时间,API里的publishedTime距离发布时间戳多久的Shit不是时间戳(PS:YouTube开放API可查询具体发布时间戳) recordedTime, //更新时间 updatedTime: recordedTime, //是否是用户自己执行的删除?用于区分是被系统删的还是自己删除。state为"DELETED"时该属性为才有意义。(劫持删除评论请求时记录) isUserDelete: false }; console.log(commentRecord); insertComment(commentRecord); console.log(createUrl(url).href); toCheck(commentRecord); } catch (err) { console.error(err); throw err; } return response; } else if (request.url.startsWith("https://www.youtube.com/youtubei/v1/comment/perform_comment_action")) { let actionBase64 = urlSafeBase64ToStandard(requestBody.actions[0]); let actionInfo = CommentAction.decode(Uint8Array.from(atob(actionBase64), (c) => c.charCodeAt(0))); if (actionInfo.action == 6) { if (checkingCommentIdSet.has(actionInfo.commentId)) { alert("现在不能删除该评论,因为评论还未完成检查,请先完成检查!"); const responseBody = { "error": { "code": 403, "message": "Can't delete comment now", "errors": [ { "message": "Can't delete comment now", "domain": "global", "reason": "forbidden" } ], "status": "FORBIDDEN" } }; return new Response(JSON.stringify(responseBody), { status: 403, headers: { "Content-Type": "application/json" } }); } else { let response = await originalFetch(request); let responseBody = await response.clone().json(); if (responseBody.actions && responseBody.actions[0].removeCommentAction.actionResult.status == "STATUS_SUCCEEDED") { let commentRecord = await selectComment(actionInfo.commentId); if (commentRecord) { commentRecord.isUserDelete = true; updateRecord(commentRecord, "DELETED"); } } return response; } } } else if (request.url.startsWith("https://www.youtube.com/youtubei/v1/comment/update_comment")) { let updateCommentParams = urlSafeBase64ToStandard(requestBody.updateCommentParams); let decodedParams = UpdateCommentParams.decode(Uint8Array.from(atob(updateCommentParams), (c) => c.charCodeAt(0))); if (checkingCommentIdSet.has(decodedParams.commentId)) { alert("现在不能修改该评论,因为评论还未完成检查,请先完成检查!"); const responseBody2 = { "error": { "code": 403, "message": "Can't edit comment now", "errors": [ { "message": "Can't edit comment now", "domain": "global", "reason": "forbidden" } ], "status": "FORBIDDEN" } }; return new Response(JSON.stringify(responseBody2), { status: 403, headers: { "Content-Type": "application/json" } }); } let response = await originalFetch(request); let responseBody = await response.clone().json(); if (responseBody.actions && responseBody.actions[0].updateCommentAction.actionResult.status == "STATUS_SUCCEEDED") { let commentRecord = await selectComment(decodedParams.commentId); if (commentRecord) { commentRecord.content = requestBody.commentText; commentRecord.currentState = "NOT_CHECK"; commentRecord.hotBan = null; updateRecord(commentRecord); } } return response; } return await originalFetch(request); } const fetchProxy = function(resource, options) { if (typeof resource == "string") { return originalFetch(resource, options); } if (!resource.url.startsWith("https://www.youtube.com/youtubei/")) { return originalFetch(resource, options); } let auth = resource.headers.get("Authorization"); if (auth) { authorizationCache = auth; if (resource.method != "POST") { return originalFetch(resource); } else { return handlerYoutubei(resource); } } return originalFetch(resource, options); }; try { _unsafeWindow.fetch = fetchProxy; } catch (err) { console.warn("替换 unsafeWindow.fetch 失败!相关信息:", err, Object.getOwnPropertyDescriptor(_unsafeWindow, "fetch")); if (confirm("fetch已被提前锁定,替换失败,YouTube发评反诈可能无法正常工作。\n你可以安装本项目的 Define property blocker 插件来反制锁定。\n\n点击“确定”前往项目地址,点击“取消”忽略。")) { window.location.href = "https://github.com/freedom-introvert/youtube-comment-censor-detector"; } } const _createElement = Document.prototype.createElement; Document.prototype.createElement = function(tagName, ...args) { const el = _createElement.call(this, tagName, ...args); if (tagName.toLowerCase() === "iframe") { el.addEventListener("load", () => { var _a; try { const fetchFromIframe = (_a = el.contentWindow) == null ? void 0 : _a.fetch; if (fetchFromIframe) { el.contentWindow.fetch = fetchProxy; console.log("已替换iframe window的fetch", el); } } catch (e) { console.log("未替换该iframe的fetch", el, e); } }); } return el; }; function openDB() { return new Promise((resolve, reject) => { let request = indexedDB.open("YT-CCD", 1); request.onerror = (event) => { reject(event); }; request.onsuccess = (event) => { resolve(event.target.result); }; request.onupgradeneeded = (event) => { let db2 = event.target.result; let objectStore = db2.createObjectStore("comments", { keyPath: "commentId" }); objectStore.createIndex("recordedTime", "recordedTime", { unique: false }); }; }); } async function init() { try { db = await openDB(); insertComment = function(comment) { return new Promise((resolve, reject) => { let request = db.transaction("comments", "readwrite").objectStore("comments").add(comment); request.onsuccess = (event) => { resolve(event); }; request.onerror = (event) => { reject(event); }; }); }; updateComment = function(comment) { return new Promise((resolve, reject) => { let request = db.transaction("comments", "readwrite").objectStore("comments").put(vue.toRaw(comment)); request.onsuccess = (event) => { resolve(event); }; request.onerror = (event) => { reject(event); }; }); }; selectComment = function(commentId) { return new Promise((resolve, reject) => { let request = db.transaction("comments").objectStore("comments").get(commentId); request.onsuccess = (event) => { resolve(request.result); }; request.onerror = (event) => { reject(event); }; }); }; deleteComment = function(commentId) { return new Promise((resolve, reject) => { let request = db.transaction("comments", "readwrite").objectStore("comments").delete(commentId); request.onsuccess = (event) => { resolve(request.result); }; request.onerror = (event) => { reject(event); }; }); }; } catch (err) { console.log("indexedDB数据库打开失败,评论历史记录相关功能已禁用,错误信息:", err); } const menuListener = { onOpenHistory: () => { alert("脚本正在初始化,请稍后……"); } }; _GM_registerMenuCommand("🧾 历史评论记录", () => { menuListener.onOpenHistory(); }); const div = document.createElement("div"); div.id = "yt-ccd"; div.style.position = "absolute"; document.body.append(div); let app = vue.createApp(App); app.use(ElementPlus); app.provide("menuListener", menuListener); app.provide("db", db); app.provide("check", check); app.provide("hotBanCheck", hotBanCheck); app.provide("deleteComment", deleteComment); app.mount(div); } window.addEventListener("load", () => { init().then(() => { console.log("YouTube反诈加载完成"); }).catch((err) => { console.error("YouTube反诈加载失败", err); }); }); })(Vue, ElementPlus);
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址