bilibili 视频合集标题搜索

bilibili 视频合集标题搜索, 分 P 搜索

// ==UserScript==
// @name         bilibili 视频合集标题搜索
// @namespace    https://github.com/LesslsMore/bili-part-video-search
// @version      0.1.1
// @author       lesslsmore
// @description  bilibili 视频合集标题搜索, 分 P 搜索
// @license      MIT
// @icon         https://i0.hdslb.com/bfs/static/jinkela/long/images/favicon.ico
// @match        https://space.bilibili.com/*
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js
// @require      data:application/javascript,%3Bwindow.Vue%3DVue%3B
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/index.full.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/dexie.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/exceljs.min.js
// @require      https://cdn.jsdelivr.net/npm/@element-plus/[email protected]/dist/index.iife.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/dexie-export-import.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/FileSaver.min.js
// @resource     element-plus/dist/index.css  https://cdn.jsdelivr.net/npm/[email protected]/dist/index.css
// @connect      https://lesslsmore-api.vercel.app/*
// @grant        GM_addStyle
// @grant        GM_getResourceText
// @grant        unsafeWindow
// ==/UserScript==

(t=>{if(typeof GM_addStyle=="function"){GM_addStyle(t);return}const a=document.createElement("style");a.textContent=t,document.head.append(a)})(" .search-fab-wrapper[data-v-ac2e5c92]{position:fixed;left:10px;bottom:50px;z-index:9999;width:40px;height:40px;display:flex;align-items:center;justify-content:center;padding:10px}.search-fab[data-v-ac2e5c92]{transform:translate(-25px);transition:transform .3s cubic-bezier(.4,0,.2,1),opacity .3s cubic-bezier(.4,0,.2,1)}.search-fab-wrapper:hover .search-fab[data-v-ac2e5c92]{transform:translate(0);opacity:1}.storage-container[data-v-a8697122]{display:flex;flex-direction:column;gap:10px;width:240px}.storage-row[data-v-a8697122]{display:flex;align-items:center;justify-content:center;margin-bottom:0}.upload-row[data-v-a8697122]{justify-content:flex-start;gap:5px}.setting-fab-wrapper[data-v-0bb163f6]{position:fixed;left:10px;bottom:10px;z-index:9999;width:40px;height:40px;display:flex;align-items:center;justify-content:center;padding:10px}.setting-fab[data-v-0bb163f6]{transform:translate(-25px);transition:transform .3s cubic-bezier(.4,0,.2,1),opacity .3s cubic-bezier(.4,0,.2,1)}.setting-fab-wrapper:hover .setting-fab[data-v-0bb163f6]{transform:translate(0);opacity:1} ");

