B站录播同步视听

在B站视频内外挂本地视频,主要用于看录播时和主播同步看B站直播不能放出画面的视频

// ==UserScript==
// @name         B站录播同步视听
// @namespace    simultaneous-hearing-and-sight
// @version      0.0.3
// @author       icinggslits
// @description  在B站视频内外挂本地视频,主要用于看录播时和主播同步看B站直播不能放出画面的视频
// @license      MIT
// @icon         https://www.bilibili.com/favicon.ico
// @match        *://www.bilibili.com/video/*
// @grant        GM_addStyle
// ==/UserScript==

/*
* 该脚本由Vite构建,源码见 https://github.com/icinggslits/simultaneous-hearing-and-sight
*/

(e=>{if(typeof GM_addStyle=="function"){GM_addStyle(e);return}const n=document.createElement("style");n.textContent=e,document.head.append(n)})(" :root{--measuringBlockResizeSize: 15px }.__sign_SHAS_panel{position:absolute;display:flex;flex-direction:column;background-color:#fff;box-shadow:0 1px 1px #0000000f,0 2px 4px #0000000f,0 4px 4px #0000000f,0 8px 8px #0000000f,0 16px 16px #0000000f,0 -4px 16px #00000012;z-index:100000}.__sign_SHAS_panel.hide{display:none}.__sign_SHAS_panel .top,.__sign_SHAS_panel .bottom{display:flex;width:100%;flex-basis:24px;background-color:#dcdcdc}.__sign_SHAS_panel .top .left{position:relative;display:flex;flex-grow:1}.__sign_SHAS_panel .top .left .back{flex-basis:24px;position:relative;cursor:pointer;display:none}.__sign_SHAS_panel .top .left .back .back_line_1{position:absolute;width:35%;height:1px;background-color:gray;left:7px;top:15px;transform:rotate(45deg)}.__sign_SHAS_panel .top .left .back .back_line_2{position:absolute;width:35%;height:1px;background-color:gray;left:7px;top:9px;transform:rotate(135deg)}.__sign_SHAS_panel .top .right{position:relative;flex-basis:24px;cursor:pointer}.__sign_SHAS_panel .top .right .close_line_1{position:absolute;width:65%;height:1px;background-color:gray;left:3px;top:11px;transform:rotate(45deg)}.__sign_SHAS_panel .top .right .close_line_2{position:absolute;width:65%;height:1px;background-color:gray;left:3px;top:11px;transform:rotate(-45deg)}.__sign_SHAS_panel .main{width:100%;flex-grow:1;flex-direction:column;flex-basis:100%;overflow:auto}.__sign_SHAS_panel .main .listPage .create_new_line{margin-top:4px}.__sign_SHAS_panel .main .listPage .create_new_line .create_new_line_button{font-size:20px;cursor:pointer;margin-left:22px;margin-top:8px;transition:background-color .3s;padding:0 4px;border-radius:4px}.__sign_SHAS_panel .main .listPage .create_new_line .create_new_line_button:hover{background-color:#dcdcdc}.__sign_SHAS_panel .main .listPage .content{display:flex;flex-direction:column;margin-top:10px;-webkit-user-select:none;user-select:none}.__sign_SHAS_panel .main .page.hide{display:none}.__sign_SHAS_panel .main .content .content_line,.__sign_SHAS_panel .main .content .content_column_line{display:flex;padding:10px 10px 0 20px}.__sign_SHAS_panel .main .content .content_line>div,.__sign_SHAS_panel .main .content .content_column_line>div{display:flex;justify-content:center;font-size:16px}.__sign_SHAS_panel .main .content .content_line .content_line_name{position:relative;cursor:pointer;padding-right:6px}.__sign_SHAS_panel .main .content .content_line .content_line_videoEdit{color:#dcdcdc;transition:color .3s}.__sign_SHAS_panel .main .content .content_line .content_line_videoEdit.editable{cursor:pointer;color:#000}.__sign_SHAS_panel .main .content .content_line .content_line_videoEdit.editable:hover{color:#00bfff}.__sign_SHAS_panel .main .content .content_line .content_line_name,.__sign_SHAS_panel .main .content .content_column_line .content_column_name{flex-basis:40%}.__sign_SHAS_panel .main .content .content_line .content_line_videoInput{flex-basis:60%;display:block;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;cursor:pointer;transition:all .3s;text-align:center}.__sign_SHAS_panel .main .content .content_column_line .content_column_videoInput{flex-basis:60%}.__sign_SHAS_panel .main .content .content_line .content_line_videoInput:hover{color:#00bfff}.__sign_SHAS_panel .main .content .content_line .content_line_videoEdit,.__sign_SHAS_panel .main .content .content_line .content_line_volume,.__sign_SHAS_panel .main .content .content_column_line .content_column_edit,.__sign_SHAS_panel .main .content .content_column_line .content_column_volume{flex-basis:80px}.__sign_SHAS_panel .main .content .content_column_line .content_column_delete,.__sign_SHAS_panel .main .content .content_line .content_line_delete{flex-basis:36px}.__sign_SHAS_panel .main .content .content_line .content_line_delete{transition:all .3s;cursor:pointer;text-align:center;border-radius:12px}.__sign_SHAS_panel .main .content .content_line .content_line_delete:hover{background-color:#dcdcdc}.__sign_SHAS_panel .user_input,.__sign_SHAS_panel .user_input:focus{position:absolute;left:0;top:-1px;width:100%;height:100%;font-size:16px;display:block;outline:0;border:0;text-align:center}.__sign_SHAS_panel .main .editPage{display:block;flex-direction:column}.__sign_SHAS_panel .main .editPage .editPage_title{padding:10px 0;font-size:18px;text-align:center}.__sign_SHAS_panel .main .editPage .editPage_column{display:flex;padding:4px 0}.__sign_SHAS_panel .main .editPage .editPage_column .editPage_column_descriptions{text-align:center;justify-content:center;flex-basis:50%;font-size:16px}.__sign_SHAS_panel .main .editPage .editPage_column .editPage_column_occupy{padding:0 6px;flex-basis:20px;margin-right:30px}.__sign_SHAS_panel .main .editPage .content{padding:10px 0}.__sign_SHAS_panel .main .editPage .editPage_tool{display:flex;padding:0 4px;height:24px}.__sign_SHAS_panel .main .editPage .editPage_newPoint{display:inline;padding:0 4px;margin:0 10px;cursor:pointer;transition:all .3s;border-radius:4px;line-height:24px}.__sign_SHAS_panel .main .editPage .editPage_newPoint:hover{background-color:#dcdcdc}.__sign_SHAS_panel .main .editPage .editPage_export{position:relative;top:1px;font-size:14px;color:gray;cursor:pointer;transition:all .3s;padding:0 4px}.__sign_SHAS_panel .main .editPage .editPage_export:hover{color:#87ceeb}.__sign_SHAS_panel .main .editPage .editPage_export:active{outline:gainsboro 1px solid}.__sign_SHAS_panel .main .editPage .editPage_bottom{position:absolute;bottom:0;left:0;width:100%;height:24px;display:flex}.__sign_SHAS_panel .main .editPage .editPage_bottom .editPage_bottom_externalVideoTime{text-align:center;flex-basis:120px;font-size:12px;color:gray;line-height:24px}.__sign_SHAS_measuringBlock{position:absolute;cursor:grab;display:flex;opacity:0;pointer-events:none;transition:opacity .3s}.__sign_SHAS_measuringBlock.edit{pointer-events:all}.__sign_SHAS_measuringBlock.edit video{outline:gainsboro 1px solid;opacity:.5}.__sign_SHAS_measuringBlock.show,.__sign_SHAS_measuringBlock.alwaysShow{opacity:1;z-index:1}.__sign_SHAS_measuringBlock.alwaysShow{z-index:2}.__sign_SHAS_measuringBlock video{position:absolute;width:100%;height:100%;pointer-events:none;outline:transparent 1px solid;transition:opacity .3s,outline-color .3s}.__sign_SHAS_measuringBlock.edit .__sign_SHAS_measuringBlock_resize{background-color:#0000001a;position:absolute;right:0;bottom:0;cursor:nwse-resize;border-top:gainsboro 1px solid;border-left:gainsboro 1px solid;width:var(--measuringBlockResizeSize);height:var(--measuringBlockResizeSize)}.__sign_SHAS_videoArea{position:absolute;pointer-events:none}.__sign_SHAS_timestampEditor{width:200px;display:flex;flex-grow:1;flex-basis:80px;margin-left:10px}.__sign_SHAS_timestampEditor_hours,.__sign_SHAS_timestampEditor_minutes,.__sign_SHAS_timestampEditor_seconds,.__sign_SHAS_timestampEditor_milliseconds{position:relative;flex-grow:1;font-size:16px;text-align:center}.__sign_SHAS_referencePointLine{display:flex}.__sign_SHAS_referencePointLine_timestampEditorOfExternalVideo,.__sign_SHAS_referencePointLine_timestampEditorOfOriginalVideo{justify-content:center;flex-basis:50%}.__sign_SHAS_referencePointLine_delete{text-align:center;padding:0 2px;flex-basis:20px;margin-right:30px;cursor:pointer;transition:all .3s;border-radius:6px;line-height:24px}.__sign_SHAS_referencePointLine_delete:hover{background-color:#dcdcdc}.bpx-player-video-area video.ban{pointer-events:none}.__sign_SHAS_replyListImport{cursor:pointer;text-decoration:underline;transition:color .3s}.__sign_SHAS_replyListImport:hover{color:gray}.__sign_SHAS_replyListImport:active{transition:color 0s;color:#8b0000} ");

