Auto Like Specific User

自动点赞特定用户,适用于discourse

当前为 2024-09-03 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Auto Like Specific User
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.1
  5. // @description 自动点赞特定用户,适用于discourse
  6. // @author liuweiqing
  7. // @match https://meta.discourse.org/*
  8. // @match https://linux.do/*
  9. // @match https://meta.appinn.net/*
  10. // @match https://community.openai.com/
  11. // @grant none
  12. // @license MIT
  13. // @icon https://www.google.com/s2/favicons?domain=linux.do
  14. // @run-at document-end
  15. // ==/UserScript==
  16.  
  17. (function () {
  18. ("use strict");
  19. // 定义可能的基本URL
  20. const possibleBaseURLs = [
  21. "https://meta.discourse.org",
  22. "https://linux.do",
  23. "https://meta.appinn.net",
  24. "https://community.openai.com",
  25. ];
  26. const commentLimit = 1000;
  27. const specificUserPostListLimit = 100;
  28. const currentURL = window.location.href;
  29. let specificUser = localStorage.getItem("specificUser") || "14790897";
  30. let likeLimit = parseInt(localStorage.getItem("likeLimit") || 200, 10);
  31. let BASE_URL = possibleBaseURLs.find((url) => currentURL.startsWith(url));
  32.  
  33. // 环境变量:阅读网址,如果没有找到匹配的URL,则默认为第一个
  34. if (!BASE_URL) {
  35. BASE_URL = possibleBaseURLs[0];
  36. console.log("当前BASE_URL设置为(默认): " + BASE_URL);
  37. } else {
  38. console.log("当前BASE_URL是: " + BASE_URL);
  39. }
  40. // 获取当前时间戳
  41. const currentTime = Date.now();
  42. // 获取存储的时间戳
  43. const defaultTimestamp = new Date("1999-01-01T00:00:00Z").getTime(); //默认值为1999年
  44. const storedTime = parseInt(
  45. localStorage.getItem("clickCounterTimestamp") ||
  46. defaultTimestamp.toString(),
  47. 10
  48. );
  49.  
  50. // 获取当前的点击计数,如果不存在则初始化为0
  51. let clickCounter = parseInt(localStorage.getItem("clickCounter") || "0", 10);
  52. // 检查是否超过12小时(12小时 = 12 * 60 * 60 * 1000 毫秒)
  53. if (currentTime - storedTime > 12 * 60 * 60 * 1000) {
  54. // 超过24小时,清空点击计数器并更新时间戳
  55. clickCounter = 0;
  56. localStorage.setItem("clickCounter", "0");
  57. localStorage.setItem("clickCounterTimestamp", currentTime.toString());
  58. }
  59.  
  60. console.log(`Initial clickCounter: ${clickCounter}`);
  61. // 入口函数
  62. window.addEventListener("load", () => {
  63. console.log("autoRead", localStorage.getItem("read"));
  64. checkFirstRun();
  65. if (localStorage.getItem("read") === "true") {
  66. console.log("点赞开始");
  67. setTimeout(() => {
  68. likeSpecificPost();
  69. }, 2000);
  70. setTimeout(() => {
  71. openSpecificUserPost();
  72. }, 4000);
  73. }
  74. });
  75. function checkFirstRun() {
  76. if (localStorage.getItem("isFirstRun") === null) {
  77. console.log("脚本第一次运行,执行初始化操作...");
  78. updateInitialData();
  79. localStorage.setItem("isFirstRun", "false");
  80. } else {
  81. console.log("脚本非第一次运行");
  82. }
  83. }
  84.  
  85. function updateInitialData() {
  86. localStorage.setItem("read", "false"); // 开始时自动滚动关闭
  87. console.log("执行了初始数据更新操作");
  88. }
  89.  
  90. function getLatestTopic() {
  91. let lastOffset = Number(localStorage.getItem("lastOffset")) || 0;
  92. let specificUserPostList = [];
  93. let isDataSufficient = false;
  94.  
  95. while (!isDataSufficient) {
  96. // lastOffset += 20;
  97. lastOffset += 1; //对于page来说
  98. // 举例:https://linux.do/user_actions.json?offset=0&username=14790897&filter=5
  99. // const url = `${BASE_URL}/user_actions.json?offset=${lastOffset}&username=${specificUser}&filter=5`;
  100. //举例:https://linux.do/search?q=%4014790897%20in%3Aunseen
  101. const url = `${BASE_URL}/search?q=%40${specificUser}%20in%3Aunseen`; //&page=${lastOffset}
  102. $.ajax({
  103. url: url,
  104. async: false,
  105. headers: {
  106. Accept: "application/json",
  107. },
  108. success: function (result) {
  109. // if (result && result.user_actions && result.user_actions.length > 0) {
  110. // result.user_actions.forEach((action) => {
  111. if (result && result.posts && result.posts.length > 0) {
  112. result.posts.forEach((action) => {
  113. const topicId = action.topic_id;
  114. // const postId = action.post_id;
  115. const postNumber = action.post_number;
  116. specificUserPostList.push({
  117. topic_id: topicId,
  118. // post_id: postId,
  119. post_number: postNumber,
  120. });
  121. });
  122.  
  123. // 检查是否已获得足够的 Posts
  124. if (specificUserPostList.length >= specificUserPostListLimit) {
  125. isDataSufficient = true;
  126. }
  127. } else {
  128. isDataSufficient = true; // 没有更多内容时停止请求
  129. }
  130. },
  131. error: function (XMLHttpRequest, textStatus, errorThrown) {
  132. console.error(XMLHttpRequest, textStatus, errorThrown);
  133. isDataSufficient = true; // 遇到错误时也停止请求
  134. },
  135. });
  136. }
  137.  
  138. // 如果列表超出限制,则截断
  139. if (specificUserPostList.length > specificUserPostListLimit) {
  140. specificUserPostList = specificUserPostList.slice(
  141. 0,
  142. specificUserPostListLimit
  143. );
  144. }
  145.  
  146. // 存储 lastOffset 和 specificUserPostList 到 localStorage
  147. localStorage.setItem("lastOffset", lastOffset);
  148. localStorage.setItem(
  149. "specificUserPostList",
  150. JSON.stringify(specificUserPostList)
  151. );
  152. }
  153.  
  154. function openSpecificUserPost() {
  155. let specificUserPostListStr = localStorage.getItem("specificUserPostList");
  156. let specificUserPostList = specificUserPostListStr
  157. ? JSON.parse(specificUserPostListStr)
  158. : [];
  159.  
  160. // 如果列表为空,则获取最新文章
  161. if (specificUserPostList.length === 0) {
  162. getLatestTopic();
  163. specificUserPostListStr = localStorage.getItem("specificUserPostList");
  164. specificUserPostList = specificUserPostListStr
  165. ? JSON.parse(specificUserPostListStr)
  166. : [];
  167. }
  168.  
  169. // 如果获取到新文章,打开第一个
  170. if (specificUserPostList.length > 0) {
  171. const post = specificUserPostList.shift(); // 获取列表中的第一个对象
  172. localStorage.setItem(
  173. "specificUserPostList",
  174. JSON.stringify(specificUserPostList)
  175. );
  176.  
  177. window.location.href = `${BASE_URL}/t/topic/${post.topic_id}/${post.post_number}`;
  178. } else {
  179. console.error("未能获取到新的帖子数据。");
  180. }
  181. }
  182.  
  183. // 检查是否点赞
  184. // const postId = data.post_id;
  185.  
  186. // const targetId = `discourse-reactions-counter-${postId}-right`;
  187.  
  188. // const element = document.getElementById(targetId);
  189. function likeSpecificPost() {
  190. const urlParts = window.location.pathname.split("/");
  191. const lastPart = urlParts[urlParts.length - 1]; // 获取最后一部分
  192. let buttons, reactionButton;
  193. console.log("post number:", lastPart);
  194. if (lastPart < 10000) {
  195. buttons = document.querySelectorAll(
  196. "button[aria-label]" //[class*='reply']
  197. );
  198.  
  199. let targetButton = null;
  200. buttons.forEach((button) => {
  201. const ariaLabel = button.getAttribute("aria-label");
  202. if (
  203. ariaLabel &&
  204. (ariaLabel.includes(`#${lastPart}`))
  205. ) {
  206. targetButton = button;
  207. console.log("找到post number按钮:", targetButton);
  208. return;
  209. }
  210. });
  211.  
  212. if (targetButton) {
  213. // 找到按钮后,获取其父级元素
  214. const parentElement = targetButton.parentElement;
  215. console.log("父级元素:", parentElement);
  216. reactionButton = parentElement.querySelector(
  217. ".discourse-reactions-reaction-button"
  218. );
  219. } else {
  220. console.log(`未找到包含 #${lastPart} 的按钮`);
  221. }
  222. } else {//大于10000说明是主题帖,选择第一个
  223. reactionButton = document.querySelectorAll(
  224. ".discourse-reactions-reaction-button"
  225. )[0];
  226. }
  227. if (
  228. reactionButton.title !== "点赞此帖子" &&
  229. reactionButton.title !== "Like this post"
  230. ) {
  231. console.log("已经点赞过");
  232. return "already liked";
  233. } else if (clickCounter >= likeLimit) {
  234. console.log("已经达到点赞上限");
  235. localStorage.setItem("read", false);
  236. return;
  237. }
  238. triggerClick(reactionButton);
  239. clickCounter++;
  240. console.log(
  241. `Clicked like button ${clickCounter},已点赞用户${specificUser}`
  242. );
  243. localStorage.setItem("clickCounter", clickCounter.toString());
  244. // 如果点击次数达到likeLimit次,则设置点赞变量为false
  245. if (clickCounter === likeLimit) {
  246. console.log(
  247. `Reached ${likeLimit} likes, setting the like variable to false.`
  248. );
  249. localStorage.setItem("read", false);
  250. } else {
  251. console.log("clickCounter:", clickCounter);
  252. }
  253. }
  254.  
  255. function triggerClick(button) {
  256. const event = new MouseEvent("click", {
  257. bubbles: true,
  258. cancelable: true,
  259. view: window,
  260. });
  261. button.dispatchEvent(event);
  262. }
  263.  
  264. const button = document.createElement("button");
  265. button.textContent =
  266. localStorage.getItem("read") === "true" ? "停止阅读" : "开始阅读";
  267. button.style.position = "fixed";
  268. button.style.bottom = "20px";
  269. button.style.left = "20px";
  270. button.style.zIndex = 1000;
  271. button.style.backgroundColor = "#e0e0e0";
  272. button.style.color = "#333";
  273. button.style.border = "1px solid #aaa";
  274. button.style.padding = "8px 16px";
  275. button.style.borderRadius = "8px";
  276. document.body.appendChild(button);
  277.  
  278. button.onclick = function () {
  279. const currentlyReading = localStorage.getItem("read") === "true";
  280. const newReadState = !currentlyReading;
  281. localStorage.setItem("read", newReadState.toString());
  282. button.textContent = newReadState ? "停止阅读" : "开始阅读";
  283. if (newReadState) {
  284. if (BASE_URL == "https://linux.do") {
  285. const maxPostNumber = 600;
  286. const randomPostNumber = Math.floor(Math.random() * maxPostNumber) + 1;
  287. const newUrl = `https://linux.do/t/topic/13716/${randomPostNumber}`;
  288. window.location.href = newUrl;
  289. } else {
  290. window.location.href = `${BASE_URL}/t/topic/1`;
  291. }
  292. }
  293. };
  294.  
  295. const userInput = document.createElement("input");
  296. userInput.type = "text";
  297. userInput.placeholder = "输入要点赞的用户ID";
  298. userInput.style.position = "fixed";
  299. userInput.style.bottom = "90px";
  300. userInput.style.left = "20px";
  301. userInput.style.zIndex = "1000";
  302. userInput.style.padding = "6px";
  303. userInput.style.border = "1px solid #aaa";
  304. userInput.style.borderRadius = "8px";
  305. userInput.style.backgroundColor = "#e0e0e0";
  306. userInput.style.width = "100px";
  307. userInput.value = localStorage.getItem("specificUser") || "14790897";
  308.  
  309. document.body.appendChild(userInput);
  310.  
  311. const saveUserButton = document.createElement("button");
  312. saveUserButton.textContent = "保存用户ID";
  313. saveUserButton.style.position = "fixed";
  314. saveUserButton.style.bottom = "60px";
  315. saveUserButton.style.left = "20px";
  316. saveUserButton.style.zIndex = "1000";
  317. saveUserButton.style.backgroundColor = "#e0e0e0";
  318. saveUserButton.style.color = "#333";
  319. saveUserButton.style.border = "1px solid #aaa";
  320. saveUserButton.style.padding = "8px 16px";
  321. saveUserButton.style.borderRadius = "8px";
  322. document.body.appendChild(saveUserButton);
  323.  
  324. saveUserButton.onclick = function () {
  325. const newSpecificUser = userInput.value.trim();
  326. if (newSpecificUser) {
  327. localStorage.setItem("specificUser", newSpecificUser);
  328. localStorage.removeItem("specificUserPostList");
  329. specificUser = newSpecificUser;
  330. console.log(
  331. `新的specificUser已保存: ${specificUser},specificUserPostList已重置`
  332. );
  333. }
  334. };
  335.  
  336. const likeLimitInput = document.createElement("input");
  337. likeLimitInput.type = "number";
  338. likeLimitInput.placeholder = "输入点赞数量";
  339. likeLimitInput.style.position = "fixed";
  340. likeLimitInput.style.bottom = "180px";
  341. likeLimitInput.style.left = "20px";
  342. likeLimitInput.style.zIndex = "1000";
  343. likeLimitInput.style.padding = "6px";
  344. likeLimitInput.style.border = "1px solid #aaa";
  345. likeLimitInput.style.borderRadius = "8px";
  346. likeLimitInput.style.backgroundColor = "#e0e0e0";
  347. likeLimitInput.style.width = "100px";
  348. likeLimitInput.value = localStorage.getItem("likeLimit") || 200;
  349. document.body.appendChild(likeLimitInput);
  350.  
  351. const saveLikeLimitButton = document.createElement("button");
  352. saveLikeLimitButton.textContent = "保存点赞数量";
  353. saveLikeLimitButton.style.position = "fixed";
  354. saveLikeLimitButton.style.bottom = "140px";
  355. saveLikeLimitButton.style.left = "20px";
  356. saveLikeLimitButton.style.zIndex = "1000";
  357. saveLikeLimitButton.style.backgroundColor = "#e0e0e0";
  358. saveLikeLimitButton.style.color = "#333";
  359. saveLikeLimitButton.style.border = "1px solid #aaa";
  360. saveLikeLimitButton.style.padding = "8px 16px";
  361. saveLikeLimitButton.style.borderRadius = "8px";
  362. document.body.appendChild(saveLikeLimitButton);
  363.  
  364. saveLikeLimitButton.onclick = function () {
  365. const newLikeLimit = parseInt(likeLimitInput.value.trim(), 10);
  366. if (newLikeLimit && newLikeLimit > 0) {
  367. localStorage.setItem("likeLimit", newLikeLimit);
  368. likeLimit = newLikeLimit;
  369. console.log(`新的likeLimit已保存: ${likeLimit}`);
  370. }
  371. };
  372.  
  373. // 增加清除数据的按钮
  374. const clearDataButton = document.createElement("button");
  375. clearDataButton.textContent = "清除所有数据";
  376. clearDataButton.style.position = "fixed";
  377. clearDataButton.style.bottom = "20px";
  378. clearDataButton.style.left = "140px";
  379. clearDataButton.style.zIndex = "1000";
  380. clearDataButton.style.backgroundColor = "#ff6666"; // 红色背景,提示删除操作
  381. clearDataButton.style.color = "#fff"; // 白色文本
  382. clearDataButton.style.border = "1px solid #ff3333"; // 深红色边框
  383. clearDataButton.style.padding = "8px 16px";
  384. clearDataButton.style.borderRadius = "8px";
  385. document.body.appendChild(clearDataButton);
  386.  
  387. clearDataButton.onclick = function () {
  388. localStorage.removeItem("lastOffset");
  389. localStorage.removeItem("clickCounter");
  390. localStorage.removeItem("clickCounterTimestamp");
  391. console.log("所有数据已清除,除了 specificUser 和 specificUserPostList");
  392. };
  393. })();

QingJ © 2025

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