(function (vue, ElementPlusIconsVue, Dexie, dexieExportImport, fileSaver, axios, ExcelJS, ElementPlus) {
  'use strict';

  function _interopNamespaceDefault(e) {
    const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
    if (e) {
      for (const k in e) {
        if (k !== 'default') {
          const d = Object.getOwnPropertyDescriptor(e, k);
          Object.defineProperty(n, k, d.get ? d : {
            enumerable: true,
            get: () => e[k]
          });
        }
      }
    }
    n.default = e;
    return Object.freeze(n);
  }

  const ElementPlusIconsVue__namespace = /*#__PURE__*/_interopNamespaceDefault(ElementPlusIconsVue);

  const db_name_bili = "bili";
  const db_name_json = "json";
  const db_schema_bili = {
    vlist: "&bvid, mid",
    cids: "&cid, bvid, mid, view"
    // 主键 索引
    // bvids: '&bvid',
  };
  const mids = [37974444, 302417610];
  const db_schema_json = {
    bvids: "&bvid"
  };
  mids.forEach((mid) => {
    let schema = `pages[${mid}]`;
    db_schema_json[schema] = "&pn";
  });
  const db_bili = get_db(db_name_bili, db_schema_bili);
  const db_json = get_db(db_name_json, db_schema_json);
  function get_db(db_name, db_schema, db_ver = 1) {
    let db2 = new Dexie(db_name);
    db2.version(db_ver).stores(db_schema);
    return db2;
  }
  async function export_db(_, databaseName) {
    console.log("export_db:");
    console.log(/* @__PURE__ */ new Date());
    let databases = await Dexie.getDatabaseNames();
    console.log(databases);
    if (!databases.includes(databaseName)) {
      throw new Error(`数据库 ${databaseName} 不存在`);
    }
    const dbInstance = new Dexie(databaseName);
    await dbInstance.open();
    const blob = await dexieExportImport.exportDB(dbInstance);
    fileSaver.saveAs(blob, `IndexedDB_${databaseName}.json`);
    console.log(/* @__PURE__ */ new Date());
  }
  async function import_db(file) {
    console.log("import_db:");
    console.log(/* @__PURE__ */ new Date());
    console.log(file);
    const blob = new Blob([file.raw], { type: file.raw.type });
    await dexieExportImport.importDB(blob);
    console.log(/* @__PURE__ */ new Date());
  }
  async function get_cids_items$1(word, page, limit) {
    console.log(word);
    const collection = db_bili.cids.orderBy("view").filter((item) => {
      try {
        return item.part.text.includes(word);
      } catch (e) {
        console.log(e);
        console.log(item.part);
      }
    });
    const res = await collection.toArray();
    const result = await collection.reverse().offset((page - 1) * limit).limit(limit).toArray();
    console.log(result);
    return {
      data: result,
      total: res.length
    };
  }
  const db = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
    __proto__: null,
    db_bili,
    db_json,
    export_db,
    get_cids_items: get_cids_items$1,
    get_db,
    import_db,
    mids
  }, Symbol.toStringTag, { value: "Module" }));
  const service = axios.create({
    baseURL: "https://lesslsmore-api.vercel.app/",
    timeout: 15e3
    // 请求超时时间
  });
  function get_cids_items(part, page, limit) {
    return service({
      url: `/cids`,
      method: "post",
      data: {
        part,
        page,
        limit
      }
    });
  }
  const _hoisted_1$4 = { style: { "display": "flex", "justify-content": "center" } };
  const _hoisted_2$1 = { style: { "display": "flex", "justify-content": "center" } };
  const _sfc_main$5 = {
    __name: "Indexed",
    setup(__props) {
      const searchObjRef = vue.ref();
      let total = vue.ref();
      let tableData = vue.ref([]);
      let currentPage4 = vue.ref(1);
      let pageSize4 = vue.ref(10);
      let searchObj = vue.ref({
        name: "",
        mid: "",
        bvid: "",
        part: ""
      });
      const dataSource = vue.ref("index");
      let keys = vue.ref(
        {
          "name": 10,
          "title.text": 45,
          "part.text": 45,
          "page": 8,
          "view": 8,
          "duration": 10,
          "mid": 10,
          "bvid": 12,
          "cid": 11,
          "url": 38
        }
      );
      function sort_data({ prop, order }) {
        console.log(prop, order);
      }
      async function fetchData() {
        if (dataSource.value === "mongo") {
          const res = await get_cids_items(searchObj.value.name, currentPage4.value, pageSize4.value);
          tableData.value = res.data.data;
          total.value = res.data.total;
        } else if (dataSource.value === "index") {
          let res = await get_cids_items$1(searchObj.value.name, currentPage4.value, pageSize4.value);
          tableData.value = res.data;
          total.value = res.total;
        }
      }
      const small = vue.ref(false);
      const background = vue.ref(false);
      const disabled = vue.ref(false);
      const handleSizeChange = (val) => {
        console.log(`${val} items per page`);
        fetchData();
      };
      const handleCurrentChange = (val) => {
        console.log(`current page: ${val}`);
        fetchData();
      };
      return (_ctx, _cache) => {
        const _component_el_option = vue.resolveComponent("el-option");
        const _component_el_select = vue.resolveComponent("el-select");
        const _component_el_form_item = vue.resolveComponent("el-form-item");
        const _component_el_input = vue.resolveComponent("el-input");
        const _component_el_button = vue.resolveComponent("el-button");
        const _component_el_form = vue.resolveComponent("el-form");
        const _component_el_table_column = vue.resolveComponent("el-table-column");
        const _component_el_table = vue.resolveComponent("el-table");
        const _component_el_pagination = vue.resolveComponent("el-pagination");
        return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
          vue.createElementVNode("div", _hoisted_1$4, [
            vue.createVNode(_component_el_form, {
              ref_key: "searchObjRef",
              ref: searchObjRef,
              style: { "max-width": "100%" },
              model: vue.unref(searchObj),
              "status-icon": "",
              rules: _ctx.rules,
              "label-width": "auto",
              class: "demo-ruleForm",
              inline: ""
            }, {
              default: vue.withCtx(() => [
                vue.createVNode(_component_el_form_item, { label: "数据来源" }, {
                  default: vue.withCtx(() => [
                    vue.createVNode(_component_el_select, {
                      modelValue: dataSource.value,
                      "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => dataSource.value = $event),
                      placeholder: "请选择",
                      style: { "width": "100px" }
                    }, {
                      default: vue.withCtx(() => [
                        vue.createVNode(_component_el_option, {
                          label: "index",
                          value: "index"
                        }),
                        vue.createVNode(_component_el_option, {
                          label: "mongo",
                          value: "mongo"
                        })
                      ]),
                      _: 1
                    }, 8, ["modelValue"])
                  ]),
                  _: 1
                }),
                vue.createVNode(_component_el_form_item, { label: "分段视频名称" }, {
                  default: vue.withCtx(() => [
                    vue.createVNode(_component_el_input, {
                      modelValue: vue.unref(searchObj).name,
                      "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => vue.unref(searchObj).name = $event),
                      onKeyup: vue.withKeys(fetchData, ["enter"])
                    }, null, 8, ["modelValue"])
                  ]),
                  _: 1
                }),
                vue.createVNode(_component_el_form_item, null, {
                  default: vue.withCtx(() => [
                    vue.createVNode(_component_el_button, {
                      type: "primary",
                      icon: vue.unref(ElementPlusIconsVue.Search),
                      size: "mini",
                      onClick: _cache[2] || (_cache[2] = ($event) => fetchData())
                    }, {
                      default: vue.withCtx(() => _cache[5] || (_cache[5] = [
                        vue.createTextVNode("搜索")
                      ])),
                      _: 1
                    }, 8, ["icon"]),
                    vue.createVNode(_component_el_button, {
                      icon: vue.unref(ElementPlusIconsVue.Refresh),
                      size: "mini",
                      onClick: _ctx.resetData
                    }, {
                      default: vue.withCtx(() => _cache[6] || (_cache[6] = [
                        vue.createTextVNode("重置")
                      ])),
                      _: 1
                    }, 8, ["icon", "onClick"])
                  ]),
                  _: 1
                })
              ]),
              _: 1
            }, 8, ["model", "rules"])
          ]),
          vue.createVNode(_component_el_table, {
            data: vue.unref(tableData),
            border: "",
            style: { "width": "100%" },
            onSortChange: sort_data
          }, {
            default: vue.withCtx(() => [
              (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(Object.entries(vue.unref(keys)), ([head, width], index) => {
                return vue.openBlock(), vue.createBlock(_component_el_table_column, {
                  sortable: "custom",
                  key: index,
                  prop: head,
                  label: head,
                  width: width * 10
                }, null, 8, ["prop", "label", "width"]);
              }), 128))
            ]),
            _: 1
          }, 8, ["data"]),
          vue.createElementVNode("div", _hoisted_2$1, [
            vue.createVNode(_component_el_pagination, {
              "current-page": vue.unref(currentPage4),
              "onUpdate:currentPage": _cache[3] || (_cache[3] = ($event) => vue.isRef(currentPage4) ? currentPage4.value = $event : currentPage4 = $event),
              "page-size": vue.unref(pageSize4),
              "onUpdate:pageSize": _cache[4] || (_cache[4] = ($event) => vue.isRef(pageSize4) ? pageSize4.value = $event : pageSize4 = $event),
              "page-sizes": [10, 20, 50, 100, 200, 500, 1e3],
              small: small.value,
              disabled: disabled.value,
              background: background.value,
              layout: "total, sizes, prev, pager, next, jumper",
              total: vue.unref(total),
              onSizeChange: handleSizeChange,
              onCurrentChange: handleCurrentChange
            }, null, 8, ["current-page", "page-size", "small", "disabled", "background", "total"])
          ])
        ], 64);
      };
    }
  };
  const _export_sfc = (sfc, props) => {
    const target = sfc.__vccOpts || sfc;
    for (const [key, val] of props) {
      target[key] = val;
    }
    return target;
  };
  const _hoisted_1$3 = { class: "search-fab-wrapper" };
  const _sfc_main$4 = {
    __name: "Search",
    setup(__props) {
      const dialogVisible = vue.ref(false);
      const openDialog = () => {
        dialogVisible.value = true;
      };
      return (_ctx, _cache) => {
        const _component_el_button = vue.resolveComponent("el-button");
        const _component_el_dialog = vue.resolveComponent("el-dialog");
        return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
          vue.createElementVNode("div", _hoisted_1$3, [
            !dialogVisible.value ? (vue.openBlock(), vue.createBlock(_component_el_button, {
              key: 0,
              type: "primary",
              onClick: openDialog,
              icon: vue.unref(ElementPlusIconsVue.Search),
              circle: "",
              plain: "",
              class: "search-fab"
            }, null, 8, ["icon"])) : vue.createCommentVNode("", true)
          ]),
          vue.createVNode(_component_el_dialog, {
            modelValue: dialogVisible.value,
            "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => dialogVisible.value = $event),
            fullscreen: "",
            top: "40vh",
            width: "70%",
            draggable: ""
          }, {
            default: vue.withCtx(() => [
              vue.createVNode(_sfc_main$5)
            ]),
            _: 1
          }, 8, ["modelValue"])
        ], 64);
      };
    }
  };
  const Search = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-ac2e5c92"]]);
  const _hoisted_1$2 = { class: "storage-row upload-row" };
  const _sfc_main$3 = {
    __name: "indexeddb",
    setup(__props) {
      let dbNames = vue.ref([]);
      let selectedDb = vue.ref("");
      const dbWhiteList = ["bili", "json"];
      vue.onMounted(async () => {
        let databases = await Dexie.getDatabaseNames();
        console.log(databases);
        dbNames.value = databases.filter((db2) => dbWhiteList.includes(db2));
        if (dbNames.value.length > 0) selectedDb.value = dbNames.value[0];
      });
      function handleExportDb() {
        if (!selectedDb.value) {
          ElMessage.error("请选择数据库名称");
          return;
        }
        export_db(null, selectedDb.value);
      }
      return (_ctx, _cache) => {
        const _component_el_button = vue.resolveComponent("el-button");
        const _component_el_upload = vue.resolveComponent("el-upload");
        const _component_el_option = vue.resolveComponent("el-option");
        const _component_el_select = vue.resolveComponent("el-select");
        return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$2, [
          vue.createVNode(_component_el_upload, {
            multiple: "",
            "auto-upload": false,
            accept: ".json",
            "on-change": vue.unref(import_db),
            "show-file-list": false
          }, {
            default: vue.withCtx(() => [
              vue.createVNode(_component_el_button, {
                icon: vue.unref(ElementPlusIconsVue.Upload),
                style: { "width": "70px" },
                type: "primary"
              }, {
                default: vue.withCtx(() => _cache[1] || (_cache[1] = [
                  vue.createTextVNode(" db")
                ])),
                _: 1
              }, 8, ["icon"])
            ]),
            _: 1
          }, 8, ["on-change"]),
          vue.createVNode(_component_el_button, {
            icon: vue.unref(ElementPlusIconsVue.Download),
            type: "primary",
            plain: "",
            style: { "width": "70px" },
            onClick: handleExportDb
          }, {
            default: vue.withCtx(() => _cache[2] || (_cache[2] = [
              vue.createTextVNode("db")
            ])),
            _: 1
          }, 8, ["icon"]),
          vue.createVNode(_component_el_select, {
            modelValue: vue.unref(selectedDb),
            "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => vue.isRef(selectedDb) ? selectedDb.value = $event : selectedDb = $event),
            placeholder: "选择数据库名称",
            style: { "width": "70px" },
            "popper-append-to-body": "",
            "popper-class": "monkey-el-select-popper"
          }, {
            default: vue.withCtx(() => [
              (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(dbNames), (db2) => {
                return vue.openBlock(), vue.createBlock(_component_el_option, {
                  key: db2,
                  label: db2,
                  value: db2
                }, null, 8, ["label", "value"]);
              }), 128))
            ]),
            _: 1
          }, 8, ["modelValue"])
        ]);
      };
    }
  };
  async function export_excel() {
    let tb_name = "cids";
    console.log("export_excel...");
    console.log(/* @__PURE__ */ new Date());
    const res = await db_bili[tb_name].toArray();
    res.sort((a, b) => {
      if (a.view != b.view) {
        return b.view - a.view;
      } else {
        return a.page - b.page;
      }
    });
    console.log(res.length);
    const keys = {
      "name": 10,
      "title": 45,
      "part": 45,
      "page": 4,
      "view": 8,
      "duration": 8,
      "mid": 10,
      "bvid": 12,
      "cid": 10,
      "url": 45
    };
    const columns = [];
    for (const [header, width] of Object.entries(keys)) {
      columns.push({ header, key: header, width: width * 1.2 });
    }
    await exportToExcel(res, tb_name, columns);
    console.log(/* @__PURE__ */ new Date());
  }
  async function exportToExcel(jsonData, tb_name, columns) {
    const workbook = new ExcelJS.Workbook();
    const worksheet = workbook.addWorksheet(tb_name);
    worksheet.columns = columns;
    jsonData.forEach((record) => {
      worksheet.addRow(record);
    });
    const buffer = await workbook.xlsx.writeBuffer();
    const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
    saveAs(blob, `${db_bili.name}.xlsx`);
  }
  async function import_excel(_, file) {
    console.log("import_excel:");
    console.log(/* @__PURE__ */ new Date());
    console.log(file);
    console.log(/* @__PURE__ */ new Date());
  }
  function bvid2cids(obj) {
    const bvid = obj.data.bvid;
    let item_info = [];
    obj.data.pages.forEach((el) => {
      let url = `https://www.bilibili.com/video/${bvid}?p=${el.page}`;
      let hyperlink = `https://www.bilibili.com/video/${bvid}`;
      let title = { text: obj.data.title, hyperlink };
      let mid = obj.data.owner.mid;
      let name = obj.data.owner.name;
      let view = obj.data.stat.view;
      let page = el.page;
      let cid = el.cid;
      let part = { text: el.part, hyperlink: url };
      let duration = new Date(el.duration * 1e3).toISOString().substr(11, 8);
      item_info.push({
        name,
        title,
        part,
        page,
        view,
        duration,
        mid,
        bvid,
        cid,
        url
      });
    });
    return item_info;
  }
  const import_json_bvids = async (_, file) => {
    console.log("import_json_bvids...");
    console.log(/* @__PURE__ */ new Date());
    let json_str = await file.raw.text();
    let json_obj = JSON.parse(json_str);
    let bvid = json_obj.data.bvid;
    db_json.bvids.put({ bvid, json_obj });
    console.log(/* @__PURE__ */ new Date());
  };
  async function vlist2bvids() {
    console.log("vlist2bvids...");
    console.log(/* @__PURE__ */ new Date());
    const new_bvids = await db_bili.vlist.orderBy("bvid").primaryKeys();
    const old_bvids = await db_json.bvids.orderBy("bvid").primaryKeys();
    const bvids = new_bvids.filter((item) => !old_bvids.includes(item));
    console.log(bvids.length);
    for (const bvid of bvids) {
      try {
        const response = await fetch(`https://api.bilibili.com/x/web-interface/view?bvid=${bvid}`);
        if (!response.ok) {
          console.error(`请求失败: ${bvid}`, response.status);
          continue;
        }
        const json_obj = await response.json();
        console.log("fetch 成功:", bvid);
        console.log(json_obj);
        await db_json.bvids.put({ bvid, json_obj });
      } catch (e) {
        console.error("fetch 异常:", bvid, e);
      }
    }
    console.log(/* @__PURE__ */ new Date());
  }
  async function bvids2cids() {
    console.log("bvids2cids...");
    console.log(/* @__PURE__ */ new Date());
    const old_bvids = await db_bili.cids.orderBy("bvid").uniqueKeys();
    let bvids = await db_json.bvids.toArray();
    for (let { bvid, json_obj } of bvids) {
      if (old_bvids.includes(bvid)) continue;
      let cids = bvid2cids(json_obj);
      console.log(`每 bvid 下 cid 数: ${cids.length}`);
      await db_bili.cids.bulkPut(cids);
    }
    console.log(/* @__PURE__ */ new Date());
  }
  const import_json_pages = async (_, file) => {
    console.log("import_json_pages...");
    console.log(/* @__PURE__ */ new Date());
    let json_str = await file.raw.text();
    let json_obj = JSON.parse(json_str);
    let vlist = json_obj.data.list.vlist;
    let mid = vlist[0].mid;
    let pn = json_obj.data.page.pn;
    await db_json[`pages[${mid}]`].put({ pn, json_obj });
    console.log(/* @__PURE__ */ new Date());
  };
  const _hoisted_1$1 = { class: "storage-container" };
  const _hoisted_2 = { class: "storage-row upload-row" };
  const _hoisted_3 = { class: "storage-row upload-row" };
  const _hoisted_4 = { class: "storage-row upload-row" };
  const _hoisted_5 = {
    class: "storage-row upload-row",
    style: { "display": "none" }
  };
  const _hoisted_6 = { class: "storage-row upload-row" };
  const _sfc_main$2 = {
    __name: "Storage",
    setup(__props) {
      const midsInput = vue.ref(JSON.stringify(mids));
      const midsArr = vue.ref(Array.isArray(mids) ? [...mids] : []);
      vue.watch(midsArr, (arr) => {
        midsInput.value = JSON.stringify(arr);
      }, { deep: true });
      vue.watch(midsInput, (val) => {
        try {
          midsArr.value = JSON.parse(val);
        } catch (e) {
          midsArr.value = [];
        }
        try {
          window.monkeyMids = JSON.parse(val);
        } catch (e) {
          window.monkeyMids = [];
        }
      }, { immediate: true });
      function addCurrentMid() {
        const url = window.location.href;
        const match = url.match(/space\.bilibili\.com\/(\d+)/);
        if (match) {
          let arr;
          try {
            arr = JSON.parse(midsInput.value);
            if (!Array.isArray(arr)) arr = [];
          } catch (e) {
            arr = [];
          }
          const mid = Number(match[1]);
          if (!arr.includes(mid)) {
            arr.push(mid);
            midsInput.value = JSON.stringify(arr);
          }
        } else {
          window.ElMessage && window.ElMessage.warning("未检测到mid");
        }
      }
      vue.watch(midsInput, (val) => {
        try {
          window.monkeyMids = JSON.parse(val);
        } catch (e) {
          window.monkeyMids = [];
        }
      }, { immediate: true });
      return (_ctx, _cache) => {
        const _component_el_button = vue.resolveComponent("el-button");
        const _component_el_option = vue.resolveComponent("el-option");
        const _component_el_select = vue.resolveComponent("el-select");
        const _component_el_upload = vue.resolveComponent("el-upload");
        return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [
          vue.createElementVNode("div", _hoisted_2, [
            vue.createVNode(_component_el_button, {
              icon: vue.unref(ElementPlusIconsVue.Plus),
              plain: "",
              style: { "width": "70px" },
              type: "primary",
              onClick: addCurrentMid
            }, {
              default: vue.withCtx(() => _cache[2] || (_cache[2] = [
                vue.createTextVNode("mids")
              ])),
              _: 1
            }, 8, ["icon"]),
            vue.createVNode(_component_el_select, {
              modelValue: midsArr.value,
              "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => midsArr.value = $event),
              multiple: "",
              "default-first-option": "",
              placeholder: "请选择或输入mid",
              style: { "width": "140px" }
            }, {
              default: vue.withCtx(() => [
                (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(mids), (mid) => {
                  return vue.openBlock(), vue.createBlock(_component_el_option, {
                    key: mid,
                    label: mid,
                    value: mid
                  }, null, 8, ["label", "value"]);
                }), 128))
              ]),
              _: 1
            }, 8, ["modelValue"])
          ]),
          vue.createElementVNode("div", _hoisted_3, [
            vue.createVNode(_sfc_main$3)
          ]),
          vue.createElementVNode("div", _hoisted_4, [
            vue.createVNode(_component_el_upload, {
              "auto-upload": false,
              accept: ".xlsx, .xls",
              "on-change": vue.unref(import_excel),
              "show-file-list": false
            }, {
              default: vue.withCtx(() => [
                vue.createVNode(_component_el_button, {
                  icon: vue.unref(ElementPlusIconsVue.Upload),
                  style: { "width": "80px" },
                  type: "primary"
                }, {
                  default: vue.withCtx(() => _cache[3] || (_cache[3] = [
                    vue.createTextVNode("excel")
                  ])),
                  _: 1
                }, 8, ["icon"])
              ]),
              _: 1
            }, 8, ["on-change"]),
            vue.createVNode(_component_el_button, {
              icon: vue.unref(ElementPlusIconsVue.Download),
              plain: "",
              type: "primary",
              style: { "width": "80px" },
              onClick: _cache[1] || (_cache[1] = ($event) => vue.unref(export_excel)())
            }, {
              default: vue.withCtx(() => _cache[4] || (_cache[4] = [
                vue.createTextVNode("excel")
              ])),
              _: 1
            }, 8, ["icon"])
          ]),
          vue.createElementVNode("div", _hoisted_5, [
            vue.createVNode(_component_el_upload, {
              multiple: "",
              "auto-upload": false,
              accept: ".json",
              "on-change": vue.unref(import_json_bvids),
              "show-file-list": false
            }, {
              default: vue.withCtx(() => [
                vue.createVNode(_component_el_button, {
                  icon: vue.unref(ElementPlusIconsVue.Upload),
                  style: { "width": "80px" },
                  type: "primary"
                }, {
                  default: vue.withCtx(() => _cache[5] || (_cache[5] = [
                    vue.createTextVNode("bvids")
                  ])),
                  _: 1
                }, 8, ["icon"])
              ]),
              _: 1
            }, 8, ["on-change"]),
            vue.createVNode(_component_el_upload, {
              multiple: "",
              "auto-upload": false,
              accept: ".json",
              "on-change": vue.unref(import_json_pages),
              "show-file-list": false
            }, {
              default: vue.withCtx(() => [
                vue.createVNode(_component_el_button, {
                  icon: vue.unref(ElementPlusIconsVue.Upload),
                  style: { "width": "80px" },
                  type: "primary"
                }, {
                  default: vue.withCtx(() => _cache[6] || (_cache[6] = [
                    vue.createTextVNode("pages")
                  ])),
                  _: 1
                }, 8, ["icon"])
              ]),
              _: 1
            }, 8, ["on-change"])
          ]),
          vue.createElementVNode("div", _hoisted_6, [
            vue.createVNode(_component_el_button, {
              style: { "width": "80px" },
              plain: "",
              type: "primary",
              onClick: vue.unref(vlist2bvids)
            }, {
              default: vue.withCtx(() => _cache[7] || (_cache[7] = [
                vue.createTextVNode("vlist2bvids")
              ])),
              _: 1
            }, 8, ["onClick"]),
            vue.createVNode(_component_el_button, {
              style: { "width": "80px", "margin": "0px" },
              plain: "",
              type: "primary",
              onClick: vue.unref(bvids2cids)
            }, {
              default: vue.withCtx(() => _cache[8] || (_cache[8] = [
                vue.createTextVNode("bvids2cids")
              ])),
              _: 1
            }, 8, ["onClick"])
          ])
        ]);
      };
    }
  };
  const Storage = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-a8697122"]]);
  const _hoisted_1 = { class: "setting-fab-wrapper" };
  const _sfc_main$1 = {
    __name: "Setting",
    setup(__props) {
      return (_ctx, _cache) => {
        const _component_el_button = vue.resolveComponent("el-button");
        const _component_el_popover = vue.resolveComponent("el-popover");
        return vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
          vue.createVNode(_component_el_popover, {
            placement: "bottom",
            width: 250,
            trigger: "click"
          }, {
            reference: vue.withCtx(() => [
              vue.createVNode(_component_el_button, {
                class: "setting-fab",
                icon: vue.unref(ElementPlusIconsVue.Setting),
                plain: "",
                type: "primary",
                circle: ""
              }, null, 8, ["icon"])
            ]),
            default: vue.withCtx(() => [
              vue.createVNode(Storage)
            ]),
            _: 1
          })
        ]);
      };
    }
  };
  const Setting = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-0bb163f6"]]);
  const _sfc_main = {
    __name: "App",
    setup(__props) {
      return (_ctx, _cache) => {
        return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
          vue.createVNode(Search),
          vue.createVNode(Setting)
        ], 64);
      };
    }
  };
  const cssLoader = (e) => {
    const t = GM_getResourceText(e);
    return GM_addStyle(t), t;
  };
  cssLoader("element-plus/dist/index.css");
  const scriptRel = /* @__PURE__ */ 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 allSettled2 = function(promises) {
        return Promise.all(
          promises.map(
            (p) => Promise.resolve(p).then(
              (value) => ({ status: "fulfilled", value }),
              (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 = allSettled2(
        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) {
      const e = new Event("vite:preloadError", {
        cancelable: true
      });
      e.payload = err;
      window.dispatchEvent(e);
      if (!e.defaultPrevented) {
        throw err;
      }
    }
    return promise.then((res) => {
      for (const item of res || []) {
        if (item.status !== "rejected") continue;
        handlePreloadError(item.reason);
      }
      return baseModule().catch(handlePreloadError);
    });
  };
  var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
  function interceptor() {
    const originalFetch = _unsafeWindow.fetch;
    _unsafeWindow.fetch = async function(input, init) {
      const response = await originalFetch(input, init);
      const url = typeof input === "string" ? input : input.url;
      if (url.includes("api.bilibili.com/x/space/wbi/arc/search")) {
        const urlParams = new URLSearchParams(url.split("?")[1]);
        const mid = urlParams.get("mid");
        const pn = urlParams.get("pn");
        const ps = urlParams.get("ps");
        console.log("提取参数:", { mid, pn, ps });
        let mids2 = [];
        try {
          if (window.monkeyMids) {
            if (typeof window.monkeyMids === "string") {
              mids2 = JSON.parse(window.monkeyMids);
            } else if (Array.isArray(window.monkeyMids)) {
              mids2 = window.monkeyMids;
            }
          }
        } catch (e) {
          console.warn("解析 monkeyMids 失败", e);
        }
        if (mids2.includes(Number(mid)) || mids2.includes(mid)) {
          const cloned = response.clone();
          cloned.json().then(async (data) => {
            console.log("Fetch响应内容:", data);
            if (data && data.data && data.data.list && data.data.list.vlist) {
              const db_bili2 = window.db_bili || (await __vitePreload(async () => {
                const { db_bili: db_bili3 } = await Promise.resolve().then(() => db);
                return { db_bili: db_bili3 };
              }, void 0 )).db_bili;
              await db_bili2.vlist.bulkPut(data.data.list.vlist);
              console.log("已同步 vlist 到 IndexedDB");
            }
          });
        }
      }
      return response;
    };
  }
  interceptor();
  const app = vue.createApp(_sfc_main);
  for (const [key, component] of Object.entries(ElementPlusIconsVue__namespace)) {
    app.component(key, component);
  }
  app.use(ElementPlus);
  app.mount(
    (() => {
      const app2 = document.createElement("div");
      document.body.append(app2);
      return app2;
    })()
  );

})(Vue, ElementPlusIconsVue, Dexie, DexieExportImport, saveAs, axios, ExcelJS, ElementPlus);