animestars Auto Helper

хелпер который помогает определить популярность карты на сайте astars.club

目前為 2025-01-25 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name animestars Auto Helper
  3. // @namespace animestars.org
  4. // @version 2.73
  5. // @description хелпер который помогает определить популярность карты на сайте astars.club
  6. // @author astars lover
  7. // @match https://astars.club/*
  8. // @match https://asstars1.astars.club/*
  9. // @match https://animestars.org/*
  10. // @match https://as1.astars.club/*
  11. // @license MIT
  12. // @grant none
  13.  
  14. // ==/UserScript==
  15.  
  16. const DELAY = 500; // Задержка между запросами в миллисекундах (по умолчанию 0,5 секунды) не менять чтоб не делать избыточную нагрузку на сайт
  17.  
  18. const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
  19.  
  20. async function getCount(cardId, type) {
  21.  
  22. // Определяем текущий домен
  23. const currentDomain = window.location.origin;
  24.  
  25. let count = 0;
  26. let needResponse = await fetch(`${currentDomain}/cards/${cardId}/users/${type}/`);
  27. if (needResponse.status === 502) {
  28. console.error("Ошибка 502: Остановка выполнения скриптов.");
  29. throw new Error("502 Bad Gateway");
  30. }
  31. let needHtml = '';
  32. let needDoc = '';
  33. if (needResponse.ok) {
  34. needHtml = await needResponse.text();
  35. needDoc = new DOMParser().parseFromString(needHtml, 'text/html');
  36. count = needDoc.querySelectorAll('.profile__friends-item').length;
  37. } else {
  38. return count;
  39. }
  40.  
  41. const pagination = needDoc.querySelector('.pagination__pages');
  42. if (pagination && count >= 50) {
  43. const lastPageNum = pagination.querySelector('a:last-of-type');
  44. const totalPages = lastPageNum ? parseInt(lastPageNum.innerText, 10) : 1;
  45. if (totalPages > 1) {
  46. count = (totalPages - 1) * 50;
  47. }
  48. needResponse = await fetch(`${currentDomain}/cards/${cardId}/users/${type}/page/${totalPages}`);
  49. if (needResponse.status === 502) {
  50. console.error("Ошибка 502: Остановка выполнения скриптов.");
  51. throw new Error("502 Bad Gateway");
  52. }
  53. if (needResponse.ok) {
  54. needHtml = await needResponse.text();
  55. needDoc = new DOMParser().parseFromString(needHtml, 'text/html');
  56. count += needDoc.querySelectorAll('.profile__friends-item').length;
  57. }
  58. }
  59.  
  60. return count;
  61. }
  62.  
  63. async function updateCardInfo(cardId, element) {
  64.  
  65. // Определяем текущий домен
  66. const currentDomain = window.location.origin;
  67.  
  68. if (!cardId || !element) {
  69. console.log(cardId, 'updateCardInfo error');
  70. return;
  71. }
  72.  
  73. try {
  74. console.log(`Обработка карточки с ID: ${cardId}`);
  75.  
  76. await sleep(DELAY);
  77.  
  78. // Получение количества "Желающих"
  79. let needCount = await getCount(cardId, 'need');
  80.  
  81. await sleep(DELAY);
  82.  
  83. // Получение количества "Готовых поменять"
  84. let tradeCount = await getCount(cardId, 'trade');
  85.  
  86. await sleep(DELAY);
  87.  
  88. // Получение популярности и ранга
  89. const popularityResponse = await fetch(`${currentDomain}/cards/${cardId}/users/`);
  90. if (popularityResponse.status === 502) {
  91. console.error("Ошибка 502: Остановка выполнения скриптов.");
  92. throw new Error("502 Bad Gateway");
  93. }
  94.  
  95. let popularityCount = 0;
  96. let rankText = '';
  97. if (popularityResponse.ok) {
  98. const popularityHtml = await popularityResponse.text();
  99. const popularityDoc = new DOMParser().parseFromString(popularityHtml, 'text/html');
  100.  
  101. const rankElement = popularityDoc.querySelector('.anime-cards__rank');
  102. if (rankElement) {
  103. rankText = rankElement.textContent.trim();
  104. }
  105.  
  106. popularityCount = popularityDoc.querySelectorAll('.card-show__owner').length;
  107.  
  108. const pagination = popularityDoc.querySelector('.pagination__pages');
  109. if (pagination) {
  110. const lastPageNum = pagination.querySelector('a:last-of-type');
  111. const totalPages = lastPageNum ? parseInt(lastPageNum.innerText, 10) : 1;
  112. if (totalPages > 1 && popularityCount >= 35) {
  113. popularityCount = (totalPages - 1) * 35;
  114. const needResponse = await fetch(`${currentDomain}/cards/${cardId}/users/page/${lastPageNum}`);
  115. if (needResponse.status === 502) {
  116. console.error("Ошибка 502: Остановка выполнения скриптов.");
  117. throw new Error("502 Bad Gateway");
  118. }
  119. if (needResponse.ok) {
  120. popularityCount += (new DOMParser().parseFromString(await needResponse.text(), 'text/html')).querySelectorAll('.card-show__owner').length;
  121. }
  122. }
  123. }
  124. }
  125.  
  126. // Очистка старой информации
  127. element.querySelector('.link-icon')?.remove();
  128.  
  129. // Добавление новой информации
  130. const icon = document.createElement('div');
  131. icon.className = 'link-icon';
  132. icon.style.position = 'absolute';
  133. icon.style.top = '10px';
  134. icon.style.right = '10px';
  135. icon.style.backgroundColor = 'rgba(0, 0, 0, 0.6)';
  136. icon.style.color = '#05ed5b';
  137. icon.style.padding = '5px';
  138. icon.style.borderRadius = '5px';
  139. icon.style.fontSize = '8px';
  140. icon.innerHTML = `Ранг: ${rankText}<br>Уже имеют: ${popularityCount}<br>Хотят получить: ${needCount}<br>Готовы поменять: ${tradeCount}`;
  141.  
  142. element.style.position = 'relative';
  143. element.appendChild(icon);
  144.  
  145. console.log(cardId, '- ok');
  146.  
  147. } catch (error) {
  148. console.error(`Ошибка обработки карты ${cardId}:`, error);
  149. // Остановка выполнения скриптов
  150. throw error;
  151. }
  152. }
  153.  
  154. function removeAllLinkIcons() {
  155. const linkIcons = document.querySelectorAll('.link-icon');
  156. linkIcons.forEach(icon => icon.remove());
  157. }
  158.  
  159. async function processCards() {
  160. removeAllLinkIcons();
  161.  
  162. const cards = document.querySelectorAll('.lootbox__card, .anime-cards__item, .trade__inventory-item, .trade__main-item, .card-filter-list__card');
  163.  
  164. console.log(cards.length, 'cards found');
  165.  
  166. for (const card of cards) {
  167.  
  168. if (card.classList.contains('trade__inventory-item--lock')) {
  169. console.log('Пропускаем карту с классом trade__inventory-item--lock');
  170. continue; // Пропускаем эту карту
  171. }
  172.  
  173. let cardId = card.getAttribute('card-id') || card.getAttribute('data-card-id') || card.getAttribute('data-id');
  174. const href = card.getAttribute('href');
  175.  
  176. if (href) {
  177. let cardIdMatch = href.match(/\/cards\/(\d+)\/users\//);
  178. console.log(cardIdMatch);
  179. if (cardIdMatch) {
  180. cardId = cardIdMatch[1];
  181. }
  182. }
  183. if (cardId) {
  184. await updateCardInfo(cardId, card).catch(error => {
  185. console.error("Остановка из-за критической ошибки:", error.message);
  186. return;
  187. });
  188. } else {
  189. console.log(cardId, 'cardId not found');
  190. console.log(card);
  191. }
  192.  
  193. if (card.classList.contains('lootbox__card')) {
  194. card.addEventListener('click', removeAllLinkIcons);
  195. }
  196. }
  197. }
  198.  
  199. function addUpdateButton() {
  200. if (!document.querySelector('#fetchLinksButton')) {
  201. const button = document.createElement('button');
  202. button.id = 'fetchLinksButton';
  203. button.innerText = 'Обновить инфу';
  204. button.style.position = 'fixed';
  205. button.style.top = '37%';
  206. button.style.right = '-50px';
  207. button.style.zIndex = '1000';
  208. button.style.backgroundColor = '#007bff';
  209. button.style.color = '#fff';
  210. button.style.border = 'none';
  211. button.style.borderRadius = '5px';
  212. button.style.padding = '10px 15px';
  213. button.style.cursor = 'pointer';
  214. button.style.boxShadow = '0 2px 5px rgba(0, 0, 0, 0.2)';
  215. button.style.transform = 'rotate(90deg)';
  216. button.addEventListener('click', processCards);
  217. document.body.appendChild(button);
  218. }
  219. }
  220.  
  221. function clearIcons() {
  222. $('.card-notification')?.first()?.click();
  223. }
  224.  
  225. function startPing() {
  226. setInterval(() => {
  227. // Получаем значение из глобальной переменной
  228. const userHash = window.dle_login_hash;
  229.  
  230. if (!userHash) {
  231. console.error("Переменная dle_login_hash не определена.");
  232. return;
  233. }
  234.  
  235. // Определяем текущий домен
  236. const currentDomain = window.location.origin;
  237.  
  238. // Формируем URL с учетом userHash
  239. const url = `${currentDomain}/engine/ajax/controller.php?mod=user_count_timer&user_hash=${userHash}`;
  240.  
  241. // Выполняем GET-запрос
  242. fetch(url)
  243. .then(response => {
  244. if (!response.ok) {
  245. throw new Error(`HTTP error! Status: ${response.status}`);
  246. }
  247. return response.json(); // Если ответ в формате JSON
  248. })
  249. .then(data => {
  250. console.log("Данные получены:", data); // Обрабатываем полученные данные
  251. })
  252. .catch(error => {
  253. console.error("Ошибка при выполнении запроса:", error);
  254. });
  255. }, 31000); // Интервал проверки — 31 сек
  256. }
  257.  
  258. function checkCard() {
  259. setInterval(() => {
  260. const today = new Date().toISOString().split('T')[0];
  261. const localStorageKey = `checkCardStopped_${today}`;
  262.  
  263. if (localStorage.getItem(localStorageKey)) {
  264. console.log("Проверка карты уже остановлена на сегодня.");
  265. return;
  266. }
  267.  
  268. // Получаем значение из глобальной переменной
  269. const userHash = window.dle_login_hash;
  270.  
  271. if (!userHash) {
  272. console.error("Переменная dle_login_hash не определена.");
  273. return;
  274. }
  275.  
  276. // Определяем текущий домен
  277. const currentDomain = window.location.origin;
  278.  
  279. // Формируем URL с учетом userHash
  280. const url = `${currentDomain}/engine/ajax/controller.php?mod=reward_card&action=check_reward&user_hash=${userHash}`;
  281. // Выполняем GET-запрос
  282. fetch(url)
  283. .then(response => {
  284. if (!response.ok) {
  285. throw new Error(`HTTP error! Status: ${response.status}`);
  286. }
  287. return response.json(); // Если ответ в формате JSON
  288. })
  289. .then(data => {
  290. if (data.stop_reward === "yes") {
  291. console.log("Проверка карт остановлена:", data.reason);
  292. localStorage.setItem(localStorageKey, "true");
  293. return;
  294. }
  295. if (!data.cards || !data.cards.owner_id) {
  296. return;
  297. }
  298. const ownerId = data.cards.owner_id;
  299. console.log("owner_id получен:", ownerId); // Выводим owner_id
  300.  
  301. const url = `${currentDomain}/engine/ajax/controller.php?mod=cards_ajax`;
  302.  
  303. // Подготавливаем параметры запроса
  304. const postData = new URLSearchParams({
  305. action: "take_card",
  306. owner_id: ownerId
  307. });
  308.  
  309. // Выполняем POST-запрос
  310. fetch(url, {
  311. method: "POST",
  312. headers: {
  313. "Content-Type": "application/x-www-form-urlencoded"
  314. },
  315. body: postData.toString() // Передаём параметры в виде строки
  316. })
  317. .then(response => {
  318. if (!response.ok) {
  319. throw new Error(`HTTP error! Status: ${response.status}`);
  320. }
  321. return response.json(); // Если ответ в формате JSON
  322. })
  323. .then(data => {
  324. console.log("Данные получены:", data); // Обрабатываем полученные данные
  325. })
  326. .catch(error => {
  327. console.error("Ошибка при выполнении запроса:", error);
  328. });
  329. })
  330. .catch(error => {
  331. console.error("Ошибка при выполнении запроса:", error);
  332. });
  333.  
  334. }, 10000); // Интервал проверки — 10 сек
  335. }
  336.  
  337. (function() {
  338. 'use strict';
  339.  
  340. setInterval(clearIcons, 2000);
  341. startPing();
  342. checkCard();
  343.  
  344. addUpdateButton();
  345. })();