// ==UserScript==
// @name 斗鱼弹幕助手
// @namespace http://tampermonkey.net/
// @version 1.0.0
// @author ienone
// @description 为斗鱼(6657)发送弹幕提供便利畅快的输入体验与补全功能
// @license MIT
// @match *://www.douyu.com/*
// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/system.min.js
// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/extras/named-register.min.js
// @require data:application/javascript,%3B(typeof%20System!%3D'undefined')%26%26(System%3Dnew%20System.constructor())%3B
// @connect data.ienone.top
// @connect localhost:*
// @grant GM_addStyle
// @grant GM_deleteValue
// @grant GM_getValue
// @grant GM_listValues
// @grant GM_log
// @grant GM_notification
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @run-at document-start
// ==/UserScript==
System.register("./__entry.js", [], (function (exports, module) {
'use strict';
return {
execute: (function () {
const d=new Set;const importCSS = async e=>{d.has(e)||(d.add(e),(t=>{typeof GM_addStyle=="function"?GM_addStyle(t):document.head.appendChild(document.createElement("style")).append(t);})(e));};
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __pow = Math.pow;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
const CONFIG = {
SCRIPT_PREFIX: "[斗鱼弹幕助手]",
DB_NAME: "DouyuDanmukuAssistant",
DB_VERSION: 2,
DB_STORE_NAME: "danmuku_templates",
SETTINGS_KEY_PREFIX: "dda_",
CSS_CLASSES: {
POPUP: "dda-popup",
POPUP_SHOW: "show",
POPUP_CONTENT: "dda-popup-content",
POPUP_ITEM: "dda-popup-item",
POPUP_ITEM_ACTIVE: "dda-popup-item-active",
POPUP_ITEM_TEXT: "dda-popup-item-text",
POPUP_EMPTY: "dda-popup-empty",
EMPTY_MESSAGE: "dda-empty-message"
},
KEYBOARD: {
ENTER: "Enter",
ESCAPE: "Escape",
ARROW_UP: "ArrowUp",
ARROW_DOWN: "ArrowDown",
ARROW_LEFT: "ArrowLeft",
ARROW_RIGHT: "ArrowRight",
TAB: "Tab",
BACKSPACE: "Backspace"
},
API: {
BASE_URL: "https://api.example.com",
TIMEOUT: 5e3,
RETRY_ATTEMPTS: 3
},
DEBUG: false,
LOG_LEVEL: "info"
};
const DEFAULT_SETTINGS = {
minSearchLength: 1,
maxSuggestions: 10,
debounceDelay: 300,
sortBy: "relevance",
autoImportEnabled: false,
autoImportMaxPages: 5,
autoImportPageSize: 50,
autoImportSortByPopularity: true,
enterSelectionModeKey: "ArrowUp",
exitSelectionModeKey: "ArrowDown",
expandCandidatesKey: "ArrowUp",
navigationLeftKey: "ArrowLeft",
navigationRightKey: "ArrowRight",
selectKey: "Enter",
cancelKey: "Escape",
popupShowDelay: 100,
popupHideDelay: 200,
animationDuration: 200,
maxPopupHeight: 300,
itemHeight: 40,
maxCandidateWidth: 200,
capsule: {
maxWidth: 150,
height: 24,
padding: 16,
margin: 16,
totalHeight: 40,
fontSize: 12,
itemsPerRow: 4,
singleRowMaxItems: 8,
preview: {
enabled: true,
showDelay: 500,
hideDelay: 100,
maxWidth: 300,
animationDuration: 200,
keyboardShowDelay: 150,
verticalOffset: 8,
horizontalOffset: 0,
preferredPosition: "top"
}
},
enableAutoComplete: true,
enableKeyboardShortcuts: true,
enableSelectionMode: true,
enableSound: false,
enableSync: false,
syncInterval: 3e5,
maxCacheSize: 1e3,
cacheExpireTime: 864e5
};
const Utils = {
log(message, level = "log") {
const logMsg = `${CONFIG.SCRIPT_PREFIX} ${message}`;
try {
if (typeof GM_log !== "undefined") {
GM_log(logMsg);
} else {
console[level](logMsg);
}
} catch (e) {
console[level](logMsg);
}
},
sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
},
debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
},
throttle(func, delay) {
let lastCall = 0;
return function(...args) {
const now = Date.now();
if (now - lastCall >= delay) {
lastCall = now;
return func.apply(this, args);
}
};
},
getCurrentRoomId() {
const match = window.location.href.match(
/douyu\.com\/(?:beta\/)?(?:topic\/[^?]+\?rid=|(\d+))/
);
return match ? match[1] || new URLSearchParams(window.location.search).get("rid") : null;
},
isInLiveRoom() {
const roomId = this.getCurrentRoomId();
return roomId !== null && document.querySelector("[data-v-5aa519d2]");
},
getElementPosition(element) {
const rect = element.getBoundingClientRect();
return {
x: rect.left + window.scrollX,
y: rect.top + window.scrollY,
width: rect.width,
height: rect.height
};
},
safeExecute(func, context = "unknown") {
try {
return func();
} catch (error) {
this.log(`执行函数时出错 [${context}]: ${error.message}`, "error");
return null;
}
},
generateId(prefix = "dda") {
return `${prefix}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
},
deepClone(obj) {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (obj instanceof Array) {
return obj.map((item) => this.deepClone(item));
}
if (typeof obj === "object") {
const cloned = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = this.deepClone(obj[key]);
}
}
return cloned;
}
}
};
const scriptRel = (function detectScriptRel() {
const relList = typeof document !== "undefined" && document.createElement("link").relList;
return relList && relList.supports && relList.supports("modulepreload") ? "modulepreload" : "preload";
})();
const assetsURL = function(dep) {
return "/" + dep;
};
const seen = {};
const __vitePreload = function preload(baseModule, deps, importerUrl) {
let promise = Promise.resolve();
if (deps && deps.length > 0) {
let allSettled = function(promises$2) {
return Promise.all(promises$2.map((p) => Promise.resolve(p).then((value$1) => ({
status: "fulfilled",
value: value$1
}), (reason) => ({
status: "rejected",
reason
}))));
};
document.getElementsByTagName("link");
const cspNonceMeta = document.querySelector("meta[property=csp-nonce]");
const cspNonce = (cspNonceMeta == null ? void 0 : cspNonceMeta.nonce) || (cspNonceMeta == null ? void 0 : cspNonceMeta.getAttribute("nonce"));
promise = allSettled(deps.map((dep) => {
dep = assetsURL(dep);
if (dep in seen) return;
seen[dep] = true;
const isCss = dep.endsWith(".css");
const cssSelector = isCss ? '[rel="stylesheet"]' : "";
if (document.querySelector(`link[href="${dep}"]${cssSelector}`)) return;
const link = document.createElement("link");
link.rel = isCss ? "stylesheet" : scriptRel;
if (!isCss) link.as = "script";
link.crossOrigin = "";
link.href = dep;
if (cspNonce) link.setAttribute("nonce", cspNonce);
document.head.appendChild(link);
if (isCss) return new Promise((res, rej) => {
link.addEventListener("load", res);
link.addEventListener("error", () => rej( new Error(`Unable to preload CSS for ${dep}`)));
});
}));
}
function handlePreloadError(err$2) {
const e$1 = new Event("vite:preloadError", { cancelable: true });
e$1.payload = err$2;
window.dispatchEvent(e$1);
if (!e$1.defaultPrevented) throw err$2;
}
return promise.then((res) => {
for (const item of res || []) {
if (item.status !== "rejected") continue;
handlePreloadError(item.reason);
}
return baseModule().catch(handlePreloadError);
});
};
var w;
function H(a, c, b) {
const e = typeof b, d = typeof a;
if (e !== "undefined") {
if (d !== "undefined") {
if (b) {
if (d === "function" && e === d) return function(k) {
return a(b(k));
};
c = a.constructor;
if (c === b.constructor) {
if (c === Array) return b.concat(a);
if (c === Map) {
var f = new Map(b);
for (var g of a) f.set(g[0], g[1]);
return f;
}
if (c === Set) {
g = new Set(b);
for (f of a.values()) g.add(f);
return g;
}
}
}
return a;
}
return b;
}
return d === "undefined" ? c : a;
}
function aa(a, c) {
return typeof a === "undefined" ? c : a;
}
function I() {
return Object.create(null);
}
function M(a) {
return typeof a === "string";
}
function ba(a) {
return typeof a === "object";
}
function ca(a, c) {
if (M(c)) a = a[c];
else for (let b = 0; a && b < c.length; b++) a = a[c[b]];
return a;
}
const ea = /[^\p{L}\p{N}]+/u, fa = /(\d{3})/g, ha = /(\D)(\d{3})/g, ia = /(\d{3})(\D)/g, ja = /[\u0300-\u036f]/g;
function ka(a = {}) {
if (!this || this.constructor !== ka) return new ka(...arguments);
if (arguments.length) for (a = 0; a < arguments.length; a++) this.assign(arguments[a]);
else this.assign(a);
}
w = ka.prototype;
w.assign = function(a) {
this.normalize = H(a.normalize, true, this.normalize);
let c = a.include, b = c || a.exclude || a.split, e;
if (b || b === "") {
if (typeof b === "object" && b.constructor !== RegExp) {
let d = "";
e = !c;
c || (d += "\\p{Z}");
b.letter && (d += "\\p{L}");
b.number && (d += "\\p{N}", e = !!c);
b.symbol && (d += "\\p{S}");
b.punctuation && (d += "\\p{P}");
b.control && (d += "\\p{C}");
if (b = b.char) d += typeof b === "object" ? b.join("") : b;
try {
this.split = new RegExp("[" + (c ? "^" : "") + d + "]+", "u");
} catch (f) {
this.split = /\s+/;
}
} else this.split = b, e = b === false || "a1a".split(b).length < 2;
this.numeric = H(a.numeric, e);
} else {
try {
this.split = H(this.split, ea);
} catch (d) {
this.split = /\s+/;
}
this.numeric = H(a.numeric, H(this.numeric, true));
}
this.prepare = H(a.prepare, null, this.prepare);
this.finalize = H(a.finalize, null, this.finalize);
b = a.filter;
this.filter = typeof b === "function" ? b : H(b && new Set(b), null, this.filter);
this.dedupe = H(a.dedupe, true, this.dedupe);
this.matcher = H((b = a.matcher) && new Map(b), null, this.matcher);
this.mapper = H((b = a.mapper) && new Map(b), null, this.mapper);
this.stemmer = H(
(b = a.stemmer) && new Map(b),
null,
this.stemmer
);
this.replacer = H(a.replacer, null, this.replacer);
this.minlength = H(a.minlength, 1, this.minlength);
this.maxlength = H(a.maxlength, 1024, this.maxlength);
this.rtl = H(a.rtl, false, this.rtl);
if (this.cache = b = H(a.cache, true, this.cache)) this.F = null, this.L = typeof b === "number" ? b : 2e5, this.B = new Map(), this.D = new Map(), this.I = this.H = 128;
this.h = "";
this.J = null;
this.A = "";
this.K = null;
if (this.matcher) for (const d of this.matcher.keys()) this.h += (this.h ? "|" : "") + d;
if (this.stemmer) for (const d of this.stemmer.keys()) this.A += (this.A ? "|" : "") + d;
return this;
};
w.addStemmer = function(a, c) {
this.stemmer || (this.stemmer = new Map());
this.stemmer.set(a, c);
this.A += (this.A ? "|" : "") + a;
this.K = null;
this.cache && Q(this);
return this;
};
w.addFilter = function(a) {
typeof a === "function" ? this.filter = a : (this.filter || (this.filter = new Set()), this.filter.add(a));
this.cache && Q(this);
return this;
};
w.addMapper = function(a, c) {
if (typeof a === "object") return this.addReplacer(a, c);
if (a.length > 1) return this.addMatcher(a, c);
this.mapper || (this.mapper = new Map());
this.mapper.set(a, c);
this.cache && Q(this);
return this;
};
w.addMatcher = function(a, c) {
if (typeof a === "object") return this.addReplacer(a, c);
if (a.length < 2 && (this.dedupe || this.mapper)) return this.addMapper(a, c);
this.matcher || (this.matcher = new Map());
this.matcher.set(a, c);
this.h += (this.h ? "|" : "") + a;
this.J = null;
this.cache && Q(this);
return this;
};
w.addReplacer = function(a, c) {
if (typeof a === "string") return this.addMatcher(a, c);
this.replacer || (this.replacer = []);
this.replacer.push(a, c);
this.cache && Q(this);
return this;
};
w.encode = function(a, c) {
if (this.cache && a.length <= this.H) if (this.F) {
if (this.B.has(a)) return this.B.get(a);
} else this.F = setTimeout(Q, 50, this);
this.normalize && (typeof this.normalize === "function" ? a = this.normalize(a) : a = ja ? a.normalize("NFKD").replace(ja, "").toLowerCase() : a.toLowerCase());
this.prepare && (a = this.prepare(a));
this.numeric && a.length > 3 && (a = a.replace(ha, "$1 $2").replace(ia, "$1 $2").replace(fa, "$1 "));
const b = !(this.dedupe || this.mapper || this.filter || this.matcher || this.stemmer || this.replacer);
let e = [], d = I(), f, g, k = this.split || this.split === "" ? a.split(this.split) : [a];
for (let l = 0, m, p; l < k.length; l++) if ((m = p = k[l]) && !(m.length < this.minlength || m.length > this.maxlength)) {
if (c) {
if (d[m]) continue;
d[m] = 1;
} else {
if (f === m) continue;
f = m;
}
if (b) e.push(m);
else if (!this.filter || (typeof this.filter === "function" ? this.filter(m) : !this.filter.has(m))) {
if (this.cache && m.length <= this.I) if (this.F) {
var h = this.D.get(m);
if (h || h === "") {
h && e.push(h);
continue;
}
} else this.F = setTimeout(Q, 50, this);
if (this.stemmer) {
this.K || (this.K = new RegExp("(?!^)(" + this.A + ")$"));
let u;
for (; u !== m && m.length > 2; ) u = m, m = m.replace(this.K, (r) => this.stemmer.get(r));
}
if (m && (this.mapper || this.dedupe && m.length > 1)) {
h = "";
for (let u = 0, r = "", t, n; u < m.length; u++) t = m.charAt(u), t === r && this.dedupe || ((n = this.mapper && this.mapper.get(t)) || n === "" ? n === r && this.dedupe || !(r = n) || (h += n) : h += r = t);
m = h;
}
this.matcher && m.length > 1 && (this.J || (this.J = new RegExp("(" + this.h + ")", "g")), m = m.replace(this.J, (u) => this.matcher.get(u)));
if (m && this.replacer) for (h = 0; m && h < this.replacer.length; h += 2) m = m.replace(
this.replacer[h],
this.replacer[h + 1]
);
this.cache && p.length <= this.I && (this.D.set(p, m), this.D.size > this.L && (this.D.clear(), this.I = this.I / 1.1 | 0));
if (m) {
if (m !== p) if (c) {
if (d[m]) continue;
d[m] = 1;
} else {
if (g === m) continue;
g = m;
}
e.push(m);
}
}
}
this.finalize && (e = this.finalize(e) || e);
this.cache && a.length <= this.H && (this.B.set(a, e), this.B.size > this.L && (this.B.clear(), this.H = this.H / 1.1 | 0));
return e;
};
function Q(a) {
a.F = null;
a.B.clear();
a.D.clear();
}
function la(a, c, b) {
b || (c || typeof a !== "object" ? typeof c === "object" && (b = c, c = 0) : b = a);
b && (a = b.query || a, c = b.limit || c);
let e = "" + (c || 0);
b && (e += (b.offset || 0) + !!b.context + !!b.suggest + (b.resolve !== false) + (b.resolution || this.resolution) + (b.boost || 0));
a = ("" + a).toLowerCase();
this.cache || (this.cache = new ma());
let d = this.cache.get(a + e);
if (!d) {
const f = b && b.cache;
f && (b.cache = false);
d = this.search(a, c, b);
f && (b.cache = f);
this.cache.set(a + e, d);
}
return d;
}
function ma(a) {
this.limit = a && a !== true ? a : 1e3;
this.cache = new Map();
this.h = "";
}
ma.prototype.set = function(a, c) {
this.cache.set(this.h = a, c);
this.cache.size > this.limit && this.cache.delete(this.cache.keys().next().value);
};
ma.prototype.get = function(a) {
const c = this.cache.get(a);
c && this.h !== a && (this.cache.delete(a), this.cache.set(this.h = a, c));
return c;
};
ma.prototype.remove = function(a) {
for (const c of this.cache) {
const b = c[0];
c[1].includes(a) && this.cache.delete(b);
}
};
ma.prototype.clear = function() {
this.cache.clear();
this.h = "";
};
const na = { normalize: false, numeric: false, dedupe: false };
const oa = {};
const ra = new Map([["b", "p"], ["v", "f"], ["w", "f"], ["z", "s"], ["x", "s"], ["d", "t"], ["n", "m"], ["c", "k"], ["g", "k"], ["j", "k"], ["q", "k"], ["i", "e"], ["y", "e"], ["u", "o"]]);
const sa = new Map([["ae", "a"], ["oe", "o"], ["sh", "s"], ["kh", "k"], ["th", "t"], ["ph", "f"], ["pf", "f"]]), ta = [/([^aeo])h(.)/g, "$1$2", /([aeo])h([^aeo]|$)/g, "$1$2", /(.)\1+/g, "$1"];
const ua = { a: "", e: "", i: "", o: "", u: "", y: "", b: 1, f: 1, p: 1, v: 1, c: 2, g: 2, j: 2, k: 2, q: 2, s: 2, x: 2, z: 2, "ß": 2, d: 3, t: 3, l: 4, m: 5, n: 5, r: 6 };
var va = { Exact: na, Default: oa, Normalize: oa, LatinBalance: { mapper: ra }, LatinAdvanced: { mapper: ra, matcher: sa, replacer: ta }, LatinExtra: { mapper: ra, replacer: ta.concat([/(?!^)[aeo]/g, ""]), matcher: sa }, LatinSoundex: { dedupe: false, include: { letter: true }, finalize: function(a) {
for (let b = 0; b < a.length; b++) {
var c = a[b];
let e = c.charAt(0), d = ua[e];
for (let f = 1, g; f < c.length && (g = c.charAt(f), g === "h" || g === "w" || !(g = ua[g]) || g === d || (e += g, d = g, e.length !== 4)); f++) ;
a[b] = e;
}
} }, CJK: { split: "" }, LatinExact: na, LatinDefault: oa, LatinSimple: oa };
function wa(a, c, b, e) {
let d = [];
for (let f = 0, g; f < a.index.length; f++) if (g = a.index[f], c >= g.length) c -= g.length;
else {
c = g[e ? "splice" : "slice"](c, b);
const k = c.length;
if (k && (d = d.length ? d.concat(c) : c, b -= k, e && (a.length -= k), !b)) break;
c = 0;
}
return d;
}
function xa(a) {
if (!this || this.constructor !== xa) return new xa(a);
this.index = a ? [a] : [];
this.length = a ? a.length : 0;
const c = this;
return new Proxy([], { get(b, e) {
if (e === "length") return c.length;
if (e === "push") return function(d) {
c.index[c.index.length - 1].push(d);
c.length++;
};
if (e === "pop") return function() {
if (c.length) return c.length--, c.index[c.index.length - 1].pop();
};
if (e === "indexOf") return function(d) {
let f = 0;
for (let g = 0, k, h; g < c.index.length; g++) {
k = c.index[g];
h = k.indexOf(d);
if (h >= 0) return f + h;
f += k.length;
}
return -1;
};
if (e === "includes") return function(d) {
for (let f = 0; f < c.index.length; f++) if (c.index[f].includes(d)) return true;
return false;
};
if (e === "slice") return function(d, f) {
return wa(c, d || 0, f || c.length, false);
};
if (e === "splice") return function(d, f) {
return wa(c, d || 0, f || c.length, true);
};
if (e === "constructor") return Array;
if (typeof e !== "symbol") return (b = c.index[e / __pow(2, 31) | 0]) && b[e];
}, set(b, e, d) {
b = e / __pow(2, 31) | 0;
(c.index[b] || (c.index[b] = []))[e] = d;
c.length++;
return true;
} });
}
xa.prototype.clear = function() {
this.index.length = 0;
};
xa.prototype.push = function() {
};
function R(a = 8) {
if (!this || this.constructor !== R) return new R(a);
this.index = I();
this.h = [];
this.size = 0;
a > 32 ? (this.B = Aa, this.A = BigInt(a)) : (this.B = Ba, this.A = a);
}
R.prototype.get = function(a) {
const c = this.index[this.B(a)];
return c && c.get(a);
};
R.prototype.set = function(a, c) {
var b = this.B(a);
let e = this.index[b];
e ? (b = e.size, e.set(a, c), (b -= e.size) && this.size++) : (this.index[b] = e = new Map([[a, c]]), this.h.push(e), this.size++);
};
function S(a = 8) {
if (!this || this.constructor !== S) return new S(a);
this.index = I();
this.h = [];
this.size = 0;
a > 32 ? (this.B = Aa, this.A = BigInt(a)) : (this.B = Ba, this.A = a);
}
S.prototype.add = function(a) {
var c = this.B(a);
let b = this.index[c];
b ? (c = b.size, b.add(a), (c -= b.size) && this.size++) : (this.index[c] = b = new Set([a]), this.h.push(b), this.size++);
};
w = R.prototype;
w.has = S.prototype.has = function(a) {
const c = this.index[this.B(a)];
return c && c.has(a);
};
w.delete = S.prototype.delete = function(a) {
const c = this.index[this.B(a)];
c && c.delete(a) && this.size--;
};
w.clear = S.prototype.clear = function() {
this.index = I();
this.h = [];
this.size = 0;
};
w.values = S.prototype.values = function* () {
for (let a = 0; a < this.h.length; a++) for (let c of this.h[a].values()) yield c;
};
w.keys = S.prototype.keys = function* () {
for (let a = 0; a < this.h.length; a++) for (let c of this.h[a].keys()) yield c;
};
w.entries = S.prototype.entries = function* () {
for (let a = 0; a < this.h.length; a++) for (let c of this.h[a].entries()) yield c;
};
function Ba(a) {
let c = __pow(2, this.A) - 1;
if (typeof a == "number") return a & c;
let b = 0, e = this.A + 1;
for (let d = 0; d < a.length; d++) b = (b * e ^ a.charCodeAt(d)) & c;
return this.A === 32 ? b + __pow(2, 31) : b;
}
function Aa(a) {
let c = __pow(BigInt(2), this.A) - BigInt(1);
var b = typeof a;
if (b === "bigint") return a & c;
if (b === "number") return BigInt(a) & c;
b = BigInt(0);
let e = this.A + BigInt(1);
for (let d = 0; d < a.length; d++) b = (b * e ^ BigInt(a.charCodeAt(d))) & c;
return b;
}
let Ca, Da;
function Ea(a) {
return __async(this, null, function* () {
a = a.data;
var c = a.task;
const b = a.id;
let e = a.args;
switch (c) {
case "init":
Da = a.options || {};
(c = a.factory) ? (Function("return " + c)()(self), Ca = new self.FlexSearch.Index(Da), delete self.FlexSearch) : Ca = new T(Da);
postMessage({ id: b });
break;
default:
let d;
c === "export" && (e[1] ? (e[0] = Da.export, e[2] = 0, e[3] = 1) : e = null);
c === "import" ? e[0] && (a = yield Da.import.call(Ca, e[0]), Ca.import(e[0], a)) : ((d = e && Ca[c].apply(Ca, e)) && d.then && (d = yield d), d && d.await && (d = yield d.await), c === "search" && d.result && (d = d.result));
postMessage(c === "search" ? { id: b, msg: d } : { id: b });
}
});
}
function Fa(a) {
Ga.call(a, "add");
Ga.call(a, "append");
Ga.call(a, "search");
Ga.call(a, "update");
Ga.call(a, "remove");
Ga.call(a, "searchCache");
}
let Ha, Ia, Ja;
function Ka() {
Ha = Ja = 0;
}
function Ga(a) {
this[a + "Async"] = function() {
const c = arguments;
var b = c[c.length - 1];
let e;
typeof b === "function" && (e = b, delete c[c.length - 1]);
Ha ? Ja || (Ja = Date.now() - Ia >= this.priority * this.priority * 3) : (Ha = setTimeout(Ka, 0), Ia = Date.now());
if (Ja) {
const f = this;
return new Promise((g) => {
setTimeout(function() {
g(f[a + "Async"].apply(f, c));
}, 0);
});
}
const d = this[a].apply(this, c);
b = d.then ? d : new Promise((f) => f(d));
e && b.then(e);
return b;
};
}
let V = 0;
function La(a = {}, c) {
function b(k) {
function h(l) {
l = l.data || l;
const m = l.id, p = m && f.h[m];
p && (p(l.msg), delete f.h[m]);
}
this.worker = k;
this.h = I();
if (this.worker) {
d ? this.worker.on("message", h) : this.worker.onmessage = h;
if (a.config) return new Promise(function(l) {
V > 1e9 && (V = 0);
f.h[++V] = function() {
l(f);
};
f.worker.postMessage({ id: V, task: "init", factory: e, options: a });
});
this.priority = a.priority || 4;
this.encoder = c || null;
this.worker.postMessage({ task: "init", factory: e, options: a });
return this;
}
}
if (!this || this.constructor !== La) return new La(a);
let e = typeof self !== "undefined" ? self._factory : typeof window !== "undefined" ? window._factory : null;
e && (e = e.toString());
const d = typeof window === "undefined", f = this, g = Ma(e, d, a.worker);
return g.then ? g.then(function(k) {
return b.call(f, k);
}) : b.call(this, g);
}
W("add");
W("append");
W("search");
W("update");
W("remove");
W("clear");
W("export");
W("import");
La.prototype.searchCache = la;
Fa(La.prototype);
function W(a) {
La.prototype[a] = function() {
const c = this, b = [].slice.call(arguments);
var e = b[b.length - 1];
let d;
typeof e === "function" && (d = e, b.pop());
e = new Promise(function(f) {
a === "export" && typeof b[0] === "function" && (b[0] = null);
V > 1e9 && (V = 0);
c.h[++V] = f;
c.worker.postMessage({ task: a, id: V, args: b });
});
return d ? (e.then(d), this) : e;
};
}
function Ma(a, c, b) {
return c ? typeof module !== "undefined" ? new (require("worker_threads"))["Worker"](__dirname + "/worker/node.js") : __vitePreload(() => module.import('./__vite-browser-external-2Ng8QIWW-Xya9USxv.js'), void 0 ).then(function(worker) {
return new worker["Worker"](module.meta.dirname + "/node/node.mjs");
}) : a ? new window.Worker(URL.createObjectURL(new Blob(["onmessage=" + Ea.toString()], { type: "text/javascript" }))) : new window.Worker(typeof b === "string" ? b : module.meta.url.replace("/worker.js", "/worker/worker.js").replace(
"flexsearch.bundle.module.min.js",
"module/worker/worker.js"
).replace("flexsearch.bundle.module.min.mjs", "module/worker/worker.js"), { type: "module" });
}
Na.prototype.add = function(a, c, b) {
ba(a) && (c = a, a = ca(c, this.key));
if (c && (a || a === 0)) {
if (!b && this.reg.has(a)) return this.update(a, c);
for (let k = 0, h; k < this.field.length; k++) {
h = this.B[k];
var e = this.index.get(this.field[k]);
if (typeof h === "function") {
var d = h(c);
d && e.add(a, d, b, true);
} else if (d = h.G, !d || d(c)) h.constructor === String ? h = ["" + h] : M(h) && (h = [h]), Qa(c, h, this.D, 0, e, a, h[0], b);
}
if (this.tag) for (e = 0; e < this.A.length; e++) {
var f = this.A[e];
d = this.tag.get(this.F[e]);
let k = I();
if (typeof f === "function") {
if (f = f(c), !f) continue;
} else {
var g = f.G;
if (g && !g(c)) continue;
f.constructor === String && (f = "" + f);
f = ca(c, f);
}
if (d && f) {
M(f) && (f = [f]);
for (let h = 0, l, m; h < f.length; h++) if (l = f[h], !k[l] && (k[l] = 1, (g = d.get(l)) ? m = g : d.set(l, m = []), !b || !m.includes(a))) {
if (m.length === __pow(2, 31) - 1) {
g = new xa(m);
if (this.fastupdate) for (let p of this.reg.values()) p.includes(m) && (p[p.indexOf(m)] = g);
d.set(l, m = g);
}
m.push(a);
this.fastupdate && ((g = this.reg.get(a)) ? g.push(m) : this.reg.set(a, [m]));
}
}
}
if (this.store && (!b || !this.store.has(a))) {
let k;
if (this.h) {
k = I();
for (let h = 0, l; h < this.h.length; h++) {
l = this.h[h];
if ((b = l.G) && !b(c)) continue;
let m;
if (typeof l === "function") {
m = l(c);
if (!m) continue;
l = [l.O];
} else if (M(l) || l.constructor === String) {
k[l] = c[l];
continue;
}
Ra(c, k, l, 0, l[0], m);
}
}
this.store.set(a, k || c);
}
this.worker && (this.fastupdate || this.reg.add(a));
}
return this;
};
function Ra(a, c, b, e, d, f) {
a = a[d];
if (e === b.length - 1) c[d] = f || a;
else if (a) if (a.constructor === Array) for (c = c[d] = Array(a.length), d = 0; d < a.length; d++) Ra(a, c, b, e, d);
else c = c[d] || (c[d] = I()), d = b[++e], Ra(a, c, b, e, d);
}
function Qa(a, c, b, e, d, f, g, k) {
if (a = a[g]) if (e === c.length - 1) {
if (a.constructor === Array) {
if (b[e]) {
for (c = 0; c < a.length; c++) d.add(f, a[c], true, true);
return;
}
a = a.join(" ");
}
d.add(f, a, k, true);
} else if (a.constructor === Array) for (g = 0; g < a.length; g++) Qa(a, c, b, e, d, f, g, k);
else g = c[++e], Qa(a, c, b, e, d, f, g, k);
}
function Sa(a, c, b, e) {
if (!a.length) return a;
if (a.length === 1) return a = a[0], a = b || a.length > c ? a.slice(b, b + c) : a, e ? Ta.call(this, a) : a;
let d = [];
for (let f = 0, g, k; f < a.length; f++) if ((g = a[f]) && (k = g.length)) {
if (b) {
if (b >= k) {
b -= k;
continue;
}
g = g.slice(b, b + c);
k = g.length;
b = 0;
}
k > c && (g = g.slice(0, c), k = c);
if (!d.length && k >= c) return e ? Ta.call(this, g) : g;
d.push(g);
c -= k;
if (!c) break;
}
d = d.length > 1 ? [].concat.apply([], d) : d[0];
return e ? Ta.call(this, d) : d;
}
function Ua(a, c, b, e) {
var d = e[0];
if (d[0] && d[0].query) return a[c].apply(a, d);
if (!(c !== "and" && c !== "not" || a.result.length || a.await || d.suggest)) return e.length > 1 && (d = e[e.length - 1]), (e = d.resolve) ? a.await || a.result : a;
let f = [], g = 0, k = 0, h, l, m, p, u;
for (c = 0; c < e.length; c++) if (d = e[c]) {
var r = void 0;
if (d.constructor === X) r = d.await || d.result;
else if (d.then || d.constructor === Array) r = d;
else {
g = d.limit || 0;
k = d.offset || 0;
m = d.suggest;
l = d.resolve;
h = ((p = d.highlight || a.highlight) || d.enrich) && l;
r = d.queue;
let t = d.async || r, n = d.index, q = d.query;
n ? a.index || (a.index = n) : n = a.index;
if (q || d.tag) {
const x = d.field || d.pluck;
x && (!q || a.query && !p || (a.query = q, a.field = x, a.highlight = p), n = n.index.get(x));
if (r && (u || a.await)) {
u = 1;
let v;
const A = a.C.length, D = new Promise(function(F) {
v = F;
});
(function(F, E) {
D.h = function() {
E.index = null;
E.resolve = false;
let B = t ? F.searchAsync(E) : F.search(E);
if (B.then) return B.then(function(z) {
a.C[A] = z = z.result || z;
v(z);
return z;
});
B = B.result || B;
v(B);
return B;
};
})(n, Object.assign({}, d));
a.C.push(D);
f[c] = D;
continue;
} else d.resolve = false, d.index = null, r = t ? n.searchAsync(d) : n.search(d), d.resolve = l, d.index = n;
} else if (d.and) r = Va(d, "and", n);
else if (d.or) r = Va(d, "or", n);
else if (d.not) r = Va(d, "not", n);
else if (d.xor) r = Va(d, "xor", n);
else continue;
}
r.await ? (u = 1, r = r.await) : r.then ? (u = 1, r = r.then(function(t) {
return t.result || t;
})) : r = r.result || r;
f[c] = r;
}
u && !a.await && (a.await = new Promise(function(t) {
a.return = t;
}));
if (u) {
const t = Promise.all(f).then(function(n) {
for (let q = 0; q < a.C.length; q++) if (a.C[q] === t) {
a.C[q] = function() {
return b.call(a, n, g, k, h, l, m, p);
};
break;
}
Wa(a);
});
a.C.push(t);
} else if (a.await) a.C.push(function() {
return b.call(a, f, g, k, h, l, m, p);
});
else return b.call(a, f, g, k, h, l, m, p);
return l ? a.await || a.result : a;
}
function Va(a, c, b) {
a = a[c];
const e = a[0] || a;
e.index || (e.index = b);
b = new X(e);
a.length > 1 && (b = b[c].apply(b, a.slice(1)));
return b;
}
X.prototype.or = function() {
return Ua(this, "or", Xa, arguments);
};
function Xa(a, c, b, e, d, f, g) {
a.length && (this.result.length && a.push(this.result), a.length < 2 ? this.result = a[0] : (this.result = Ya(a, c, b, false, this.h), b = 0));
d && (this.await = null);
return d ? this.resolve(c, b, e, g) : this;
}
X.prototype.and = function() {
return Ua(this, "and", Za, arguments);
};
function Za(a, c, b, e, d, f, g) {
if (!f && !this.result.length) return d ? this.result : this;
let k;
if (a.length) if (this.result.length && a.unshift(this.result), a.length < 2) this.result = a[0];
else {
let h = 0;
for (let l = 0, m, p; l < a.length; l++) if ((m = a[l]) && (p = m.length)) h < p && (h = p);
else if (!f) {
h = 0;
break;
}
h ? (this.result = $a(a, h, c, b, f, this.h, d), k = true) : this.result = [];
}
else f || (this.result = a);
d && (this.await = null);
return d ? this.resolve(c, b, e, g, k) : this;
}
X.prototype.xor = function() {
return Ua(this, "xor", ab, arguments);
};
function ab(a, c, b, e, d, f, g) {
if (a.length) if (this.result.length && a.unshift(this.result), a.length < 2) this.result = a[0];
else {
a: {
f = b;
var k = this.h;
const h = [], l = I();
let m = 0;
for (let p = 0, u; p < a.length; p++) if (u = a[p]) {
m < u.length && (m = u.length);
for (let r = 0, t; r < u.length; r++) if (t = u[r]) for (let n = 0, q; n < t.length; n++) q = t[n], l[q] = l[q] ? 2 : 1;
}
for (let p = 0, u, r = 0; p < m; p++) for (let t = 0, n; t < a.length; t++) if (n = a[t]) {
if (u = n[p]) {
for (let q = 0, x; q < u.length; q++) if (x = u[q], l[x] === 1) if (f) f--;
else if (d) {
if (h.push(x), h.length === c) {
a = h;
break a;
}
} else {
const v = p + (t ? k : 0);
h[v] || (h[v] = []);
h[v].push(x);
if (++r === c) {
a = h;
break a;
}
}
}
}
a = h;
}
this.result = a;
k = true;
}
else f || (this.result = a);
d && (this.await = null);
return d ? this.resolve(c, b, e, g, k) : this;
}
X.prototype.not = function() {
return Ua(this, "not", bb, arguments);
};
function bb(a, c, b, e, d, f, g) {
if (!f && !this.result.length) return d ? this.result : this;
if (a.length && this.result.length) {
a: {
f = b;
var k = [];
a = new Set(a.flat().flat());
for (let h = 0, l, m = 0; h < this.result.length; h++) if (l = this.result[h]) {
for (let p = 0, u; p < l.length; p++) if (u = l[p], !a.has(u)) {
if (f) f--;
else if (d) {
if (k.push(u), k.length === c) {
a = k;
break a;
}
} else if (k[h] || (k[h] = []), k[h].push(u), ++m === c) {
a = k;
break a;
}
}
}
a = k;
}
this.result = a;
k = true;
}
d && (this.await = null);
return d ? this.resolve(c, b, e, g, k) : this;
}
function cb(a, c, b, e, d) {
let f, g, k;
typeof d === "string" ? (f = d, d = "") : f = d.template;
g = f.indexOf("$1");
k = f.substring(g + 2);
g = f.substring(0, g);
let h = d && d.boundary, l = !d || d.clip !== false, m = d && d.merge && k && g && new RegExp(k + " " + g, "g");
d = d && d.ellipsis;
var p = 0;
if (typeof d === "object") {
var u = d.template;
p = u.length - 2;
d = d.pattern;
}
typeof d !== "string" && (d = d === false ? "" : "...");
p && (d = u.replace("$1", d));
u = d.length - p;
let r, t;
typeof h === "object" && (r = h.before, r === 0 && (r = -1), t = h.after, t === 0 && (t = -1), h = h.total || 9e5);
p = new Map();
for (let Oa = 0, da, db, pa; Oa < c.length; Oa++) {
let qa;
if (e) qa = c, pa = e;
else {
var n = c[Oa];
pa = n.field;
if (!pa) continue;
qa = n.result;
}
db = b.get(pa);
da = db.encoder;
n = p.get(da);
typeof n !== "string" && (n = da.encode(a), p.set(da, n));
for (let ya = 0; ya < qa.length; ya++) {
var q = qa[ya].doc;
if (!q) continue;
q = ca(q, pa);
if (!q) continue;
var x = q.trim().split(/\s+/);
if (!x.length) continue;
q = "";
var v = [];
let za = [];
var A = -1, D = -1, F = 0;
for (var E = 0; E < x.length; E++) {
var B = x[E], z = da.encode(B);
z = z.length > 1 ? z.join(" ") : z[0];
let y;
if (z && B) {
var C = B.length, J = (da.split ? B.replace(da.split, "") : B).length - z.length, G = "", N = 0;
for (var O = 0; O < n.length; O++) {
var P = n[O];
if (P) {
var L = P.length;
L += J < 0 ? 0 : J;
N && L <= N || (P = z.indexOf(P), P > -1 && (G = (P ? B.substring(0, P) : "") + g + B.substring(P, P + L) + k + (P + L < C ? B.substring(P + L) : ""), N = L, y = true));
}
}
G && (h && (A < 0 && (A = q.length + (q ? 1 : 0)), D = q.length + (q ? 1 : 0) + G.length, F += C, za.push(v.length), v.push({ match: G })), q += (q ? " " : "") + G);
}
if (!y) B = x[E], q += (q ? " " : "") + B, h && v.push({ text: B });
else if (h && F >= h) break;
}
F = za.length * (f.length - 2);
if (r || t || h && q.length - F > h) if (F = h + F - u * 2, E = D - A, r > 0 && (E += r), t > 0 && (E += t), E <= F) x = r ? A - (r > 0 ? r : 0) : A - ((F - E) / 2 | 0), v = t ? D + (t > 0 ? t : 0) : x + F, l || (x > 0 && q.charAt(x) !== " " && q.charAt(x - 1) !== " " && (x = q.indexOf(" ", x), x < 0 && (x = 0)), v < q.length && q.charAt(v - 1) !== " " && q.charAt(v) !== " " && (v = q.lastIndexOf(" ", v), v < D ? v = D : ++v)), q = (x ? d : "") + q.substring(x, v) + (v < q.length ? d : "");
else {
D = [];
A = {};
F = {};
E = {};
B = {};
z = {};
G = J = C = 0;
for (O = N = 1; ; ) {
var U = void 0;
for (let y = 0, K; y < za.length; y++) {
K = za[y];
if (G) if (J !== G) {
if (E[y + 1]) continue;
K += G;
if (A[K]) {
C -= u;
F[y + 1] = 1;
E[y + 1] = 1;
continue;
}
if (K >= v.length - 1) {
if (K >= v.length) {
E[y + 1] = 1;
K >= x.length && (F[y + 1] = 1);
continue;
}
C -= u;
}
q = v[K].text;
if (L = t && z[y]) if (L > 0) {
if (q.length > L) if (E[y + 1] = 1, l) q = q.substring(0, L);
else continue;
(L -= q.length) || (L = -1);
z[y] = L;
} else {
E[y + 1] = 1;
continue;
}
if (C + q.length + 1 <= h) q = " " + q, D[y] += q;
else if (l) U = h - C - 1, U > 0 && (q = " " + q.substring(0, U), D[y] += q), E[y + 1] = 1;
else {
E[y + 1] = 1;
continue;
}
} else {
if (E[y]) continue;
K -= J;
if (A[K]) {
C -= u;
E[y] = 1;
F[y] = 1;
continue;
}
if (K <= 0) {
if (K < 0) {
E[y] = 1;
F[y] = 1;
continue;
}
C -= u;
}
q = v[K].text;
if (L = r && B[y]) if (L > 0) {
if (q.length > L) if (E[y] = 1, l) q = q.substring(q.length - L);
else continue;
(L -= q.length) || (L = -1);
B[y] = L;
} else {
E[y] = 1;
continue;
}
if (C + q.length + 1 <= h) q += " ", D[y] = q + D[y];
else if (l) U = q.length + 1 - (h - C), U >= 0 && U < q.length && (q = q.substring(U) + " ", D[y] = q + D[y]), E[y] = 1;
else {
E[y] = 1;
continue;
}
}
else {
q = v[K].match;
r && (B[y] = r);
t && (z[y] = t);
y && C++;
let Pa;
K ? !y && u && (C += u) : (F[y] = 1, E[y] = 1);
K >= x.length - 1 ? Pa = 1 : K < v.length - 1 && v[K + 1].match ? Pa = 1 : u && (C += u);
C -= f.length - 2;
if (!y || C + q.length <= h) D[y] = q;
else {
U = N = O = F[y] = 0;
break;
}
Pa && (F[y + 1] = 1, E[y + 1] = 1);
}
C += q.length;
U = A[K] = 1;
}
if (U) J === G ? G++ : J++;
else {
J === G ? N = 0 : O = 0;
if (!N && !O) break;
N ? (J++, G = J) : G++;
}
}
q = "";
for (let y = 0, K; y < D.length; y++) K = (F[y] ? y ? " " : "" : (y && !d ? " " : "") + d) + D[y], q += K;
d && !F[D.length] && (q += d);
}
m && (q = q.replace(m, " "));
qa[ya].highlight = q;
}
if (e) break;
}
return c;
}
function X(a, c) {
if (!this || this.constructor !== X) return new X(a, c);
let b = 0, e, d, f, g, k, h;
if (a && a.index) {
const l = a;
c = l.index;
b = l.boost || 0;
if (d = l.query) {
f = l.field || l.pluck;
g = l.highlight;
const m = l.resolve;
a = l.async || l.queue;
l.resolve = false;
l.index = null;
a = a ? c.searchAsync(l) : c.search(l);
l.resolve = m;
l.index = c;
a = a.result || a;
} else a = [];
}
if (a && a.then) {
const l = this;
a = a.then(function(m) {
l.C[0] = l.result = m.result || m;
Wa(l);
});
e = [a];
a = [];
k = new Promise(function(m) {
h = m;
});
}
this.index = c || null;
this.result = a || [];
this.h = b;
this.C = e || [];
this.await = k || null;
this.return = h || null;
this.highlight = g || null;
this.query = d || "";
this.field = f || "";
}
w = X.prototype;
w.limit = function(a) {
if (this.await) {
const c = this;
this.C.push(function() {
return c.limit(a).result;
});
} else if (this.result.length) {
const c = [];
for (let b = 0, e; b < this.result.length; b++) if (e = this.result[b]) if (e.length <= a) {
if (c[b] = e, a -= e.length, !a) break;
} else {
c[b] = e.slice(0, a);
break;
}
this.result = c;
}
return this;
};
w.offset = function(a) {
if (this.await) {
const c = this;
this.C.push(function() {
return c.offset(a).result;
});
} else if (this.result.length) {
const c = [];
for (let b = 0, e; b < this.result.length; b++) if (e = this.result[b]) e.length <= a ? a -= e.length : (c[b] = e.slice(a), a = 0);
this.result = c;
}
return this;
};
w.boost = function(a) {
if (this.await) {
const c = this;
this.C.push(function() {
return c.boost(a).result;
});
} else this.h += a;
return this;
};
function Wa(a, c) {
let b = a.result;
var e = a.await;
a.await = null;
for (let d = 0, f; d < a.C.length; d++) if (f = a.C[d]) {
if (typeof f === "function") b = f(), a.C[d] = b = b.result || b, d--;
else if (f.h) b = f.h(), a.C[d] = b = b.result || b, d--;
else if (f.then) return a.await = e;
}
e = a.return;
a.C = [];
a.return = null;
c || e(b);
return b;
}
w.resolve = function(a, c, b, e, d) {
let f = this.await ? Wa(this, true) : this.result;
if (f.then) {
const g = this;
return f.then(function() {
return g.resolve(a, c, b, e, d);
});
}
f.length && (typeof a === "object" ? (e = a.highlight || this.highlight, b = !!e || a.enrich, c = a.offset, a = a.limit) : (e = e || this.highlight, b = !!e || b), f = d ? b ? Ta.call(this.index, f) : f : Sa.call(this.index, f, a || 100, c, b));
return this.finalize(f, e);
};
w.finalize = function(a, c) {
if (a.then) {
const e = this;
return a.then(function(d) {
return e.finalize(d, c);
});
}
c && a.length && this.query && (a = cb(this.query, a, this.index.index, this.field, c));
const b = this.return;
this.highlight = this.index = this.result = this.C = this.await = this.return = null;
this.query = this.field = "";
b && b(a);
return a;
};
function $a(a, c, b, e, d, f, g) {
const k = a.length;
let h = [], l, m;
l = I();
for (let p = 0, u, r, t, n; p < c; p++) for (let q = 0; q < k; q++) if (t = a[q], p < t.length && (u = t[p])) for (let x = 0; x < u.length; x++) {
r = u[x];
(m = l[r]) ? l[r]++ : (m = 0, l[r] = 1);
n = h[m] || (h[m] = []);
if (!g) {
let v = p + (q || !d ? 0 : f || 0);
n = n[v] || (n[v] = []);
}
n.push(r);
if (g && b && m === k - 1 && n.length - e === b) return e ? n.slice(e) : n;
}
if (a = h.length) if (d) h = h.length > 1 ? Ya(h, b, e, g, f) : (h = h[0]) && b && h.length > b || e ? h.slice(e, b + e) : h;
else {
if (a < k) return [];
h = h[a - 1];
if (b || e) if (g) {
if (h.length > b || e) h = h.slice(e, b + e);
} else {
d = [];
for (let p = 0, u; p < h.length; p++) if (u = h[p]) if (e && u.length > e) e -= u.length;
else {
if (b && u.length > b || e) u = u.slice(e, b + e), b -= u.length, e && (e -= u.length);
d.push(u);
if (!b) break;
}
h = d;
}
}
return h;
}
function Ya(a, c, b, e, d) {
const f = [], g = I();
let k;
var h = a.length;
let l;
if (e) for (d = h - 1; d >= 0; d--) {
if (l = (e = a[d]) && e.length) {
for (h = 0; h < l; h++) if (k = e[h], !g[k]) {
if (g[k] = 1, b) b--;
else if (f.push(k), f.length === c) return f;
}
}
}
else for (let m = h - 1, p, u = 0; m >= 0; m--) {
p = a[m];
for (let r = 0; r < p.length; r++) if (l = (e = p[r]) && e.length) {
for (let t = 0; t < l; t++) if (k = e[t], !g[k]) if (g[k] = 1, b) b--;
else {
let n = (r + (m < h - 1 ? d || 0 : 0)) / (m + 1) | 0;
(f[n] || (f[n] = [])).push(k);
if (++u === c) return f;
}
}
}
return f;
}
function eb(a, c, b, e, d) {
const f = I(), g = [];
for (let k = 0, h; k < c.length; k++) {
h = c[k];
for (let l = 0; l < h.length; l++) f[h[l]] = 1;
}
if (d) for (let k = 0, h; k < a.length; k++) {
if (h = a[k], f[h]) {
if (e) e--;
else if (g.push(h), f[h] = 0, b && --b === 0) break;
}
}
else for (let k = 0, h, l; k < a.result.length; k++) for (h = a.result[k], c = 0; c < h.length; c++) l = h[c], f[l] && ((g[k] || (g[k] = [])).push(l), f[l] = 0);
return g;
}
Na.prototype.search = function(a, c, b, e) {
b || (!c && ba(a) ? (b = a, a = "") : ba(c) && (b = c, c = 0));
let d = [];
var f = [];
let g;
let k, h, l, m, p;
let u = 0, r = true, t;
if (b) {
b.constructor === Array && (b = { index: b });
a = b.query || a;
g = b.pluck;
k = b.merge;
l = b.boost;
p = g || b.field || (p = b.index) && (p.index ? null : p);
var n = this.tag && b.tag;
h = b.suggest;
r = b.resolve !== false;
m = b.cache;
t = r && this.store && b.highlight;
var q = !!t || r && this.store && b.enrich;
c = b.limit || c;
var x = b.offset || 0;
c || (c = r ? 100 : 0);
if (n && (!this.db || !e)) {
n.constructor !== Array && (n = [n]);
var v = [];
for (let B = 0, z; B < n.length; B++) if (z = n[B], z.field && z.tag) {
var A = z.tag;
if (A.constructor === Array) for (var D = 0; D < A.length; D++) v.push(z.field, A[D]);
else v.push(z.field, A);
} else {
A = Object.keys(z);
for (let C = 0, J, G; C < A.length; C++) if (J = A[C], G = z[J], G.constructor === Array) for (D = 0; D < G.length; D++) v.push(J, G[D]);
else v.push(J, G);
}
n = v;
if (!a) {
f = [];
if (v.length) for (n = 0; n < v.length; n += 2) {
if (this.db) {
e = this.index.get(v[n]);
if (!e) continue;
f.push(e = e.db.tag(v[n + 1], c, x, q));
} else e = fb.call(this, v[n], v[n + 1], c, x, q);
d.push(r ? { field: v[n], tag: v[n + 1], result: e } : [e]);
}
if (f.length) {
const B = this;
return Promise.all(f).then(function(z) {
for (let C = 0; C < z.length; C++) r ? d[C].result = z[C] : d[C] = z[C];
return r ? d : new X(d.length > 1 ? $a(d, 1, 0, 0, h, l) : d[0], B);
});
}
return r ? d : new X(d.length > 1 ? $a(d, 1, 0, 0, h, l) : d[0], this);
}
}
r || g || !(p = p || this.field) || (M(p) ? g = p : (p.constructor === Array && p.length === 1 && (p = p[0]), g = p.field || p.index));
p && p.constructor !== Array && (p = [p]);
}
p || (p = this.field);
let F;
v = (this.worker || this.db) && !e && [];
for (let B = 0, z, C, J; B < p.length; B++) {
C = p[B];
if (this.db && this.tag && !this.B[B]) continue;
let G;
M(C) || (G = C, C = G.field, a = G.query || a, c = aa(G.limit, c), x = aa(G.offset, x), h = aa(G.suggest, h), t = r && this.store && aa(G.highlight, t), q = !!t || r && this.store && aa(G.enrich, q), m = aa(G.cache, m));
if (e) z = e[B];
else {
A = G || b || {};
D = A.enrich;
var E = this.index.get(C);
n && (this.db && (A.tag = n, A.field = p, F = E.db.support_tag_search), !F && D && (A.enrich = false), F || (A.limit = 0, A.offset = 0));
z = m ? E.searchCache(a, n && !F ? 0 : c, A) : E.search(a, n && !F ? 0 : c, A);
n && !F && (A.limit = c, A.offset = x);
D && (A.enrich = D);
if (v) {
v[B] = z;
continue;
}
}
J = (z = z.result || z) && z.length;
if (n && J) {
A = [];
D = 0;
if (this.db && e) {
if (!F) for (E = p.length; E < e.length; E++) {
let N = e[E];
if (N && N.length) D++, A.push(N);
else if (!h) return r ? d : new X(d, this);
}
} else for (let N = 0, O, P; N < n.length; N += 2) {
O = this.tag.get(n[N]);
if (!O) if (h) continue;
else return r ? d : new X(d, this);
if (P = (O = O && O.get(n[N + 1])) && O.length) D++, A.push(O);
else if (!h) return r ? d : new X(d, this);
}
if (D) {
z = eb(z, A, c, x, r);
J = z.length;
if (!J && !h) return r ? z : new X(z, this);
D--;
}
}
if (J) f[u] = C, d.push(z), u++;
else if (p.length === 1) return r ? d : new X(
d,
this
);
}
if (v) {
if (this.db && n && n.length && !F) for (q = 0; q < n.length; q += 2) {
f = this.index.get(n[q]);
if (!f) if (h) continue;
else return r ? d : new X(d, this);
v.push(f.db.tag(n[q + 1], c, x, false));
}
const B = this;
return Promise.all(v).then(function(z) {
b && (b.resolve = r);
z.length && (z = B.search(a, c, b, z));
return z;
});
}
if (!u) return r ? d : new X(d, this);
if (g && (!q || !this.store)) return d = d[0], r ? d : new X(d, this);
v = [];
for (x = 0; x < f.length; x++) {
n = d[x];
q && n.length && typeof n[0].doc === "undefined" && (this.db ? v.push(n = this.index.get(this.field[0]).db.enrich(n)) : n = Ta.call(this, n));
if (g) return r ? t ? cb(a, n, this.index, g, t) : n : new X(n, this);
d[x] = { field: f[x], result: n };
}
if (q && this.db && v.length) {
const B = this;
return Promise.all(v).then(function(z) {
for (let C = 0; C < z.length; C++) d[C].result = z[C];
t && (d = cb(a, d, B.index, g, t));
return k ? gb(d) : d;
});
}
t && (d = cb(a, d, this.index, g, t));
return k ? gb(d) : d;
};
function gb(a) {
const c = [], b = I(), e = I();
for (let d = 0, f, g, k, h, l, m, p; d < a.length; d++) {
f = a[d];
g = f.field;
k = f.result;
for (let u = 0; u < k.length; u++) if (l = k[u], typeof l !== "object" ? l = { id: h = l } : h = l.id, (m = b[h]) ? m.push(g) : (l.field = b[h] = [g], c.push(l)), p = l.highlight) m = e[h], m || (e[h] = m = {}, l.highlight = m), m[g] = p;
}
return c;
}
function fb(a, c, b, e, d) {
a = this.tag.get(a);
if (!a) return [];
a = a.get(c);
if (!a) return [];
c = a.length - e;
if (c > 0) {
if (b && c > b || e) a = a.slice(e, e + b);
d && (a = Ta.call(this, a));
}
return a;
}
function Ta(a) {
if (!this || !this.store) return a;
if (this.db) return this.index.get(this.field[0]).db.enrich(a);
const c = Array(a.length);
for (let b = 0, e; b < a.length; b++) e = a[b], c[b] = { id: e, doc: this.store.get(e) };
return c;
}
function Na(a) {
if (!this || this.constructor !== Na) return new Na(a);
const c = a.document || a.doc || a;
let b, e;
this.B = [];
this.field = [];
this.D = [];
this.key = (b = c.key || c.id) && hb(b, this.D) || "id";
(e = a.keystore || 0) && (this.keystore = e);
this.fastupdate = !!a.fastupdate;
this.reg = !this.fastupdate || a.worker || a.db ? e ? new S(e) : new Set() : e ? new R(e) : new Map();
this.h = (b = c.store || null) && b && b !== true && [];
this.store = b ? e ? new R(e) : new Map() : null;
this.cache = (b = a.cache || null) && new ma(b);
a.cache = false;
this.worker = a.worker || false;
this.priority = a.priority || 4;
this.index = ib.call(this, a, c);
this.tag = null;
if (b = c.tag) {
if (typeof b === "string" && (b = [b]), b.length) {
this.tag = new Map();
this.A = [];
this.F = [];
for (let d = 0, f, g; d < b.length; d++) {
f = b[d];
g = f.field || f;
if (!g) throw Error("The tag field from the document descriptor is undefined.");
f.custom ? this.A[d] = f.custom : (this.A[d] = hb(g, this.D), f.filter && (typeof this.A[d] === "string" && (this.A[d] = new String(this.A[d])), this.A[d].G = f.filter));
this.F[d] = g;
this.tag.set(g, new Map());
}
}
}
if (this.worker) {
this.fastupdate = false;
a = [];
for (const d of this.index.values()) d.then && a.push(d);
if (a.length) {
const d = this;
return Promise.all(a).then(function(f) {
let g = 0;
for (const k of d.index.entries()) {
const h = k[0];
let l = k[1];
l.then && (l = f[g], d.index.set(h, l), g++);
}
return d;
});
}
} else a.db && (this.fastupdate = false, this.mount(a.db));
}
w = Na.prototype;
w.mount = function(a) {
let c = this.field;
if (this.tag) for (let f = 0, g; f < this.F.length; f++) {
g = this.F[f];
var b = void 0;
this.index.set(g, b = new T({}, this.reg));
c === this.field && (c = c.slice(0));
c.push(g);
b.tag = this.tag.get(g);
}
b = [];
const e = { db: a.db, type: a.type, fastupdate: a.fastupdate };
for (let f = 0, g, k; f < c.length; f++) {
e.field = k = c[f];
g = this.index.get(k);
const h = new a.constructor(a.id, e);
h.id = a.id;
b[f] = h.mount(g);
g.document = true;
f ? g.bypass = true : g.store = this.store;
}
const d = this;
return this.db = Promise.all(b).then(function() {
d.db = true;
});
};
w.commit = function() {
return __async(this, null, function* () {
const a = [];
for (const c of this.index.values()) a.push(c.commit());
yield Promise.all(a);
this.reg.clear();
});
};
w.destroy = function() {
const a = [];
for (const c of this.index.values()) a.push(c.destroy());
return Promise.all(a);
};
function ib(a, c) {
const b = new Map();
let e = c.index || c.field || c;
M(e) && (e = [e]);
for (let f = 0, g, k; f < e.length; f++) {
g = e[f];
M(g) || (k = g, g = g.field);
k = ba(k) ? Object.assign({}, a, k) : a;
if (this.worker) {
var d = void 0;
d = (d = k.encoder) && d.encode ? d : new ka(typeof d === "string" ? va[d] : d || {});
d = new La(k, d);
b.set(g, d);
}
this.worker || b.set(g, new T(k, this.reg));
k.custom ? this.B[f] = k.custom : (this.B[f] = hb(g, this.D), k.filter && (typeof this.B[f] === "string" && (this.B[f] = new String(this.B[f])), this.B[f].G = k.filter));
this.field[f] = g;
}
if (this.h) {
a = c.store;
M(a) && (a = [a]);
for (let f = 0, g, k; f < a.length; f++) g = a[f], k = g.field || g, g.custom ? (this.h[f] = g.custom, g.custom.O = k) : (this.h[f] = hb(k, this.D), g.filter && (typeof this.h[f] === "string" && (this.h[f] = new String(this.h[f])), this.h[f].G = g.filter));
}
return b;
}
function hb(a, c) {
const b = a.split(":");
let e = 0;
for (let d = 0; d < b.length; d++) a = b[d], a[a.length - 1] === "]" && (a = a.substring(0, a.length - 2)) && (c[e] = true), a && (b[e++] = a);
e < b.length && (b.length = e);
return e > 1 ? b : b[0];
}
w.append = function(a, c) {
return this.add(a, c, true);
};
w.update = function(a, c) {
return this.remove(a).add(a, c);
};
w.remove = function(a) {
ba(a) && (a = ca(a, this.key));
for (var c of this.index.values()) c.remove(a, true);
if (this.reg.has(a)) {
if (this.tag && !this.fastupdate) for (let b of this.tag.values()) for (let e of b) {
c = e[0];
const d = e[1], f = d.indexOf(a);
f > -1 && (d.length > 1 ? d.splice(f, 1) : b.delete(c));
}
this.store && this.store.delete(a);
this.reg.delete(a);
}
this.cache && this.cache.remove(a);
return this;
};
w.clear = function() {
const a = [];
for (const c of this.index.values()) {
const b = c.clear();
b.then && a.push(b);
}
if (this.tag) for (const c of this.tag.values()) c.clear();
this.store && this.store.clear();
this.cache && this.cache.clear();
return a.length ? Promise.all(a) : this;
};
w.contain = function(a) {
return this.db ? this.index.get(this.field[0]).db.has(a) : this.reg.has(a);
};
w.cleanup = function() {
for (const a of this.index.values()) a.cleanup();
return this;
};
w.get = function(a) {
return this.db ? this.index.get(this.field[0]).db.enrich(a).then(function(c) {
return c[0] && c[0].doc || null;
}) : this.store.get(a) || null;
};
w.set = function(a, c) {
typeof a === "object" && (c = a, a = ca(c, this.key));
this.store.set(a, c);
return this;
};
w.searchCache = la;
w.export = jb;
w.import = kb;
Fa(Na.prototype);
function lb(a, c = 0) {
let b = [], e = [];
c && (c = 25e4 / c * 5e3 | 0);
for (const d of a.entries()) e.push(d), e.length === c && (b.push(e), e = []);
e.length && b.push(e);
return b;
}
function mb(a, c) {
c || (c = new Map());
for (let b = 0, e; b < a.length; b++) e = a[b], c.set(e[0], e[1]);
return c;
}
function nb(a, c = 0) {
let b = [], e = [];
c && (c = 25e4 / c * 1e3 | 0);
for (const d of a.entries()) e.push([d[0], lb(d[1])[0] || []]), e.length === c && (b.push(e), e = []);
e.length && b.push(e);
return b;
}
function ob(a, c) {
c || (c = new Map());
for (let b = 0, e, d; b < a.length; b++) e = a[b], d = c.get(e[0]), c.set(e[0], mb(e[1], d));
return c;
}
function pb(a) {
let c = [], b = [];
for (const e of a.keys()) b.push(e), b.length === 25e4 && (c.push(b), b = []);
b.length && c.push(b);
return c;
}
function qb(a, c) {
c || (c = new Set());
for (let b = 0; b < a.length; b++) c.add(a[b]);
return c;
}
function rb(a, c, b, e, d, f, g = 0) {
const k = e && e.constructor === Array;
var h = k ? e.shift() : e;
if (!h) return this.export(a, c, d, f + 1);
if ((h = a((c ? c + "." : "") + (g + 1) + "." + b, JSON.stringify(h))) && h.then) {
const l = this;
return h.then(function() {
return rb.call(l, a, c, b, k ? e : null, d, f, g + 1);
});
}
return rb.call(this, a, c, b, k ? e : null, d, f, g + 1);
}
function jb(a, c, b = 0, e = 0) {
if (b < this.field.length) {
const g = this.field[b];
if ((c = this.index.get(g).export(a, g, b, e = 1)) && c.then) {
const k = this;
return c.then(function() {
return k.export(a, g, b + 1);
});
}
return this.export(a, g, b + 1);
}
let d, f;
switch (e) {
case 0:
d = "reg";
f = pb(this.reg);
c = null;
break;
case 1:
d = "tag";
f = this.tag && nb(this.tag, this.reg.size);
c = null;
break;
case 2:
d = "doc";
f = this.store && lb(this.store);
c = null;
break;
default:
return;
}
return rb.call(this, a, c, d, f || null, b, e);
}
function kb(a, c) {
var b = a.split(".");
b[b.length - 1] === "json" && b.pop();
const e = b.length > 2 ? b[0] : "";
b = b.length > 2 ? b[2] : b[1];
if (this.worker && e) return this.index.get(e).import(a);
if (c) {
typeof c === "string" && (c = JSON.parse(c));
if (e) return this.index.get(e).import(b, c);
switch (b) {
case "reg":
this.fastupdate = false;
this.reg = qb(c, this.reg);
for (let d = 0, f; d < this.field.length; d++) f = this.index.get(this.field[d]), f.fastupdate = false, f.reg = this.reg;
if (this.worker) {
c = [];
for (const d of this.index.values()) c.push(d.import(a));
return Promise.all(c);
}
break;
case "tag":
this.tag = ob(c, this.tag);
break;
case "doc":
this.store = mb(c, this.store);
}
}
}
function sb(a, c) {
let b = "";
for (const e of a.entries()) {
a = e[0];
const d = e[1];
let f = "";
for (let g = 0, k; g < d.length; g++) {
k = d[g] || [""];
let h = "";
for (let l = 0; l < k.length; l++) h += (h ? "," : "") + (c === "string" ? '"' + k[l] + '"' : k[l]);
h = "[" + h + "]";
f += (f ? "," : "") + h;
}
f = '["' + a + '",[' + f + "]]";
b += (b ? "," : "") + f;
}
return b;
}
T.prototype.remove = function(a, c) {
const b = this.reg.size && (this.fastupdate ? this.reg.get(a) : this.reg.has(a));
if (b) {
if (this.fastupdate) for (let e = 0, d, f; e < b.length; e++) {
if ((d = b[e]) && (f = d.length)) if (d[f - 1] === a) d.pop();
else {
const g = d.indexOf(a);
g >= 0 && d.splice(g, 1);
}
}
else tb(this.map, a), this.depth && tb(this.ctx, a);
c || this.reg.delete(a);
}
this.db && (this.commit_task.push({ del: a }), this.M && ub(this));
this.cache && this.cache.remove(a);
return this;
};
function tb(a, c) {
let b = 0;
var e = typeof c === "undefined";
if (a.constructor === Array) for (let d = 0, f, g, k; d < a.length; d++) {
if ((f = a[d]) && f.length) {
if (e) return 1;
g = f.indexOf(c);
if (g >= 0) {
if (f.length > 1) return f.splice(g, 1), 1;
delete a[d];
if (b) return 1;
k = 1;
} else {
if (k) return 1;
b++;
}
}
}
else for (let d of a.entries()) e = d[0], tb(d[1], c) ? b++ : a.delete(e);
return b;
}
const vb = { memory: { resolution: 1 }, performance: { resolution: 3, fastupdate: true, context: { depth: 1, resolution: 1 } }, match: { tokenize: "forward" }, score: { resolution: 9, context: { depth: 2, resolution: 3 } } };
T.prototype.add = function(a, c, b, e) {
if (c && (a || a === 0)) {
if (!e && !b && this.reg.has(a)) return this.update(a, c);
e = this.depth;
c = this.encoder.encode(c, !e);
const l = c.length;
if (l) {
const m = I(), p = I(), u = this.resolution;
for (let r = 0; r < l; r++) {
let t = c[this.rtl ? l - 1 - r : r];
var d = t.length;
if (d && (e || !p[t])) {
var f = this.score ? this.score(c, t, r, null, 0) : wb(u, l, r), g = "";
switch (this.tokenize) {
case "tolerant":
Y(this, p, t, f, a, b);
if (d > 2) {
for (let n = 1, q, x, v, A; n < d - 1; n++) q = t.charAt(n), x = t.charAt(n + 1), v = t.substring(0, n) + x, A = t.substring(n + 2), g = v + q + A, Y(this, p, g, f, a, b), g = v + A, Y(this, p, g, f, a, b);
Y(this, p, t.substring(0, t.length - 1), f, a, b);
}
break;
case "full":
if (d > 2) {
for (let n = 0, q; n < d; n++) for (f = d; f > n; f--) {
g = t.substring(n, f);
q = this.rtl ? d - 1 - n : n;
var k = this.score ? this.score(c, t, r, g, q) : wb(u, l, r, d, q);
Y(this, p, g, k, a, b);
}
break;
}
case "bidirectional":
case "reverse":
if (d > 1) {
for (k = d - 1; k > 0; k--) {
g = t[this.rtl ? d - 1 - k : k] + g;
var h = this.score ? this.score(c, t, r, g, k) : wb(u, l, r, d, k);
Y(this, p, g, h, a, b);
}
g = "";
}
case "forward":
if (d > 1) {
for (k = 0; k < d; k++) g += t[this.rtl ? d - 1 - k : k], Y(
this,
p,
g,
f,
a,
b
);
break;
}
default:
if (Y(this, p, t, f, a, b), e && l > 1 && r < l - 1) for (d = this.N, g = t, f = Math.min(e + 1, this.rtl ? r + 1 : l - r), k = 1; k < f; k++) {
t = c[this.rtl ? l - 1 - r - k : r + k];
h = this.bidirectional && t > g;
const n = this.score ? this.score(c, g, r, t, k - 1) : wb(d + (l / 2 > d ? 0 : 1), l, r, f - 1, k - 1);
Y(this, m, h ? g : t, n, a, b, h ? t : g);
}
}
}
}
this.fastupdate || this.reg.add(a);
}
}
this.db && (this.commit_task.push(b ? { ins: a } : { del: a }), this.M && ub(this));
return this;
};
function Y(a, c, b, e, d, f, g) {
let k, h;
if (!(k = c[b]) || g && !k[g]) {
g ? (c = k || (c[b] = I()), c[g] = 1, h = a.ctx, (k = h.get(g)) ? h = k : h.set(g, h = a.keystore ? new R(a.keystore) : new Map())) : (h = a.map, c[b] = 1);
(k = h.get(b)) ? h = k : h.set(b, h = k = []);
if (f) {
for (let l = 0, m; l < k.length; l++) if ((m = k[l]) && m.includes(d)) {
if (l <= e) return;
m.splice(m.indexOf(d), 1);
a.fastupdate && (c = a.reg.get(d)) && c.splice(c.indexOf(m), 1);
break;
}
}
h = h[e] || (h[e] = []);
h.push(d);
if (h.length === __pow(2, 31) - 1) {
c = new xa(h);
if (a.fastupdate) for (let l of a.reg.values()) l.includes(h) && (l[l.indexOf(h)] = c);
k[e] = h = c;
}
a.fastupdate && ((e = a.reg.get(d)) ? e.push(h) : a.reg.set(d, [h]));
}
}
function wb(a, c, b, e, d) {
return b && a > 1 ? c + (e || 0) <= a ? b + (d || 0) : (a - 1) / (c + (e || 0)) * (b + (d || 0)) + 1 | 0 : 0;
}
T.prototype.search = function(a, c, b) {
b || (c || typeof a !== "object" ? typeof c === "object" && (b = c, c = 0) : (b = a, a = ""));
if (b && b.cache) return b.cache = false, a = this.searchCache(a, c, b), b.cache = true, a;
let e = [], d, f, g, k = 0, h, l, m, p, u;
b && (a = b.query || a, c = b.limit || c, k = b.offset || 0, f = b.context, g = b.suggest, u = (h = b.resolve) && b.enrich, m = b.boost, p = b.resolution, l = this.db && b.tag);
typeof h === "undefined" && (h = this.resolve);
f = this.depth && f !== false;
let r = this.encoder.encode(a, !f);
d = r.length;
c = c || (h ? 100 : 0);
if (d === 1) return xb.call(
this,
r[0],
"",
c,
k,
h,
u,
l
);
if (d === 2 && f && !g) return xb.call(this, r[1], r[0], c, k, h, u, l);
let t = I(), n = 0, q;
f && (q = r[0], n = 1);
p || p === 0 || (p = q ? this.N : this.resolution);
if (this.db) {
if (this.db.search && (b = this.db.search(this, r, c, k, g, h, u, l), b !== false)) return b;
const x = this;
return (function() {
return __async(this, null, function* () {
for (let v, A; n < d; n++) {
if ((A = r[n]) && !t[A]) {
t[A] = 1;
v = yield yb(x, A, q, 0, 0, false, false);
if (v = zb(v, e, g, p)) {
e = v;
break;
}
q && (g && v && e.length || (q = A));
}
g && q && n === d - 1 && !e.length && (p = x.resolution, q = "", n = -1, t = I());
}
return Ab(e, p, c, k, g, m, h);
});
})();
}
for (let x, v; n < d; n++) {
if ((v = r[n]) && !t[v]) {
t[v] = 1;
x = yb(this, v, q, 0, 0, false, false);
if (x = zb(x, e, g, p)) {
e = x;
break;
}
q && (g && x && e.length || (q = v));
}
g && q && n === d - 1 && !e.length && (p = this.resolution, q = "", n = -1, t = I());
}
return Ab(e, p, c, k, g, m, h);
};
function Ab(a, c, b, e, d, f, g) {
let k = a.length, h = a;
if (k > 1) h = $a(a, c, b, e, d, f, g);
else if (k === 1) return g ? Sa.call(null, a[0], b, e) : new X(a[0], this);
return g ? h : new X(h, this);
}
function xb(a, c, b, e, d, f, g) {
a = yb(this, a, c, b, e, d, f, g);
return this.db ? a.then(function(k) {
return d ? k || [] : new X(k, this);
}) : a && a.length ? d ? Sa.call(this, a, b, e) : new X(a, this) : d ? [] : new X([], this);
}
function zb(a, c, b, e) {
let d = [];
if (a && a.length) {
if (a.length <= e) {
c.push(a);
return;
}
for (let f = 0, g; f < e; f++) if (g = a[f]) d[f] = g;
if (d.length) {
c.push(d);
return;
}
}
if (!b) return d;
}
function yb(a, c, b, e, d, f, g, k) {
let h;
b && (h = a.bidirectional && c > b) && (h = b, b = c, c = h);
if (a.db) return a.db.get(c, b, e, d, f, g, k);
a = b ? (a = a.ctx.get(b)) && a.get(c) : a.map.get(c);
return a;
}
function T(a, c) {
if (!this || this.constructor !== T) return new T(a);
if (a) {
var b = M(a) ? a : a.preset;
b && (a = Object.assign({}, vb[b], a));
} else a = {};
b = a.context;
const e = b === true ? { depth: 1 } : b || {}, d = M(a.encoder) ? va[a.encoder] : a.encode || a.encoder || {};
this.encoder = d.encode ? d : typeof d === "object" ? new ka(d) : { encode: d };
this.resolution = a.resolution || 9;
this.tokenize = b = (b = a.tokenize) && b !== "default" && b !== "exact" && b || "strict";
this.depth = b === "strict" && e.depth || 0;
this.bidirectional = e.bidirectional !== false;
this.fastupdate = !!a.fastupdate;
this.score = a.score || null;
(b = a.keystore || 0) && (this.keystore = b);
this.map = b ? new R(b) : new Map();
this.ctx = b ? new R(b) : new Map();
this.reg = c || (this.fastupdate ? b ? new R(b) : new Map() : b ? new S(b) : new Set());
this.N = e.resolution || 3;
this.rtl = d.rtl || a.rtl || false;
this.cache = (b = a.cache || null) && new ma(b);
this.resolve = a.resolve !== false;
if (b = a.db) this.db = this.mount(b);
this.M = a.commit !== false;
this.commit_task = [];
this.commit_timer = null;
this.priority = a.priority || 4;
}
w = T.prototype;
w.mount = function(a) {
this.commit_timer && (clearTimeout(this.commit_timer), this.commit_timer = null);
return a.mount(this);
};
w.commit = function() {
this.commit_timer && (clearTimeout(this.commit_timer), this.commit_timer = null);
return this.db.commit(this);
};
w.destroy = function() {
this.commit_timer && (clearTimeout(this.commit_timer), this.commit_timer = null);
return this.db.destroy();
};
function ub(a) {
a.commit_timer || (a.commit_timer = setTimeout(function() {
a.commit_timer = null;
a.db.commit(a);
}, 1));
}
w.clear = function() {
this.map.clear();
this.ctx.clear();
this.reg.clear();
this.cache && this.cache.clear();
return this.db ? (this.commit_timer && clearTimeout(this.commit_timer), this.commit_timer = null, this.commit_task = [], this.db.clear()) : this;
};
w.append = function(a, c) {
return this.add(a, c, true);
};
w.contain = function(a) {
return this.db ? this.db.has(a) : this.reg.has(a);
};
w.update = function(a, c) {
const b = this, e = this.remove(a);
return e && e.then ? e.then(() => b.add(a, c)) : this.add(a, c);
};
w.cleanup = function() {
if (!this.fastupdate) return this;
tb(this.map);
this.depth && tb(this.ctx);
return this;
};
w.searchCache = la;
w.export = function(a, c, b = 0, e = 0) {
let d, f;
switch (e) {
case 0:
d = "reg";
f = pb(this.reg);
break;
case 1:
d = "cfg";
f = null;
break;
case 2:
d = "map";
f = lb(this.map, this.reg.size);
break;
case 3:
d = "ctx";
f = nb(this.ctx, this.reg.size);
break;
default:
return;
}
return rb.call(this, a, c, d, f, b, e);
};
w.import = function(a, c) {
if (c) switch (typeof c === "string" && (c = JSON.parse(c)), a = a.split("."), a[a.length - 1] === "json" && a.pop(), a.length === 3 && a.shift(), a = a.length > 1 ? a[1] : a[0], a) {
case "reg":
this.fastupdate = false;
this.reg = qb(c, this.reg);
break;
case "map":
this.map = mb(c, this.map);
break;
case "ctx":
this.ctx = ob(c, this.ctx);
}
};
w.serialize = function(a = true) {
let c = "", b = "", e = "";
if (this.reg.size) {
let f;
for (var d of this.reg.keys()) f || (f = typeof d), c += (c ? "," : "") + (f === "string" ? '"' + d + '"' : d);
c = "index.reg=new Set([" + c + "]);";
b = sb(this.map, f);
b = "index.map=new Map([" + b + "]);";
for (const g of this.ctx.entries()) {
d = g[0];
let k = sb(g[1], f);
k = "new Map([" + k + "])";
k = '["' + d + '",' + k + "]";
e += (e ? "," : "") + k;
}
e = "index.ctx=new Map([" + e + "]);";
}
return a ? "function inject(index){" + c + b + e + "}" : c + b + e;
};
Fa(T.prototype);
const Bb = typeof window !== "undefined" && (window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB), Cb = ["map", "ctx", "tag", "reg", "cfg"], Db = I();
function Eb(a, c = {}) {
if (!this || this.constructor !== Eb) return new Eb(a, c);
typeof a === "object" && (c = a, a = a.name);
a || console.info("Default storage space was used, because a name was not passed.");
this.id = "flexsearch" + (a ? ":" + a.toLowerCase().replace(/[^a-z0-9_\-]/g, "") : "");
this.field = c.field ? c.field.toLowerCase().replace(/[^a-z0-9_\-]/g, "") : "";
this.type = c.type;
this.fastupdate = this.support_tag_search = false;
this.db = null;
this.h = {};
}
w = Eb.prototype;
w.mount = function(a) {
if (a.index) return a.mount(this);
a.db = this;
return this.open();
};
w.open = function() {
if (this.db) return this.db;
let a = this;
navigator.storage && navigator.storage.persist && navigator.storage.persist();
Db[a.id] || (Db[a.id] = []);
Db[a.id].push(a.field);
const c = Bb.open(a.id, 1);
c.onupgradeneeded = function() {
const b = a.db = this.result;
for (let e = 0, d; e < Cb.length; e++) {
d = Cb[e];
for (let f = 0, g; f < Db[a.id].length; f++) g = Db[a.id][f], b.objectStoreNames.contains(d + (d !== "reg" ? g ? ":" + g : "" : "")) || b.createObjectStore(d + (d !== "reg" ? g ? ":" + g : "" : ""));
}
};
return a.db = Z(c, function(b) {
a.db = b;
a.db.onversionchange = function() {
a.close();
};
});
};
w.close = function() {
this.db && this.db.close();
this.db = null;
};
w.destroy = function() {
const a = Bb.deleteDatabase(this.id);
return Z(a);
};
w.clear = function() {
const a = [];
for (let b = 0, e; b < Cb.length; b++) {
e = Cb[b];
for (let d = 0, f; d < Db[this.id].length; d++) f = Db[this.id][d], a.push(e + (e !== "reg" ? f ? ":" + f : "" : ""));
}
const c = this.db.transaction(a, "readwrite");
for (let b = 0; b < a.length; b++) c.objectStore(a[b]).clear();
return Z(c);
};
w.get = function(a, c, b = 0, e = 0, d = true, f = false) {
a = this.db.transaction((c ? "ctx" : "map") + (this.field ? ":" + this.field : ""), "readonly").objectStore((c ? "ctx" : "map") + (this.field ? ":" + this.field : "")).get(c ? c + ":" + a : a);
const g = this;
return Z(a).then(function(k) {
let h = [];
if (!k || !k.length) return h;
if (d) {
if (!b && !e && k.length === 1) return k[0];
for (let l = 0, m; l < k.length; l++) if ((m = k[l]) && m.length) {
if (e >= m.length) {
e -= m.length;
continue;
}
const p = b ? e + Math.min(m.length - e, b) : m.length;
for (let u = e; u < p; u++) h.push(m[u]);
e = 0;
if (h.length === b) break;
}
return f ? g.enrich(h) : h;
}
return k;
});
};
w.tag = function(a, c = 0, b = 0, e = false) {
a = this.db.transaction("tag" + (this.field ? ":" + this.field : ""), "readonly").objectStore("tag" + (this.field ? ":" + this.field : "")).get(a);
const d = this;
return Z(a).then(function(f) {
if (!f || !f.length || b >= f.length) return [];
if (!c && !b) return f;
f = f.slice(b, b + c);
return e ? d.enrich(f) : f;
});
};
w.enrich = function(a) {
typeof a !== "object" && (a = [a]);
const c = this.db.transaction("reg", "readonly").objectStore("reg"), b = [];
for (let e = 0; e < a.length; e++) b[e] = Z(c.get(a[e]));
return Promise.all(b).then(function(e) {
for (let d = 0; d < e.length; d++) e[d] = { id: a[d], doc: e[d] ? JSON.parse(e[d]) : null };
return e;
});
};
w.has = function(a) {
a = this.db.transaction("reg", "readonly").objectStore("reg").getKey(a);
return Z(a).then(function(c) {
return !!c;
});
};
w.search = null;
w.info = function() {
};
w.transaction = function(a, c, b) {
a += a !== "reg" ? this.field ? ":" + this.field : "" : "";
let e = this.h[a + ":" + c];
if (e) return b.call(this, e);
let d = this.db.transaction(a, c);
this.h[a + ":" + c] = e = d.objectStore(a);
const f = b.call(this, e);
this.h[a + ":" + c] = null;
return Z(d).finally(function() {
return f;
});
};
w.commit = function(a) {
return __async(this, null, function* () {
let c = a.commit_task, b = [];
a.commit_task = [];
for (let e = 0, d; e < c.length; e++) d = c[e], d.del && b.push(d.del);
b.length && (yield this.remove(b));
a.reg.size && (yield this.transaction("map", "readwrite", function(e) {
for (const d of a.map) {
const f = d[0], g = d[1];
g.length && (e.get(f).onsuccess = function() {
let k = this.result;
var h;
if (k && k.length) {
const l = Math.max(k.length, g.length);
for (let m = 0, p, u; m < l; m++) if ((u = g[m]) && u.length) {
if ((p = k[m]) && p.length) for (h = 0; h < u.length; h++) p.push(u[h]);
else k[m] = u;
h = 1;
}
} else k = g, h = 1;
h && e.put(k, f);
});
}
}), yield this.transaction("ctx", "readwrite", function(e) {
for (const d of a.ctx) {
const f = d[0], g = d[1];
for (const k of g) {
const h = k[0], l = k[1];
l.length && (e.get(f + ":" + h).onsuccess = function() {
let m = this.result;
var p;
if (m && m.length) {
const u = Math.max(m.length, l.length);
for (let r = 0, t, n; r < u; r++) if ((n = l[r]) && n.length) {
if ((t = m[r]) && t.length) for (p = 0; p < n.length; p++) t.push(n[p]);
else m[r] = n;
p = 1;
}
} else m = l, p = 1;
p && e.put(m, f + ":" + h);
});
}
}
}), a.store ? yield this.transaction(
"reg",
"readwrite",
function(e) {
for (const d of a.store) {
const f = d[0], g = d[1];
e.put(typeof g === "object" ? JSON.stringify(g) : 1, f);
}
}
) : a.bypass || (yield this.transaction("reg", "readwrite", function(e) {
for (const d of a.reg.keys()) e.put(1, d);
})), a.tag && (yield this.transaction("tag", "readwrite", function(e) {
for (const d of a.tag) {
const f = d[0], g = d[1];
g.length && (e.get(f).onsuccess = function() {
let k = this.result;
k = k && k.length ? k.concat(g) : g;
e.put(k, f);
});
}
})), a.map.clear(), a.ctx.clear(), a.tag && a.tag.clear(), a.store && a.store.clear(), a.document || a.reg.clear());
});
};
function Fb(a, c, b) {
const e = a.value;
let d, f = 0;
for (let g = 0, k; g < e.length; g++) {
if (k = b ? e : e[g]) {
for (let h = 0, l, m; h < c.length; h++) if (m = c[h], l = k.indexOf(m), l >= 0) if (d = 1, k.length > 1) k.splice(l, 1);
else {
e[g] = [];
break;
}
f += k.length;
}
if (b) break;
}
f ? d && a.update(e) : a.delete();
a.continue();
}
w.remove = function(a) {
typeof a !== "object" && (a = [a]);
return Promise.all([this.transaction("map", "readwrite", function(c) {
c.openCursor().onsuccess = function() {
const b = this.result;
b && Fb(b, a);
};
}), this.transaction("ctx", "readwrite", function(c) {
c.openCursor().onsuccess = function() {
const b = this.result;
b && Fb(b, a);
};
}), this.transaction("tag", "readwrite", function(c) {
c.openCursor().onsuccess = function() {
const b = this.result;
b && Fb(b, a, true);
};
}), this.transaction("reg", "readwrite", function(c) {
for (let b = 0; b < a.length; b++) c.delete(a[b]);
})]);
};
function Z(a, c) {
return new Promise((b, e) => {
a.onsuccess = a.oncomplete = function() {
c && c(this.result);
c = null;
b(this.result);
};
a.onerror = a.onblocked = e;
a = null;
});
}
const Index = T;
const DanmukuDB = {
db: null,
initialized: false,
memoryCache: new Map(),
searchIndex: null,
indexBuilt: false,
init() {
return __async(this, null, function* () {
if (this.initialized) {
return true;
}
try {
this.db = yield this._openDatabase();
this.initialized = true;
yield this._buildMemoryIndex();
Utils.log("弹幕数据库初始化成功");
return true;
} catch (error) {
Utils.log(`弹幕数据库初始化失败: ${error.message}`, "error");
return false;
}
});
},
_openDatabase() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(CONFIG.DB_NAME, CONFIG.DB_VERSION);
request.onerror = () => {
reject(new Error("数据库打开失败"));
};
request.onsuccess = (event) => {
resolve(event.target.result);
};
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains(CONFIG.DB_STORE_NAME)) {
const store = db.createObjectStore(CONFIG.DB_STORE_NAME, {
keyPath: "id",
autoIncrement: true
});
store.createIndex("text", "text", { unique: false });
store.createIndex("tags", "tags", { unique: false, multiEntry: true });
store.createIndex("syncState", "syncState", { unique: false });
store.createIndex("lastUsed", "lastUsed", { unique: false });
store.createIndex("useCount", "useCount", { unique: false });
store.createIndex("popularity", "popularity", { unique: false });
store.createIndex("originalId", "originalId", { unique: false });
store.createIndex("category", "category", { unique: false });
}
if (!db.objectStoreNames.contains("tag_dictionary")) {
const tagStore = db.createObjectStore("tag_dictionary", {
keyPath: "dictValue"
});
tagStore.createIndex("dictLabel", "dictLabel", { unique: false });
tagStore.createIndex("dictType", "dictType", { unique: false });
}
if (!db.objectStoreNames.contains("import_logs")) {
const logStore = db.createObjectStore("import_logs", {
keyPath: "id",
autoIncrement: true
});
logStore.createIndex("timestamp", "timestamp", { unique: false });
logStore.createIndex("status", "status", { unique: false });
}
};
});
},
add(_0) {
return __async(this, arguments, function* (text, tags = []) {
if (!this.initialized) {
Utils.log("数据库未初始化", "error");
return null;
}
try {
const danmukuData = {
text: text.trim(),
tags: tags.filter((tag) => tag.trim()),
syncState: "pending",
createdAt: Date.now(),
lastUsed: Date.now(),
useCount: 1
};
const transaction = this.db.transaction([CONFIG.DB_STORE_NAME], "readwrite");
const store = transaction.objectStore(CONFIG.DB_STORE_NAME);
const request = store.add(danmukuData);
return new Promise((resolve, reject) => {
request.onsuccess = (event) => {
const id = event.target.result;
const newData = __spreadProps(__spreadValues({}, danmukuData), { id });
this.memoryCache.set(id, newData);
if (this.searchIndex) {
const searchContent = [newData.text, ...newData.tags].join(" ");
this.searchIndex.add(newData.id, searchContent);
}
Utils.log(`弹幕模板添加成功: ${text}`);
resolve(id);
};
request.onerror = () => {
reject(new Error("添加弹幕模板失败"));
};
});
} catch (error) {
Utils.log(`添加弹幕模板异常: ${error.message}`, "error");
return null;
}
});
},
search(_0) {
return __async(this, arguments, function* (query, limit = DEFAULT_SETTINGS.maxSuggestions, sortBy = "relevance") {
if (!this.initialized || !query) {
Utils.log("搜索条件无效: 数据库未初始化或查询为空");
return [];
}
try {
if (!this.indexBuilt) {
yield this._buildMemoryIndex();
}
const searchIds = this.searchIndex.search(query, limit * 2);
let matchedDanmuku = searchIds.map((id) => this.memoryCache.get(id)).filter((item) => item);
switch (sortBy) {
case "popularity":
matchedDanmuku.sort((a, b) => (b.popularity || 0) - (a.popularity || 0));
break;
case "recent":
matchedDanmuku.sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));
break;
case "usage":
matchedDanmuku.sort((a, b) => {
if (b.useCount !== a.useCount) {
return (b.useCount || 0) - (a.useCount || 0);
}
return (b.lastUsed || 0) - (a.lastUsed || 0);
});
break;
default:
matchedDanmuku.sort((a, b) => {
const scoreA = (a.useCount || 0) * 0.4 + (a.popularity || 0) * 0.3 + (a.lastUsed || 0) / 1e6 * 0.3;
const scoreB = (b.useCount || 0) * 0.4 + (b.popularity || 0) * 0.3 + (b.lastUsed || 0) / 1e6 * 0.3;
return scoreB - scoreA;
});
break;
}
const finalResults = matchedDanmuku.slice(0, limit);
Utils.log(`搜索 "${query}" (${sortBy}) 返回 ${finalResults.length} 条结果`);
return finalResults;
} catch (error) {
Utils.log(`搜索弹幕模板异常: ${error.message}`, "error");
return [];
}
});
},
updateUsage(id) {
return __async(this, null, function* () {
if (!this.initialized) {
return false;
}
try {
const transaction = this.db.transaction([CONFIG.DB_STORE_NAME], "readwrite");
const store = transaction.objectStore(CONFIG.DB_STORE_NAME);
const getRequest = store.get(id);
return new Promise((resolve) => {
getRequest.onsuccess = (event) => {
const data = event.target.result;
if (data) {
data.useCount = (data.useCount || 0) + 1;
data.lastUsed = Date.now();
const putRequest = store.put(data);
putRequest.onsuccess = () => {
this.memoryCache.set(id, data);
if (this.searchIndex) {
const searchContent = [data.text, ...data.tags].join(" ");
this.searchIndex.update(data.id, searchContent);
}
resolve(true);
};
putRequest.onerror = () => resolve(false);
} else {
resolve(false);
}
};
getRequest.onerror = () => resolve(false);
});
} catch (error) {
Utils.log(`更新使用统计异常: ${error.message}`, "error");
return false;
}
});
},
delete(id) {
return __async(this, null, function* () {
if (!this.initialized) {
return false;
}
try {
const transaction = this.db.transaction([CONFIG.DB_STORE_NAME], "readwrite");
const store = transaction.objectStore(CONFIG.DB_STORE_NAME);
const request = store.delete(id);
return new Promise((resolve) => {
request.onsuccess = () => {
this.memoryCache.delete(id);
if (this.searchIndex) {
this.searchIndex.remove(id);
}
Utils.log(`弹幕模板删除成功: ID ${id}`);
resolve(true);
};
request.onerror = () => {
Utils.log(`弹幕模板删除失败: ID ${id}`, "error");
resolve(false);
};
});
} catch (error) {
Utils.log(`删除弹幕模板异常: ${error.message}`, "error");
return false;
}
});
},
getAll() {
return __async(this, null, function* () {
if (!this.initialized) {
return [];
}
try {
const transaction = this.db.transaction([CONFIG.DB_STORE_NAME], "readonly");
const store = transaction.objectStore(CONFIG.DB_STORE_NAME);
const request = store.getAll();
return new Promise((resolve) => {
request.onsuccess = (event) => {
resolve(event.target.result || []);
};
request.onerror = () => {
Utils.log("获取所有弹幕模板失败", "error");
resolve([]);
};
});
} catch (error) {
Utils.log(`获取所有弹幕模板异常: ${error.message}`, "error");
return [];
}
});
},
clear() {
return __async(this, null, function* () {
if (!this.initialized) {
return false;
}
try {
const transaction = this.db.transaction([CONFIG.DB_STORE_NAME], "readwrite");
const store = transaction.objectStore(CONFIG.DB_STORE_NAME);
const request = store.clear();
return new Promise((resolve) => {
request.onsuccess = () => {
this.memoryCache.clear();
if (this.searchIndex) {
this.searchIndex = null;
this.indexBuilt = false;
}
Utils.log("弹幕数据库已清空");
resolve(true);
};
request.onerror = () => {
Utils.log("清空弹幕数据库失败", "error");
resolve(false);
};
});
} catch (error) {
Utils.log(`清空数据库异常: ${error.message}`, "error");
return false;
}
});
},
initTagDictionary() {
return __async(this, null, function* () {
try {
const response = yield fetch("https://hguofichp.cn:10086/machine/dictList");
const result = yield response.json();
if (result.code === 200 && result.data) {
const transaction = this.db.transaction(["tag_dictionary"], "readwrite");
const store = transaction.objectStore("tag_dictionary");
yield new Promise((resolve, reject) => {
const clearRequest = store.clear();
clearRequest.onsuccess = () => resolve();
clearRequest.onerror = () => reject(new Error("清空标签字典失败"));
});
for (const tag of result.data) {
yield new Promise((resolve, reject) => {
const addRequest = store.add(tag);
addRequest.onsuccess = () => resolve();
addRequest.onerror = () => reject(new Error("添加标签失败"));
});
}
Utils.log(`标签字典初始化完成,共 ${result.data.length} 个标签`);
return true;
}
return false;
} catch (error) {
Utils.log(`标签字典初始化失败: ${error.message}`, "error");
return false;
}
});
},
getTagDictionary() {
return __async(this, null, function* () {
try {
const transaction = this.db.transaction(["tag_dictionary"], "readonly");
const store = transaction.objectStore("tag_dictionary");
const request = store.getAll();
return new Promise((resolve) => {
request.onsuccess = (event) => {
resolve(event.target.result || []);
};
request.onerror = () => resolve([]);
});
} catch (error) {
Utils.log(`获取标签字典失败: ${error.message}`, "error");
return [];
}
});
},
importFromUrl(url) {
return __async(this, null, function* () {
Utils.log(`开始从 URL 下载弹幕数据: ${url}`);
try {
const response = yield fetch(url, {
method: "GET",
headers: {
"Accept": "application/json"
}
});
if (!response.ok) {
throw new Error(`网络响应错误: ${response.status} ${response.statusText}`);
}
const jsonData = yield response.json();
Utils.log(`数据下载成功,共 ${jsonData.length} 条。开始导入数据库...`);
return yield this.importFromJson(jsonData);
} catch (error) {
Utils.log(`从 URL 导入数据失败: ${error.message}`, "error");
return null;
}
});
},
importFromJson(jsonData) {
return __async(this, null, function* () {
const startTime = Date.now();
const importLog = {
timestamp: startTime,
source: "json_data",
status: "running",
totalProcessed: 0,
successCount: 0,
failCount: 0,
duplicateCount: 0,
errors: []
};
try {
const tagDict = yield this.getTagDictionary();
const tagMap = new Map(tagDict.map((tag) => [tag.dictValue, tag.dictLabel]));
const existingData = yield this.getAll();
const existingTexts = new Set(existingData.map((item) => item.text));
importLog.totalProcessed = jsonData.length;
for (const item of jsonData) {
try {
if (existingTexts.has(item.barrage)) {
importLog.duplicateCount++;
continue;
}
const tagValues = item.tags ? String(item.tags).split(",").map((t) => t.trim()) : [];
const tagLabels = tagValues.map((value) => tagMap.get(value) || value).filter(Boolean);
const danmakuData = {
text: item.barrage.trim(),
tags: tagLabels,
originalId: item.id,
popularity: parseInt(item.cnt) || 0,
category: "imported",
syncState: "synced",
createdAt: new Date(item.submitTime).getTime(),
lastUsed: 0,
useCount: 0,
source: "json_import",
importBatch: startTime
};
const transaction = this.db.transaction([CONFIG.DB_STORE_NAME], "readwrite");
const store = transaction.objectStore(CONFIG.DB_STORE_NAME);
yield new Promise((resolve, reject) => {
const addRequest = store.add(danmakuData);
addRequest.onsuccess = () => resolve();
addRequest.onerror = (e) => reject(new Error(`数据库添加失败: ${e.target.error}`));
});
existingTexts.add(item.barrage);
importLog.successCount++;
} catch (error) {
importLog.failCount++;
importLog.errors.push(`处理弹幕 (ID: ${item.id}) 失败: ${error.message}`);
}
}
importLog.status = "completed";
importLog.duration = Date.now() - startTime;
yield this._saveImportLog(importLog);
yield this._buildMemoryIndex();
Utils.log(`JSON数据导入完成!成功 ${importLog.successCount}, 失败 ${importLog.failCount}, 重复 ${importLog.duplicateCount}`);
return importLog;
} catch (error) {
importLog.status = "failed";
importLog.duration = Date.now() - startTime;
importLog.errors.push(`导入过程异常: ${error.message}`);
yield this._saveImportLog(importLog);
Utils.log(`从JSON导入数据失败: ${error.message}`, "error");
return importLog;
}
});
},
autoImportData() {
return __async(this, null, function* () {
const startTime = Date.now();
const importLog = {
timestamp: startTime,
source: "url_import",
status: "running",
errors: []
};
try {
yield this.initTagDictionary();
const dataUrl = "https://data.ienone.top/danmuku/danmuku_v0.json";
const result = yield this.importFromUrl(dataUrl);
if (result) {
Utils.log(`弹幕数据导入完成!`);
return result;
} else {
throw new Error("从URL导入返回了null");
}
} catch (error) {
importLog.status = "failed";
importLog.duration = Date.now() - startTime;
importLog.errors.push(`导入过程异常: ${error.message}`);
yield this._saveImportLog(importLog);
Utils.log(`弹幕数据导入失败: ${error.message}`, "error");
return importLog;
}
});
},
_saveImportLog(logData) {
return __async(this, null, function* () {
try {
const transaction = this.db.transaction(["import_logs"], "readwrite");
const store = transaction.objectStore("import_logs");
yield new Promise((resolve, reject) => {
const addRequest = store.add(logData);
addRequest.onsuccess = () => resolve();
addRequest.onerror = () => reject(new Error("保存日志失败"));
});
} catch (error) {
Utils.log(`保存导入日志失败: ${error.message}`, "error");
}
});
},
getImportLogs(limit = 10) {
return __async(this, null, function* () {
try {
const transaction = this.db.transaction(["import_logs"], "readonly");
const store = transaction.objectStore("import_logs");
const index = store.index("timestamp");
const request = index.openCursor(null, "prev");
return new Promise((resolve) => {
const logs = [];
let count = 0;
request.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor && count < limit) {
logs.push(cursor.value);
count++;
cursor.continue();
} else {
resolve(logs);
}
};
request.onerror = () => resolve([]);
});
} catch (error) {
Utils.log(`获取导入日志失败: ${error.message}`, "error");
return [];
}
});
},
_buildMemoryIndex() {
return __async(this, null, function* () {
if (this.indexBuilt || !this.initialized) {
return;
}
try {
const allData = yield this.getAll();
this.memoryCache.clear();
allData.forEach((item) => {
this.memoryCache.set(item.id, item);
});
this.searchIndex = new Index({
tokenize: "forward",
resolution: 9,
depth: 3,
encode: false,
cache: true
});
allData.forEach((item) => {
const searchContent = [item.text, ...item.tags].join(" ");
this.searchIndex.add(item.id, searchContent);
});
this.indexBuilt = true;
Utils.log(`内存索引构建完成,缓存 ${allData.length} 条弹幕模板`);
} catch (error) {
Utils.log(`构建内存索引异常: ${error.message}`, "error");
}
});
},
testAutoImport() {
return __async(this, null, function* () {
Utils.log(`=== 开始测试自动导入功能 ===`);
const result = yield this.autoImportData();
Utils.log("=== 导入测试完成,结果统计 ===");
Utils.log(`导入状态: ${result.status}`);
Utils.log(`总处理数量: ${result.totalProcessed}`);
Utils.log(`成功导入: ${result.successCount}`);
Utils.log(`失败数量: ${result.failCount}`);
Utils.log(`重复跳过: ${result.duplicateCount}`);
Utils.log(`耗时: ${(result.duration / 1e3).toFixed(2)} 秒`);
if (result.errors.length > 0) {
Utils.log("错误详情:", "warn");
result.errors.forEach((error, index) => {
Utils.log(`${index + 1}. ${error}`, "warn");
});
}
const totalCount = yield this.getDataCount();
Utils.log(`当前数据库总数据量: ${totalCount}`);
return result;
});
},
getDataCount() {
return __async(this, null, function* () {
try {
const transaction = this.db.transaction([CONFIG.DB_STORE_NAME], "readonly");
const store = transaction.objectStore(CONFIG.DB_STORE_NAME);
const request = store.count();
return new Promise((resolve) => {
request.onsuccess = (event) => {
resolve(event.target.result || 0);
};
request.onerror = () => resolve(0);
});
} catch (error) {
Utils.log(`获取数据总量失败: ${error.message}`, "error");
return 0;
}
});
},
getStatistics() {
return __async(this, null, function* () {
try {
const allData = yield this.getAll();
const imported = allData.filter((item) => item.category === "imported");
const userCreated = allData.filter((item) => item.category !== "imported");
const stats = {
total: allData.length,
imported: imported.length,
userCreated: userCreated.length,
avgPopularity: imported.length > 0 ? (imported.reduce((sum, item) => sum + (item.popularity || 0), 0) / imported.length).toFixed(1) : 0,
topUsed: allData.sort((a, b) => (b.useCount || 0) - (a.useCount || 0)).slice(0, 5).map((item) => ({ text: item.text, useCount: item.useCount || 0 }))
};
Utils.log("=== 数据库统计信息 ===");
Utils.log(`总数据量: ${stats.total}`);
Utils.log(`导入数据: ${stats.imported}`);
Utils.log(`用户创建: ${stats.userCreated}`);
Utils.log(`平均人气: ${stats.avgPopularity}`);
Utils.log("最常用弹幕:");
stats.topUsed.forEach((item, index) => {
Utils.log(`${index + 1}. "${item.text}" (使用${item.useCount}次)`);
});
return stats;
} catch (error) {
Utils.log(`获取统计信息失败: ${error.message}`, "error");
return {};
}
});
}
};
const PanelState = {
HIDDEN: "hidden",
VISIBLE: "visible"
};
const SelectionMode = {
KEYBOARD: "keyboard",
MOUSE: "mouse"
};
const CandidateItem = {
createCandidateItem(candidate, index, isActive = false) {
const item = document.createElement("div");
item.className = CONFIG.CSS_CLASSES.POPUP_ITEM;
item.dataset.index = index;
if (isActive) {
item.classList.add(CONFIG.CSS_CLASSES.POPUP_ITEM_ACTIVE);
}
const textElement = document.createElement("div");
textElement.className = CONFIG.CSS_CLASSES.POPUP_ITEM_TEXT;
textElement.textContent = candidate.getDisplayText ? candidate.getDisplayText() : candidate.text;
if (candidate.useCount > 0) {
textElement.title = `使用次数: ${candidate.useCount}`;
}
item.appendChild(textElement);
this.bindItemEvents(item, candidate, index);
return item;
},
bindItemEvents(itemEl, candidate, index) {
this.bindItemClick(itemEl, candidate, index);
this.bindItemHover(itemEl, index);
},
bindItemClick(itemEl, candidate, index) {
itemEl.addEventListener("click", (event) => {
event.preventDefault();
event.stopPropagation();
this._emitSelectEvent(candidate, index, "click");
});
},
bindItemHover(itemEl, index) {
let previewTimer = null;
itemEl.addEventListener("mouseenter", () => {
var _a, _b, _c;
this._emitHoverEvent(index);
previewTimer = setTimeout(() => {
this._showPreview(itemEl);
}, ((_c = (_b = (_a = CONFIG.DEFAULT_SETTINGS) == null ? void 0 : _a.capsule) == null ? void 0 : _b.preview) == null ? void 0 : _c.showDelay) || 500);
});
itemEl.addEventListener("mouseleave", () => {
if (previewTimer) {
clearTimeout(previewTimer);
previewTimer = null;
}
this._hidePreview();
});
},
updateActiveState(itemEl, isActive) {
if (isActive) {
itemEl.classList.add(CONFIG.CSS_CLASSES.POPUP_ITEM_ACTIVE);
} else {
itemEl.classList.remove(CONFIG.CSS_CLASSES.POPUP_ITEM_ACTIVE);
}
},
updateActiveStates(container, activeIndex) {
const items = container.querySelectorAll(`.${CONFIG.CSS_CLASSES.POPUP_ITEM}`);
items.forEach((item, index) => {
this.updateActiveState(item, index === activeIndex);
});
},
_emitSelectEvent(candidate, index, trigger) {
const event = new CustomEvent("candidateSelected", {
detail: { candidate, index, trigger }
});
document.dispatchEvent(event);
},
_emitHoverEvent(index) {
const event = new CustomEvent("candidateHovered", {
detail: { index }
});
document.dispatchEvent(event);
},
_showPreview(itemEl) {
var _a, _b, _c;
const previewElement = document.createElement("div");
previewElement.className = CONFIG.CSS_CLASSES.PREVIEW_POPUP;
previewElement.textContent = itemEl.textContent;
document.body.appendChild(previewElement);
const itemRect = itemEl.getBoundingClientRect();
const previewWidth = 200;
const previewHeight = 100;
const verticalOffset = ((_c = (_b = (_a = CONFIG.DEFAULT_SETTINGS) == null ? void 0 : _a.capsule) == null ? void 0 : _b.preview) == null ? void 0 : _c.verticalOffset) || 8;
let left = itemRect.left + window.scrollX;
let top = itemRect.top + window.scrollY - previewHeight - verticalOffset;
const rightEdge = left + previewWidth;
if (rightEdge > window.innerWidth) {
left = window.innerWidth - previewWidth - 10;
}
if (top < window.scrollY) {
top = itemRect.bottom + window.scrollY + verticalOffset;
}
previewElement.style.left = `${left}px`;
previewElement.style.top = `${top}px`;
previewElement.classList.add("fade-in");
},
_hidePreview() {
const previewElement = document.querySelector(`.${CONFIG.CSS_CLASSES.PREVIEW_POPUP}`);
if (previewElement) {
previewElement.classList.add("fade-out");
previewElement.addEventListener("animationend", () => {
previewElement.remove();
}, { once: true });
}
},
getItemHeight() {
return CONFIG.ITEM_HEIGHT;
}
};
const CandidatePanel = {
panelElement: null,
contentElement: null,
currentCandidates: [],
currentActiveIndex: -1,
showTimer: null,
hideTimer: null,
init() {
this.createPanelDOM();
this.bindPanelEvents();
console.log("CandidatePanel initialized");
},
createPanelDOM() {
this.panelElement = document.createElement("div");
this.panelElement.className = CONFIG.CSS_CLASSES.POPUP;
this.panelElement.style.display = "none";
console.log("创建弹窗元素:", this.panelElement);
console.log("弹窗CSS类名:", CONFIG.CSS_CLASSES.POPUP);
this.contentElement = document.createElement("div");
this.contentElement.className = CONFIG.CSS_CLASSES.POPUP_CONTENT;
this.panelElement.appendChild(this.contentElement);
document.body.appendChild(this.panelElement);
const addedElement = document.querySelector(`.${CONFIG.CSS_CLASSES.POPUP}`);
console.log("弹窗是否成功添加到DOM:", !!addedElement);
console.log("添加的弹窗元素:", addedElement);
},
renderCandidatePanel(candidates, activeIndex = 0) {
this.currentCandidates = candidates || [];
this.currentActiveIndex = activeIndex;
this.contentElement.innerHTML = "";
if (this.currentCandidates.length === 0) {
this._renderEmptyState();
return;
}
this.currentCandidates.forEach((candidate, index) => {
const isActive = index === activeIndex;
const itemElement = CandidateItem.createCandidateItem(candidate, index, isActive);
this.contentElement.appendChild(itemElement);
});
this._updatePanelHeight();
},
showPanel(targetInput) {
if (this.hideTimer) {
clearTimeout(this.hideTimer);
this.hideTimer = null;
}
this.showTimer = setTimeout(() => {
this._positionPanel(targetInput);
this.panelElement.style.display = "block";
requestAnimationFrame(() => {
this.panelElement.classList.add(CONFIG.CSS_CLASSES.POPUP_SHOW);
});
this._emitPanelEvent("panelShown");
}, CONFIG.POPUP_SHOW_DELAY);
},
hidePanel() {
if (this.showTimer) {
clearTimeout(this.showTimer);
this.showTimer = null;
}
this.hideTimer = setTimeout(() => {
this.panelElement.classList.remove(CONFIG.CSS_CLASSES.POPUP_SHOW);
setTimeout(() => {
this.panelElement.style.display = "none";
}, CONFIG.ANIMATION_DURATION);
this._emitPanelEvent("panelHidden");
}, CONFIG.POPUP_HIDE_DELAY);
},
setActiveIndex(newActiveIndex) {
if (newActiveIndex === this.currentActiveIndex) return;
this.currentActiveIndex = newActiveIndex;
CandidateItem.updateActiveStates(this.contentElement, newActiveIndex);
this._emitPanelEvent("activeIndexChanged", {
activeIndex: newActiveIndex,
candidate: this.currentCandidates[newActiveIndex] || null
});
},
getActiveCandidate() {
if (this.currentActiveIndex >= 0 && this.currentActiveIndex < this.currentCandidates.length) {
return this.currentCandidates[this.currentActiveIndex];
}
return null;
},
isVisible() {
return this.panelElement.style.display !== "none" && this.panelElement.classList.contains(CONFIG.CSS_CLASSES.POPUP_SHOW);
},
bindPanelEvents() {
document.addEventListener("candidateSelected", (event) => {
const { candidate, index } = event.detail;
this._handleCandidateSelected(candidate, index);
});
document.addEventListener("candidateHovered", (event) => {
const { index } = event.detail;
this.setActiveIndex(index);
});
this.panelElement.addEventListener("click", (event) => {
event.stopPropagation();
});
},
_renderEmptyState() {
this.contentElement.innerHTML = "";
this.panelElement.classList.add(CONFIG.CSS_CLASSES.POPUP_EMPTY);
const emptyElement = document.createElement("div");
emptyElement.className = CONFIG.CSS_CLASSES.EMPTY_MESSAGE;
emptyElement.textContent = "暂无匹配的弹幕模板";
this.contentElement.appendChild(emptyElement);
this.contentElement.style.maxHeight = "60px";
},
_positionPanel(targetInput) {
if (!targetInput) return;
const inputRect = targetInput.getBoundingClientRect();
const panelRect = this.panelElement.getBoundingClientRect();
let left = inputRect.left;
let top = inputRect.bottom + 5;
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
if (left + panelRect.width > windowWidth - 20) {
left = windowWidth - panelRect.width - 20;
}
if (left < 20) {
left = 20;
}
if (top + panelRect.height > windowHeight - 20) {
top = inputRect.top - panelRect.height - 5;
}
this.panelElement.style.left = `${left}px`;
this.panelElement.style.top = `${top}px`;
},
_updatePanelHeight() {
const itemCount = this.currentCandidates.length;
const itemHeight = CandidateItem.getItemHeight();
const maxHeight = CONFIG.MAX_POPUP_HEIGHT;
let height = Math.min(itemCount * itemHeight, maxHeight);
this.contentElement.style.maxHeight = `${height}px`;
this.panelElement.classList.remove(CONFIG.CSS_CLASSES.POPUP_EMPTY);
},
_handleCandidateSelected(candidate, index) {
this._emitPanelEvent("candidateSelected", { candidate, index });
},
_emitPanelEvent(eventName, detail = {}) {
const event = new CustomEvent(eventName, { detail });
document.dispatchEvent(event);
},
destroy() {
if (this.showTimer) {
clearTimeout(this.showTimer);
}
if (this.hideTimer) {
clearTimeout(this.hideTimer);
}
if (this.panelElement && this.panelElement.parentNode) {
this.panelElement.parentNode.removeChild(this.panelElement);
}
this.panelElement = null;
this.contentElement = null;
this.currentCandidates = [];
this.currentActiveIndex = -1;
}
};
const NativeSetter = {
inputValueDescriptor: null,
textareaValueDescriptor: null,
init() {
this.inputValueDescriptor = Object.getOwnPropertyDescriptor(
HTMLInputElement.prototype,
"value"
);
this.textareaValueDescriptor = Object.getOwnPropertyDescriptor(
HTMLTextAreaElement.prototype,
"value"
);
console.log("NativeSetter initialized");
},
setValue(element, value) {
if (!element) return false;
try {
let descriptor = null;
if (element.tagName === "INPUT") {
descriptor = this.inputValueDescriptor;
} else if (element.tagName === "TEXTAREA") {
descriptor = this.textareaValueDescriptor;
}
if (!descriptor || !descriptor.set) {
element.value = value;
return true;
}
descriptor.set.call(element, value);
this.dispatchInputEvent(element);
return true;
} catch (error) {
console.warn("NativeSetter failed, falling back to direct assignment:", error);
element.value = value;
this.dispatchInputEvent(element);
return false;
}
},
dispatchInputEvent(element) {
try {
const inputEvent = new Event("input", {
bubbles: true,
cancelable: true
});
element.dispatchEvent(inputEvent);
const changeEvent = new Event("change", {
bubbles: true,
cancelable: true
});
element.dispatchEvent(changeEvent);
} catch (error) {
console.warn("Failed to dispatch input event:", error);
}
},
isFrameworkManaged(element) {
return element && (element.dataset.frameworkManaged === "true" || element.hasAttribute("v-model") ||
element.hasAttribute("ng-model") ||
element._valueTracker ||
element.__reactInternalFiber ||
element.__reactInternalInstance);
},
smartSetValue(element, value, options = {}) {
const {
forceNative = false,
skipEvents = false
} = options;
if (!element) return false;
try {
if (forceNative || this.isFrameworkManaged(element)) {
const result = this.setValue(element, value);
if (!skipEvents && result) {
this.dispatchAdditionalEvents(element);
}
return result;
} else {
element.value = value;
if (!skipEvents) {
this.dispatchInputEvent(element);
}
return true;
}
} catch (error) {
console.error("SmartSetValue failed:", error);
return false;
}
},
dispatchAdditionalEvents(element) {
try {
["keydown", "keyup"].forEach((eventType) => {
const keyEvent = new KeyboardEvent(eventType, {
bubbles: true,
cancelable: true,
key: "Unidentified"
});
element.dispatchEvent(keyEvent);
});
if (document.activeElement !== element) {
const focusEvent = new FocusEvent("focus", {
bubbles: true,
cancelable: true
});
element.dispatchEvent(focusEvent);
}
} catch (error) {
console.warn("Failed to dispatch additional events:", error);
}
},
getValue(element) {
if (!element) return "";
try {
let descriptor = null;
if (element.tagName === "INPUT") {
descriptor = this.inputValueDescriptor;
} else if (element.tagName === "TEXTAREA") {
descriptor = this.textareaValueDescriptor;
}
if (descriptor && descriptor.get) {
return descriptor.get.call(element) || "";
}
return element.value || "";
} catch (error) {
console.warn("Failed to get value using native getter:", error);
return element.value || "";
}
}
};
const InputInteraction = {
activeInput: null,
inputListeners: new Map(),
init() {
this.bindGlobalEvents();
console.log("InputInteraction initialized");
},
bindInputEvents(inputEl) {
if (!inputEl || this.inputListeners.has(inputEl)) {
return;
}
const listeners = {
focus: (event) => this._handleInputFocus(event, inputEl),
blur: (event) => this._handleInputBlur(event, inputEl),
input: (event) => this._handleInputChange(event, inputEl),
keydown: (event) => this._handleInputKeyDown(event, inputEl)
};
Object.entries(listeners).forEach(([eventName, listener]) => {
inputEl.addEventListener(eventName, listener);
});
this.inputListeners.set(inputEl, listeners);
},
unbindInputEvents(inputEl) {
if (!this.inputListeners.has(inputEl)) return;
const listeners = this.inputListeners.get(inputEl);
Object.entries(listeners).forEach(([eventName, listener]) => {
inputEl.removeEventListener(eventName, listener);
});
this.inputListeners.delete(inputEl);
},
replaceInputWithText(inputEl, text) {
if (!inputEl) return;
NativeSetter.setValue(inputEl, text);
this._setCursorToEnd(inputEl);
this._triggerInputEvent(inputEl);
},
getActiveInput() {
return this.activeInput;
},
bindGlobalEvents() {
document.addEventListener("candidateSelected", (event) => {
const { candidate } = event.detail;
this._handleCandidateSelected(candidate);
});
},
_handleInputFocus(event, inputEl) {
this.activeInput = inputEl;
this._emitInputEvent("inputFocused", { inputEl, event });
},
_handleInputBlur(event, inputEl) {
setTimeout(() => {
if (this.activeInput === inputEl) {
this.activeInput = null;
this._emitInputEvent("inputBlurred", { inputEl, event });
}
}, 200);
},
_handleInputChange(event, inputEl) {
this._emitInputEvent("inputChanged", {
inputEl,
value: inputEl.value,
event
});
},
_handleInputKeyDown(event, inputEl) {
this._emitInputEvent("inputKeyDown", {
inputEl,
key: event.key,
event
});
},
_handleCandidateSelected(candidate) {
if (this.activeInput && candidate) {
const text = candidate.getDisplayText ? candidate.getDisplayText() : candidate.text;
this.replaceInputWithText(this.activeInput, text);
}
},
_emitInputEvent(eventName, detail) {
const event = new CustomEvent(eventName, { detail });
document.dispatchEvent(event);
},
_triggerInputEvent(inputEl) {
const inputEvent = new Event("input", { bubbles: true });
inputEl.dispatchEvent(inputEvent);
},
_setCursorToEnd(inputEl) {
if (inputEl.setSelectionRange) {
const len = inputEl.value.length;
inputEl.setSelectionRange(len, len);
}
},
cleanup() {
for (const inputEl of this.inputListeners.keys()) {
this.unbindInputEvents(inputEl);
}
this.activeInput = null;
}
};
const CandidatePanelState = {
currentState: PanelState.HIDDEN,
candidates: [],
activeIndex: 0,
selectionMode: SelectionMode.KEYBOARD,
panelElement: null,
targetInput: null,
listeners: new Map(),
getPanelState() {
return {
state: this.currentState,
activeIndex: this.activeIndex,
candidateCount: this.candidates.length,
isVisible: this.currentState === PanelState.VISIBLE,
hasSelection: this.activeIndex >= 0 && this.activeIndex < this.candidates.length
};
},
setCandidates(candidates) {
this.candidates = candidates || [];
this.activeIndex = this.candidates.length > 0 ? 0 : -1;
},
navigateLeft() {
if (this.candidates.length === 0) return;
this.activeIndex = this.activeIndex > 0 ? this.activeIndex - 1 : this.candidates.length - 1;
this.selectionMode = SelectionMode.KEYBOARD;
this._updateActiveItem();
this._emitNavigationEvent("left");
},
navigateRight() {
if (this.candidates.length === 0) return;
this.activeIndex = this.activeIndex < this.candidates.length - 1 ? this.activeIndex + 1 : 0;
this.selectionMode = SelectionMode.KEYBOARD;
this._updateActiveItem();
this._emitNavigationEvent("right");
},
navigateUp() {
this.navigateLeft();
this._emitNavigationEvent("up");
},
navigateDown() {
this.navigateRight();
this._emitNavigationEvent("down");
},
selectActiveCandidate() {
if (this.activeIndex >= 0 && this.activeIndex < this.candidates.length) {
const selected = this.candidates[this.activeIndex];
if (selected && typeof selected.updateUsage === "function") {
selected.updateUsage();
}
return selected;
}
return null;
},
setActiveByMouse(index) {
if (index >= 0 && index < this.candidates.length) {
this.activeIndex = index;
this.selectionMode = SelectionMode.MOUSE;
this._updateActiveItem();
}
},
resetSelection() {
this.activeIndex = this.candidates.length > 0 ? 0 : -1;
this.selectionMode = SelectionMode.KEYBOARD;
this._updateActiveItem();
},
setState(newState) {
const oldState = this.currentState;
this.currentState = newState;
this._onStateChange(oldState, newState);
},
setPanelElement(element) {
this.panelElement = element;
},
setTargetInput(input) {
this.targetInput = input;
},
addEventListener(event, callback) {
if (!this.listeners.has(event)) {
this.listeners.set(event, []);
}
this.listeners.get(event).push(callback);
},
removeEventListener(event, callback) {
if (this.listeners.has(event)) {
const callbacks = this.listeners.get(event);
const index = callbacks.indexOf(callback);
if (index > -1) {
callbacks.splice(index, 1);
}
}
},
_emit(event, data) {
if (this.listeners.has(event)) {
this.listeners.get(event).forEach((callback) => {
try {
callback(data);
} catch (error) {
console.error(`Error in event listener for ${event}:`, error);
}
});
}
},
_updateActiveItem() {
this._emit("activeIndexChanged", {
activeIndex: this.activeIndex,
selectionMode: this.selectionMode,
candidate: this.candidates[this.activeIndex] || null
});
},
_onStateChange(oldState, newState) {
this._emit("stateChanged", {
oldState,
newState,
panelState: this.getPanelState()
});
},
_emitNavigationEvent(direction) {
this._emit("navigation", {
direction,
activeIndex: this.activeIndex,
candidate: this.candidates[this.activeIndex] || null
});
}
};
const CapsulePreview = {
previewElement: null,
currentCapsule: null,
showTimer: null,
hideTimer: null,
currentTriggerSource: null,
isInSelectionMode: false,
initialized: false,
enterSelectionMode() {
this.isInSelectionMode = true;
Utils.log("预览框进入选择模式,将持续显示");
},
exitSelectionMode() {
this.isInSelectionMode = false;
this.hidePreview(0, "keyboard");
Utils.log("预览框退出选择模式");
},
updateSelectionModePreview(capsule, text) {
if (!this.isInSelectionMode || !capsule || !text) return;
if (this.showTimer) {
clearTimeout(this.showTimer);
this.showTimer = null;
}
if (this.hideTimer) {
clearTimeout(this.hideTimer);
this.hideTimer = null;
}
this.currentCapsule = capsule;
this.currentTriggerSource = "keyboard";
this.previewElement.textContent = text;
this.previewElement.classList.add("active");
this.positionPreview(capsule);
if (this.previewElement.style.display !== "block") {
this.previewElement.style.display = "block";
requestAnimationFrame(() => {
this.previewElement.classList.add("show");
});
}
Utils.log(`选择模式预览已更新: ${text.substring(0, 20)}...`);
},
init() {
if (this.initialized) return;
this.createPreviewElement();
this.bindGlobalEvents();
this.initialized = true;
Utils.log("胶囊悬浮框预览组件已初始化");
},
createPreviewElement() {
this.previewElement = document.createElement("div");
this.previewElement.className = "ddp-capsule-preview";
this.previewElement.style.display = "none";
document.body.appendChild(this.previewElement);
},
showPreview(capsule, text, isActive = false, triggerSource = "mouse") {
if (!this.initialized || !text || text.length <= 15) {
return;
}
if (this.currentTriggerSource === "keyboard" && triggerSource === "mouse") {
Utils.log("键盘预览活跃中,忽略鼠标悬停事件");
return;
}
if (this.hideTimer) {
clearTimeout(this.hideTimer);
this.hideTimer = null;
}
const config = DEFAULT_SETTINGS.capsule.preview;
const delay = triggerSource === "keyboard" ? 0 : config.showDelay;
Utils.log(`显示预览框: 触发源=${triggerSource}, 文本=${text.substring(0, 20)}...`);
this.showTimer = setTimeout(() => {
this.currentCapsule = capsule;
this.currentTriggerSource = triggerSource;
this.previewElement.textContent = text;
if (isActive || triggerSource === "keyboard") {
this.previewElement.classList.add("active");
} else {
this.previewElement.classList.remove("active");
}
this.positionPreview(capsule);
this.previewElement.style.display = "block";
requestAnimationFrame(() => {
this.previewElement.classList.add("show");
});
Utils.log(`悬浮框预览已显示 (${triggerSource}): ${text.substring(0, 20)}...`);
}, delay);
},
hidePreview(delay = null, triggerSource = "mouse") {
if (!this.initialized) return;
if (this.currentTriggerSource === "keyboard" && triggerSource === "mouse") {
Utils.log("键盘预览活跃中,忽略鼠标离开事件");
return;
}
if (this.showTimer) {
clearTimeout(this.showTimer);
this.showTimer = null;
}
const config = DEFAULT_SETTINGS.capsule.preview;
const hideDelay = delay !== null ? delay : config.hideDelay;
Utils.log(`隐藏预览框: 触发源=${triggerSource}, 延迟=${hideDelay}ms`);
this.hideTimer = setTimeout(() => {
this.previewElement.classList.remove("show");
setTimeout(() => {
this.previewElement.style.display = "none";
this.previewElement.classList.remove("active");
this.previewElement.classList.remove("show-below");
this.currentCapsule = null;
this.currentTriggerSource = null;
}, config.animationDuration);
}, hideDelay);
},
positionPreview(capsule) {
const capsuleRect = capsule.getBoundingClientRect();
Utils.log(`=== 预览框定位(强制上方) ===`);
Utils.log(`胶囊位置: top=${capsuleRect.top}px, left=${capsuleRect.left}px, width=${capsuleRect.width}px`);
this.previewElement.style.visibility = "hidden";
this.previewElement.style.display = "block";
const previewRect = this.previewElement.getBoundingClientRect();
const previewWidth = previewRect.width || 300;
const previewHeight = previewRect.height || 40;
this.previewElement.style.visibility = "";
Utils.log(`预览框尺寸: width=${previewWidth}px, height=${previewHeight}px`);
let left = capsuleRect.left + capsuleRect.width / 2 - previewWidth / 2;
const verticalGap = 8;
let top = capsuleRect.top - previewHeight - verticalGap;
Utils.log(`强制上方显示: top=${top}px (胶囊顶部${capsuleRect.top} - 预览框高度${previewHeight} - 间距${verticalGap})`);
const windowWidth = window.innerWidth;
const horizontalPadding = 10;
if (left < horizontalPadding) {
left = horizontalPadding;
} else if (left + previewWidth > windowWidth - horizontalPadding) {
left = windowWidth - previewWidth - horizontalPadding;
}
this.previewElement.classList.remove("show-below");
this.previewElement.style.left = `${left}px`;
this.previewElement.style.top = `${top}px`;
Utils.log(`最终位置: left=${left}px, top=${top}px, 显示位置: 上方`);
Utils.log(`=== 预览框定位完成 ===`);
},
updateActiveState(isActive) {
if (!this.initialized || !this.currentCapsule) return;
if (isActive) {
this.previewElement.classList.add("active");
} else {
this.previewElement.classList.remove("active");
}
},
bindGlobalEvents() {
document.addEventListener("scroll", () => {
this.hidePreview(0);
}, true);
window.addEventListener("resize", () => {
if (this.currentCapsule) {
this.positionPreview(this.currentCapsule);
}
});
},
bindCapsuleEvents(capsule, text) {
if (!capsule || !text) return;
capsule.addEventListener("mouseenter", () => {
this.showPreview(capsule, text, false, "mouse");
});
capsule.addEventListener("mouseleave", () => {
this.hidePreview(null, "mouse");
});
},
destroy() {
if (!this.initialized) return;
if (this.showTimer) {
clearTimeout(this.showTimer);
}
if (this.hideTimer) {
clearTimeout(this.hideTimer);
}
if (this.previewElement && this.previewElement.parentNode) {
this.previewElement.parentNode.removeChild(this.previewElement);
}
this.previewElement = null;
this.currentCapsule = null;
this.currentTriggerSource = null;
this.isInSelectionMode = false;
this.initialized = false;
Utils.log("胶囊悬浮框预览组件已销毁");
}
};
const UIManager = {
initialized: false,
currentState: "idle",
currentTargetInput: null,
currentSuggestions: [],
activeIndex: 0,
isSelectionModeActive: false,
init() {
return __async(this, null, function* () {
if (this.initialized) {
return true;
}
try {
CandidatePanel.init();
InputInteraction.init();
CapsulePreview.init();
this.bindComponentEvents();
this.initialized = true;
Utils.log("UI管理器初始化成功");
return true;
} catch (error) {
Utils.log(`UI管理器初始化失败: ${error.message}`, "error");
return false;
}
});
},
showPopup(suggestions, targetInput) {
if (!this.initialized) {
Utils.log("UIManager未初始化", "warn");
return;
}
this.currentSuggestions = suggestions || [];
this.currentTargetInput = targetInput;
this.activeIndex = -1;
if (this.currentSuggestions.length === 0) {
this.hidePopup();
return;
}
this.currentState = "showing";
CandidatePanelState.setCandidates(this.currentSuggestions);
CandidatePanelState.setTargetInput(targetInput);
CandidatePanelState.resetSelection();
const isChatInput = targetInput && targetInput.closest(".ChatSend");
if (isChatInput) {
this.showChatCandidateList(this.currentSuggestions, targetInput);
} else {
CandidatePanel.renderCandidatePanel(this.currentSuggestions, this.activeIndex);
CandidatePanel.showPanel(targetInput);
}
if (targetInput) {
InputInteraction.bindInputEvents(targetInput);
}
setTimeout(() => {
if (this.currentState === "showing") {
this.currentState = "selecting";
}
}, 100);
Utils.log(`弹窗已显示,包含 ${this.currentSuggestions.length} 个候选项`);
},
showChatCandidateList(suggestions, targetInput, multiRow = false) {
var _a;
const capsuleConfig = DEFAULT_SETTINGS.capsule;
document.documentElement.style.setProperty("--ddp-capsule-item-height", `${capsuleConfig.height}px`);
document.documentElement.style.setProperty("--ddp-capsule-padding", "8px");
document.documentElement.style.setProperty("--ddp-capsule-margin", "8px");
document.documentElement.style.setProperty("--ddp-capsule-item-padding", "3px");
Utils.log(`CSS变量已设置 (margin会计入高度):`);
Utils.log(`--ddp-capsule-item-height: 24px (胶囊高度)`);
Utils.log(`--ddp-capsule-padding: 8px (容器padding,计入高度)`);
Utils.log(`--ddp-capsule-margin: 8px (容器margin,计入高度)`);
Utils.log(`--ddp-capsule-item-padding: 3px (胶囊内padding)`);
Utils.log(`预期测量高度: 24px + 3*2 + 8*2 + 8*2 = 62px (margin计入高度)`);
const chat = document.querySelector(".layout-Player-chat .Chat");
if (!chat) {
Utils.log("未找到 Chat 容器,回退到普通弹窗模式");
CandidatePanel.renderCandidatePanel(suggestions, this.activeIndex);
CandidatePanel.showPanel(targetInput);
return;
}
chat.style.paddingBottom = "";
this.applyChatLayoutFix();
const existingList = document.querySelector(".ddp-candidate-capsules");
if (existingList) {
if (existingList._dynamicStyle) {
existingList._dynamicStyle.remove();
}
existingList.remove();
}
const candidateList = document.createElement("div");
candidateList.className = `ddp-candidate-capsules ${multiRow ? "multi-row" : ""}`;
const maxItems = multiRow ? suggestions.length : (
Math.min(suggestions.length, ((_a = DEFAULT_SETTINGS == null ? void 0 : DEFAULT_SETTINGS.capsule) == null ? void 0 : _a.singleRowMaxItems) || 8)
);
const displaySuggestions = suggestions.slice(0, maxItems);
displaySuggestions.forEach((suggestion, index) => {
const capsule = document.createElement("div");
capsule.className = `ddp-candidate-capsule ${index === this.activeIndex ? "active" : ""}`;
capsule.dataset.index = index;
const text = suggestion.getDisplayText ? suggestion.getDisplayText() : suggestion.text;
capsule.textContent = text;
this.bindCapsulePreviewEvents(capsule, suggestion, text);
capsule.addEventListener("click", () => {
this.selectCandidate(suggestion);
});
candidateList.appendChild(capsule);
});
const chatSpeak = chat.querySelector(".ChatSpeak");
if (chatSpeak) {
chatSpeak.parentNode.insertBefore(candidateList, chatSpeak);
} else {
chat.appendChild(candidateList);
}
this.updateChatLayoutForCandidates(candidateList);
this.currentCandidateMode = multiRow ? "multi-row" : "single-row";
Utils.log(`胶囊候选列表已显示 (${this.currentCandidateMode}),包含 ${displaySuggestions.length}/${suggestions.length} 个候选项,布局已调整`);
Utils.log(`DOM结构: Chat > [ChatToolBar, ddp-candidate-capsules, ChatSpeak]`);
},
hidePopup() {
if (!this.initialized) return;
console.log("=== HIDEOPOPUP 被调用 ===");
console.log(`当前状态: ${this.currentState}`);
console.log("完整调用栈:");
console.trace("hidePopup调用追踪");
Utils.log(`隐藏弹窗,当前状态: ${this.currentState}`);
CapsulePreview.hidePreview(0, "keyboard");
CapsulePreview.hidePreview(0, "mouse");
CandidatePanel.hidePanel();
const existingList = document.querySelector(".ddp-candidate-capsules");
if (existingList) {
if (existingList._dynamicStyle) {
existingList._dynamicStyle.remove();
}
existingList.remove();
}
this.removeChatLayoutFix();
this.currentSuggestions = [];
this.currentTargetInput = null;
this.activeIndex = -1;
this.currentState = "idle";
this.currentCandidateMode = null;
Utils.log("弹窗已隐藏,布局已恢复");
},
applyChatLayoutFix() {
Utils.log("=== 应用CSS布局修复 ===");
const chatArea = document.querySelector(".layout-Player-chat");
if (!chatArea) {
Utils.log("未找到聊天区域,跳过布局修复");
return;
}
chatArea.classList.add("ddp-candidates-visible");
Utils.log("已添加 ddp-candidates-visible 类,CSS样式将控制布局");
Utils.log("=== CSS布局修复完成 ===");
},
updateChatLayoutForCandidates(candidateList) {
const chat = document.querySelector(".layout-Player-chat .Chat");
if (!chat || !candidateList) {
Utils.log("缺少必要元素,跳过padding更新");
return;
}
chat.style.paddingBottom = "";
const beforeHeight = chat.getBoundingClientRect().height;
const currentPadding = getComputedStyle(chat).paddingBottom;
const initialPaddingValue = parseFloat(currentPadding) || 0;
Utils.log(`=== 更新候选框布局开始 ===`);
Utils.log(`Chat当前高度: ${beforeHeight}px`);
Utils.log(`Chat初始paddingBottom: ${initialPaddingValue}px (必须保留)`);
const configuredHeight = DEFAULT_SETTINGS.capsule.totalHeight;
const marginTop = parseFloat(getComputedStyle(candidateList).marginTop) || 0;
const marginBottom = parseFloat(getComputedStyle(candidateList).marginBottom) || 0;
const totalMargin = marginTop + marginBottom;
requestAnimationFrame(() => {
requestAnimationFrame(() => {
const actualHeight = Math.round(candidateList.getBoundingClientRect().height);
const candidateHeightWithMargin = actualHeight + totalMargin;
const heightDifference = Math.abs(candidateHeightWithMargin - configuredHeight);
const candidateHeight = heightDifference <= 2 ? configuredHeight : candidateHeightWithMargin;
const finalPadding = initialPaddingValue + candidateHeight;
document.documentElement.style.setProperty("--ddp-candidate-height", `${candidateHeight}px`);
chat.style.paddingBottom = `${finalPadding}px`;
const afterHeight = chat.getBoundingClientRect().height;
const actualPaddingBottom = getComputedStyle(chat).paddingBottom;
const heightIncrease = afterHeight - beforeHeight;
Utils.log(`候选项所需高度(含margin): ${candidateHeight}px`);
Utils.log(`最终设置padding: ${finalPadding}px (初始${initialPaddingValue}px + 候选项${candidateHeight}px)`);
Utils.log(`transform向上移动距离: ${candidateHeight}px`);
Utils.log(`实际应用padding: ${actualPaddingBottom}`);
Utils.log(`Chat更新后高度: ${afterHeight}px`);
Utils.log(`实际高度增加: ${heightIncrease}px (应约等于${candidateHeight}px)`);
Utils.log(`=== 候选框布局更新完成 ===`);
});
});
},
removeChatLayoutFix() {
Utils.log("=== 移除CSS布局修复 ===");
const chatArea = document.querySelector(".layout-Player-chat");
const chat = chatArea ? chatArea.querySelector(".Chat") : null;
if (!chatArea) {
Utils.log("未找到聊天区域,跳过布局恢复");
return;
}
chatArea.classList.remove("ddp-candidates-visible");
document.documentElement.style.removeProperty("--ddp-candidate-height");
document.documentElement.style.removeProperty("--ddp-capsule-item-height");
document.documentElement.style.removeProperty("--ddp-capsule-padding");
document.documentElement.style.removeProperty("--ddp-capsule-margin");
document.documentElement.style.removeProperty("--ddp-capsule-total-height");
document.documentElement.style.removeProperty("--ddp-capsule-item-padding");
if (chat) {
chat.style.paddingBottom = "";
}
Utils.log("已移除 ddp-candidates-visible 类,清理所有CSS变量和padding,布局已恢复");
Utils.log("=== CSS布局恢复完成 ===");
},
setActiveIndex(index) {
if (!this.initialized || index < 0 || index >= this.currentSuggestions.length) {
return;
}
const oldIndex = this.activeIndex;
this.activeIndex = index;
const isChatInput = this.currentTargetInput && this.currentTargetInput.closest(".ChatSend");
if (isChatInput) {
this.updateChatCandidateStyles(oldIndex, index);
} else {
CandidatePanel.setActiveIndex(index);
CandidatePanelState.setActiveByMouse(index);
}
},
updateChatCandidateStyles(oldIndex, newIndex) {
const candidateList = document.querySelector(".ddp-candidate-capsules");
if (!candidateList) return;
Utils.log(`=== 更新胶囊样式 ===`);
Utils.log(`从索引 ${oldIndex} 切换到索引 ${newIndex}`);
if (oldIndex >= 0) {
const oldCapsule = candidateList.querySelector(`[data-index="${oldIndex}"]`);
if (oldCapsule) {
oldCapsule.classList.remove("active");
Utils.log(`已移除旧胶囊 ${oldIndex} 的活跃状态`);
}
}
const newCapsule = candidateList.querySelector(`[data-index="${newIndex}"]`);
if (newCapsule) {
newCapsule.classList.add("active");
Utils.log(`已设置新胶囊 ${newIndex} 为活跃状态`);
if (!candidateList.classList.contains("multi-row")) {
this.scrollCapsuleIntoView(candidateList, newCapsule);
const capsuleIndex = parseInt(newCapsule.dataset.index) || 0;
const isCircularNavigation = capsuleIndex === 0 && candidateList.scrollLeft > candidateList.offsetWidth || capsuleIndex === this.currentSuggestions.length - 1 && candidateList.scrollLeft === 0;
const delay = isCircularNavigation ? 50 : 150;
Utils.log(`等待滚动完成,延迟: ${delay}ms (循环导航: ${isCircularNavigation})`);
setTimeout(() => {
this.showPreviewForCapsule(newCapsule, newIndex);
}, delay);
} else {
newCapsule.scrollIntoView({
behavior: "smooth",
block: "nearest",
inline: "center"
});
setTimeout(() => {
this.showPreviewForCapsule(newCapsule, newIndex);
}, 150);
}
} else {
Utils.log(`未找到索引为 ${newIndex} 的胶囊元素,隐藏预览框`);
CapsulePreview.hidePreview(0, "keyboard");
}
Utils.log(`=== 胶囊样式更新完成 ===`);
},
scrollCapsuleIntoView(candidateList, capsule) {
if (!candidateList || !capsule) {
Utils.log("scrollCapsuleIntoView: 缺少必要元素");
return;
}
try {
const listRect = candidateList.getBoundingClientRect();
const capsuleRect = capsule.getBoundingClientRect();
const scrollLeft = candidateList.scrollLeft;
const capsuleRelativeLeft = capsule.offsetLeft;
const capsuleWidth = capsule.offsetWidth;
const listWidth = candidateList.offsetWidth;
const capsuleIndex = parseInt(capsule.dataset.index) || 0;
Utils.log(`滚动检查: 胶囊索引=${capsuleIndex}, 位置=${capsuleRelativeLeft}px, 宽度=${capsuleWidth}px, 容器宽度=${listWidth}px, 当前滚动=${scrollLeft}px`);
const isCircularNavigation = capsuleIndex === 0 && scrollLeft > listWidth || capsuleIndex === this.currentSuggestions.length - 1 && scrollLeft === 0;
const scrollBehavior = isCircularNavigation ? "instant" : "smooth";
Utils.log(`循环导航检测: ${isCircularNavigation}, 滚动行为: ${scrollBehavior}`);
if (capsuleRelativeLeft + capsuleWidth > scrollLeft + listWidth) {
const newScrollLeft = capsuleRelativeLeft + capsuleWidth - listWidth + 20;
Utils.log(`向右滚动到: ${newScrollLeft}px`);
candidateList.scrollTo({
left: newScrollLeft,
behavior: scrollBehavior
});
} else if (capsuleRelativeLeft < scrollLeft) {
const newScrollLeft = Math.max(0, capsuleRelativeLeft - 20);
Utils.log(`向左滚动到: ${newScrollLeft}px`);
candidateList.scrollTo({
left: newScrollLeft,
behavior: scrollBehavior
});
} else {
Utils.log("胶囊已在可见区域,无需滚动");
}
} catch (error) {
Utils.log(`滚动出错: ${error.message}`, "error");
console.error("scrollCapsuleIntoView error:", error);
}
},
bindCapsulePreviewEvents(capsule, suggestion, text) {
capsule.removeAttribute("title");
Object.defineProperty(capsule, "title", {
set: function() {
Utils.log("阻止设置title属性,避免双重预览");
},
get: function() {
return "";
},
configurable: true
});
CapsulePreview.bindCapsuleEvents(capsule, text);
},
showPreviewForCapsule(capsule, index) {
if (!capsule || index < 0 || index >= this.currentSuggestions.length) {
Utils.log(`无法为胶囊显示预览: 胶囊=${!!capsule}, 索引=${index}, 总数=${this.currentSuggestions.length}`);
return;
}
const candidate = this.currentSuggestions[index];
const text = candidate ? candidate.getDisplayText ? candidate.getDisplayText() : candidate.text : capsule.textContent;
Utils.log(`胶囊文本: "${text}", 长度: ${text ? text.length : 0}`);
const capsuleRect = capsule.getBoundingClientRect();
Utils.log(`滚动后胶囊位置: left=${capsuleRect.left}px, top=${capsuleRect.top}px, 可见=${capsuleRect.left >= 0 && capsuleRect.left < window.innerWidth}`);
if (text && text.length > 8) {
Utils.log(`键盘选中胶囊,显示预览: ${text.substring(0, 20)}...`);
CapsulePreview.showPreview(capsule, text, true, "keyboard");
} else {
Utils.log(`文本过短或不存在,隐藏预览框`);
CapsulePreview.hidePreview(0, "keyboard");
}
},
navigateUp() {
if (!this.initialized || this.currentSuggestions.length === 0) return;
const isChatInput = this.currentTargetInput && this.currentTargetInput.closest(".ChatSend");
if (isChatInput) {
this.navigateLeft();
} else {
if (!this.isSelectionModeActive) {
this.setSelectionModeActive(true);
}
CandidatePanelState.navigateUp();
const newIndex = CandidatePanelState.activeIndex;
this.setActiveIndex(newIndex);
}
},
navigateDown() {
if (!this.initialized || this.currentSuggestions.length === 0) return;
const isChatInput = this.currentTargetInput && this.currentTargetInput.closest(".ChatSend");
if (isChatInput) {
this.navigateRight();
} else {
if (!this.isSelectionModeActive) {
this.setSelectionModeActive(true);
}
CandidatePanelState.navigateDown();
const newIndex = CandidatePanelState.activeIndex;
this.setActiveIndex(newIndex);
}
},
navigateLeft() {
if (!this.initialized || this.currentSuggestions.length === 0) return;
if (!this.isSelectionModeActive) {
this.setSelectionModeActive(true);
}
let newIndex = this.activeIndex - 1;
if (newIndex < 0) {
newIndex = this.currentSuggestions.length - 1;
}
this.setActiveIndex(newIndex);
},
navigateRight() {
if (!this.initialized || this.currentSuggestions.length === 0) return;
if (!this.isSelectionModeActive) {
this.setSelectionModeActive(true);
}
let newIndex = this.activeIndex + 1;
if (newIndex >= this.currentSuggestions.length) {
newIndex = 0;
}
this.setActiveIndex(newIndex);
},
selectActiveCandidate() {
if (!this.initialized || this.activeIndex < 0 || this.activeIndex >= this.currentSuggestions.length) {
return;
}
const selectedCandidate = this.currentSuggestions[this.activeIndex];
this.selectCandidate(selectedCandidate);
},
selectCandidate(candidate) {
if (!candidate || !this.currentTargetInput) return;
const text = candidate.getDisplayText ? candidate.getDisplayText() : candidate.text;
if (typeof candidate.updateUsage === "function") {
candidate.updateUsage();
}
InputInteraction.replaceInputWithText(this.currentTargetInput, text);
this.hidePopup();
this.currentState = "idle";
Utils.log(`候选项已选择并填入输入框: ${text}`);
},
isPopupVisible() {
const chatCandidateList = document.querySelector(".ddp-candidate-capsules");
if (chatCandidateList && chatCandidateList.style.display !== "none") {
return true;
}
return this.initialized && CandidatePanel.isVisible();
},
clearActiveIndex() {
this.activeIndex = -1;
if (this.isSelectionModeActive) {
this.setSelectionModeActive(false);
}
const chatCandidateList = document.querySelector(".ddp-candidate-capsules");
if (chatCandidateList) {
const capsules = chatCandidateList.querySelectorAll(".ddp-candidate-capsule");
capsules.forEach((capsule) => {
capsule.classList.remove("active");
});
}
if (CandidatePanel.panelElement) {
const items = CandidatePanel.panelElement.querySelectorAll(".dda-popup-item");
items.forEach((item) => {
item.classList.remove("dda-popup-item-active");
});
}
},
setSelectionModeActive(active) {
this.isSelectionModeActive = active;
if (active) {
CapsulePreview.enterSelectionMode();
if (this.activeIndex === -1 && this.currentSuggestions.length > 0) {
this.setActiveIndex(0);
}
} else {
CapsulePreview.exitSelectionMode();
this.clearActiveIndex();
}
const chatCandidateList = document.querySelector(".ddp-candidate-capsules");
if (chatCandidateList) {
if (active) {
chatCandidateList.classList.add("selection-mode-active");
} else {
chatCandidateList.classList.remove("selection-mode-active");
}
}
if (CandidatePanel.panelElement) {
if (active) {
CandidatePanel.panelElement.classList.add("selection-mode-active");
} else {
CandidatePanel.panelElement.classList.remove("selection-mode-active");
}
}
Utils.log(`选择模式: ${active ? "激活" : "关闭"}`);
},
updateCandidates(suggestions) {
this.currentSuggestions = suggestions;
if (this.currentTargetInput) {
const isChatInput = this.currentTargetInput.closest(".ChatSend");
if (isChatInput) {
this.showChatCandidateList(suggestions, this.currentTargetInput);
} else {
CandidatePanel.renderCandidatePanel(suggestions, this.activeIndex);
}
}
},
getCurrentState() {
return this.currentState;
},
bindComponentEvents() {
document.addEventListener("blur", (event) => {
if (event.target && event.target.matches && event.target.matches("input, textarea")) {
console.log("🔍 全局检测到输入框失焦:", event.target.className, "value:", event.target.value);
}
}, true);
const originalDispatchEvent = document.dispatchEvent;
document.dispatchEvent = function(event) {
if (event.type.includes("input") || event.type.includes("blur") || event.type.includes("focus")) {
console.log("🎯 自定义事件被触发:", event.type, event.detail);
}
return originalDispatchEvent.call(this, event);
};
document.addEventListener("candidateSelected", (event) => {
const { candidate } = event.detail;
this.selectCandidate(candidate);
});
document.addEventListener("candidateHovered", (event) => {
const { index } = event.detail;
this.setActiveIndex(index);
});
document.addEventListener("inputFocused", (event) => {
const { inputEl } = event.detail;
this.currentTargetInput = inputEl;
});
document.addEventListener("inputBlurred", (event) => {
Utils.log("=== 输入框失焦事件触发(已完全禁用隐藏逻辑) ===");
return;
});
document.addEventListener("panelShown", () => {
this.currentState = "selecting";
});
document.addEventListener("panelHidden", () => {
this.currentState = "idle";
});
},
destroy() {
if (!this.initialized) return;
CandidatePanel.destroy();
InputInteraction.cleanup();
CapsulePreview.destroy();
this.initialized = false;
this.currentState = "idle";
this.currentTargetInput = null;
this.currentSuggestions = [];
this.activeIndex = 0;
Utils.log("UI管理器已销毁");
},
calculateCandidateListHeight(suggestions) {
const baseHeight = 12;
const capsuleHeight = 32;
const maxCapsulesPerRow = Math.floor(window.innerWidth * 0.6 / 120);
const rows = Math.ceil(suggestions.length / maxCapsulesPerRow);
const calculatedHeight = baseHeight + rows * capsuleHeight;
Utils.log(`计算候选列表高度:`);
Utils.log(`- 建议数量: ${suggestions.length}`);
Utils.log(`- 窗口宽度: ${window.innerWidth}px`);
Utils.log(`- 每行最大胶囊数: ${maxCapsulesPerRow}`);
Utils.log(`- 计算行数: ${rows}`);
Utils.log(`- 基础高度: ${baseHeight}px`);
Utils.log(`- 胶囊高度: ${capsuleHeight}px`);
Utils.log(`- 计算总高度: ${calculatedHeight}px`);
return calculatedHeight;
},
calculateCandidateListHeight(suggestions) {
const baseHeight = 12;
const capsuleHeight = 32;
const maxCapsulesPerRow = Math.floor(window.innerWidth * 0.6 / 120);
const rows = Math.ceil(suggestions.length / maxCapsulesPerRow);
const calculatedHeight = baseHeight + rows * capsuleHeight;
Utils.log(`计算候选列表高度:`);
Utils.log(`- 建议数量: ${suggestions.length}`);
Utils.log(`- 窗口宽度: ${window.innerWidth}px`);
Utils.log(`- 每行最大胶囊数: ${maxCapsulesPerRow}`);
Utils.log(`- 计算行数: ${rows}`);
Utils.log(`- 基础高度: ${baseHeight}px`);
Utils.log(`- 胶囊高度: ${capsuleHeight}px`);
Utils.log(`- 计算总高度: ${calculatedHeight}px`);
return calculatedHeight;
}
};
const INPUT_TYPES = {
MAIN_CHAT: "main_chat",
FULLSCREEN_FLOAT: "fullscreen",
UNKNOWN: "unknown"
};
const InputDetector = {
mutationObserver: null,
detectedInputs: new WeakSet(),
onInputDetected: null,
onInputRemoved: null,
init(callbacks = {}) {
this.onInputDetected = callbacks.onInputDetected || (() => {
});
this.onInputRemoved = callbacks.onInputRemoved || (() => {
});
this.detectExistingInputs();
this.startMutationObserver();
console.log("InputDetector initialized");
},
detectExistingInputs() {
this.detectMainChatInput();
this.detectFullscreenInput();
},
detectMainChatInput() {
const checkMainInput = () => {
const mainInput = document.querySelector(".ChatSend-txt");
if (mainInput && !this.detectedInputs.has(mainInput)) {
this.handleInputDetected(mainInput, INPUT_TYPES.MAIN_CHAT);
return true;
}
return false;
};
if (!checkMainInput()) {
let attempts = 0;
const maxAttempts = 50;
const pollInterval = setInterval(() => {
attempts++;
if (checkMainInput() || attempts >= maxAttempts) {
clearInterval(pollInterval);
}
}, 200);
}
},
detectFullscreenInput() {
const fullscreenInput = document.querySelector(".inputView-2a65aa");
if (fullscreenInput && !this.detectedInputs.has(fullscreenInput)) {
this.handleInputDetected(fullscreenInput, INPUT_TYPES.FULLSCREEN_FLOAT);
}
},
startMutationObserver() {
if (this.mutationObserver) {
this.mutationObserver.disconnect();
}
this.mutationObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
this.checkNodeForInputs(node, true);
}
});
mutation.removedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
this.checkNodeForInputs(node, false);
}
});
});
});
const playerContainer = document.querySelector("#js-player-video-case") || document.body;
this.mutationObserver.observe(playerContainer, {
childList: true,
subtree: true
});
},
checkNodeForInputs(node, isAdded) {
const inputType = this.getInputType(node);
if (inputType !== INPUT_TYPES.UNKNOWN) {
if (isAdded) {
this.handleInputDetected(node, inputType);
} else {
this.handleInputRemoved(node, inputType);
}
return;
}
const selectors = [
".ChatSend-txt",
".inputView-2a65aa"
];
selectors.forEach((selector) => {
const inputs = node.querySelectorAll(selector);
inputs.forEach((input) => {
const type = this.getInputType(input);
if (type !== INPUT_TYPES.UNKNOWN) {
if (isAdded) {
this.handleInputDetected(input, type);
} else {
this.handleInputRemoved(input, type);
}
}
});
});
},
handleInputDetected(input, type) {
if (this.detectedInputs.has(input)) return;
this.detectedInputs.add(input);
console.log(`Detected ${type} input:`, input);
this.setupInputSpecialHandling(input, type);
this.onInputDetected(input, type);
},
handleInputRemoved(input, type) {
if (!this.detectedInputs.has(input)) return;
this.detectedInputs.delete(input);
console.log(`Removed ${type} input:`, input);
this.onInputRemoved(input, type);
},
setupInputSpecialHandling(input, type) {
switch (type) {
case INPUT_TYPES.MAIN_CHAT:
this.setupMainChatInput(input);
break;
case INPUT_TYPES.FULLSCREEN_FLOAT:
this.setupFullscreenInput(input);
break;
}
},
setupMainChatInput(input) {
let hasSetupFocusHandler = false;
const setupFocusHandler = () => {
if (hasSetupFocusHandler) return;
hasSetupFocusHandler = true;
input.addEventListener("focus", () => {
console.log("Main chat input focused");
input.dataset.frameworkManaged = "true";
}, { once: true });
};
if (document.readyState === "complete") {
setupFocusHandler();
} else {
document.addEventListener("DOMContentLoaded", setupFocusHandler);
}
},
setupFullscreenInput(input) {
console.log("Fullscreen input detected and ready");
input.dataset.frameworkManaged = "true";
input.dataset.dynamicCreated = "true";
},
getInputType(element) {
if (!element || element.tagName !== "INPUT" && element.tagName !== "TEXTAREA") {
return INPUT_TYPES.UNKNOWN;
}
if (element.classList.contains("ChatSend-txt")) {
return INPUT_TYPES.MAIN_CHAT;
}
return INPUT_TYPES.UNKNOWN;
},
isChatInput(element) {
return this.getInputType(element) !== INPUT_TYPES.UNKNOWN;
},
getSendButton(input) {
const type = this.getInputType(input);
switch (type) {
case INPUT_TYPES.MAIN_CHAT:
const chatSend = input.closest(".ChatSend");
return chatSend ? chatSend.querySelector(".ChatSend-button") : null;
case INPUT_TYPES.FULLSCREEN_FLOAT:
const fullscreenSendor = input.closest('[class*="fullScreenSendor-"]');
return fullscreenSendor ? fullscreenSendor.querySelector('.sendDanmu-592760, [class*="sendDanmu-"]') : null;
default:
return null;
}
},
destroy() {
if (this.mutationObserver) {
this.mutationObserver.disconnect();
this.mutationObserver = null;
}
this.detectedInputs = new WeakSet();
this.onInputDetected = null;
this.onInputRemoved = null;
console.log("InputDetector destroyed");
}
};
const SettingsManager = {
STORAGE_KEY_PREFIX: CONFIG.SETTINGS_KEY_PREFIX,
get(key, defaultValue = null) {
const storageKey = `${this.STORAGE_KEY_PREFIX}${key}`;
return GM_getValue(storageKey, defaultValue);
},
set(key, value) {
const storageKey = `${this.STORAGE_KEY_PREFIX}${key}`;
GM_setValue(storageKey, value);
},
remove(key) {
const storageKey = `${this.STORAGE_KEY_PREFIX}${key}`;
GM_deleteValue(storageKey);
},
getAll() {
const allKeys = GM_listValues();
const settings = {};
allKeys.forEach((key) => {
if (key.startsWith(this.STORAGE_KEY_PREFIX)) {
const settingKey = key.replace(this.STORAGE_KEY_PREFIX, "");
settings[settingKey] = GM_getValue(key);
}
});
return settings;
},
getSettings() {
const userSettings = this.getAll();
return __spreadValues(__spreadValues({}, DEFAULT_SETTINGS), userSettings);
},
setAll(settings) {
Object.entries(settings).forEach(([key, value]) => {
this.set(key, value);
});
},
reset() {
const allKeys = GM_listValues();
allKeys.forEach((key) => {
if (key.startsWith(this.STORAGE_KEY_PREFIX)) {
GM_deleteValue(key);
}
});
},
getDefaults() {
return {
maxSuggestions: CONFIG.MAX_SUGGESTIONS,
minSearchLength: CONFIG.MIN_SEARCH_LENGTH,
enableSync: false,
triggerKeys: CONFIG.TRIGGER_KEYS,
navigationKeys: CONFIG.NAVIGATION_KEYS,
debounceDelay: CONFIG.DEBOUNCE_DELAY,
sortBy: "relevance",
autoImport: {
maxPages: 5,
pageSize: 50,
sortByPopularity: true
}
};
},
applyDefaults() {
const defaults = this.getDefaults();
Object.entries(defaults).forEach(([key, value]) => {
if (this.get(key) === null) {
this.set(key, value);
}
});
}
};
const APP_STATES = {
IDLE: "idle",
TYPING: "typing",
SELECTING: "selecting"
};
const InputManager = {
currentState: APP_STATES.IDLE,
currentInput: null,
currentSuggestions: [],
activeIndex: -1,
isInSelectionMode: false,
debounceTimer: null,
processedInputs: new WeakSet(),
init() {
return __async(this, null, function* () {
NativeSetter.init();
yield UIManager.init();
InputDetector.init({
onInputDetected: this.handleInputDetected.bind(this),
onInputRemoved: this.handleInputRemoved.bind(this)
});
this.bindInputEvents();
console.log("InputManager initialized");
});
},
bindInputEvents() {
document.addEventListener("focusin", this.handleFocusIn.bind(this));
document.addEventListener("focusout", this.handleFocusOut.bind(this));
document.addEventListener("keydown", this.handleKeyDown.bind(this), true);
document.addEventListener("input", this.handleInput.bind(this));
this.startInputValueWatcher();
},
startInputValueWatcher() {
setInterval(() => {
if (this.currentInput && this.currentSuggestions.length > 0) {
const currentValue = this.currentInput.value;
if (currentValue.length === 0) {
this.hidePopup();
this.setState(APP_STATES.IDLE);
this.isInSelectionMode = false;
this.activeIndex = -1;
}
}
}, 100);
},
handleInputDetected(input, type) {
if (this.processedInputs.has(input)) return;
this.processedInputs.add(input);
console.log(`Processing detected input of type: ${type}`);
this.setupInputByType(input, type);
},
handleInputRemoved(input, type) {
if (!this.processedInputs.has(input)) return;
this.processedInputs.delete(input);
if (this.currentInput === input) {
this.currentInput = null;
this.setState(APP_STATES.IDLE);
UIManager.hidePopup();
}
console.log(`Removed input of type: ${type}`);
},
setupInputByType(input, type) {
switch (type) {
case INPUT_TYPES.MAIN_CHAT:
this.setupMainChatInput(input);
break;
case INPUT_TYPES.FULLSCREEN_FLOAT:
this.setupFullscreenInput(input);
break;
}
},
setupMainChatInput(input) {
const focusHandler = (event) => {
this.currentInput = input;
this.setState(APP_STATES.IDLE);
console.log("Main chat input focused and activated");
};
input.addEventListener("focus", focusHandler, { once: true });
input.addEventListener("blur", () => {
setTimeout(() => {
input.addEventListener("focus", focusHandler, { once: true });
}, 100);
});
},
setupFullscreenInput(input) {
console.log("Fullscreen input setup completed");
const focusHandler = (event) => {
this.currentInput = input;
this.setState(APP_STATES.IDLE);
console.log("Fullscreen input focused and activated");
};
input.addEventListener("focus", focusHandler);
},
handleFocusIn(event) {
const target = event.target;
if (InputDetector.isChatInput(target)) {
this.currentInput = target;
this.setState(APP_STATES.IDLE);
}
},
handleFocusOut(event) {
console.log("=== InputManager.handleFocusOut 被调用 ===");
console.log("失焦的元素:", event.target.className, "value:", event.target.value);
if (event.target === this.currentInput) {
console.log("当前输入框失焦,检查焦点转移目标...");
const related = event.relatedTarget;
const isPluginUI = related && (related.closest(".dda-popup") || related.closest(".ddp-candidate-capsules"));
if (!isPluginUI) {
setTimeout(() => {
const hasContent = this.currentInput && this.currentInput.value && this.currentInput.value.trim().length > 0;
console.log("焦点转移到非插件UI,输入框有内容:", hasContent);
this.setState(APP_STATES.IDLE);
this.currentInput = null;
if (!hasContent) {
console.log("输入框为空,隐藏候选项");
this.hidePopup();
} else {
console.log("输入框有内容,保持候选项显示");
}
}, 150);
} else {
console.log("焦点转移到插件UI内,保持候选项显示");
}
}
},
handleInput(event) {
if (event.target !== this.currentInput) return;
const inputValue = event.target.value;
if (inputValue.length === 0) {
this.hidePopup();
this.setState(APP_STATES.IDLE);
this.isInSelectionMode = false;
this.activeIndex = -1;
if (this.debounceTimer) clearTimeout(this.debounceTimer);
return;
}
this.debounceProcessInput(inputValue);
},
debounceProcessInput(inputValue) {
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
}
const settings = SettingsManager.getSettings();
this.debounceTimer = setTimeout(() => {
this.processInput(inputValue);
}, settings.debounceDelay);
},
handleKeyDown(event) {
if (event.target !== this.currentInput) return;
const key = event.key;
SettingsManager.getSettings();
const hasVisibleCandidates = UIManager.isPopupVisible();
if (hasVisibleCandidates) {
if (this.isInSelectionMode) {
if (key === CONFIG.KEYBOARD.ARROW_UP) {
event.preventDefault();
this.navigateUp();
} else if (key === CONFIG.KEYBOARD.ARROW_DOWN) {
event.preventDefault();
this.exitSelectionMode();
} else if (key === CONFIG.KEYBOARD.ARROW_LEFT) {
event.preventDefault();
this.navigateLeft();
} else if (key === CONFIG.KEYBOARD.ARROW_RIGHT) {
event.preventDefault();
this.navigateRight();
} else if (key === CONFIG.KEYBOARD.ENTER && !event.shiftKey) {
event.preventDefault();
event.stopPropagation();
this.selectActiveCandidate();
this.exitSelectionMode();
} else if (key === CONFIG.KEYBOARD.ESCAPE) {
event.preventDefault();
this.exitSelectionMode();
this.hidePopup();
}
} else {
if (key === CONFIG.KEYBOARD.ARROW_UP) {
event.preventDefault();
event.stopPropagation();
this.enterSelectionMode();
}
}
}
},
enterSelectionMode() {
this.isInSelectionMode = true;
this.setState(APP_STATES.SELECTING);
UIManager.setSelectionModeActive(true);
if (this.currentSuggestions.length > 0) {
this.setActiveIndex(0);
}
Utils.log("进入候选项选择模式");
},
exitSelectionMode() {
this.isInSelectionMode = false;
this.setState(APP_STATES.TYPING);
UIManager.setSelectionModeActive(false);
this.setActiveIndex(-1);
Utils.log("退出候选项选择模式");
},
navigateUp() {
if (this.currentSuggestions.length === 0) return;
let newIndex = this.activeIndex - 1;
if (newIndex < 0) {
newIndex = this.currentSuggestions.length - 1;
}
this.setActiveIndex(newIndex);
},
navigateDown() {
if (this.currentSuggestions.length === 0) return;
let newIndex = this.activeIndex + 1;
if (newIndex >= this.currentSuggestions.length) {
newIndex = 0;
}
this.setActiveIndex(newIndex);
},
navigateLeft() {
this.navigateUp();
},
navigateRight() {
this.navigateDown();
},
setActiveIndex(index) {
if (index < -1 || index >= this.currentSuggestions.length && index !== -1) {
return;
}
this.activeIndex = index;
UIManager.setActiveIndex(index);
},
selectActiveCandidate() {
if (this.activeIndex >= 0 && this.activeIndex < this.currentSuggestions.length) {
const selectedCandidate = this.currentSuggestions[this.activeIndex];
this.selectCandidate(selectedCandidate);
}
},
selectCandidate(candidate) {
if (!candidate || !this.currentInput) return;
const text = candidate.getDisplayText ? candidate.getDisplayText() : candidate.text;
if (typeof candidate.updateUsage === "function") {
candidate.updateUsage();
} else if (candidate.id) {
DanmukuDB.updateUsage(candidate.id);
}
NativeSetter.setValue(this.currentInput, text);
this.hidePopup();
this.setState(APP_STATES.IDLE);
this.isInSelectionMode = false;
this.activeIndex = -1;
Utils.log(`候选项已选择并填入输入框: ${text}`);
},
hidePopup() {
UIManager.hidePopup();
this.currentSuggestions = [];
this.activeIndex = -1;
},
processInput(inputValue) {
return __async(this, null, function* () {
const settings = SettingsManager.getSettings();
if (inputValue.length < settings.minSearchLength) {
this.setState(APP_STATES.IDLE);
this.isInSelectionMode = false;
this.activeIndex = -1;
this.hidePopup();
return;
}
let suggestions = yield DanmukuDB.search(inputValue);
this.currentSuggestions = suggestions;
if (suggestions.length > 0) {
this.setState(APP_STATES.TYPING);
this.isInSelectionMode = false;
UIManager.showPopup(suggestions, this.currentInput);
} else {
this.setState(APP_STATES.IDLE);
this.isInSelectionMode = false;
this.hidePopup();
}
});
},
setState(newState) {
const oldState = this.currentState;
this.currentState = newState;
console.log(`State changed: ${oldState} -> ${newState}`);
this.onStateChange(oldState, newState);
},
onStateChange(oldState, newState) {
console.log(`=== onStateChange: ${oldState} -> ${newState} ===`);
switch (newState) {
case APP_STATES.IDLE:
console.log("状态变为IDLE,但不自动隐藏弹窗");
break;
case APP_STATES.TYPING:
console.log("状态变为TYPING");
break;
case APP_STATES.SELECTING:
console.log("状态变为SELECTING,设置活跃索引");
if (this.activeIndex === -1 && this.currentSuggestions.length > 0) {
this.setActiveIndex(0);
}
break;
}
},
isChatInput(element) {
return InputDetector.isChatInput(element);
}
};
const KeyboardController = {
activeIndex: 0,
enabled: true,
init() {
console.log("KeyboardController initialized");
},
handleKeyDown(event, currentState) {
if (!this.enabled) return;
const key = event.code || event.key;
switch (currentState) {
case APP_STATES.IDLE:
this.handleIdleState(event, key);
break;
case APP_STATES.TYPING:
this.handleTypingState(event, key);
break;
case APP_STATES.SELECTING:
this.handleSelectingState(event, key);
break;
}
},
handleIdleState(event, key) {
if (this.isTriggerKey(key)) {
event.preventDefault();
}
},
handleTypingState(event, key) {
if (this.isTriggerKey(key)) {
event.preventDefault();
} else if (this.isCancelKey(key)) {
event.preventDefault();
}
},
handleSelectingState(event, key) {
if (this.isNavigationKey(key)) {
this.handleNavigation(event, key);
} else if (this.isSelectKey(key)) {
this.handleSelection(event);
} else if (this.isCancelKey(key)) {
this.handleCancel(event);
}
},
handleNavigation(event, key) {
event.preventDefault();
const direction = this.getNavigationDirection(key);
if (direction === "up") {
this.moveSelection(-1);
} else if (direction === "down") {
this.moveSelection(1);
}
},
handleSelection(event) {
event.preventDefault();
if (UIManager) {
UIManager.selectActiveCandidate();
}
},
handleCancel(event) {
event.preventDefault();
if (UIManager) {
UIManager.hidePopup();
}
},
moveSelection(delta) {
if (UIManager) {
if (delta < 0) {
UIManager.navigateUp();
} else {
UIManager.navigateDown();
}
}
},
resetSelection() {
this.activeIndex = 0;
},
isTriggerKey(key) {
return CONFIG.TRIGGER_KEYS.includes(key) || key === "Tab" && CONFIG.TRIGGER_KEYS.includes("Tab");
},
isNavigationKey(key) {
return CONFIG.NAVIGATION_KEYS.includes(key) || ["ArrowUp", "ArrowDown", "KeyW", "KeyS"].includes(key);
},
isSelectKey(key) {
return CONFIG.SELECT_KEYS.includes(key) || ["Enter", "Tab"].includes(key);
},
isCancelKey(key) {
return CONFIG.CANCEL_KEYS.includes(key) || key === "Escape";
},
getNavigationDirection(key) {
switch (key) {
case "ArrowUp":
case "KeyW":
return "up";
case "ArrowDown":
case "KeyS":
return "down";
default:
return null;
}
},
enable() {
this.enabled = true;
},
disable() {
this.enabled = false;
}
};
const mainCss = ':root{color-scheme:light dark;--motion-easing: cubic-bezier(.4, 0, .2, 1);--status-color-waiting: #4CAF50;--status-color-claiming: #2196F3;--status-color-switching: #FFC107;--status-color-error: #F44336;--status-color-opening: #9C27B0;--status-color-dormant: #757575;--status-color-unresponsive: #FFA000;--status-color-disconnected: #BDBDBD;--status-color-stalled: #9af39dff}body[data-theme=dark]{--md-sys-color-primary: #D0BCFF;--md-sys-color-on-primary: #381E72;--md-sys-color-primary-container: #4F378B;--md-sys-color-on-primary-container: #EADDFF;--md-sys-color-surface-container: #211F26;--md-sys-color-on-surface: #E6E1E5;--md-sys-color-on-surface-variant: #CAC4D0;--md-sys-color-outline: #938F99;--md-sys-color-surface-bright: #36343B;--md-sys-color-tertiary: #EFB8C8;--md-sys-color-scrim: #000000;--surface-container-highest: #3D3B42}body[data-theme=light]{--md-sys-color-primary: #6750A4;--md-sys-color-on-primary: #FFFFFF;--md-sys-color-primary-container: #EADDFF;--md-sys-color-on-primary-container: #21005D;--md-sys-color-surface-container: #F3EDF7;--md-sys-color-surface-bright: #FEF7FF;--md-sys-color-on-surface: #1C1B1F;--md-sys-color-on-surface-variant: #49454F;--md-sys-color-outline: #79747E;--md-sys-color-tertiary: #7D5260;--md-sys-color-scrim: #000000;--surface-container-highest: #E6E0E9}.qmx-hidden{display:none!important}.qmx-modal-open-scroll-lock{overflow:hidden!important}.is-dragging{transition:none!important}.qmx-flex-center{display:flex;align-items:center;justify-content:center}.qmx-flex-between{display:flex;align-items:center;justify-content:space-between}.qmx-flex-column{display:flex;flex-direction:column}.qmx-modal-base{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%) scale(.95);z-index:10001;background-color:var(--md-sys-color-surface-bright);color:var(--md-sys-color-on-surface);border-radius:28px;box-shadow:0 12px 32px #00000080;display:flex;flex-direction:column;opacity:0;visibility:hidden;transition:opacity .25s cubic-bezier(.4,0,.2,1),visibility .25s cubic-bezier(.4,0,.2,1),transform .25s cubic-bezier(.4,0,.2,1)}.qmx-modal-base.visible{opacity:1;visibility:visible;transform:translate(-50%,-50%) scale(1)}.qmx-backdrop{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:var(--md-sys-color-scrim);z-index:9998;opacity:0;visibility:hidden;transition:opacity .25s cubic-bezier(.4,0,.2,1)}.qmx-backdrop.visible{opacity:.5;visibility:visible}.qmx-btn{padding:10px 24px;border:1px solid var(--md-sys-color-outline);background-color:transparent;color:var(--md-sys-color-primary);border-radius:20px;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s var(--motion-easing),transform .2s var(--motion-easing),box-shadow .2s var(--motion-easing);user-select:none;display:inline-flex;align-items:center;justify-content:center;gap:8px;height:40px}.qmx-btn:hover{background-color:var(--md-sys-color-primary-container);box-shadow:0 1px 2px #0000004d,0 1px 3px 1px #00000026}.qmx-btn:active{transform:scale(.98);box-shadow:none}.qmx-btn:disabled{opacity:.38;cursor:not-allowed;background-color:var(--md-sys-color-on-surface);color:var(--md-sys-color-surface-container)}.qmx-btn--primary{background-color:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary);border:none}.qmx-btn--primary:hover{background-color:var(--md-sys-color-on-primary-container);color:var(--md-sys-color-on-primary-container);box-shadow:0 1px 2px #0000004d,0 2px 6px 2px #00000026}.qmx-btn--danger{border-color:var(--status-color-error);color:var(--status-color-error)}.qmx-btn--danger:hover{background-color:#f443361a}.qmx-btn--icon{width:40px;height:40px;padding:0;border-radius:50%;background-color:transparent;border:none;color:var(--md-sys-color-on-surface-variant)}.qmx-btn--icon:hover{background-color:#d0bcff26;color:var(--md-sys-color-primary)}.qmx-styled-list{list-style:none;padding-left:0}.qmx-styled-list li{position:relative;padding-left:20px;margin-bottom:8px}.qmx-styled-list li:before{content:"◆";position:absolute;left:0;top:2px;color:var(--md-sys-color-primary);font-size:12px}.qmx-scrollbar::-webkit-scrollbar{width:10px}.qmx-scrollbar::-webkit-scrollbar-track{background:var(--md-sys-color-surface-bright);border-radius:10px}.qmx-scrollbar::-webkit-scrollbar-thumb{background-color:var(--md-sys-color-primary);border-radius:10px;border:2px solid var(--md-sys-color-surface-bright)}.qmx-scrollbar::-webkit-scrollbar-thumb:hover{background-color:var(--md-sys-color-on-primary-container)}.dda-popup{position:fixed;z-index:9999;background:var(--md-sys-color-surface-container);border:1px solid var(--md-sys-color-outline);transition:all .3s var(--motion-easing),box-shadow .3s var(--motion-easing);border-radius:12px;box-shadow:0 4px 8px 3px #00000026,0 1px 3px #0000004d;max-width:400px;max-height:300px;overflow:hidden;opacity:0;transform:translateY(-10px)}.dda-popup.show{opacity:1;transform:translateY(0)}.dda-popup.selection-mode-active{border-color:var(--md-sys-color-primary);box-shadow:0 6px 16px 4px #0003,0 2px 6px #0006,0 0 0 1px var(--md-sys-color-primary);background:var(--md-sys-color-surface-bright)}.dda-popup-content{max-height:300px;overflow-y:auto;padding:4px 0}.dda-popup-item{padding:8px 16px;cursor:pointer;border-bottom:1px solid var(--md-sys-color-outline);transition:all .25s cubic-bezier(.4,0,.2,1);min-height:40px;display:flex;flex-direction:column;justify-content:center;position:relative;border-left:6px solid transparent;will-change:transform}.dda-popup-item-active{background-color:var(--md-sys-color-tertiary-container);border-left-color:var(--md-sys-color-tertiary);transform:translate(2px);box-shadow:0 4px 12px #0003,inset 0 0 0 2px rgba(var(--md-sys-color-tertiary-rgb),.3);z-index:10}.dda-popup-item:last-child{border-bottom:none}.dda-popup-item:hover{background-color:var(--md-sys-color-surface-bright);transform:translate(4px)}.dda-preview-tooltip{position:fixed;z-index:10000;background:var(--md-sys-color-surface-bright);border:1px solid var(--md-sys-color-outline);border-radius:8px;padding:12px 16px;box-shadow:0 8px 24px #0000004d;max-width:400px;word-wrap:break-word;font-size:14px;color:var(--md-sys-color-on-surface);opacity:0;transform:translateY(-10px);transition:opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);pointer-events:none}.dda-preview-tooltip.show{opacity:1;transform:translateY(0)}.dda-popup-item-text{font-size:14px;color:var(--md-sys-color-on-surface);line-height:1.4;margin-bottom:4px}.dda-popup-item-active .dda-popup-item-text{color:var(--md-sys-color-on-tertiary-container);font-weight:600}.dda-popup-item-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.dda-popup-tag{display:inline-block;padding:2px 6px;background-color:var(--md-sys-color-tertiary);color:var(--md-sys-color-on-primary);font-size:11px;border-radius:12px;line-height:1.2}.dda-popup-item-active .dda-popup-tag{background-color:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}.dda-popup-empty{max-height:60px}.dda-empty-message{padding:16px;text-align:center;color:var(--md-sys-color-on-surface-variant);font-size:13px}@media (max-width: 480px){.dda-popup{max-width:90vw;left:5vw!important;right:5vw!important}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.dda-popup.animate-in{animation:fadeInUp .2s var(--motion-easing)}.send-button:hover{background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.send-button:active{transform:scale(.98)}.ddp-candidate-capsules{display:flex;flex-wrap:nowrap;gap:6px;padding:var(--ddp-capsule-padding, 8px) 12px;background:#000000d9;border-radius:8px;margin:var(--ddp-capsule-margin, 8px) 12px;max-width:calc(100% - 24px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none;position:relative;z-index:1000}.ddp-candidate-capsules::-webkit-scrollbar{display:none}.ddp-candidate-capsules.multi-row{flex-wrap:wrap;max-height:120px;overflow-y:auto;mask:none;-webkit-mask:none}.ddp-candidate-capsule{flex-shrink:0;padding:var(--ddp-capsule-item-padding, 3px) 8px;background:#ffffff1a;border:1px solid rgba(255,255,255,.2);border-radius:12px;color:#fff;font-size:12px;line-height:1.3;cursor:pointer;transition:all .25s cubic-bezier(.4,0,.2,1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;direction:ltr;text-align:left;max-width:150px;min-width:30px;height:var(--ddp-capsule-item-height, 24px);display:flex;align-items:center;justify-content:flex-start;box-sizing:border-box;user-select:none;position:relative}.ddp-candidate-capsules.multi-row .ddp-candidate-capsule{flex:0 0 calc(25% - 5px);max-width:calc(25% - 5px);min-width:60px}.ddp-candidate-capsule:hover{background:#fff3;border-color:#fff6;transform:translateY(-1px);box-shadow:0 2px 4px #0003}.ddp-candidate-capsule.active{background:#f60;border-color:#f83;color:#fff;font-weight:500;box-shadow:0 2px 6px #ff66004d}.ddp-candidate-capsules.selection-mode-active{box-shadow:0 0 0 2px #f60;background:#000000e6}.ddp-candidate-capsule[title]{position:relative}.ddp-capsule-preview{position:fixed;z-index:10000;background:#282828f2;border:1px solid rgba(255,255,255,.2);border-radius:8px;padding:8px 12px;box-shadow:0 4px 8px 3px #0000004d,0 1px 3px #0006;max-width:300px;min-width:100px;word-wrap:break-word;white-space:normal;opacity:0;transform:translateY(-5px);transition:opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);pointer-events:none;font-size:13px;line-height:1.4;color:#fff;backdrop-filter:blur(4px)}.ddp-capsule-preview.show{opacity:1;transform:translateY(0)}.ddp-capsule-preview:before{content:"";position:absolute;bottom:-5px;left:50%;transform:translate(-50%);width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid rgba(40,40,40,.95)}.ddp-capsule-preview.show-below:before{bottom:auto;top:-5px;border-top:none;border-bottom:5px solid rgba(40,40,40,.95)}.ddp-capsule-preview.active{border-color:#f60;background:#323232f2;box-shadow:0 4px 8px 3px #0000004d,0 1px 3px #0006,0 0 0 1px #f60}.ddp-capsule-preview.active:before{border-top-color:#323232f2}.ddp-capsule-preview.active.show-below:before{border-bottom-color:#323232f2}.layout-Player-chat .Chat .ddp-candidate-capsules{z-index:1000;position:relative}@media (max-width: 768px){.ddp-candidate-capsules{gap:6px;padding:6px 8px}.ddp-candidate-capsule{padding:4px 8px;font-size:12px;max-width:150px}}@media (prefers-color-scheme: dark){.ddp-candidate-capsules{box-shadow:0 2px 8px #00000040}.ddp-candidate-capsule:hover{box-shadow:0 2px 8px #0000004d}}@keyframes ddp-capsule-appear{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.ddp-candidate-capsules{animation:ddp-capsule-appear .2s var(--motion-easing)}.ddp-candidate-capsule{animation:ddp-capsule-appear .3s var(--motion-easing) backwards}.ddp-candidate-capsule:nth-child(1){animation-delay:.05s}.ddp-candidate-capsule:nth-child(2){animation-delay:.1s}.ddp-candidate-capsule:nth-child(3){animation-delay:.15s}.ddp-candidate-capsule:nth-child(4){animation-delay:.2s}.ddp-candidate-capsule:nth-child(5){animation-delay:.25s}.dda-settings-content{width:90%;max-width:600px;max-height:80vh;overflow:hidden}.dda-settings-header{display:flex;justify-content:space-between;align-items:center;padding:16px 24px;border-bottom:1px solid var(--md-sys-color-outline)}.dda-settings-header h2{margin:0;color:var(--md-sys-color-on-surface);font-size:22px;font-weight:400}.dda-settings-body{padding:24px;max-height:calc(80vh - 130px);overflow-y:auto}.dda-settings-section{margin-bottom:32px}.dda-settings-section:last-child{margin-bottom:0}.dda-settings-section h3{margin:0 0 16px;color:var(--md-sys-color-primary);font-size:16px;font-weight:500;padding-bottom:8px;border-bottom:1px solid var(--md-sys-color-outline)}.dda-setting-item{display:flex;justify-content:space-between;align-items:center;padding:16px 0;border-bottom:1px solid var(--md-sys-color-outline)}.dda-setting-item:last-child{border-bottom:none}.dda-setting-item label{color:var(--md-sys-color-on-surface-variant);font-size:14px;font-weight:400;flex:1}.dda-key-group{display:flex;gap:16px;flex-wrap:wrap;align-items:center}.dda-key-group label{display:flex;align-items:center;font-size:14px;color:var(--md-sys-color-on-surface-variant);flex:none}.dda-settings-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid var(--md-sys-color-outline)}@media (max-width: 640px){.dda-settings-content{width:100%;height:100%;max-height:100vh;border-radius:0;margin:0}.dda-settings-header,.dda-settings-footer{padding:16px}.dda-settings-body{padding:16px;max-height:calc(100vh - 120px)}.dda-setting-item{flex-direction:column;align-items:flex-start;gap:12px}}.qmx-input{background-color:var(--md-sys-color-surface-container);border:1px solid var(--md-sys-color-outline);color:var(--md-sys-color-on-surface);border-radius:4px;padding:16px;width:100%;box-sizing:border-box;transition:box-shadow .2s var(--motion-easing),border-color .2s var(--motion-easing);font-size:16px;height:56px}.qmx-input:hover{border-color:var(--md-sys-color-on-surface)}.qmx-input:focus{outline:none;border-color:var(--md-sys-color-primary);border-width:2px;padding:15px}.qmx-input[type=number]::-webkit-inner-spin-button,.qmx-input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.qmx-input[type=number]{-moz-appearance:textfield;appearance:textfield}.qmx-fieldset-unit{position:relative;padding:0;margin:0;border:1px solid var(--md-sys-color-outline);border-radius:4px;background-color:var(--md-sys-color-surface-container);transition:border-color .25s cubic-bezier(.4,0,.2,1);width:100%;box-sizing:border-box;height:56px;display:flex;align-items:center}.qmx-fieldset-unit:hover{border-color:var(--md-sys-color-on-surface)}.qmx-fieldset-unit:focus-within{border-color:var(--md-sys-color-primary);border-width:2px}.qmx-fieldset-unit input[type=number]{border:none;background:none;outline:none;color:var(--md-sys-color-on-surface);padding:16px;width:100%;box-sizing:border-box;font-size:16px}.qmx-fieldset-unit legend{padding:0 4px;font-size:12px;color:var(--md-sys-color-on-surface-variant);margin-left:12px;pointer-events:none;position:absolute;top:-8px;background-color:var(--md-sys-color-surface-container)}.qmx-toggle{position:relative;display:inline-block;width:52px;height:32px}.qmx-toggle input{opacity:0;width:0;height:0}.qmx-toggle .slider{position:absolute;cursor:pointer;inset:0;background-color:var(--md-sys-color-surface-container);border:2px solid var(--md-sys-color-outline);border-radius:16px;transition:background-color .3s var(--motion-easing),border-color .3s var(--motion-easing)}.qmx-toggle .slider:before{position:absolute;content:"";height:16px;width:16px;left:6px;bottom:6px;background-color:var(--md-sys-color-outline);border-radius:50%;transition:all .3s var(--motion-easing)}.qmx-toggle input:checked+.slider{background-color:var(--md-sys-color-primary);border-color:var(--md-sys-color-primary)}.qmx-toggle input:checked+.slider:before{background-color:var(--md-sys-color-on-primary);transform:translate(20px);height:24px;width:24px;left:2px;bottom:2px}.qmx-toggle:hover .slider{border-color:var(--md-sys-color-on-surface-variant)}.qmx-select{position:relative;width:100%}.qmx-select-styled{position:relative;padding:16px 40px 16px 16px;background-color:var(--md-sys-color-surface-container);border:1px solid var(--md-sys-color-outline);border-radius:4px;cursor:pointer;transition:all .2s var(--motion-easing);user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;height:56px;box-sizing:border-box;font-size:16px;color:var(--md-sys-color-on-surface)}.qmx-select-styled:after{content:"▼";position:absolute;top:50%;right:16px;transform:translateY(-50%);color:var(--md-sys-color-on-surface-variant);transition:transform .3s var(--motion-easing);font-size:12px}.qmx-select:hover .qmx-select-styled{border-color:var(--md-sys-color-on-surface)}.qmx-select.active .qmx-select-styled{border-color:var(--md-sys-color-primary);border-width:2px}.qmx-select.active .qmx-select-styled:after{transform:translateY(-50%) rotate(180deg)}.qmx-select-options{position:absolute;top:105%;left:0;right:0;z-index:10;background-color:var(--md-sys-color-surface-bright);border:1px solid var(--md-sys-color-outline);border-radius:4px;max-height:0;overflow:hidden;opacity:0;transform:translateY(-10px);transition:all .3s var(--motion-easing);padding:8px 0;box-shadow:0 4px 8px 3px #00000026,0 1px 3px #0000004d}.qmx-select.active .qmx-select-options{max-height:200px;opacity:1;transform:translateY(0)}.qmx-select-options div{padding:12px 16px;cursor:pointer;transition:background-color .2s var(--motion-easing);font-size:16px}.qmx-select-options div:hover{background-color:var(--md-sys-color-on-primary-container)}.qmx-select-options div.selected{background-color:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary);font-weight:500}.qmx-range-slider-wrapper{display:flex;flex-direction:column;gap:8px;padding:16px 0}.qmx-range-slider-container{position:relative;height:24px;display:flex;align-items:center}.qmx-range-slider-container input[type=range]{position:absolute;width:100%;height:4px;-webkit-appearance:none;appearance:none;background:none;pointer-events:none;margin:0}.qmx-range-slider-container input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;pointer-events:auto;width:20px;height:20px;background-color:var(--md-sys-color-primary);border-radius:50%;cursor:grab;border:none;transition:transform .2s var(--motion-easing),box-shadow .2s var(--motion-easing)}.qmx-range-slider-container input[type=range]::-webkit-slider-thumb:active{cursor:grabbing;transform:scale(1.2);box-shadow:0 0 0 10px #d0bcff4d}.qmx-range-slider-container input[type=range]::-moz-range-thumb{pointer-events:auto;width:20px;height:20px;background-color:var(--md-sys-color-primary);border-radius:50%;cursor:grab;border:none;transition:transform .2s var(--motion-easing),box-shadow .2s var(--motion-easing)}.qmx-range-slider-container input[type=range]::-moz-range-thumb:active{cursor:grabbing;transform:scale(1.2);box-shadow:0 0 0 10px #d0bcff4d}.qmx-range-slider-track-container{position:absolute;width:100%;height:4px;background-color:var(--md-sys-color-surface-container);border-radius:2px}.qmx-range-slider-progress{position:absolute;height:100%;background-color:var(--md-sys-color-primary);border-radius:2px}.qmx-range-slider-values{font-size:14px;color:var(--md-sys-color-primary);text-align:center;font-weight:500}.qmx-tooltip-icon{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;background-color:var(--md-sys-color-outline);color:var(--md-sys-color-surface-container);font-size:14px;font-weight:700;cursor:help;user-select:none;transition:background-color .2s var(--motion-easing),transform .2s var(--motion-easing)}.qmx-tooltip-icon:hover{background-color:var(--md-sys-color-on-surface-variant);transform:scale(1.1)}#qmx-global-tooltip{position:fixed;background-color:var(--surface-container-highest);color:var(--md-sys-color-on-surface);padding:6px 12px;border-radius:4px;box-shadow:0 4px 8px 3px #00000026,0 1px 3px #0000004d;font-size:14px;font-weight:400;line-height:1.4;z-index:10002;max-width:320px;opacity:0;visibility:hidden;transform:scale(.9);transition:opacity .15s var(--motion-easing),transform .15s var(--motion-easing),visibility .15s;pointer-events:none}#qmx-global-tooltip.visible{opacity:1;visibility:visible;transform:scale(1)}';
importCSS(mainCss);
const danmukuPopupCss = ".dda-popup{position:fixed;z-index:9999;background:var(--md-sys-color-surface-container);border:1px solid var(--md-sys-color-outline);transition:all .3s var(--motion-easing),box-shadow .3s var(--motion-easing);border-radius:12px;box-shadow:0 4px 8px 3px #00000026,0 1px 3px #0000004d;max-width:400px;max-height:300px;overflow:hidden;opacity:0;transform:translateY(-10px)}.dda-popup.show{opacity:1;transform:translateY(0)}.dda-popup.selection-mode-active{border-color:var(--md-sys-color-primary);box-shadow:0 6px 16px 4px #0003,0 2px 6px #0006,0 0 0 1px var(--md-sys-color-primary);background:var(--md-sys-color-surface-bright)}.dda-popup-content{max-height:300px;overflow-y:auto;padding:4px 0}.dda-popup-item{padding:8px 16px;cursor:pointer;border-bottom:1px solid var(--md-sys-color-outline);transition:all .25s cubic-bezier(.4,0,.2,1);min-height:40px;display:flex;flex-direction:column;justify-content:center;position:relative;border-left:6px solid transparent;will-change:transform}.dda-popup-item-active{background-color:var(--md-sys-color-tertiary-container);border-left-color:var(--md-sys-color-tertiary);transform:translate(2px);box-shadow:0 4px 12px #0003,inset 0 0 0 2px rgba(var(--md-sys-color-tertiary-rgb),.3);z-index:10}.dda-popup-item:last-child{border-bottom:none}.dda-popup-item:hover{background-color:var(--md-sys-color-surface-bright);transform:translate(4px)}.dda-preview-tooltip{position:fixed;z-index:10000;background:var(--md-sys-color-surface-bright);border:1px solid var(--md-sys-color-outline);border-radius:8px;padding:12px 16px;box-shadow:0 8px 24px #0000004d;max-width:400px;word-wrap:break-word;font-size:14px;color:var(--md-sys-color-on-surface);opacity:0;transform:translateY(-10px);transition:opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);pointer-events:none}.dda-preview-tooltip.show{opacity:1;transform:translateY(0)}.dda-popup-item-text{font-size:14px;color:var(--md-sys-color-on-surface);line-height:1.4;margin-bottom:4px}.dda-popup-item-active .dda-popup-item-text{color:var(--md-sys-color-on-tertiary-container);font-weight:600}.dda-popup-item-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.dda-popup-tag{display:inline-block;padding:2px 6px;background-color:var(--md-sys-color-tertiary);color:var(--md-sys-color-on-primary);font-size:11px;border-radius:12px;line-height:1.2}.dda-popup-item-active .dda-popup-tag{background-color:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}.dda-popup-empty{max-height:60px}.dda-empty-message{padding:16px;text-align:center;color:var(--md-sys-color-on-surface-variant);font-size:13px}@media (max-width: 480px){.dda-popup{max-width:90vw;left:5vw!important;right:5vw!important}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.dda-popup.animate-in{animation:fadeInUp .2s var(--motion-easing)}.send-button:hover{background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.send-button:active{transform:scale(.98)}";
importCSS(danmukuPopupCss);
const candidateCapsulesCss = '.ddp-candidate-capsules{display:flex;flex-wrap:nowrap;gap:6px;padding:var(--ddp-capsule-padding, 8px) 12px;background:#000000d9;border-radius:8px;margin:var(--ddp-capsule-margin, 8px) 12px;max-width:calc(100% - 24px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none;position:relative;z-index:1000}.ddp-candidate-capsules::-webkit-scrollbar{display:none}.ddp-candidate-capsules.multi-row{flex-wrap:wrap;max-height:120px;overflow-y:auto;mask:none;-webkit-mask:none}.ddp-candidate-capsule{flex-shrink:0;padding:var(--ddp-capsule-item-padding, 3px) 8px;background:#ffffff1a;border:1px solid rgba(255,255,255,.2);border-radius:12px;color:#fff;font-size:12px;line-height:1.3;cursor:pointer;transition:all .25s cubic-bezier(.4,0,.2,1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;direction:ltr;text-align:left;max-width:150px;min-width:30px;height:var(--ddp-capsule-item-height, 24px);display:flex;align-items:center;justify-content:flex-start;box-sizing:border-box;user-select:none;position:relative}.ddp-candidate-capsules.multi-row .ddp-candidate-capsule{flex:0 0 calc(25% - 5px);max-width:calc(25% - 5px);min-width:60px}.ddp-candidate-capsule:hover{background:#fff3;border-color:#fff6;transform:translateY(-1px);box-shadow:0 2px 4px #0003}.ddp-candidate-capsule.active{background:#f60;border-color:#f83;color:#fff;font-weight:500;box-shadow:0 2px 6px #ff66004d}.ddp-candidate-capsules.selection-mode-active{box-shadow:0 0 0 2px #f60;background:#000000e6}.ddp-candidate-capsule[title]{position:relative}.ddp-capsule-preview{position:fixed;z-index:10000;background:#282828f2;border:1px solid rgba(255,255,255,.2);border-radius:8px;padding:8px 12px;box-shadow:0 4px 8px 3px #0000004d,0 1px 3px #0006;max-width:300px;min-width:100px;word-wrap:break-word;white-space:normal;opacity:0;transform:translateY(-5px);transition:opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);pointer-events:none;font-size:13px;line-height:1.4;color:#fff;backdrop-filter:blur(4px)}.ddp-capsule-preview.show{opacity:1;transform:translateY(0)}.ddp-capsule-preview:before{content:"";position:absolute;bottom:-5px;left:50%;transform:translate(-50%);width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid rgba(40,40,40,.95)}.ddp-capsule-preview.show-below:before{bottom:auto;top:-5px;border-top:none;border-bottom:5px solid rgba(40,40,40,.95)}.ddp-capsule-preview.active{border-color:#f60;background:#323232f2;box-shadow:0 4px 8px 3px #0000004d,0 1px 3px #0006,0 0 0 1px #f60}.ddp-capsule-preview.active:before{border-top-color:#323232f2}.ddp-capsule-preview.active.show-below:before{border-bottom-color:#323232f2}.layout-Player-chat .Chat .ddp-candidate-capsules{z-index:1000;position:relative}@media (max-width: 768px){.ddp-candidate-capsules{gap:6px;padding:6px 8px}.ddp-candidate-capsule{padding:4px 8px;font-size:12px;max-width:150px}}@media (prefers-color-scheme: dark){.ddp-candidate-capsules{box-shadow:0 2px 8px #00000040}.ddp-candidate-capsule:hover{box-shadow:0 2px 8px #0000004d}}@keyframes ddp-capsule-appear{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.ddp-candidate-capsules{animation:ddp-capsule-appear .2s var(--motion-easing)}.ddp-candidate-capsule{animation:ddp-capsule-appear .3s var(--motion-easing) backwards}.ddp-candidate-capsule:nth-child(1){animation-delay:.05s}.ddp-candidate-capsule:nth-child(2){animation-delay:.1s}.ddp-candidate-capsule:nth-child(3){animation-delay:.15s}.ddp-candidate-capsule:nth-child(4){animation-delay:.2s}.ddp-candidate-capsule:nth-child(5){animation-delay:.25s}';
importCSS(candidateCapsulesCss);
class DouyuDanmukuAssistant {
constructor() {
this.initialized = false;
this.modules = {};
}
init() {
return __async(this, null, function* () {
try {
Utils.log("初始化斗鱼弹幕助手...");
if (document.readyState === "loading") {
yield new Promise((resolve) => {
document.addEventListener("DOMContentLoaded", resolve);
});
}
const dbSuccess = yield DanmukuDB.init();
if (!dbSuccess) {
Utils.log("数据库初始化失败,某些功能可能无法正常工作", "warn");
}
yield this.firstTimeImport();
KeyboardController.init();
yield InputManager.init();
this.initialized = true;
Utils.log("斗鱼弹幕助手初始化完成");
} catch (error) {
Utils.log(`初始化失败: ${error.message}`, "error");
}
});
}
firstTimeImport() {
return __async(this, null, function* () {
try {
const dataCount = yield DanmukuDB.getDataCount();
if (dataCount === 0) {
Utils.log("数据库为空,开始首次数据导入...");
const result = yield DanmukuDB.autoImportData();
if (result && result.successCount > 0) {
Utils.log(`首次数据导入成功,共导入 ${result.successCount} 条弹幕。`);
} else {
Utils.log("首次数据导入失败或没有导入任何数据。", "warn");
}
} else {
Utils.log(`数据库中已存在 ${dataCount} 条数据,跳过首次导入。`);
}
} catch (error) {
Utils.log(`检查首次导入时发生错误: ${error.message}`, "error");
}
});
}
destroy() {
if (!this.initialized) return;
this.initialized = false;
Utils.log("斗鱼弹幕助手已销毁");
}
}
if (window.douyuDanmakuAssistantLoaded) {
Utils.log("检测到重复执行,已阻止。请检查是否安装了多个版本的插件。", "warn");
} else {
window.douyuDanmakuAssistantLoaded = true;
const app = new DouyuDanmukuAssistant();
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () => {
app.init();
});
} else {
app.init();
}
window.addEventListener("beforeunload", () => {
app.destroy();
});
window.DouyuDanmukuAssistant = app;
window.DanmukuDB = DanmukuDB;
}
})
};
}));
System.register("./__vite-browser-external-2Ng8QIWW-Xya9USxv.js", [], (function (exports, module) {
'use strict';
return {
execute: (function () {
const __viteBrowserExternal = exports("default", {});
})
};
}));
System.import("./__entry.js", "./");