(function () {
  'use strict';

  var __accessCheck = (obj, member, msg) => {
    if (!member.has(obj))
      throw TypeError("Cannot " + msg);
  };
  var __privateGet = (obj, member, getter) => {
    __accessCheck(obj, member, "read from private field");
    return getter ? getter.call(obj) : member.get(obj);
  };
  var __privateAdd = (obj, member, value) => {
    if (member.has(obj))
      throw TypeError("Cannot add the same private member more than once");
    member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
  };
  var __privateSet = (obj, member, value, setter) => {
    __accessCheck(obj, member, "write to private field");
    setter ? setter.call(obj, value) : member.set(obj, value);
    return value;
  };
  var __privateMethod = (obj, member, method) => {
    __accessCheck(obj, member, "access private method");
    return method;
  };
  var _intervals, _cb, _timeoutID, _inProgress, _execute, execute_fn;
  const Config = {
    // 面板开关按键
    code: "KeyP",
    // 是否需要按住Ctrl
    ctrlKey: false,
    // 是否需要按住Alt
    altKey: false,
    // 是否需要按住Shift
    shiftKey: true,
    // 测量方块边长
    measuringBlockResizeSize: 15,
    // 默认音量
    defaultVolume: 40
  };
  const Convert = {
    /**
     * 转换为数字
     * @param value {any}
     * @param unable {number}
     * @return {number}
     */
    toNumber(value, unable = 0) {
      let result = unable;
      switch (true) {
        case typeof value === "string":
          (() => {
            result = Number(value.replace(/[^\d.-]/ig, ""));
          })();
          break;
        case typeof value === "number":
          (() => {
            result = value;
          })();
          break;
      }
      if (isFinite(result)) {
        return result;
      } else {
        return unable;
      }
    },
    /**
     * 是否是数字
     *
     * 字符串'25' - true
     *
     * @param value {any}
     * @return {boolean}
     */
    isNumber(value) {
      return !isNaN(parseFloat(value)) && isFinite(value);
    },
    /**
     * 过滤虚值返回规定的值
     * @param value
     * @param unreal
     * @return {*|null}
     */
    toReal(value, unreal = null) {
      if (!Convert.isReal(value)) {
        return unreal;
      } else {
        return value;
      }
    },
    /**
     * 是否是实在的值
     * @param value {any}
     * @return {boolean}
     */
    isReal(value) {
      return !(value === void 0 || value === null || Number.isNaN(value));
    },
    /**
     * 转为Array
     * @template T
     * @param value {T}
     * @param arrayInArray {boolean} 是否包含数组
     * @return {T[]}
     */
    toList(value, arrayInArray = false) {
      if (Array.isArray(value) && Array.isArray(value[0]) === arrayInArray) {
        return value;
      } else {
        return [value];
      }
    },
    /**
     * 限制number在lower<=number<=upper之间,返回这个数
     * @param number {number}
     * @param lower {number}
     * @param upper {number}
     * @return {number}
     */
    limits(number, lower, upper) {
      return this.lowerLimit(this.upperLimit(number, upper), lower);
    },
    /**
     * 限制number在number<=upper之间,返回这个数
     * @param number
     * @param upper
     * @return {number}
     */
    upperLimit(number, upper) {
      if (number > upper) {
        return upper;
      } else {
        return number;
      }
    },
    /**
     * 限制number在lower<=number之间,返回这个数
     * @param number
     * @param lower
     * @return {number}
     */
    lowerLimit(number, lower) {
      if (number < lower) {
        return lower;
      } else {
        return number;
      }
    },
    /**
     * 是否是Error
     * @param object
     * @return {boolean}
     */
    isError(object) {
      return Error.prototype.isPrototypeOf(object);
    }
  };
  const Range = document.createRange();
  const createNode = (fragment) => {
    const contextualFragment = Range.createContextualFragment(fragment.trim());
    return contextualFragment.childNodes[0];
  };
  const mouseDrag = (() => {
    let press = false;
    let isTarget = false;
    let targetCb;
    let original_x = 0;
    let original_y = 0;
    let onceData;
    const targetDomList = [];
    document.addEventListener("pointerdown", (event) => {
      const { x, y } = event;
      press = true;
      original_x = x;
      original_y = y;
      for (const [el, cb, onceCb] of targetDomList) {
        if (document.elementFromPoint(x, y) === el) {
          isTarget = true;
          targetCb = cb;
          onceData = onceCb == null ? void 0 : onceCb();
          event.preventDefault();
          break;
        }
      }
    });
    document.addEventListener("pointerup", (event) => {
      press = false;
      isTarget = false;
    });
    document.addEventListener("pointermove", (event) => {
      if (press && isTarget) {
        const { x, y } = event;
        targetCb({
          original_x,
          original_y,
          x,
          y,
          diff_x: x - original_x,
          diff_y: y - original_y,
          onceData
        });
      }
    });
    return (el, cb, onceCb) => {
      targetDomList.push([el, cb, onceCb]);
    };
  })();
  const barDrag = /* @__PURE__ */ (() => {
    return (bar, body, limitNode = null) => {
      let original_left = 0;
      let original_top = 0;
      document.addEventListener("pointerdown", (event) => {
        const { x, y } = event;
        if (document.elementFromPoint(x, y) === bar) {
          original_left = Convert.toNumber(body.style.left);
          original_top = Convert.toNumber(body.style.top);
        }
      });
      mouseDrag(bar, (dragInfo) => {
        const { diff_x, diff_y } = dragInfo;
        body.style.left = `${original_left + diff_x}px`;
        body.style.top = `${original_top + diff_y}px`;
      });
    };
  })();
  const userSelectFile = (suffix) => {
    return new Promise((resolve, reject) => {
      const inputFileNode = createNode(`<input type="file" accept="${suffix}" />`);
      inputFileNode.addEventListener("change", () => {
        resolve(inputFileNode.files[0]);
        inputFileNode.remove();
      });
      inputFileNode.click();
    });
  };
  const parseTime = {
    /**
     *
     * @param {number} seconds
     * @return {{milliseconds: number, hours: number, seconds: number, minutes: number}}
     */
    secondsToTime(seconds) {
      const milliseconds = Math.floor(seconds * 1e3);
      const date = new Date(milliseconds);
      const hours = date.getUTCHours();
      const minutes = date.getUTCMinutes();
      const remainderSeconds = date.getUTCSeconds();
      const remainderMilliseconds = date.getUTCMilliseconds();
      return {
        hours,
        minutes,
        seconds: remainderSeconds,
        milliseconds: remainderMilliseconds
      };
    }
  };
  class Trigger {
    /**
     *
     * @param {function} cb
     * @param {number} intervals
     */
    constructor(cb, intervals) {
      __privateAdd(this, _execute);
      __privateAdd(this, _intervals, 10);
      /** @type function */
      __privateAdd(this, _cb, void 0);
      __privateAdd(this, _timeoutID, void 0);
      __privateAdd(this, _inProgress, false);
      __privateSet(this, _intervals, intervals);
      __privateSet(this, _cb, cb);
    }
    stop() {
      if (__privateGet(this, _inProgress)) {
        __privateSet(this, _inProgress, false);
        clearTimeout(__privateGet(this, _timeoutID));
      }
    }
    start() {
      if (!__privateGet(this, _inProgress)) {
        __privateSet(this, _inProgress, true);
        __privateGet(this, _cb).call(this);
        __privateMethod(this, _execute, execute_fn).call(this);
      }
    }
  }
  _intervals = new WeakMap();
  _cb = new WeakMap();
  _timeoutID = new WeakMap();
  _inProgress = new WeakMap();
  _execute = new WeakSet();
  execute_fn = function() {
    __privateSet(this, _timeoutID, setTimeout(() => {
      __privateGet(this, _cb).call(this);
      __privateMethod(this, _execute, execute_fn).call(this);
    }, __privateGet(this, _intervals)));
  };
  const triggerBuilder = (cb, intervals = 100) => new Trigger(cb, intervals);
  const findInsertIndex = (numberList, x) => {
    let low = 0;
    let high = numberList.length - 1;
    while (low <= high) {
      let mid = Math.floor((low + high) / 2);
      if (numberList[mid] === x) {
        return mid;
      } else if (numberList[mid] < x) {
        low = mid + 1;
      } else {
        high = mid - 1;
      }
    }
    return low;
  };
  const debounceExecuteBuilder = (fn, milliseconds = 300) => {
    const timeoutIDAttr = Symbol();
    const debounceFn = () => {
      clearTimeout(debounceFn[timeoutIDAttr]);
      debounceFn[timeoutIDAttr] = setTimeout(() => fn(), milliseconds);
    };
    debounceFn[timeoutIDAttr] = -1;
    return debounceFn;
  };
  const triggerSource = {
    PLAY: Symbol("play"),
    PAUSE: Symbol("pause"),
    SEEKING: Symbol("seeking"),
    TRIGGER: Symbol("trigger")
  };
  const videoProportions = () => {
    const bilibiliPlayerVideo2 = document.querySelector(".bpx-player-video-area video");
    if (bilibiliPlayerVideo2) {
      return {
        videoWidth: bilibiliPlayerVideo2.videoWidth,
        videoHeight: bilibiliPlayerVideo2.videoHeight
      };
    } else {
      return {
        videoWidth: 1920,
        videoHeight: 1080
      };
    }
  };
  const { area, videoArea } = (() => {
    const area2 = document.querySelector(".bpx-player-video-area");
    const videoArea2 = createNode(`<div class="__sign_SHAS_videoArea"></div>`);
    area2.appendChild(videoArea2);
    const { width, height } = area2.getBoundingClientRect();
    area2.dataset.lastWidth = width.toString();
    area2.dataset.lastHeight = height.toString();
    return { area: area2, videoArea: videoArea2 };
  })();
  const updateArea = () => {
    const { width: areaWidth, height: areaHeight } = area.getBoundingClientRect();
    const { videoWidth, videoHeight } = videoProportions();
    const { width, height } = area.getBoundingClientRect();
    if (videoHeight * (areaWidth / areaHeight) >= videoWidth) {
      const videoAreaWidth = areaHeight * (videoWidth / videoHeight);
      videoArea.style.left = `${(areaWidth - videoAreaWidth) / 2}px`;
      videoArea.style.top = `0`;
      videoArea.style.width = `${videoAreaWidth}px`;
      videoArea.style.height = "100%";
    } else {
      const videoAreaHeight = areaWidth * (videoHeight / videoWidth);
      videoArea.style.top = `${(areaHeight - videoAreaHeight) / 2}px`;
      videoArea.style.left = `0`;
      videoArea.style.width = "100%";
      videoArea.style.height = `${videoAreaHeight}px`;
    }
    area.dataset.lastWidth = width.toString();
    area.dataset.lastHeight = height.toString();
  };
  {
    const ob = new ResizeObserver(() => {
      updateArea();
    });
    ob.observe(area);
  }
  const bilibiliPlayerVideo = document.querySelector(".bpx-player-video-area video");
  const syncVideo = (source) => {
    const currentTime = bilibiliPlayerVideo.currentTime;
    const awaitingPlaybackList = [];
    const videoRange = externalVideoHub$1.allVideoRange();
    for (const { targetMeasuringBlock, keyframeList: keyframeList2 } of videoRange) {
      let latestStartTime = null;
      let targetOriginalTime = 0;
      let targetExternalVideoTime = 0;
      const maxEndTime = (() => {
        let max = Number.MIN_VALUE;
        keyframeList2.forEach(({ endTime }) => endTime > max ? max = endTime : null);
        return max;
      })();
      for (const keyframe of keyframeList2) {
        const { startTime, endTime, originalTime, externalVideoTime } = keyframe;
        if (currentTime >= originalTime && currentTime < maxEndTime) {
          if (latestStartTime === null) {
            latestStartTime = originalTime;
            targetOriginalTime = originalTime;
            targetExternalVideoTime = externalVideoTime;
          } else {
            if (latestStartTime < originalTime) {
              latestStartTime = originalTime;
              targetOriginalTime = originalTime;
              targetExternalVideoTime = externalVideoTime;
            }
          }
        }
      }
      if (latestStartTime !== null) {
        awaitingPlaybackList.push({
          measuringBlock: targetMeasuringBlock,
          currentTime: targetExternalVideoTime + currentTime - targetOriginalTime
        });
      }
    }
    that:
      for (const oneOfMeasuringBlock of externalVideoHub$1.allMeasuringBlock()) {
        for (const { measuringBlock, currentTime: currentTime2 } of awaitingPlaybackList) {
          if (oneOfMeasuringBlock === measuringBlock) {
            MeasuringBlock$1.show(measuringBlock);
            MeasuringBlock$1.videoSetCurrentTime(measuringBlock, currentTime2);
            switch (source) {
              case triggerSource.PAUSE:
                {
                  MeasuringBlock$1.videoPause(measuringBlock);
                }
                break;
              case triggerSource.PLAY:
                {
                  MeasuringBlock$1.videoPlay(measuringBlock);
                }
                break;
              case triggerSource.SEEKING:
                {
                  MeasuringBlock$1.videoPause(measuringBlock);
                  bilibiliPlayerVideo.addEventListener("canplay", () => {
                    MeasuringBlock$1.videoPlay(measuringBlock);
                  }, { once: true });
                }
                break;
              case triggerSource.TRIGGER:
                {
                  MeasuringBlock$1.videoPlay(measuringBlock);
                }
                break;
            }
            continue that;
          }
        }
        MeasuringBlock$1.videoPause(oneOfMeasuringBlock);
        MeasuringBlock$1.hide(oneOfMeasuringBlock);
      }
  };
  let keyframeList = [];
  let nextKeyframeIndex = 0;
  const triggerCallback = [];
  const trigger = triggerBuilder(() => {
    const currentTime = bilibiliPlayerVideo.currentTime;
    const nextKeyframe = keyframeList[nextKeyframeIndex];
    if (currentTime >= nextKeyframe) {
      syncVideo(triggerSource.TRIGGER);
      nextKeyframeIndex++;
    }
    triggerCallback.forEach((cb) => cb());
  });
  const videoTrigger = (callback) => {
    triggerCallback.push(callback);
  };
  const resetTriggerPointer = () => {
    const referencePointList = externalVideoHub$1.allReferencePoint();
    const currentTime = bilibiliPlayerVideo.currentTime;
    {
      keyframeList = [];
      for (const { originalTime, measuringBlock, externalVideoTime } of referencePointList) {
        keyframeList.push(originalTime);
      }
      nextKeyframeIndex = findInsertIndex(keyframeList, currentTime);
    }
  };
  bilibiliPlayerVideo.addEventListener("play", () => {
    resetTriggerPointer();
    syncVideo(triggerSource.PLAY);
    trigger.start();
  });
  bilibiliPlayerVideo.addEventListener("pause", () => {
    resetTriggerPointer();
    syncVideo(triggerSource.PAUSE);
    trigger.stop();
  });
  bilibiliPlayerVideo.addEventListener("seeking", () => {
    resetTriggerPointer();
    syncVideo(triggerSource.SEEKING);
  });
  bilibiliPlayerVideo.addEventListener("ratechange", (event) => {
    MeasuringBlock$1.setAllVideoPlaybackRate(bilibiliPlayerVideo.playbackRate);
  });
  let lastVideoPaused = false;
  let isBan = false;
  const bilibiliPlayerVideoController = {
    // 暂停b站视频并禁用交互
    pauseAndBan() {
      isBan = true;
      lastVideoPaused = bilibiliPlayerVideo.paused;
      bilibiliPlayerVideo.pause();
      bilibiliPlayerVideo.classList.add("ban");
    },
    // 解除禁用
    relieve() {
      if (isBan) {
        isBan = false;
        bilibiliPlayerVideo.classList.remove("ban");
        if (lastVideoPaused) {
          bilibiliPlayerVideo.pause();
        } else {
          bilibiliPlayerVideo.play().then();
        }
      }
    },
    syncVideo() {
      resetTriggerPointer();
      syncVideo();
    },
    /**
     *
     * @param {function} callback
     */
    videoTrigger(callback) {
      videoTrigger(callback);
    }
  };
  const regularExpression = {
    // 原本打算使用方括号,但是b站评论会自动把半角方括号变全角方括号([] -> 【】),所以换成了半角花括号
    // // 匹配主体的正则
    // patternMain: /(\[1v(.*?)])|(\{1v(.*?)})/g,
    //
    // // 匹配描述的正则
    // patternDescription: /(\[(.*?)]$)|(\{(.*?)}$)/,
    //
    // // 匹配包含可能存在的描述的正则
    // patternCompletely: /((\[(.*?)])?\[1v(.*?)])|((\{(.*?)})?\[1v(.*?)})/g,
    // 匹配主体的正则
    patternMain: /\{1v(.*?)}/g,
    // 匹配描述的正则
    patternDescription: /\{(.*?)}$/,
    // 匹配包含可能存在的描述的正则
    patternCompletely: /(\{(.*?)})?\{1v(.*?)}/g
  };
  const searchDeserializingData = (text) => {
    const list = [];
    const patternMain = regularExpression.patternMain;
    const patternDescription = regularExpression.patternDescription;
    let lastSliceIndex = 0;
    for (const regExpMatchArray of text.matchAll(patternMain)) {
      const frontText = regExpMatchArray.input.slice(lastSliceIndex, regExpMatchArray.index);
      const deserializingData = regExpMatchArray[1];
      lastSliceIndex = regExpMatchArray.index + regExpMatchArray[0].length;
      let description = null;
      const descriptionMatch = frontText.match(patternDescription);
      if (descriptionMatch) {
        description = descriptionMatch[1];
      }
      list.push({
        description,
        deserializingData
      });
    }
    return list;
  };
  const contentLineMappingConfig = /* @__PURE__ */ new Map();
  const contentLineMappingMeasuringBlock = /* @__PURE__ */ new Map();
  let referencePointOfCache = [];
  const contentLineMappingFile = /* @__PURE__ */ new Map();
  const serializeV1 = (contentLine) => {
    const { referencePointList } = contentLineMappingConfig.get(contentLine);
    const measuringBlock = contentLineMappingMeasuringBlock.get(contentLine);
    const list = [];
    for (const { originalTime, externalVideoTime } of referencePointList) {
      list.push(`${originalTime}>${externalVideoTime}`);
    }
    const listString = (() => {
      if (list.length === 0) {
        return "null";
      } else {
        return list.join(",");
      }
    })();
    return `{${ListContentLine.getName(contentLine)}}{1v${MeasuringBlock$1.serialize(measuringBlock)};${listString}}`;
  };
  const targetReferencePoint = (referencePointLine) => {
    const { panelNode: panel2, editingContentLine: editingContentLine2 } = Panel;
    const referencePointLineList = panel2.querySelectorAll(".__sign_SHAS_referencePointLine");
    for (let i = 0; i < referencePointLineList.length; i++) {
      const referencePointLineElement = referencePointLineList[i];
      if (referencePointLineElement === referencePointLine) {
        const externalVideo1 = contentLineMappingConfig.get(editingContentLine2);
        if (externalVideo1) {
          const { versions, referencePointList } = externalVideo1;
          return [referencePointList[i], i];
        }
        return null;
      }
    }
    return null;
  };
  const updateReferencePointOfCache = () => {
    referencePointOfCache = [];
    const panel2 = Panel.panelNode;
    const contentLineList = panel2.querySelectorAll(".content_line");
    let i = 0;
    for (const { versions, referencePointList } of contentLineMappingConfig.values()) {
      for (const { originalTime, externalVideoTime } of referencePointList) {
        referencePointOfCache.push({
          originalTime,
          externalVideoTime,
          measuringBlock: contentLineMappingMeasuringBlock.get(contentLineList[i])
        });
      }
      i++;
    }
    referencePointOfCache.sort(({ originalTime: a }, { originalTime: b }) => a - b);
  };
  const externalVideoHub = {
    addByContentLine(contentLine, measuringBlock) {
      contentLineMappingConfig.set(contentLine, {
        versions: "1",
        referencePointList: []
      });
      contentLineMappingMeasuringBlock.set(contentLine, measuringBlock);
      updateReferencePointOfCache();
    },
    /**
     *
     * @param contentLine
     * @return {?any}
     */
    getMeasuringBlock(contentLine) {
      return contentLineMappingMeasuringBlock.get(contentLine);
    },
    /**
     *
     * @param contentLine
     * @param {referencePoint} referencePoint
     * @return {boolean}
     */
    addReferencePoint(contentLine, referencePoint) {
      const referencePointList = contentLineMappingConfig.get(contentLine);
      if (referencePointList) {
        referencePointList.referencePointList.push(referencePoint);
        updateReferencePointOfCache();
        return true;
      }
      return false;
    },
    /**
     *
     * @param contentLine
     * @return {externalVideo1}
     */
    getReferencePointAll(contentLine) {
      return contentLineMappingConfig.get(contentLine);
    },
    setOriginalTimeOfReferencePoint(referencePointLine, seconds) {
      const ok = targetReferencePoint(referencePointLine);
      if (ok) {
        const [referencePoint] = ok;
        referencePoint.originalTime = seconds;
        updateReferencePointOfCache();
      }
    },
    setExternalVideoTimeBySeconds(referencePointLine, seconds) {
      const ok = targetReferencePoint(referencePointLine);
      if (ok) {
        const [referencePoint] = ok;
        referencePoint.externalVideoTime = seconds;
        updateReferencePointOfCache();
      }
    },
    deleteReferencePoint(referencePointLine) {
      const ok = targetReferencePoint(referencePointLine);
      if (ok) {
        const [referencePoint, i] = ok;
        const { versions, referencePointList } = contentLineMappingConfig.get(Panel.editingContentLine);
        referencePointList.splice(i, 1);
      }
    },
    /**
     *
     * @param contentLine
     * @param {File} file
     */
    setFile(contentLine, file) {
      contentLineMappingFile.set(contentLine, file);
    },
    /**
     *
     * @param contentLine
     * @return {?File}
     */
    getFile(contentLine) {
      return contentLineMappingFile.get(contentLine);
    },
    /**
     * 返回全部的referencePoint数组,根据originalTime按从小到大排序
     * @return {{originalTime: number, externalVideoTime: number, measuringBlock}[]}
     */
    allReferencePoint() {
      return referencePointOfCache;
    },
    /**
     *
     * @return {any[]}
     */
    allMeasuringBlock() {
      return [...contentLineMappingMeasuringBlock.values()];
    },
    /**
     *
     * @return {any[]}
     */
    allContentLine() {
      return [...contentLineMappingMeasuringBlock.keys()];
    },
    /**
     *
     * @return {{targetMeasuringBlock, keyframeList: {startTime: number, endTime: number, originalTime: number, externalVideoTime: number}[]}[]}
     */
    allVideoRange() {
      const videoRange = [];
      for (const [contentLine, measuringBlock] of contentLineMappingMeasuringBlock) {
        const { versions, referencePointList } = contentLineMappingConfig.get(contentLine);
        const measuringBlock2 = contentLineMappingMeasuringBlock.get(contentLine);
        const { currentTime, duration } = MeasuringBlock$1.getVideoInfo(measuringBlock2);
        const keyframeList2 = [];
        if (referencePointList.length > 0) {
          for (const { externalVideoTime, originalTime } of referencePointList) {
            const startTime = originalTime - externalVideoTime;
            const endTime = startTime + duration;
            keyframeList2.push({
              startTime,
              endTime,
              originalTime,
              externalVideoTime
            });
          }
        }
        videoRange.push({
          targetMeasuringBlock: measuringBlock2,
          keyframeList: keyframeList2
        });
      }
      videoRange.sort(({ startTime: a }, { startTime: b }) => a - b);
      return videoRange;
    },
    deleteContentLine(contentLine) {
      contentLineMappingConfig.delete(contentLine);
      contentLineMappingMeasuringBlock.delete(contentLine);
      contentLineMappingFile.delete(contentLine);
    },
    /**
     *
     * @param contentLine
     * @return {?string}
     */
    serialize(contentLine) {
      const { versions, referencePointList } = contentLineMappingConfig.get(contentLine);
      contentLineMappingMeasuringBlock.get(contentLine);
      return (() => {
        switch (versions) {
          case "1": {
            return serializeV1(contentLine);
          }
        }
        return null;
      })();
    },
    deserializeTo(contentLine) {
    }
  };
  const externalVideoHub$1 = externalVideoHub;
  const videoAttr = Symbol();
  const targetNodeAttr = Symbol();
  const importedCreateAttr = Symbol("Marked as imported to create");
  const measuringBlockMappingResize = /* @__PURE__ */ new Map();
  const measuringBlockMappingPosition = /* @__PURE__ */ new Map();
  const updateVideoRatios = (measuringBlock) => {
    const video = measuringBlock.querySelector("video");
    measuringBlock.dataset.videoWidth = video.videoWidth;
    measuringBlock.dataset.videoHeight = video.videoHeight;
    updateArea();
  };
  const MeasuringBlock = {
    /**
     * 是否是MeasuringBlock对象
     * @param measuringBlock
     * @return {boolean}
     */
    is(measuringBlock) {
      var _a;
      return !!((_a = measuringBlock == null ? void 0 : measuringBlock.classList) == null ? void 0 : _a.contains(".__sign_SHAS_measuringBlock"));
    },
    /**
     *
     * @param targetNode - 插入到targetNode
     */
    create(targetNode) {
      const measuringBlock = createNode(`
			<div class="__sign_SHAS_measuringBlock">
				<video></video>
				<div class="__sign_SHAS_measuringBlock_resize"></div>
			</div>
		`);
      measuringBlock.style.width = "300px";
      measuringBlock.style.height = "200px";
      measuringBlock.style.top = "0";
      measuringBlock.style.left = "0";
      const video = measuringBlock.querySelector("video");
      measuringBlock[videoAttr] = video;
      measuringBlock[targetNodeAttr] = targetNode;
      video.addEventListener("loadedmetadata", () => {
        MeasuringBlock.setVideoRatios(measuringBlock, video.videoWidth, video.videoHeight);
        if (measuringBlock[importedCreateAttr] !== true) {
          MeasuringBlock.setPositionByRatio(measuringBlock, [0, 1], [0, 1]);
        }
      });
      video.addEventListener("ended", () => {
        MeasuringBlock.hide(measuringBlock);
      });
      const resizeBlock = measuringBlock.querySelector(".__sign_SHAS_measuringBlock_resize");
      mouseDrag(resizeBlock, ({ diff_x, diff_y, onceData: { width, height } }) => {
        const { left: measuringBlockLeft, top: measuringBlockTop } = measuringBlock.getBoundingClientRect();
        const {
          right: targetNodeRight,
          bottom: targetNodeBottom,
          width: targetNodeWidth,
          height: targetNodeHeight
        } = targetNode.getBoundingClientRect();
        const maxResizeWidth = targetNodeRight - measuringBlockLeft;
        const maxResizeHeight = targetNodeBottom - measuringBlockTop;
        const resizeWidth = Convert.limits(
          width + diff_x,
          Config.measuringBlockResizeSize,
          maxResizeWidth
        );
        if (Convert.isNumber(measuringBlock.dataset.videoWidth)) {
          const aspectRatio = Convert.toNumber(measuringBlock.dataset.videoHeight) / Convert.toNumber(measuringBlock.dataset.videoWidth);
          const resizeHeight = Convert.limits(
            height + diff_x * aspectRatio,
            Config.measuringBlockResizeSize,
            maxResizeHeight
          );
          if (resizeHeight !== maxResizeHeight && resizeWidth !== maxResizeWidth) {
            this.setVideoRatioWidthAndKeepAspectRatio(measuringBlock, [resizeWidth, targetNodeWidth]);
          }
        } else {
          const resizeHeight = Convert.upperLimit(
            Convert.lowerLimit(height + diff_y, Config.measuringBlockResizeSize),
            maxResizeHeight
          );
          measuringBlock.style.width = `${resizeWidth / targetNodeWidth * 100}%`;
          measuringBlock.style.height = `${resizeHeight / targetNodeHeight * 100}%`;
        }
      }, () => {
        const { width, height } = measuringBlock.getBoundingClientRect();
        return {
          width,
          height
        };
      });
      mouseDrag(measuringBlock, ({ diff_x, diff_y, onceData: { top: originalTop, left: originalLeft, width: originalWidth, height: originalHeight } }) => {
        measuringBlock.getBoundingClientRect();
        const {
          width: targetNodeWidth,
          height: targetNodeHeight,
          left: targetNodeLeft,
          right: targetNodeRight,
          top: targetNodeTop,
          bottom: targetNodeBottom
        } = targetNode.getBoundingClientRect();
        const leftOfPx = originalLeft + diff_x;
        const topOfPx = originalTop + diff_y;
        const left = Convert.limits(leftOfPx - targetNodeLeft, 0, targetNodeWidth - originalWidth);
        const top = Convert.limits(topOfPx - targetNodeTop, 0, targetNodeHeight - originalHeight);
        this.setPositionByRatio(measuringBlock, [left, targetNodeWidth], [top, targetNodeHeight]);
      }, () => {
        const { top, left, width, height } = measuringBlock.getBoundingClientRect();
        return {
          top,
          left,
          width,
          height
        };
      });
      targetNode.appendChild(measuringBlock);
      return measuringBlock;
    },
    /**
     *
     * @param measuringBlock
     * @param {[number, number]} ratio
     */
    setVideoRatioWidthAndKeepAspectRatio(measuringBlock, ratio) {
      const videoWidth = Convert.toNumber(measuringBlock.dataset.videoWidth);
      const videoHeight = Convert.toNumber(measuringBlock.dataset.videoHeight);
      const [width, parentWidth] = ratio;
      const aspectRatio = videoHeight / videoWidth;
      const { height: parentHeight } = measuringBlock[targetNodeAttr].getBoundingClientRect();
      measuringBlock.style.width = `${width / parentWidth * 100}%`;
      measuringBlock.style.height = `${width * aspectRatio / parentHeight * 100}%`;
      measuringBlockMappingResize.set(measuringBlock, { width, parentWidth });
    },
    /**
     *
     * @param measuringBlock
     * @param {[number, number]} ratioX
     * @param {[number, number]} ratioY
     */
    setPositionByRatio(measuringBlock, ratioX, ratioY) {
      const [leftOfPx, targetNodeWidth] = ratioX;
      const [topOfPx, targetNodeHeight] = ratioY;
      const left = leftOfPx / targetNodeWidth;
      const top = topOfPx / targetNodeHeight;
      measuringBlock.style.left = `${left * 100}%`;
      measuringBlock.style.top = `${top * 100}%`;
      measuringBlockMappingPosition.set(measuringBlock, {
        left: leftOfPx,
        top: topOfPx,
        parentWidth: targetNodeWidth,
        parentHeight: targetNodeHeight
      });
    },
    /**
     * 设置对应的视频尺寸比例
     * @param measuringBlock
     * @param {number} width
     * @param {number} height
     */
    setVideoRatios(measuringBlock, width, height) {
      measuringBlock.dataset.videoWidth = width.toString();
      measuringBlock.dataset.videoHeight = height.toString();
      const { width: parentWidth } = measuringBlock[targetNodeAttr].getBoundingClientRect();
      const { width: measuringBlockWidth } = measuringBlock.getBoundingClientRect();
      this.setVideoRatioWidthAndKeepAspectRatio(measuringBlock, [measuringBlockWidth, parentWidth]);
    },
    show(measuringBlock) {
      var _a;
      (_a = measuringBlock == null ? void 0 : measuringBlock.classList) == null ? void 0 : _a.add("show");
    },
    alwaysShow(measuringBlock) {
      var _a;
      (_a = measuringBlock == null ? void 0 : measuringBlock.classList) == null ? void 0 : _a.add("alwaysShow");
    },
    closeAlwaysShow(measuringBlock) {
      var _a;
      (_a = measuringBlock == null ? void 0 : measuringBlock.classList) == null ? void 0 : _a.remove("alwaysShow");
    },
    editMode(measuringBlock) {
      var _a;
      (_a = measuringBlock == null ? void 0 : measuringBlock.classList) == null ? void 0 : _a.add("edit");
    },
    exitEditMode(measuringBlock) {
      var _a;
      (_a = measuringBlock == null ? void 0 : measuringBlock.classList) == null ? void 0 : _a.remove("edit");
    },
    allExitEditMode() {
      for (const measuringBlock of document.querySelectorAll(".__sign_SHAS_measuringBlock.edit")) {
        this.exitEditMode(measuringBlock);
        this.closeAlwaysShow(measuringBlock);
      }
    },
    hide(measuringBlock) {
      var _a, _b, _c;
      if (((_a = measuringBlock == null ? void 0 : measuringBlock.classList) == null ? void 0 : _a.contains("alwaysShow")) === false) {
        (_b = measuringBlock == null ? void 0 : measuringBlock.classList) == null ? void 0 : _b.remove("show");
        (_c = measuringBlock == null ? void 0 : measuringBlock.classList) == null ? void 0 : _c.remove("alwaysShow");
      }
    },
    hideAll() {
      for (const measuringBlock of document.querySelectorAll(".__sign_SHAS_measuringBlock")) {
        this.hide(measuringBlock);
      }
    },
    /**
     *
     * @param measuringBlock
     * @param {string} videoFileUrl
     */
    importVideo(measuringBlock, videoFileUrl) {
      const video = measuringBlock[videoAttr];
      video.src = videoFileUrl;
      updateVideoRatios(measuringBlock);
    },
    /**
     *
     * @param measuringBlock
     * @return {{currentTime: number, duration: number}}
     */
    getVideoInfo(measuringBlock) {
      const { currentTime, duration } = measuringBlock[videoAttr];
      return {
        currentTime,
        duration
      };
    },
    videoPlay(measuringBlock) {
      measuringBlock[videoAttr].play().then();
    },
    videoPause(measuringBlock) {
      measuringBlock[videoAttr].pause();
    },
    videoSetCurrentTime(measuringBlock, currentTime) {
      measuringBlock[videoAttr].currentTime = currentTime;
    },
    videoAllPause() {
      for (const measuringBlock of document.querySelectorAll(".__sign_SHAS_measuringBlock")) {
        this.videoPause(measuringBlock);
      }
    },
    /**
     *
     * @param measuringBlock
     * @param {number} volume
     */
    setVideoVolume(measuringBlock, volume) {
      measuringBlock[videoAttr].volume = volume;
    },
    /**
     *
     * @param measuringBlock
     * @param {number} playbackRate
     */
    setVideoPlaybackRate(measuringBlock, playbackRate) {
      measuringBlock[videoAttr].playbackRate = playbackRate;
    },
    /**
     *
     * @param {number} playbackRate
     */
    setAllVideoPlaybackRate(playbackRate) {
      externalVideoHub$1.allMeasuringBlock().forEach((measuringBlock) => this.setVideoPlaybackRate(measuringBlock, playbackRate));
    },
    remove(measuringBlock) {
      measuringBlockMappingResize.delete(measuringBlock);
      measuringBlockMappingPosition.delete(measuringBlock);
      measuringBlock.remove();
    },
    /**
     *
     * @param measuringBlock
     * @return {string}
     */
    serialize(measuringBlock) {
      const { width, parentWidth: parentWidthOfResize } = measuringBlockMappingResize.get(measuringBlock);
      const { left, top, parentWidth: parentWidthOfPosition, parentHeight } = measuringBlockMappingPosition.get(measuringBlock);
      return `${width},${parentWidthOfResize};${left},${parentWidthOfPosition},${top},${parentHeight}`;
    },
    markAsImportedCreate(measuringBlock) {
      measuringBlock[importedCreateAttr] = true;
    }
  };
  const MeasuringBlock$1 = MeasuringBlock;
  const numberNodeAttr = Symbol();
  const editingCallbackList = [];
  const NumberEditor = {
    is(numberEditor) {
      var _a;
      return !!((_a = numberEditor == null ? void 0 : numberEditor.classList) == null ? void 0 : _a.contains("content_line"));
    },
    create(defaultNumber = 60) {
      const numberEditor = createNode(`
			<div class="__sign_SHAS_numberEditor">
				<div class="__sign_SHAS_numberEditor_number">
				  ${defaultNumber}
				</div>
			</div>
		`);
      numberEditor[numberNodeAttr] = numberEditor.querySelector(".__sign_SHAS_numberEditor_number");
      numberEditor.addEventListener("wheel", (event) => {
        const { deltaY, shiftKey } = event;
        const number = (() => {
          if (shiftKey) {
            return 1;
          } else {
            return 5;
          }
        })();
        if (deltaY > 0) {
          this.add(numberEditor, -number);
        } else if (deltaY < 0) {
          this.add(numberEditor, number);
        }
        event.preventDefault();
      });
      return numberEditor;
    },
    /**
     *
     * @param numberEditor
     * @param {number} number
     */
    add(numberEditor, number) {
      const originalNumber = Convert.toNumber(numberEditor[numberNodeAttr].textContent);
      const currentNumber = Convert.limits(originalNumber + number, 0, 100);
      if (originalNumber !== currentNumber) {
        numberEditor[numberNodeAttr].textContent = currentNumber;
        editingCallbackList.forEach((cb) => cb({ originalNumber, currentNumber }));
      }
    },
    /**
     *
     * @param numberEditor
     * @param {numberEditorCallback} cb
     */
    editing(numberEditor, cb) {
      editingCallbackList.push(cb);
    },
    /**
     *
     * @param numberEditor
     * @return {number}
     */
    getNumber(numberEditor) {
      return Convert.toNumber(numberEditor[numberNodeAttr].textContent);
    }
  };
  const videoInputCallbackAttr = Symbol();
  const videoEditCallbackAttr = Symbol();
  const videoDeleteCallbackAttr = Symbol();
  const bindMeasuringBlockAttr = Symbol();
  const ListContentLine = {
    /**
     *
     * @param contentLine
     * @return {boolean}
     */
    is(contentLine) {
      var _a;
      return !!((_a = contentLine == null ? void 0 : contentLine.classList) == null ? void 0 : _a.contains("content_line"));
    },
    /**
     *
     * @param measuringBlock - 绑定的measuringBlock
     */
    create(measuringBlock) {
      const contentLine = createNode(`
				<div class="content_line">
					<div class="content_line_name">视频${document.querySelectorAll(".content_line").length + 1}</div>
					<div class="content_line_videoInput">点击选择视频源</div>
					<div class="content_line_volume"></div>
					<div class="content_line_videoEdit">编辑</div>
					<div class="content_line_delete">✖</div>
				</div>
			`);
      contentLine[bindMeasuringBlockAttr] = measuringBlock;
      {
        const defaultVolume = Config.defaultVolume;
        const numberEditor = NumberEditor.create(defaultVolume);
        MeasuringBlock$1.setVideoVolume(measuringBlock, defaultVolume / 100);
        NumberEditor.editing(numberEditor, ({ currentNumber }) => {
          MeasuringBlock$1.setVideoVolume(measuringBlock, currentNumber / 100);
        });
        contentLine.querySelector(".content_line_volume").appendChild(numberEditor);
      }
      {
        const videoInput = contentLine.querySelector(".content_line_videoInput");
        videoInput.dataset.videoUrl = "null";
        videoInput.addEventListener("click", () => {
          userSelectFile(".mp4, .mkv, .flv").then((file) => {
            var _a;
            URL.revokeObjectURL(videoInput.dataset.videoUrl);
            const videoFileUrl = URL.createObjectURL(file);
            videoInput.dataset.videoUrl = videoFileUrl;
            contentLine.querySelector(".content_line_videoEdit").classList.add("editable");
            videoInput.textContent = file.name;
            (_a = contentLine == null ? void 0 : contentLine[videoInputCallbackAttr]) == null ? void 0 : _a.call(contentLine, { videoFileUrl, file });
          });
        });
      }
      {
        const lineNameNode = contentLine.querySelector(".content_line_name");
        lineNameNode.addEventListener("click", () => {
          const input = createNode(`<input class="user_input" type="text" autocomplete="off" />`);
          input.value = lineNameNode.textContent;
          lineNameNode.appendChild(input);
          input.focus();
          input.addEventListener("blur", () => {
            if (input.value.trim().length > 0) {
              this.setName(contentLine, input.value);
            }
            input.remove();
          });
        });
      }
      {
        const videoEdit = contentLine.querySelector(".content_line_videoEdit");
        videoEdit.addEventListener("click", () => {
          var _a;
          if (videoEdit.classList.contains("editable")) {
            (_a = contentLine == null ? void 0 : contentLine[videoEditCallbackAttr]) == null ? void 0 : _a.call(contentLine);
          }
        });
      }
      {
        const videoDelete = contentLine.querySelector(".content_line_delete");
        videoDelete.addEventListener("click", () => {
          var _a;
          (_a = contentLine == null ? void 0 : contentLine[videoDeleteCallbackAttr]) == null ? void 0 : _a.call(contentLine);
        });
      }
      return contentLine;
    },
    /**
     * 获取描述
     * @param contentLine
     * @return {string}
     */
    getName(contentLine) {
      return contentLine.querySelector(".content_line_name").textContent;
    },
    /**
     *
     * @param contentLine
     * @param {string} name
     */
    setName(contentLine, name) {
      const lineNameNode = contentLine.querySelector(".content_line_name");
      lineNameNode.textContent = name;
    },
    /**
     * 获取视频文件url
     * @param contentLine
     * @return {?string}
     */
    getVideoUrl(contentLine) {
      var _a, _b;
      const url = (_b = (_a = contentLine.querySelector(".content_line_videoInput")) == null ? void 0 : _a.dataset) == null ? void 0 : _b.videoUrl;
      if ((url == null ? void 0 : url.length) > 4) {
        return url;
      }
      return null;
    },
    /**
     *
     * @param contentLine
     * @param {videoInputCallback} cb
     */
    setVideoInputCallback(contentLine, cb) {
      contentLine[videoInputCallbackAttr] = cb;
    },
    /**
     *
     * @param contentLine
     * @param {function} cb
     */
    setVideoEditCallback(contentLine, cb) {
      contentLine[videoEditCallbackAttr] = cb;
    },
    /**
     *
     * @param contentLine
     * @param {function} cb
     */
    setVideoDeleteCallback(contentLine, cb) {
      contentLine[videoDeleteCallbackAttr] = cb;
    },
    remove(contentLine) {
      MeasuringBlock$1.remove(contentLine[bindMeasuringBlockAttr]);
      contentLine.remove();
    }
  };
  const editingCb = Symbol();
  const TimestampEditor = {
    create() {
      const timestampEditor = createNode(`
				<div class="__sign_SHAS_timestampEditor">
					<div class="__sign_SHAS_timestampEditor_hours" data-hours="0">00</div>
					<div class="__sign_SHAS_timestampEditor_semicolon">:</div>
					<div class="__sign_SHAS_timestampEditor_minutes" data-minutes="0">00</div>
					<div class="__sign_SHAS_timestampEditor_semicolon">:</div>
					<div class="__sign_SHAS_timestampEditor_seconds" data-seconds="0">00</div>
					<div class="__sign_SHAS_timestampEditor_semicolon">,</div>
					<div class="__sign_SHAS_timestampEditor_milliseconds" data-milliseconds="0">000</div>
				</div>
			`);
      const syncVideo2 = debounceExecuteBuilder(() => {
        bilibiliPlayerVideoController.syncVideo();
      }, 100);
      const editing = () => {
        var _a;
        (_a = timestampEditor == null ? void 0 : timestampEditor[editingCb]) == null ? void 0 : _a.call(timestampEditor);
        syncVideo2();
      };
      timestampEditor.querySelector(".__sign_SHAS_timestampEditor_hours").addEventListener("wheel", (event) => {
        const { deltaY, shiftKey } = event;
        const hours = (() => {
          if (shiftKey) {
            return 10;
          } else {
            return 1;
          }
        })();
        if (deltaY > 0) {
          TimestampEditor.hours(timestampEditor, -hours);
        } else if (deltaY < 0) {
          TimestampEditor.hours(timestampEditor, hours);
        }
        event.preventDefault();
        editing();
      });
      timestampEditor.querySelector(".__sign_SHAS_timestampEditor_minutes").addEventListener("wheel", (event) => {
        const { deltaY, shiftKey } = event;
        const minutes = (() => {
          if (shiftKey) {
            return 10;
          } else {
            return 1;
          }
        })();
        if (deltaY > 0) {
          TimestampEditor.minutes(timestampEditor, -minutes);
        } else if (deltaY < 0) {
          TimestampEditor.minutes(timestampEditor, minutes);
        }
        event.preventDefault();
        editing();
      });
      timestampEditor.querySelector(".__sign_SHAS_timestampEditor_seconds").addEventListener("wheel", (event) => {
        const { deltaY, shiftKey } = event;
        const seconds = (() => {
          if (shiftKey) {
            return 10;
          } else {
            return 1;
          }
        })();
        if (deltaY > 0) {
          TimestampEditor.seconds(timestampEditor, -seconds);
        } else if (deltaY < 0) {
          TimestampEditor.seconds(timestampEditor, seconds);
        }
        event.preventDefault();
        editing();
      });
      timestampEditor.querySelector(".__sign_SHAS_timestampEditor_milliseconds").addEventListener("wheel", (event) => {
        const { deltaY, shiftKey, altKey } = event;
        const milliseconds = (() => {
          if (shiftKey && altKey) {
            return 1;
          } else if (shiftKey) {
            return 10;
          } else {
            return 100;
          }
        })();
        if (deltaY > 0) {
          TimestampEditor.milliseconds(timestampEditor, -milliseconds);
        } else if (deltaY < 0) {
          TimestampEditor.milliseconds(timestampEditor, milliseconds);
        }
        event.preventDefault();
        editing();
      });
      return timestampEditor;
    },
    /**
     * 获取时间
     * @param timestampEditor
     * @return {{hours: number, minutes: number, seconds: number, milliseconds: number}}
     */
    getTime(timestampEditor) {
      const hoursNode = timestampEditor.querySelector(".__sign_SHAS_timestampEditor_hours");
      const minutesNode = timestampEditor.querySelector(".__sign_SHAS_timestampEditor_minutes");
      const secondsNode = timestampEditor.querySelector(".__sign_SHAS_timestampEditor_seconds");
      const millisecondsNode = timestampEditor.querySelector(".__sign_SHAS_timestampEditor_milliseconds");
      const hours = Convert.toNumber(hoursNode.dataset.hours);
      const minutes = Convert.toNumber(minutesNode.dataset.minutes);
      const seconds = Convert.toNumber(secondsNode.dataset.seconds);
      const milliseconds = Convert.toNumber(millisecondsNode.dataset.milliseconds);
      return { hours, minutes, seconds, milliseconds };
    },
    /**
     * 获取表示总秒数的时间
     * @param timestampEditor
     * @return {number}
     */
    getTimeOfSeconds(timestampEditor) {
      const { hours, minutes, seconds, milliseconds } = this.getTime(timestampEditor);
      return hours * 3600 + minutes * 60 + seconds + milliseconds / 1e3;
    },
    /**
     *
     * @param timestampEditor
     * @param {number} hours
     */
    setHours(timestampEditor, hours) {
      const hoursNode = timestampEditor.querySelector(".__sign_SHAS_timestampEditor_hours");
      const hoursString = hours.toString();
      hoursNode.textContent = hoursString.padStart(2, "0");
      hoursNode.dataset.hours = hoursString;
    },
    /**
     *
     * @param timestampEditor
     * @param {number} minutes
     */
    setMinutes(timestampEditor, minutes) {
      const minutesNode = timestampEditor.querySelector(".__sign_SHAS_timestampEditor_minutes");
      const minutesString = minutes.toString();
      minutesNode.textContent = minutesString.padStart(2, "0");
      minutesNode.dataset.minutes = minutesString;
    },
    /**
     *
     * @param timestampEditor
     * @param {number} seconds
     */
    setSeconds(timestampEditor, seconds) {
      const secondsNode = timestampEditor.querySelector(".__sign_SHAS_timestampEditor_seconds");
      const secondsString = seconds.toString();
      secondsNode.textContent = secondsString.padStart(2, "0");
      secondsNode.dataset.seconds = secondsString;
    },
    /**
     *
     * @param timestampEditor
     * @param {number} milliseconds
     */
    setMilliseconds(timestampEditor, milliseconds) {
      const millisecondsNode = timestampEditor.querySelector(".__sign_SHAS_timestampEditor_milliseconds");
      const millisecondsString = milliseconds.toString();
      millisecondsNode.textContent = millisecondsString.padStart(3, "0");
      millisecondsNode.dataset.milliseconds = millisecondsString;
    },
    /**
     *
     * @param timestampEditor
     * @param {number} seconds
     */
    setTimeBySeconds(timestampEditor, seconds) {
      const { hours, minutes, seconds: remainderSeconds, milliseconds } = parseTime.secondsToTime(seconds);
      this.setHours(timestampEditor, hours);
      this.setMinutes(timestampEditor, minutes);
      this.setSeconds(timestampEditor, remainderSeconds);
      this.setMilliseconds(timestampEditor, milliseconds);
    },
    hours(timestampEditor, hours) {
      const { hours: currentHours } = this.getTime(timestampEditor);
      this.setHours(timestampEditor, Convert.limits(currentHours + hours, 0, 99));
    },
    minutes(timestampEditor, minutes) {
      const { hours, minutes: currentMinutes } = this.getTime(timestampEditor);
      const totalMinutes = Convert.limits(hours * 60 + currentMinutes + minutes, 0, 5999);
      this.setHours(timestampEditor, Math.floor(totalMinutes / 60));
      this.setMinutes(timestampEditor, totalMinutes % 60);
    },
    seconds(timestampEditor, seconds) {
      const { hours, minutes, seconds: currentSeconds } = this.getTime(timestampEditor);
      const totalSeconds = Convert.limits(hours * 3600 + minutes * 60 + currentSeconds + seconds, 0, 359940);
      this.setHours(timestampEditor, Math.floor(totalSeconds / 3600));
      this.setMinutes(timestampEditor, Math.floor(totalSeconds % 3600 / 60));
      this.setSeconds(timestampEditor, totalSeconds % 60);
    },
    milliseconds(timestampEditor, milliseconds) {
      const { hours, minutes, seconds, milliseconds: currentMilliseconds } = this.getTime(timestampEditor);
      const totalSeconds = Convert.limits(hours * 3600 + minutes * 60 + seconds + (currentMilliseconds + milliseconds) / 1e3, 0, 359940);
      this.setHours(timestampEditor, Math.floor(totalSeconds / 3600));
      this.setMinutes(timestampEditor, Math.floor(totalSeconds % 3600 / 60));
      this.setSeconds(timestampEditor, Math.floor(totalSeconds % 60));
      if (seconds >= 1 || minutes >= 1 || hours >= 1) {
        this.setMilliseconds(timestampEditor, (currentMilliseconds + Math.ceil(Math.abs(milliseconds / 1e3)) * 1e3 + milliseconds) % 1e3);
      } else {
        if (currentMilliseconds + milliseconds < 0) {
          this.setMilliseconds(timestampEditor, 0);
        } else {
          this.setMilliseconds(timestampEditor, (currentMilliseconds + Math.ceil(Math.abs(milliseconds / 1e3)) * 1e3 + milliseconds) % 1e3);
        }
      }
    },
    /**
     *
     * @param timestampEditor
     * @param {function} cb
     */
    editing(timestampEditor, cb) {
      timestampEditor[editingCb] = cb;
    }
  };
  const originalVideoAttr = Symbol();
  const externalVideoAttr = Symbol();
  const deleteCallbackAttr = Symbol();
  const ReferencePointLine = {
    /**
     * 是否是ReferencePointLine对象
     * @param referencePointLine
     * @return {boolean}
     */
    is(referencePointLine) {
      var _a;
      return !!((_a = referencePointLine == null ? void 0 : referencePointLine.classList) == null ? void 0 : _a.contains(".__sign_SHAS_referencePointLine"));
    },
    create() {
      const referencePointLine = createNode(`
				<div class="__sign_SHAS_referencePointLine">
					<div class="__sign_SHAS_referencePointLine_timestampEditorOfOriginalVideo"></div>
					<div class="__sign_SHAS_referencePointLine_timestampEditorOfExternalVideo"></div>
					<div class="__sign_SHAS_referencePointLine_delete">✖</div>
				</div>
			`);
      const timestampEditorOfOriginalVideo = TimestampEditor.create();
      referencePointLine[originalVideoAttr] = timestampEditorOfOriginalVideo;
      TimestampEditor.editing(timestampEditorOfOriginalVideo, () => {
        const timeOfSeconds = TimestampEditor.getTimeOfSeconds(timestampEditorOfOriginalVideo);
        externalVideoHub$1.setOriginalTimeOfReferencePoint(referencePointLine, timeOfSeconds);
      });
      referencePointLine.querySelector(".__sign_SHAS_referencePointLine_timestampEditorOfOriginalVideo").appendChild(timestampEditorOfOriginalVideo);
      const timestampEditorOfExternalVideo = TimestampEditor.create();
      referencePointLine[externalVideoAttr] = timestampEditorOfExternalVideo;
      TimestampEditor.editing(timestampEditorOfExternalVideo, () => {
        const timeOfSeconds = TimestampEditor.getTimeOfSeconds(timestampEditorOfExternalVideo);
        externalVideoHub$1.setExternalVideoTimeBySeconds(referencePointLine, timeOfSeconds);
      });
      referencePointLine.querySelector(".__sign_SHAS_referencePointLine_timestampEditorOfExternalVideo").appendChild(timestampEditorOfExternalVideo);
      referencePointLine.querySelector(".__sign_SHAS_referencePointLine_delete").addEventListener("click", () => {
        var _a;
        externalVideoHub$1.deleteReferencePoint(referencePointLine);
        (_a = referencePointLine == null ? void 0 : referencePointLine[deleteCallbackAttr]) == null ? void 0 : _a.call(referencePointLine);
      });
      return referencePointLine;
    },
    setOriginalTimeBySeconds(referencePointLine, seconds) {
      const timestampEditorOfOriginalVideo = referencePointLine[originalVideoAttr];
      TimestampEditor.setTimeBySeconds(timestampEditorOfOriginalVideo, seconds);
    },
    setExternalVideoTimeBySeconds(referencePointLine, seconds) {
      const timestampEditorOfExternalVideo = referencePointLine[externalVideoAttr];
      TimestampEditor.setTimeBySeconds(timestampEditorOfExternalVideo, seconds);
    },
    setTimeBySeconds(referencePointLine, originalTime, externalVideoTime) {
      this.setOriginalTimeBySeconds(referencePointLine, originalTime);
      this.setExternalVideoTimeBySeconds(referencePointLine, externalVideoTime);
    },
    /**
     *
     * @param referencePointLine
     * @param {function} cb
     */
    setDeleteCallback(referencePointLine, cb) {
      referencePointLine[deleteCallbackAttr] = cb;
    }
  };
  const panelConfig = {
    width: 500,
    height: 400
  };
  let isOpen = false;
  let firstOpen = true;
  const panel = createNode(`
		<div class="__sign_SHAS_panel">
		  <div class="top">
		    <div class="left">
			  <div class="back">
                <div class="back_line_1"></div>
                <div class="back_line_2"></div>
              </div>
			</div>
		  	<div class="right">
		      <div class="close_line_1"></div>
		      <div class="close_line_2"></div>
            </div>
		  </div>
		  <div class="main">
		  	<div class="listPage page">
		  		<div class="content">
				  <div class="content_column_line">
				    <div class="content_column_name">描述</div>
				    <div class="content_column_videoInput">视频源</div>
				    <div class="content_column_volume">音量</div>
				    <div class="content_column_edit">轴对轴</div>
				    <div class="content_column_delete"></div>
				  </div>
		  		  
				</div>
				<div class="create_new_line">
				  <span class="create_new_line_button">✚</span>
				</div>
			</div>
			<div class="editPage page hide">
			  <div class="editPage_title"></div>
			  <div class="editPage_column">
			  	<div class="editPage_column_descriptions">网站视频</div>
			  	<div class="editPage_column_descriptions">挂载视频</div>
			  	<div class="editPage_column_occupy"></div>
			  </div>
			  <div class="content"></div>
			  <div class="editPage_tool">
			    <div class="editPage_newPoint">✚</div>
			    <div class="editPage_export">复制配置</div>
			  </div>
			  <div class="editPage_bottom">
			  	<div class="editPage_bottom_externalVideoTime"></div>
			  </div>
			</div>
		  </div>
		</div>
	`);
  panel.querySelector(".main");
  let editingContentLine;
  const createLine = () => {
    const measuringBlock = MeasuringBlock$1.create(document.querySelector(".__sign_SHAS_videoArea"));
    const contentLine = ListContentLine.create(measuringBlock);
    ListContentLine.setVideoEditCallback(contentLine, () => {
      panelPage.toEdit(contentLine);
    });
    ListContentLine.setVideoInputCallback(contentLine, ({ videoFileUrl, file }) => {
      MeasuringBlock$1.importVideo(measuringBlock, videoFileUrl);
      externalVideoHub$1.setFile(contentLine, file);
    });
    ListContentLine.setVideoDeleteCallback(contentLine, () => {
      externalVideoHub$1.deleteContentLine(contentLine);
      ListContentLine.remove(contentLine);
    });
    externalVideoHub$1.addByContentLine(contentLine, measuringBlock);
    const content = panel.querySelector(".listPage .content");
    content.appendChild(contentLine);
    return contentLine;
  };
  const createLineByDeserialize = (deserializingData, description = null) => {
    const contentLine = createLine();
    const measuringBlock = externalVideoHub$1.getMeasuringBlock(contentLine);
    const {
      width,
      parentWidthOfResize,
      left,
      parentWidthOfPosition,
      top,
      parentHeight,
      referencePointList
    } = deserializeV1(deserializingData);
    MeasuringBlock$1.markAsImportedCreate(measuringBlock);
    MeasuringBlock$1.setVideoRatioWidthAndKeepAspectRatio(measuringBlock, [width, parentWidthOfResize]);
    MeasuringBlock$1.setPositionByRatio(measuringBlock, [left, parentWidthOfPosition], [top, parentHeight]);
    referencePointList.forEach((referencePoint) => externalVideoHub$1.addReferencePoint(contentLine, referencePoint));
    if (description) {
      ListContentLine.setName(contentLine, description);
    }
  };
  const deserializeV1 = (deserializingData) => {
    const infoBlockList = deserializingData.split(";");
    const resizeInfo = infoBlockList[0];
    const resizeList = resizeInfo.split(",");
    const width = Convert.toNumber(resizeList[0]);
    const parentWidthOfResize = Convert.toNumber(resizeList[1]);
    const positionInfo = infoBlockList[1];
    const positionList = positionInfo.split(",");
    const left = Convert.toNumber(positionList[0]);
    const parentWidthOfPosition = Convert.toNumber(positionList[1]);
    const top = Convert.toNumber(positionList[2]);
    const parentHeight = Convert.toNumber(positionList[3]);
    const referencePointListInfo = infoBlockList[2];
    const referencePointList = [];
    for (const referencePointString of referencePointListInfo.split(",")) {
      const list = referencePointString.split(">");
      const originalTime = Convert.toNumber(list[0]);
      const externalVideoTime = Convert.toNumber(list[1]);
      referencePointList.push({
        originalTime,
        externalVideoTime
      });
    }
    return {
      width,
      parentWidthOfResize,
      left,
      parentWidthOfPosition,
      top,
      parentHeight,
      referencePointList
    };
  };
  const createReferencePointLineNodeOnly = (originalTime, externalVideoTime) => {
    const referencePointLine = ReferencePointLine.create();
    ReferencePointLine.setTimeBySeconds(referencePointLine, originalTime, externalVideoTime);
    ReferencePointLine.setDeleteCallback(referencePointLine, () => {
      buildEditPage(editingContentLine);
    });
    panel.querySelector(".__sign_SHAS_panel .main .editPage .content").appendChild(referencePointLine);
    return referencePointLine;
  };
  const buildEditPage = (contentLine) => {
    clearReferencePointLineNode();
    const { versions, referencePointList } = externalVideoHub$1.getReferencePointAll(contentLine);
    for (const { originalTime, externalVideoTime } of referencePointList) {
      createReferencePointLineNodeOnly(originalTime, externalVideoTime);
    }
  };
  const clearReferencePointLineNode = () => {
    [...panel.querySelectorAll(".__sign_SHAS_referencePointLine")].forEach((node) => node.remove());
  };
  const pageType = {
    list: Symbol("list"),
    edit: Symbol("edit")
  };
  const panelPage = (() => {
    let currentPage = pageType.list;
    const hideAllPage = () => {
      for (const page of panel.querySelectorAll(".page")) {
        page.classList.add("hide");
      }
    };
    const backButton = {
      hide() {
        panel.querySelector(".back").style.display = "none";
      },
      display() {
        panel.querySelector(".back").style.display = "block";
      }
    };
    return {
      // 切换到列表页
      toList() {
        currentPage = pageType.list;
        hideAllPage();
        panel.querySelector(".listPage").classList.remove("hide");
        editingContentLine = null;
        backButton.hide();
        MeasuringBlock$1.allExitEditMode();
      },
      // 切换到编辑页
      toEdit(contentLine) {
        currentPage = pageType.edit;
        hideAllPage();
        editingContentLine = contentLine;
        const name = ListContentLine.getName(contentLine);
        {
          buildEditPage(contentLine);
        }
        {
          const measuringBlock = externalVideoHub$1.getMeasuringBlock(contentLine);
          if (measuringBlock) {
            MeasuringBlock$1.alwaysShow(measuringBlock);
            MeasuringBlock$1.editMode(measuringBlock);
          }
        }
        panel.querySelector(".editPage").classList.remove("hide");
        panel.querySelector(".editPage_title").textContent = name;
        backButton.display();
      },
      get currentPage() {
        return currentPage;
      }
    };
  })();
  const initPanel = () => {
    {
      panel.style.left = `${(window.innerWidth - panelConfig.width) / 2}px`;
      panel.style.top = "100px";
      panel.style.width = `${panelConfig.width}px`;
      panel.style.height = `${panelConfig.height}px`;
    }
    document.body.appendChild(panel);
    {
      const showExternalVideoTimeNode = panel.querySelector(".editPage_bottom_externalVideoTime");
      bilibiliPlayerVideoController.videoTrigger(() => {
        if (panelPage.currentPage === pageType.edit) {
          const { currentTime, duration } = MeasuringBlock$1.getVideoInfo(externalVideoHub$1.getMeasuringBlock(editingContentLine));
          const { milliseconds, seconds, minutes, hours } = parseTime.secondsToTime(currentTime);
          showExternalVideoTimeNode.textContent = `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")},${milliseconds.toString().padStart(3, "0")}`;
        }
      });
    }
    {
      const dragRegion = panel.querySelector(".top .left");
      barDrag(dragRegion, panel);
    }
    panel.querySelector(".top .right").addEventListener("click", Panel.close);
    {
      panel.querySelector(".create_new_line_button").addEventListener("click", () => {
        createLine();
      });
      panel.querySelector(".editPage_newPoint").addEventListener("click", () => {
        const { currentTime } = MeasuringBlock$1.getVideoInfo(externalVideoHub$1.getMeasuringBlock(editingContentLine));
        const originalTime = Convert.toNumber(bilibiliPlayerVideo.currentTime.toFixed(3));
        const externalVideoTime = Convert.toNumber(currentTime.toFixed(3));
        createReferencePointLineNodeOnly(originalTime, externalVideoTime);
        externalVideoHub$1.addReferencePoint(editingContentLine, {
          originalTime,
          externalVideoTime
        });
        bilibiliPlayerVideoController.syncVideo();
      });
      panel.querySelector(".back").addEventListener("click", () => {
        panelPage.toList();
        bilibiliPlayerVideoController.syncVideo();
      });
      panel.querySelector(".editPage_export").addEventListener("click", () => {
        const configText = externalVideoHub$1.serialize(editingContentLine);
        if (configText) {
          const list = externalVideoHub$1.getReferencePointAll(editingContentLine);
          if (list.referencePointList.length > 0) {
            navigator.clipboard.writeText(configText).then();
          }
        }
      });
    }
    {
      window.addEventListener("paste", (event) => {
        const { clipboardData } = event;
        if (panelPage.currentPage === pageType.list && isOpen) {
          const text = clipboardData.getData("text/plain");
          searchDeserializingData(text).forEach(({ deserializingData, description }) => createLineByDeserialize(deserializingData, description));
        }
      });
    }
  };
  const Panel = {
    /**
     * @return {boolean}
     */
    get initialised() {
      return !firstOpen;
    },
    get panelNode() {
      return panel;
    },
    get editingContentLine() {
      return editingContentLine;
    },
    open() {
      isOpen = true;
      if (firstOpen) {
        firstOpen = false;
        initPanel();
      }
      panel.classList.remove("hide");
    },
    close() {
      panelPage.toList();
      isOpen = false;
      panel.classList.add("hide");
    },
    toggle() {
      if (isOpen) {
        this.close();
      } else {
        this.open();
      }
    },
    toList() {
      panelPage.toList();
    },
    /**
     * 导入配置字符串创建挂载视频
     * @param {string} deserializingData
     * @param {?string} description
     */
    createLineByDeserialize(deserializingData, description = null) {
      createLineByDeserialize(deserializingData, description);
    }
  };
  const replyList = document.querySelector(".left-container-under-player");
  if (replyList) {
    const options = { childList: true, subtree: true };
    const replyContentNode = /* @__PURE__ */ new Set();
    const ob = new MutationObserver((mutations, observer) => {
      const nodeList = [];
      for (const mutation of mutations) {
        const { target } = mutation;
        if (target.classList.contains("reply-content") && !replyContentNode.has(target)) {
          replyContentNode.add(target);
          nodeList.push(target);
        }
      }
      observer.disconnect();
      nodeList.forEach((node) => {
        const pattern = regularExpression.patternCompletely;
        node.innerHTML = node.innerHTML.replaceAll(pattern, (text) => `<span class="__sign_SHAS_replyListImport">${text}</span>`);
        for (const clickNode of node.querySelectorAll(".__sign_SHAS_replyListImport")) {
          clickNode.addEventListener("click", () => {
            const data = searchDeserializingData(clickNode.textContent);
            if (data.length > 0) {
              const [{ deserializingData, description }] = data;
              Panel.createLineByDeserialize(deserializingData, description);
              Panel.open();
              Panel.toList();
            }
          });
        }
      });
      observer.observe(replyList, options);
    });
    ob.observe(replyList, options);
  }
  window.addEventListener("keydown", (event) => {
    const { code, ctrlKey, shiftKey, altKey } = event;
    if (code === Config.code && ctrlKey === Config.ctrlKey && shiftKey === Config.shiftKey && altKey === Config.altKey) {
      const focusNode = document.body.querySelector("*:focus");
      if (!focusNode) {
        Panel.toggle();
      }
    }
  });

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址