0x3f-problem-solution

配合灵神题单解题

// ==UserScript==
// @name         0x3f-problem-solution
// @namespace    https://greasyfork.org/zh-CN/users/1326420-wuxin0012
// @version      0.0.1
// @author       wuxin0011
// @description  配合灵神题单解题
// @license      MIT
// @icon         https://assets.leetcode.cn/aliyun-lc-upload/users/endlesscheng/avatar_1690721039.png
// @source       https://greasyfork.org/zh-CN/users/1326420-wuxin0012
// @match        https://leetcode.cn/circle/discuss/*
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js
// @require      data:application/javascript,%3Bwindow.Vue%3DVue%3B
// @require      https://unpkg.com/[email protected]/dist/index.full.js
// @resource     elementPlusCss  https://unpkg.com/[email protected]/dist/index.css
// @grant        GM_addStyle
// @grant        GM_getResourceText
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// ==/UserScript==

(t=>{if(typeof GM_addStyle=="function"){GM_addStyle(t);return}const e=document.createElement("style");e.textContent=t,document.head.append(e)})(" .m-setting-button[data-v-6d3b190f]{position:fixed;top:200px;right:0;z-index:100000} ");

(function (vue, ElementPlus) {
  'use strict';

  var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
  var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
  const inf = 4e3;
  const mi = 1e3;
  const __0x3f_problmes_solution__ = "__0x3f_problmes_solution__";
  const __0x3f_problmes_urls__ = "__0x3f_problmes_urls__";
  const __0x3f_problmes_update__ = "__0x3f_problmes_update__";
  const __add_cur__ = "__add_cur__";
  const Problems = () => Array.from(document.querySelectorAll(".css-1ayia3m-MarkdownContent li>a"));
  const defaultObj = {
    min: mi,
    max: inf,
    visiableMember: true,
    onlyUrls: false,
    useDefaultSetting: true
  };
  function isShow(text, min, max) {
    if (!text) {
      return true;
    }
    let res = text.match(/\d+/ig);
    if (!res) {
      return true;
    }
    if (Array.isArray(res) && res.length < 2) {
      return true;
    }
    let s = 0;
    for (let i = res.length - 1; i >= 0; i--) {
      s = res[i];
      if (s >= mi && s <= inf) {
        return s >= min && s <= max;
      }
    }
    return true;
  }
  let A = Problems();
  function handlerProblem(data) {
    var _a;
    if (!Array.isArray(A) || Array.isArray(A) && A.length == 0) {
      A = Problems();
    }
    let { min, max, visiableMember, useDefaultSetting, onlyUrls } = data;
    if (isNaN(min) || isNaN(max)) {
      min = mi;
      max = inf;
    }
    if (min < mi) {
      min = mi;
    }
    if (max < min) {
      max = inf;
    }
    min = Number(min);
    max = Number(max);
    data.min = min;
    data.max = max;
    _GM_setValue(__0x3f_problmes_solution__, data);
    for (let i = 0; i < A.length; i++) {
      let d = (_a = A[i]) == null ? void 0 : _a.parentElement;
      if (!d) {
        continue;
      }
      let flag = isShow(d.textContent, min, max);
      d.style.display = flag ? "" : "none";
      let c = d.textContent && d.textContent.indexOf("会员") != -1;
      if (!c) {
        continue;
      }
      d.style.display = visiableMember ? "" : "none";
    }
  }
  const initUrls = () => _GM_getValue(__0x3f_problmes_update__) ? Array.isArray(_GM_getValue(__0x3f_problmes_urls__)) ? _GM_getValue(__0x3f_problmes_urls__) : [] : defaultUrls;
  const initObj = () => _GM_getValue(__0x3f_problmes_solution__) ? Object.assign(defaultObj, _GM_getValue(__0x3f_problmes_solution__)) : defaultObj;
  const support_plugins = () => {
    const u = initObj();
    if (!u || !u.onlyUrls) return true;
    const url = window.location.href;
    const urls = initUrls();
    for (let info of urls) {
      if (!info || !(info == null ? void 0 : info.link)) {
        continue;
      }
      console.log("url find", info.link.indexOf(url) != -1, info.link, url);
      if (info.link.indexOf(url) != -1) {
        return true;
      }
    }
    return false;
  };
  const defaultUrls = [
    {
      title: "滑动窗口(定长/不定长/多指针)",
      link: "https://leetcode.cn/circle/discuss/0viNMK/"
    },
    {
      title: "二分算法(二分答案/最小化最大值/最大化最小值/第K小)",
      link: "https://leetcode.cn/circle/discuss/SqopEo/"
    },
    {
      title: "单调栈(矩形面积/贡献法/最小字典序)",
      link: "https://leetcode.cn/circle/discuss/9oZFK9/"
    },
    {
      title: "网格图(DFS/BFS/综合应用)",
      link: "https://leetcode.cn/circle/discuss/YiXPXW/"
    },
    {
      title: "位运算(基础/性质/拆位/试填/恒等式/贪心/脑筋急转弯)",
      link: "https://leetcode.cn/circle/discuss/dHn9Vk/"
    },
    {
      title: "图论算法(DFS/BFS/拓扑排序/最短路/最小生成树/二分图/基环树/欧拉路径)",
      link: "https://leetcode.cn/circle/discuss/01LUak/"
    },
    {
      title: "动态规划(入门/背包/状态机/划分/区间/状压/数位/树形/数据结构优化)",
      link: "https://leetcode.cn/circle/discuss/tXLS3i/"
    },
    {
      title: "常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)",
      link: "https://leetcode.cn/circle/discuss/mOr1u6/"
    },
    {
      title: "数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)",
      link: "https://leetcode.cn/circle/discuss/IYT3ss/"
    }
  ];
  const _export_sfc = (sfc, props) => {
    const target = sfc.__vccOpts || sfc;
    for (const [key, val] of props) {
      target[key] = val;
    }
    return target;
  };
  const _hoisted_1 = { class: "dialog-footer" };
  const formLabelWidth = "44px";
  const _sfc_main = {
    __name: "App",
    setup(__props) {
      const drawer = vue.ref(false);
      const fromData = vue.reactive(initObj());
      vue.watch(fromData, () => {
        handlerProblem(vue.toRaw(Object.assign({}, fromData)));
      });
      let tableData = vue.reactive(initUrls());
      const keywords = vue.ref("");
      const dialogTableVisible = vue.ref(false);
      const urlsData = vue.computed(() => tableData.filter((v) => v && v.title && v.title.indexOf(keywords.value) != -1));
      const dialogFormVisible = vue.ref(false);
      const info = vue.reactive({
        title: "",
        link: "",
        status: "add"
      });
      const addlocal = () => {
        let ok = false;
        for (let a of tableData) {
          if (a && a.link.indexOf(window.location.href) != -1) {
            ok = true;
          }
        }
        if (ok) {
          return;
        }
        tableData.unshift({ title: document.title, link: window.location.href });
      };
      const updateIndex = vue.ref(-1);
      const showProblems = () => {
        dialogTableVisible.value = true;
        if (_GM_getValue(__add_cur__)) {
          addlocal();
        }
      };
      const handlerProblems = (status, updateInfo = { title: "", link: "" }, index = -1) => {
        dialogFormVisible.value = true;
        info.status = status;
        updateIndex.value = index;
        Object.assign(info, updateInfo);
      };
      const handlerMessage = (u, title, link) => {
        const a = u ? "添加" : "修改";
        const error = !title || !/https?:\/\/.*/.test(link);
        if (error) {
          ElementPlus.ElMessage.error(`${a} 失败 请保证标题或者链接有效 `);
        } else {
          ElementPlus.ElMessage.success(`${a} 成功 `);
        }
        return !error;
      };
      const addOrUpdate = () => {
        if (!handlerMessage(info.status == "add", info.title, info.link)) {
          return;
        }
        if (info.status == "add") {
          tableData.unshift({ title: info.title, link: info.link });
        } else {
          let index = updateIndex.value;
          if (index != -1 && index < tableData.length) {
            tableData[index].link = info.link;
            tableData[index].title = info.title;
          }
        }
        dialogFormVisible.value = false;
      };
      const deleteProblems = (index) => {
        tableData.splice(index, 1);
        _GM_setValue(__0x3f_problmes_urls__, vue.toRaw(tableData));
      };
      const handlerDefault = () => {
        ElementPlus.ElMessageBox.confirm(
          "确认使用默认题单,将会重置题单?",
          "警告",
          {
            confirmButtonText: "确认",
            cancelButtonText: "取消",
            type: "warning"
          }
        ).then(() => {
          for (let i = 0; i < tableData.length; i++) {
            delete tableData[i];
          }
          for (let item of defaultUrls) {
            tableData.unshift(item);
          }
          ElementPlus.ElMessage({
            type: "success",
            message: "重置成功"
          });
        }).catch(() => {
          ElementPlus.ElMessage({
            type: "info",
            message: "取消重置"
          });
        });
      };
      window.addEventListener("beforeunload", () => {
        console.log("save ....");
        _GM_setValue(__0x3f_problmes_urls__, vue.toRaw(tableData));
        _GM_setValue(__0x3f_problmes_update__, true);
        _GM_setValue(__add_cur__, false);
      });
      vue.onMounted(() => {
        if (support_plugins()) {
          setTimeout(() => {
            handlerProblem(vue.toRaw(Object.assign({}, fromData)));
          }, 3e3);
        }
      });
      return (_ctx, _cache) => {
        const _component_el_button = vue.resolveComponent("el-button");
        const _component_el_input = vue.resolveComponent("el-input");
        const _component_el_col = vue.resolveComponent("el-col");
        const _component_el_form_item = vue.resolveComponent("el-form-item");
        const _component_el_switch = vue.resolveComponent("el-switch");
        const _component_el_tooltip = vue.resolveComponent("el-tooltip");
        const _component_el_form = vue.resolveComponent("el-form");
        const _component_el_divider = vue.resolveComponent("el-divider");
        const _component_el_row = vue.resolveComponent("el-row");
        const _component_el_link = vue.resolveComponent("el-link");
        const _component_el_table_column = vue.resolveComponent("el-table-column");
        const _component_el_table = vue.resolveComponent("el-table");
        const _component_el_dialog = vue.resolveComponent("el-dialog");
        const _component_el_drawer = vue.resolveComponent("el-drawer");
        return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
          vue.createElementVNode("div", null, [
            vue.createVNode(_component_el_button, {
              type: "primary",
              style: { "margin-left": "16px" },
              onClick: _cache[0] || (_cache[0] = ($event) => drawer.value = !drawer.value),
              class: "m-setting-button"
            }, {
              default: vue.withCtx(() => [
                vue.createTextVNode(" 设置 ")
              ]),
              _: 1
            })
          ]),
          vue.createVNode(_component_el_drawer, {
            modelValue: drawer.value,
            "onUpdate:modelValue": _cache[13] || (_cache[13] = ($event) => drawer.value = $event),
            "with-header": false,
            size: "30%"
          }, {
            default: vue.withCtx(() => [
              vue.createVNode(_component_el_form, {
                "label-position": "left",
                "label-width": "auto",
                model: fromData,
                style: { "max-width": "600px" }
              }, {
                default: vue.withCtx(() => [
                  vue.createVNode(_component_el_form_item, { label: "分数区间" }, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_col, { span: 10 }, {
                        default: vue.withCtx(() => [
                          vue.createVNode(_component_el_input, {
                            modelValue: fromData.min,
                            "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => fromData.min = $event),
                            "aria-placeholder": "",
                            placeholder: " min  "
                          }, null, 8, ["modelValue"])
                        ]),
                        _: 1
                      }),
                      vue.createVNode(_component_el_col, {
                        class: "text-center",
                        span: 1,
                        style: { "margin": "0 0.5rem" }
                      }, {
                        default: vue.withCtx(() => [
                          vue.createTextVNode("-")
                        ]),
                        _: 1
                      }),
                      vue.createVNode(_component_el_col, { span: 10 }, {
                        default: vue.withCtx(() => [
                          vue.createVNode(_component_el_input, {
                            modelValue: fromData.max,
                            "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => fromData.max = $event),
                            "aria-placeholder": "",
                            placeholder: " max"
                          }, null, 8, ["modelValue"])
                        ]),
                        _: 1
                      })
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_form_item, { label: "显示会员题" }, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_switch, {
                        modelValue: fromData.visiableMember,
                        "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => fromData.visiableMember = $event)
                      }, null, 8, ["modelValue"])
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_form_item, { label: "只在收藏题单中生效" }, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_tooltip, {
                        content: "插件只在收藏题单中生效,刷新生效 ",
                        placement: "bottom-end"
                      }, {
                        default: vue.withCtx(() => [
                          vue.createVNode(_component_el_switch, {
                            modelValue: fromData.onlyUrls,
                            "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => fromData.onlyUrls = $event)
                          }, null, 8, ["modelValue"])
                        ]),
                        _: 1
                      })
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_form_item, { label: "使用题单" }, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_switch, {
                        modelValue: fromData.useDefaultSetting,
                        "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => fromData.useDefaultSetting = $event)
                      }, null, 8, ["modelValue"])
                    ]),
                    _: 1
                  })
                ]),
                _: 1
              }, 8, ["model"]),
              fromData.useDefaultSetting ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
                vue.createVNode(_component_el_divider),
                vue.createVNode(_component_el_button, {
                  plain: "",
                  onClick: showProblems
                }, {
                  default: vue.withCtx(() => [
                    vue.createTextVNode(" 查看收藏的题单 ")
                  ]),
                  _: 1
                }),
                vue.createVNode(_component_el_divider)
              ], 64)) : vue.createCommentVNode("", true),
              vue.createVNode(_component_el_dialog, {
                modelValue: dialogTableVisible.value,
                "onUpdate:modelValue": _cache[8] || (_cache[8] = ($event) => dialogTableVisible.value = $event),
                title: "题单"
              }, {
                default: vue.withCtx(() => [
                  vue.createVNode(_component_el_row, { gutter: 10 }, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_col, { span: 8 }, {
                        default: vue.withCtx(() => [
                          vue.createVNode(_component_el_input, {
                            modelValue: keywords.value,
                            "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => keywords.value = $event),
                            placeholder: "请输入关键词过滤",
                            clearable: ""
                          }, null, 8, ["modelValue"])
                        ]),
                        _: 1
                      }),
                      vue.createVNode(_component_el_col, { span: 16 }, {
                        default: vue.withCtx(() => [
                          vue.createVNode(_component_el_button, {
                            plain: "",
                            onClick: addlocal
                          }, {
                            default: vue.withCtx(() => [
                              vue.createTextVNode(" 添加本页 ")
                            ]),
                            _: 1
                          }),
                          vue.createVNode(_component_el_button, {
                            plain: "",
                            onClick: _cache[7] || (_cache[7] = ($event) => handlerProblems("add"))
                          }, {
                            default: vue.withCtx(() => [
                              vue.createTextVNode(" 自定义 ")
                            ]),
                            _: 1
                          }),
                          vue.createVNode(_component_el_button, {
                            plain: "",
                            onClick: handlerDefault
                          }, {
                            default: vue.withCtx(() => [
                              vue.createTextVNode(" 默认 ")
                            ]),
                            _: 1
                          })
                        ]),
                        _: 1
                      })
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_table, {
                    data: urlsData.value,
                    height: "300",
                    style: { "width": "100%", "margin-top": "10px" }
                  }, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_table_column, {
                        label: "标题",
                        width: "auto",
                        align: "center"
                      }, {
                        default: vue.withCtx((scope) => [
                          vue.createVNode(_component_el_link, {
                            href: scope.row.link,
                            target: "_blank",
                            type: "default"
                          }, {
                            default: vue.withCtx(() => [
                              vue.createTextVNode(vue.toDisplayString(scope.row.title), 1)
                            ]),
                            _: 2
                          }, 1032, ["href"])
                        ]),
                        _: 1
                      }),
                      vue.createVNode(_component_el_table_column, {
                        label: "操作",
                        width: "auto",
                        align: "center"
                      }, {
                        default: vue.withCtx((scope) => [
                          vue.createVNode(_component_el_button, {
                            type: "primary",
                            size: "small",
                            onClick: ($event) => handlerProblems("update", scope.row, scope.$index)
                          }, {
                            default: vue.withCtx(() => [
                              vue.createTextVNode("编辑")
                            ]),
                            _: 2
                          }, 1032, ["onClick"]),
                          vue.createVNode(_component_el_button, {
                            type: "danger",
                            size: "small",
                            onClick: ($event) => deleteProblems(scope.$index)
                          }, {
                            default: vue.withCtx(() => [
                              vue.createTextVNode("删除")
                            ]),
                            _: 2
                          }, 1032, ["onClick"])
                        ]),
                        _: 1
                      })
                    ]),
                    _: 1
                  }, 8, ["data"])
                ]),
                _: 1
              }, 8, ["modelValue"]),
              vue.createVNode(_component_el_dialog, {
                modelValue: dialogFormVisible.value,
                "onUpdate:modelValue": _cache[12] || (_cache[12] = ($event) => dialogFormVisible.value = $event),
                title: `${info.status == "add" ? "添加" : "编辑"}`,
                width: "400"
              }, {
                footer: vue.withCtx(() => [
                  vue.createElementVNode("div", _hoisted_1, [
                    vue.createVNode(_component_el_button, {
                      onClick: _cache[11] || (_cache[11] = ($event) => dialogFormVisible.value = false)
                    }, {
                      default: vue.withCtx(() => [
                        vue.createTextVNode("取消")
                      ]),
                      _: 1
                    }),
                    vue.createVNode(_component_el_button, {
                      type: "primary",
                      onClick: addOrUpdate
                    }, {
                      default: vue.withCtx(() => [
                        vue.createTextVNode(" 确认 ")
                      ]),
                      _: 1
                    })
                  ])
                ]),
                default: vue.withCtx(() => [
                  vue.createVNode(_component_el_form, null, {
                    default: vue.withCtx(() => [
                      vue.createVNode(_component_el_form_item, {
                        label: "标题",
                        "label-width": formLabelWidth
                      }, {
                        default: vue.withCtx(() => [
                          vue.createVNode(_component_el_input, {
                            modelValue: info.title,
                            "onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => info.title = $event),
                            autocomplete: "off"
                          }, null, 8, ["modelValue"])
                        ]),
                        _: 1
                      }),
                      vue.createVNode(_component_el_form_item, {
                        label: "链接",
                        "label-width": formLabelWidth
                      }, {
                        default: vue.withCtx(() => [
                          vue.createVNode(_component_el_input, {
                            modelValue: info.link,
                            "onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => info.link = $event),
                            autocomplete: "off"
                          }, null, 8, ["modelValue"])
                        ]),
                        _: 1
                      })
                    ]),
                    _: 1
                  })
                ]),
                _: 1
              }, 8, ["modelValue", "title"])
            ]),
            _: 1
          }, 8, ["modelValue"])
        ], 64);
      };
    }
  };
  const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-6d3b190f"]]);
  const cssLoader = (e) => {
    const t = GM_getResourceText(e);
    return GM_addStyle(t), t;
  };
  cssLoader("elementPlusCss");
  let Container = null;
  const VueApp = vue.createApp(App);
  const start = () => {
    Container = document.createElement("div");
    const body = document.querySelector("body");
    body.append(Container);
    Container.style.display = support_plugins() ? "block" : "none";
    return Container;
  };
  VueApp.use(ElementPlus).mount(start());
  _GM_registerMenuCommand(`${initObj().onlyUrls ? "仅在收藏题单页面生效" : "所有题单生效"}`, () => {
    const u = initObj();
    u.onlyUrls = !u.onlyUrls;
    Container.style.display = support_plugins() ? "block" : "none";
    _GM_setValue(__0x3f_problmes_solution__, u);
  });
  _GM_registerMenuCommand(`添加本页`, () => {
    const urls = initUrls();
    let ok = false;
    const url = window.location.href;
    for (let info of urls) {
      if (!info || !(info == null ? void 0 : info.link)) {
        continue;
      }
      if (info.link.indexOf(url) != -1) {
        ok = true;
        break;
      }
    }
    if (ok) {
      ElementPlus.ElMessage({
        message: "收藏失败,链接已经存在!",
        type: "error"
      });
    } else {
      urls.unshift({
        title: document.title,
        link: url
      });
      Container.style.display = "block";
      _GM_setValue(__0x3f_problmes_urls__, urls);
      _GM_setValue(__add_cur__, true);
      ElementPlus.ElMessage({
        message: "收藏成功!刷新生效",
        type: "success"
      });
    }
  });

})(Vue, ElementPlus);