鉴赏家小工具

添加删除按钮

  1. // ==UserScript==
  2. // @name:zh-CN 鉴赏家小工具
  3. // @name Curator_Tools
  4. // @namespace https://blog.chrxw.com
  5. // @supportURL https://blog.chrxw.com/scripts.html
  6. // @contributionURL https://afdian.com/@chr233
  7. // @version 1.10
  8. // @description 添加删除按钮
  9. // @description:zh-CN 添加删除按钮
  10. // @author Chr_
  11. // @include https://store.steampowered.com/curator/*
  12. // @license AGPL-3.0
  13. // @icon https://blog.chrxw.com/favicon.ico
  14. // @grant GM_addStyle
  15. // ==/UserScript==
  16.  
  17. // 初始化
  18. (() => {
  19. "use strict";
  20.  
  21. const eleContailer = document.getElementById("subpage_container");
  22. if (eleContailer) {
  23. const observer = new MutationObserver(onPageLoad);
  24. observer.observe(eleContailer, { childList: true, subtree: true });
  25. }
  26.  
  27. let lastPathname = "";
  28. let lastCount = 0;
  29. let t = 0;
  30.  
  31. function onPageLoad() {
  32. if (lastPathname == location.pathname) {
  33. return;
  34. }
  35. lastPathname = location.pathname;
  36.  
  37. if (t !== 0) {
  38. clearInterval(t);
  39. t = 0;
  40. }
  41.  
  42. if (location.pathname.includes("admin/review_create")) {
  43. injectReviewCreate();
  44. } else if (location.pathname.includes("admin/stats")) {
  45. injectStats();
  46. }
  47. }
  48.  
  49. onPageLoad();
  50.  
  51. function genBtn(text, cls, foo) {
  52. const btn = document.createElement("button");
  53. btn.textContent = text;
  54. btn.className = cls;
  55. btn.addEventListener("click", foo);
  56. return btn;
  57. }
  58. function genA(url) {
  59. const a = document.createElement("a");
  60. a.href = url;
  61. a.target = "_blank";
  62. return a;
  63. }
  64. function genDiv(cls) {
  65. const div = document.createElement("div");
  66. div.className = cls;
  67. return div;
  68. }
  69. function genSpan(name) {
  70. const span = document.createElement("span");
  71. span.textContent = name;
  72. return span;
  73. }
  74.  
  75. function injectReviewCreate() {
  76. const [_, curator, appid] = lastPathname.match(
  77. /\/curator\/([^\/]+)\/admin\/review_create\/?(\d+)?/
  78. ) ?? [null, null, null];
  79.  
  80. if (curator) {
  81. const btnArea = document.querySelector("div.titleframe");
  82.  
  83. if (appid) {
  84. const btn = genBtn(
  85. "删除该评测",
  86. "ct_btn",
  87. async () => await deleteReview(curator, appid)
  88. );
  89. btnArea.appendChild(btn);
  90. const link = genA(`https://store.steampowered.com/app/${appid}`);
  91. const btn2 = genBtn("商店页", "ct_btn");
  92. link.appendChild(btn2);
  93. btnArea.appendChild(link);
  94. } else {
  95. const appSuggest = document.querySelector("#app_suggest_id");
  96. const reviewType = document.querySelector('textarea[name="blurb"]');
  97. if (appSuggest && reviewType) {
  98. let suggestAppId = null;
  99.  
  100. const btn = genBtn("编辑原先的评测", "ct_btn");
  101. const link = genA("#");
  102. link.appendChild(btn);
  103. btnArea.appendChild(link);
  104.  
  105. const btn2 = genBtn(
  106. "删除原先的评测",
  107. "ct_btn",
  108. async () => await deleteReview(curator, suggestAppId)
  109. );
  110. btnArea.appendChild(btn2);
  111.  
  112. const link3 = genA("#");
  113. const btn3 = genBtn("商店页", "ct_btn");
  114. link3.appendChild(btn3);
  115. btnArea.appendChild(link3);
  116.  
  117. const spStatus = genSpan("test");
  118. btnArea.appendChild(spStatus);
  119.  
  120. t = setInterval(() => {
  121. if (appSuggest.value !== suggestAppId) {
  122. suggestAppId = appSuggest.value;
  123. btn.disabled = true;
  124. btn2.disabled = true;
  125. link.href = "#";
  126.  
  127. if (suggestAppId) {
  128. spStatus.textContent = "正在获取评测内容";
  129.  
  130. getReviewText(curator, suggestAppId)
  131. .then((text) => {
  132. if (text) {
  133. spStatus.textContent = "读取完成";
  134. reviewType.value = text;
  135. btn.disabled = false;
  136. btn2.disabled = false;
  137. link.href = `https://store.steampowered.com/curator/${curator}/admin/review_create/${suggestAppId}`;
  138. } else {
  139. spStatus.textContent = "未写过评测";
  140. }
  141. })
  142. .catch((e) => {
  143. spStatus.textContent = "读取失败";
  144. console.error(e);
  145. });
  146.  
  147. link3.href = `https://store.steampowered.com/app/${suggestAppId}`;
  148. btn3.disabled = false;
  149. } else {
  150. spStatus.textContent = "未选择游戏";
  151. link3.href = "#";
  152. btn3.disabled = true;
  153. }
  154. }
  155. }, 500);
  156. }
  157. }
  158. }
  159. }
  160.  
  161. function injectStats() {
  162. injectBtn();
  163. injectGotoBtn();
  164.  
  165. lastCount = document.querySelectorAll(
  166. "#RecentReferralsRows td>.ct_div,#TopReferralsRows td>.ct_div"
  167. ).length;
  168.  
  169. const spanList = document.querySelectorAll(
  170. "#RecentReferrals_controls>span,#RecentReferrals_controls>span>span,#TopReferrals_controls>span,#TopReferrals_controls>span>span"
  171. );
  172. for (let span of spanList) {
  173. span.addEventListener("click", updateInjectBtn);
  174. }
  175. }
  176.  
  177. // 删除评测
  178. async function deleteReview(curator, appid, ele = null) {
  179. ShowConfirmDialog("", "真的要删除这篇评测吗", "给我删", "手滑了").done(
  180. () => {
  181. fetch(
  182. `https://store.steampowered.com/curator/${curator}/admin/ajaxdeletereview/`,
  183. {
  184. method: "POST",
  185. credentials: "include",
  186. body: `appid=${appid}&sessionid=${g_sessionID}`,
  187. headers: {
  188. "content-type":
  189. "application/x-www-form-urlencoded; charset=UTF-8",
  190. },
  191. }
  192. )
  193. .then(async (response) => {
  194. if (response.ok) {
  195. showAlert("删除成功", true);
  196.  
  197. setTimeout(() => {
  198. if (location.pathname.includes("review_create")) {
  199. if (location.pathname.includes(appid)) {
  200. location.pathname = `/curator/${curator}/admin/reviews_manage`;
  201. }
  202. } else {
  203. if (ele) {
  204. ele.style.opacity = "0.5";
  205. }
  206. }
  207. }, 500);
  208. } else {
  209. showAlert("删除失败", false);
  210. }
  211. })
  212. .catch((err) => {
  213. console.error(err);
  214. showAlert(`删除出错 ${err}`, false);
  215. });
  216. }
  217. );
  218. }
  219.  
  220. function updateInjectBtn() {
  221. const t = setInterval(() => {
  222. const count = document.querySelectorAll(
  223. "#RecentReferralsRows td>.ct_div,#TopReferralsRows td>.ct_div"
  224. ).length;
  225. if (count != lastCount) {
  226. clearInterval(t);
  227. injectBtn();
  228. lastCount = document.querySelectorAll(
  229. "#RecentReferralsRows td>.ct_div,#TopReferralsRows td>.ct_div"
  230. ).length;
  231. }
  232. }, 500);
  233. }
  234.  
  235. function injectBtn() {
  236. const tdList = document.querySelectorAll(
  237. "#RecentReferralsRows>table>tbody>tr>td:last-child,#TopReferralsRows>table>tbody>tr>td:last-child"
  238. );
  239. for (let td of tdList) {
  240. const a = td.childNodes[0];
  241.  
  242. if (a.nodeName !== "A") {
  243. continue;
  244. }
  245.  
  246. const div = genDiv("ct_div");
  247. div.appendChild(a);
  248. td.appendChild(div);
  249.  
  250. const [_, curator, appid] = a.href.match(
  251. /\/curator\/([^\/]+)\/admin\/review_create\/(\d+)/
  252. ) ?? [null, null, null];
  253.  
  254. if (curator !== null && appid !== null) {
  255. const btn = genBtn("删", "ct_btn", async () =>
  256. deleteReview(curator, appid, td.parentNode)
  257. );
  258. div.appendChild(btn);
  259.  
  260. getReviewType(curator, appid).then((type) => {
  261. let text = "";
  262. let color = "#fff";
  263. switch (type) {
  264. case 0:
  265. text = "推荐";
  266. color = "#a9be7b";
  267. break;
  268. case 1:
  269. text = "不推荐";
  270. color = "#9e2a22";
  271. break;
  272. case 2:
  273. text = "情报";
  274. color = "#ecd452";
  275. break;
  276. default:
  277. text = "错误";
  278. color = "#d3ccd6";
  279. break;
  280. }
  281. const span = genSpan(text);
  282. span.style.color = color;
  283. td.insertBefore(span, td.childNodes[0]);
  284. });
  285. }
  286. }
  287. }
  288.  
  289. function injectGotoBtn() {
  290. const recentController = new CAjaxPagingControls(
  291. g_RecentReferralsPagingData,
  292. g_RecentReferralsPagingData["url"]
  293. );
  294. const recentCtn = document.querySelector(
  295. "#RecentReferrals_ctn > div:nth-child(2)"
  296. );
  297. recentCtn.appendChild(
  298. genBtn("跳转到...", "ct_btn2", () => {
  299. gotoPage(recentController);
  300. })
  301. );
  302.  
  303. const topController = new CAjaxPagingControls(
  304. g_TopReferralsPagingData,
  305. g_TopReferralsPagingData["url"]
  306. );
  307. const topCtn = document.querySelector(
  308. "#TopReferrals_ctn > div:nth-child(2)"
  309. );
  310. topCtn.appendChild(
  311. genBtn("跳转到...", "ct_btn2", () => {
  312. gotoPage(topController);
  313. })
  314. );
  315. }
  316.  
  317. function gotoPage(controller) {
  318. const dialog = ShowPromptDialog("请输入页码", "", "跳转", "取消");
  319.  
  320. dialog.done((txt) => {
  321. const page = parseInt(txt);
  322. if (page !== page || page < 1) {
  323. showAlert("请输入有效数字", false);
  324. return;
  325. }
  326.  
  327. controller.GoToPage(page - 1, true);
  328. updateInjectBtn();
  329. });
  330.  
  331. dialog.fail(() => {
  332. dialog.Dismiss();
  333. });
  334. }
  335.  
  336. function showAlert(text, succ = true) {
  337. return ShowAlertDialog(`${succ ? "✅" : "❌"}`, text);
  338. }
  339.  
  340. //获取评测类型
  341. function getReviewType(curatorId, appId) {
  342. return new Promise((resolve, reject) => {
  343. fetch(
  344. `https://store.steampowered.com/curator/${curatorId}/admin/review_create/${appId}`,
  345. {
  346. method: "GET",
  347. credentials: "include",
  348. }
  349. )
  350. .then((response) => {
  351. if (response.ok) {
  352. return response.text();
  353. } else {
  354. resolve(-2);
  355. }
  356. })
  357. .then((data) => {
  358. const match = data.match(
  359. /"recommendation_state" value="(\d)" checked/
  360. );
  361. if (match) {
  362. resolve(parseInt(match[1]));
  363. } else {
  364. resolve(-1);
  365. }
  366. })
  367. .catch((err) => {
  368. console.error(err);
  369. resolve(-3);
  370. });
  371. });
  372. }
  373.  
  374. //获取写过的评测
  375. function getReviewText(curatorId, appId) {
  376. return new Promise((resolve, reject) => {
  377. fetch(
  378. `https://store.steampowered.com/curator/${curatorId}/admin/review_create/${appId}`,
  379. {
  380. method: "GET",
  381. credentials: "include",
  382. }
  383. )
  384. .then((response) => {
  385. if (response.ok) {
  386. return response.text();
  387. } else {
  388. resolve(-2);
  389. }
  390. })
  391. .then((data) => {
  392. const parser = new DOMParser();
  393. const xmlDoc = parser.parseFromString(data, "text/html");
  394. const match = xmlDoc.querySelector('textarea[name="blurb"]');
  395. if (match) {
  396. resolve(match.value);
  397. } else {
  398. resolve(-1);
  399. }
  400. })
  401. .catch((err) => {
  402. console.error(err);
  403. resolve(-3);
  404. });
  405. });
  406. }
  407. })();
  408.  
  409. GM_addStyle(`
  410. .ct_btn {
  411. padding: 3px;
  412. margin-right: 10px;
  413. }
  414. .ct_btn2 {
  415. padding: 0 3px;
  416. margin-right: 10px;
  417. }
  418. td {
  419. height: 100%;
  420. }
  421. .ct_div {
  422. display: flex;
  423. align-content: center;
  424. align-items: center;
  425. height: 25px;
  426. width: 40px;
  427. }
  428. tr > td > .ct_div > .ct_btn {
  429. display: none;
  430. }
  431. tr:hover > td > .ct_div > .ct_btn {
  432. display: block;
  433. }
  434. `);

QingJ © 2025

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