Auto Like Specific User

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

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

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

QingJ © 2025

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