Friend_Manager

按照共同群组管理好友

  1. // ==UserScript==
  2. // @name:zh-CN 好友管理工具
  3. // @name Friend_Manager
  4. // @namespace https://blog.chrxw.com
  5. // @supportURL https://blog.chrxw.com/scripts.html
  6. // @contributionURL https://afdian.net/@chr233
  7. // @version 1.1
  8. // @description 按照共同群组管理好友
  9. // @description:zh-CN 按照共同群组管理好友
  10. // @author Chr_
  11. // @include https://steamcommunity.com/id/*/friends/
  12. // @include https://steamcommunity.com/profiles/*/friends/
  13. // @include https://steamcommunity.com/id/*/friends
  14. // @include https://steamcommunity.com/profiles/*/friends
  15. // @license AGPL-3.0
  16. // @icon https://blog.chrxw.com/favicon.ico
  17. // @grant GM_registerMenuCommand
  18. // ==/UserScript==
  19.  
  20. // 初始化
  21. (() => {
  22. "use strict";
  23.  
  24. GM_registerMenuCommand("选择在群组中的好友", () => doSelectInGroup(true));
  25. GM_registerMenuCommand("选择不在群组中的好友", () => doSelectInGroup(false));
  26.  
  27. async function doSelectInGroup(mode) {
  28. enforceToManageMode();
  29. await showOperationDialog();
  30.  
  31. const groupLink = await showInputGroupLinkDialog();
  32. const match = groupLink.match(/^(?:https:\/\/steamcommunity\.com\/groups\/)?([^/\s]+)\/?/)
  33.  
  34. if (!match) {
  35. ShowAlertDialog("提示", "群组链接错误, 无法完成操作");
  36. return;
  37. }
  38.  
  39. const group = match[1];
  40.  
  41. const friendList = new Set();
  42.  
  43. let page = 1;
  44. let dialog = ShowDialog("提示", `正在读取共同好友列表, ${page} 页, 已读取 ${friendList.size} 个好友`);
  45. while (true) {
  46. const result = await getGroupFriendList(group, page++);
  47. for (let id of result) {
  48. friendList.add(id);
  49. }
  50.  
  51. dialog?.Dismiss();
  52. if (result.length < 51) {
  53. dialog = ShowDialog("提示", `读取完成, 共读取 ${friendList.size} 个好友`);
  54. setTimeout(() => {
  55. dialog?.Dismiss();
  56. }, 1000);
  57. break;
  58. } else {
  59. dialog = ShowDialog("提示", `正在读取共同好友列表, ${page} 页, 已读取 ${friendList.size} 个好友`);
  60. }
  61. }
  62.  
  63. if (friendList.size === 0) {
  64. ShowAlertDialog("提示", "未获取到共同好友, 群组链接可能无效");
  65. return;
  66. }
  67.  
  68. const eles = document.querySelectorAll("#search_results>.friend_block_v2");
  69. const regex = /steamcommunity\.com\/((?:id\/[^"]+)|(?:profiles\/\d+))/;
  70. for (let ele of eles) {
  71. const profileLink = ele.querySelector("a")?.href;
  72. if (profileLink) {
  73. const m = profileLink.match(regex);
  74. if (m) {
  75. const id = m[1];
  76. if (mode === friendList.has(id)) {
  77. ele.classList.add("selected");
  78. const input = ele.querySelector("div.indicator.select_friend>input");
  79. if (input) {
  80. input.checked = true;
  81. }
  82. }
  83. }
  84. }
  85. }
  86. }
  87.  
  88. function enforceToManageMode() {
  89. const ele = document.querySelector("#search_results>.friend_block_v2");
  90. if (!ele.classList.contains("manage")) {
  91. ToggleManageFriends();
  92. }
  93. }
  94.  
  95. function showOperationDialog() {
  96. return new Promise((resolve, reject) => {
  97. const eles = document.querySelectorAll("#search_results>.friend_block_v2.selected");
  98.  
  99. if (eles.length > 0) {
  100. ShowConfirmDialog(
  101. "需要如何处理已经勾选的项目?",
  102. "",
  103. "不做处理",
  104. "取消勾选"
  105. ).done(() => {
  106. resolve();
  107. }).fail((bool) => {
  108. if (bool) {
  109. for (let ele of eles) {
  110. ele.classList.remove("selected");
  111. const input = ele.querySelector("div.indicator.select_friend>input");
  112. if (input) {
  113. input.checked = false;
  114. }
  115. }
  116. }
  117. resolve();
  118. });
  119. }else{
  120. resolve();
  121. }
  122. });
  123. }
  124.  
  125. function showInputGroupLinkDialog() {
  126. return new Promise((resolve, reject) => {
  127. ShowPromptDialog(
  128. "请输入群组链接",
  129. "例如 https://steamcommunity.com/groups/keylol-player-club",
  130. "查找好友"
  131. ).done((text) => {
  132. resolve(text.trim());
  133. }).fail(() => {
  134. resolve(null);
  135. });
  136. });
  137. }
  138.  
  139. //读取群组共同好友
  140. function getGroupFriendList(group, page = 1) {
  141. return new Promise((resolve, reject) => {
  142. fetch(`https://steamcommunity.com/groups/${group}/members/?friends=1&p=${page}`, {
  143. method: "GET",
  144. credentials: "include",
  145. })
  146. .then(async (response) => {
  147. if (response.ok) {
  148. const data = await response.text();
  149. const parser = new DOMParser();
  150. const xmlDoc = parser.parseFromString(data, "text/html");
  151. const container = xmlDoc.querySelector("#memberList");
  152. const linkFriends = container.querySelectorAll(".member_block a.linkFriend");
  153.  
  154. const result = [];
  155. const regex = /steamcommunity\.com\/((?:id\/[^"]+)|(?:profiles\/\d+))/;
  156. for (let link of linkFriends) {
  157. const href = link.href;
  158. const match = href.match(regex);
  159. if (match) {
  160. result.push(match[1]);
  161. }
  162. }
  163. console.log(result);
  164. resolve(result);
  165. } else {
  166. console.error("网络请求失败");
  167. resolve(null);
  168. }
  169. })
  170. .catch((err) => {
  171. console.error(err);
  172. resolve(null);
  173. });
  174. });
  175. }
  176. })();
  177.  

QingJ © 2025

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