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