Curator_Tools

添加删除按钮

// ==UserScript==
// @name:zh-CN      鉴赏家小工具
// @name            Curator_Tools
// @namespace       https://blog.chrxw.com
// @supportURL      https://blog.chrxw.com/scripts.html
// @contributionURL https://afdian.com/@chr233
// @version         1.10
// @description     添加删除按钮
// @description:zh-CN  添加删除按钮
// @author          Chr_
// @include         https://store.steampowered.com/curator/*
// @license         AGPL-3.0
// @icon            https://blog.chrxw.com/favicon.ico
// @grant           GM_addStyle
// ==/UserScript==

// 初始化
(() => {
  "use strict";

  const eleContailer = document.getElementById("subpage_container");
  if (eleContailer) {
    const observer = new MutationObserver(onPageLoad);
    observer.observe(eleContailer, { childList: true, subtree: true });
  }

  let lastPathname = "";
  let lastCount = 0;
  let t = 0;

  function onPageLoad() {
    if (lastPathname == location.pathname) {
      return;
    }
    lastPathname = location.pathname;

    if (t !== 0) {
      clearInterval(t);
      t = 0;
    }

    if (location.pathname.includes("admin/review_create")) {
      injectReviewCreate();
    } else if (location.pathname.includes("admin/stats")) {
      injectStats();
    }
  }

  onPageLoad();

  function genBtn(text, cls, foo) {
    const btn = document.createElement("button");
    btn.textContent = text;
    btn.className = cls;
    btn.addEventListener("click", foo);
    return btn;
  }
  function genA(url) {
    const a = document.createElement("a");
    a.href = url;
    a.target = "_blank";
    return a;
  }
  function genDiv(cls) {
    const div = document.createElement("div");
    div.className = cls;
    return div;
  }
  function genSpan(name) {
    const span = document.createElement("span");
    span.textContent = name;
    return span;
  }

  function injectReviewCreate() {
    const [_, curator, appid] = lastPathname.match(
      /\/curator\/([^\/]+)\/admin\/review_create\/?(\d+)?/
    ) ?? [null, null, null];

    if (curator) {
      const btnArea = document.querySelector("div.titleframe");

      if (appid) {
        const btn = genBtn(
          "删除该评测",
          "ct_btn",
          async () => await deleteReview(curator, appid)
        );
        btnArea.appendChild(btn);
        const link = genA(`https://store.steampowered.com/app/${appid}`);
        const btn2 = genBtn("商店页", "ct_btn");
        link.appendChild(btn2);
        btnArea.appendChild(link);
      } else {
        const appSuggest = document.querySelector("#app_suggest_id");
        const reviewType = document.querySelector('textarea[name="blurb"]');
        if (appSuggest && reviewType) {
          let suggestAppId = null;

          const btn = genBtn("编辑原先的评测", "ct_btn");
          const link = genA("#");
          link.appendChild(btn);
          btnArea.appendChild(link);

          const btn2 = genBtn(
            "删除原先的评测",
            "ct_btn",
            async () => await deleteReview(curator, suggestAppId)
          );
          btnArea.appendChild(btn2);

          const link3 = genA("#");
          const btn3 = genBtn("商店页", "ct_btn");
          link3.appendChild(btn3);
          btnArea.appendChild(link3);

          const spStatus = genSpan("test");
          btnArea.appendChild(spStatus);

          t = setInterval(() => {
            if (appSuggest.value !== suggestAppId) {
              suggestAppId = appSuggest.value;
              btn.disabled = true;
              btn2.disabled = true;
              link.href = "#";

              if (suggestAppId) {
                spStatus.textContent = "正在获取评测内容";

                getReviewText(curator, suggestAppId)
                  .then((text) => {
                    if (text) {
                      spStatus.textContent = "读取完成";
                      reviewType.value = text;
                      btn.disabled = false;
                      btn2.disabled = false;
                      link.href = `https://store.steampowered.com/curator/${curator}/admin/review_create/${suggestAppId}`;
                    } else {
                      spStatus.textContent = "未写过评测";
                    }
                  })
                  .catch((e) => {
                    spStatus.textContent = "读取失败";
                    console.error(e);
                  });

                link3.href = `https://store.steampowered.com/app/${suggestAppId}`;
                btn3.disabled = false;
              } else {
                spStatus.textContent = "未选择游戏";
                link3.href = "#";
                btn3.disabled = true;
              }
            }
          }, 500);
        }
      }
    }
  }

  function injectStats() {
    injectBtn();
    injectGotoBtn();

    lastCount = document.querySelectorAll(
      "#RecentReferralsRows td>.ct_div,#TopReferralsRows td>.ct_div"
    ).length;

    const spanList = document.querySelectorAll(
      "#RecentReferrals_controls>span,#RecentReferrals_controls>span>span,#TopReferrals_controls>span,#TopReferrals_controls>span>span"
    );
    for (let span of spanList) {
      span.addEventListener("click", updateInjectBtn);
    }
  }

  // 删除评测
  async function deleteReview(curator, appid, ele = null) {
    ShowConfirmDialog("", "真的要删除这篇评测吗", "给我删", "手滑了").done(
      () => {
        fetch(
          `https://store.steampowered.com/curator/${curator}/admin/ajaxdeletereview/`,
          {
            method: "POST",
            credentials: "include",
            body: `appid=${appid}&sessionid=${g_sessionID}`,
            headers: {
              "content-type":
                "application/x-www-form-urlencoded; charset=UTF-8",
            },
          }
        )
          .then(async (response) => {
            if (response.ok) {
              showAlert("删除成功", true);

              setTimeout(() => {
                if (location.pathname.includes("review_create")) {
                  if (location.pathname.includes(appid)) {
                    location.pathname = `/curator/${curator}/admin/reviews_manage`;
                  }
                } else {
                  if (ele) {
                    ele.style.opacity = "0.5";
                  }
                }
              }, 500);
            } else {
              showAlert("删除失败", false);
            }
          })
          .catch((err) => {
            console.error(err);
            showAlert(`删除出错 ${err}`, false);
          });
      }
    );
  }

  function updateInjectBtn() {
    const t = setInterval(() => {
      const count = document.querySelectorAll(
        "#RecentReferralsRows td>.ct_div,#TopReferralsRows td>.ct_div"
      ).length;
      if (count != lastCount) {
        clearInterval(t);
        injectBtn();
        lastCount = document.querySelectorAll(
          "#RecentReferralsRows td>.ct_div,#TopReferralsRows td>.ct_div"
        ).length;
      }
    }, 500);
  }

  function injectBtn() {
    const tdList = document.querySelectorAll(
      "#RecentReferralsRows>table>tbody>tr>td:last-child,#TopReferralsRows>table>tbody>tr>td:last-child"
    );
    for (let td of tdList) {
      const a = td.childNodes[0];

      if (a.nodeName !== "A") {
        continue;
      }

      const div = genDiv("ct_div");
      div.appendChild(a);
      td.appendChild(div);

      const [_, curator, appid] = a.href.match(
        /\/curator\/([^\/]+)\/admin\/review_create\/(\d+)/
      ) ?? [null, null, null];

      if (curator !== null && appid !== null) {
        const btn = genBtn("删", "ct_btn", async () =>
          deleteReview(curator, appid, td.parentNode)
        );
        div.appendChild(btn);

        getReviewType(curator, appid).then((type) => {
          let text = "";
          let color = "#fff";
          switch (type) {
            case 0:
              text = "推荐";
              color = "#a9be7b";
              break;
            case 1:
              text = "不推荐";
              color = "#9e2a22";
              break;
            case 2:
              text = "情报";
              color = "#ecd452";
              break;
            default:
              text = "错误";
              color = "#d3ccd6";
              break;
          }
          const span = genSpan(text);
          span.style.color = color;
          td.insertBefore(span, td.childNodes[0]);
        });
      }
    }
  }

  function injectGotoBtn() {
    const recentController = new CAjaxPagingControls(
      g_RecentReferralsPagingData,
      g_RecentReferralsPagingData["url"]
    );
    const recentCtn = document.querySelector(
      "#RecentReferrals_ctn > div:nth-child(2)"
    );
    recentCtn.appendChild(
      genBtn("跳转到...", "ct_btn2", () => {
        gotoPage(recentController);
      })
    );

    const topController = new CAjaxPagingControls(
      g_TopReferralsPagingData,
      g_TopReferralsPagingData["url"]
    );
    const topCtn = document.querySelector(
      "#TopReferrals_ctn > div:nth-child(2)"
    );
    topCtn.appendChild(
      genBtn("跳转到...", "ct_btn2", () => {
        gotoPage(topController);
      })
    );
  }

  function gotoPage(controller) {
    const dialog = ShowPromptDialog("请输入页码", "", "跳转", "取消");

    dialog.done((txt) => {
      const page = parseInt(txt);
      if (page !== page || page < 1) {
        showAlert("请输入有效数字", false);
        return;
      }

      controller.GoToPage(page - 1, true);
      updateInjectBtn();
    });

    dialog.fail(() => {
      dialog.Dismiss();
    });
  }

  function showAlert(text, succ = true) {
    return ShowAlertDialog(`${succ ? "✅" : "❌"}`, text);
  }

  //获取评测类型
  function getReviewType(curatorId, appId) {
    return new Promise((resolve, reject) => {
      fetch(
        `https://store.steampowered.com/curator/${curatorId}/admin/review_create/${appId}`,
        {
          method: "GET",
          credentials: "include",
        }
      )
        .then((response) => {
          if (response.ok) {
            return response.text();
          } else {
            resolve(-2);
          }
        })
        .then((data) => {
          const match = data.match(
            /"recommendation_state" value="(\d)" checked/
          );
          if (match) {
            resolve(parseInt(match[1]));
          } else {
            resolve(-1);
          }
        })
        .catch((err) => {
          console.error(err);
          resolve(-3);
        });
    });
  }

  //获取写过的评测
  function getReviewText(curatorId, appId) {
    return new Promise((resolve, reject) => {
      fetch(
        `https://store.steampowered.com/curator/${curatorId}/admin/review_create/${appId}`,
        {
          method: "GET",
          credentials: "include",
        }
      )
        .then((response) => {
          if (response.ok) {
            return response.text();
          } else {
            resolve(-2);
          }
        })
        .then((data) => {
          const parser = new DOMParser();
          const xmlDoc = parser.parseFromString(data, "text/html");
          const match = xmlDoc.querySelector('textarea[name="blurb"]');
          if (match) {
            resolve(match.value);
          } else {
            resolve(-1);
          }
        })
        .catch((err) => {
          console.error(err);
          resolve(-3);
        });
    });
  }
})();

GM_addStyle(`
.ct_btn {
  padding: 3px;
  margin-right: 10px;
}
.ct_btn2 {
  padding: 0 3px;
  margin-right: 10px;
}
td {
  height: 100%;
}
.ct_div {
  display: flex;
  align-content: center;
  align-items: center;
  height: 25px;
  width: 40px;
}
tr > td > .ct_div > .ct_btn {
  display: none;
}
tr:hover > td > .ct_div > .ct_btn {
  display: block;
}
`);