animestars Auto Helper

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

当前为 2025-02-04 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name animestars Auto Helper
  3. // @namespace animestars.org
  4. // @version 2.94
  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. // @match https://asstars.tv/*
  12. // @license MIT
  13. // @grant none
  14.  
  15. // ==/UserScript==
  16.  
  17. const DELAY = 500; // Задержка между запросами в миллисекундах (по умолчанию 0,5 секунды) не менять чтоб не делать избыточную нагрузку на сайт
  18.  
  19. const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
  20.  
  21. async function getCount(cardId, type) {
  22.  
  23. // Определяем текущий домен
  24. const currentDomain = window.location.origin;
  25.  
  26. let count = 0;
  27. let needResponse = await fetch(`${currentDomain}/cards/${cardId}/users/${type}/`);
  28. if (needResponse.status === 502) {
  29. console.error("Ошибка 502: Остановка выполнения скриптов.");
  30. throw new Error("502 Bad Gateway");
  31. }
  32. let needHtml = '';
  33. let needDoc = '';
  34. if (needResponse.ok) {
  35. needHtml = await needResponse.text();
  36. needDoc = new DOMParser().parseFromString(needHtml, 'text/html');
  37. count = needDoc.querySelectorAll('.profile__friends-item').length;
  38. } else {
  39. return count;
  40. }
  41.  
  42. const pagination = needDoc.querySelector('.pagination__pages');
  43. if (pagination && count >= 50) {
  44. const lastPageNum = pagination.querySelector('a:last-of-type');
  45. const totalPages = lastPageNum ? parseInt(lastPageNum.innerText, 10) : 1;
  46. if (totalPages > 1) {
  47. count = (totalPages - 1) * 50;
  48. }
  49. needResponse = await fetch(`${currentDomain}/cards/${cardId}/users/${type}/page/${totalPages}`);
  50. if (needResponse.status === 502) {
  51. console.error("Ошибка 502: Остановка выполнения скриптов.");
  52. throw new Error("502 Bad Gateway");
  53. }
  54. if (needResponse.ok) {
  55. needHtml = await needResponse.text();
  56. needDoc = new DOMParser().parseFromString(needHtml, 'text/html');
  57. count += needDoc.querySelectorAll('.profile__friends-item').length;
  58. }
  59. }
  60.  
  61. return count;
  62. }
  63.  
  64. async function updateCardInfo(cardId, element) {
  65.  
  66. // Определяем текущий домен
  67. const currentDomain = window.location.origin;
  68.  
  69. if (!cardId || !element) {
  70. console.log(cardId, 'updateCardInfo error');
  71. return;
  72. }
  73.  
  74. try {
  75. console.log(`Обработка карточки с ID: ${cardId}`);
  76.  
  77. await sleep(DELAY);
  78.  
  79. // Получение количества "Желающих"
  80. let needCount = await getCount(cardId, 'need');
  81.  
  82. await sleep(DELAY);
  83.  
  84. // Получение количества "Готовых поменять"
  85. let tradeCount = await getCount(cardId, 'trade');
  86.  
  87. await sleep(DELAY);
  88.  
  89. // Получение популярности и ранга
  90. const popularityResponse = await fetch(`${currentDomain}/cards/${cardId}/users/`);
  91. if (popularityResponse.status === 502) {
  92. console.error("Ошибка 502: Остановка выполнения скриптов.");
  93. throw new Error("502 Bad Gateway");
  94. }
  95.  
  96. let popularityCount = 0;
  97. let rankText = '';
  98. if (popularityResponse.ok) {
  99. const popularityHtml = await popularityResponse.text();
  100. const popularityDoc = new DOMParser().parseFromString(popularityHtml, 'text/html');
  101.  
  102. const rankElement = popularityDoc.querySelector('.anime-cards__rank');
  103. if (rankElement) {
  104. rankText = rankElement.textContent.trim();
  105. }
  106.  
  107. popularityCount = popularityDoc.querySelectorAll('.card-show__owner').length;
  108.  
  109. const pagination = popularityDoc.querySelector('.pagination__pages');
  110. if (pagination) {
  111. const lastPageNum = pagination.querySelector('a:last-of-type');
  112. const totalPages = lastPageNum ? parseInt(lastPageNum.innerText, 10) : 1;
  113. if (totalPages > 1 && popularityCount >= 35) {
  114. popularityCount = (totalPages - 1) * 35;
  115. const needResponse = await fetch(`${currentDomain}/cards/${cardId}/users/page/${totalPages}`);
  116. if (needResponse.status === 502) {
  117. console.error("Ошибка 502: Остановка выполнения скриптов.");
  118. throw new Error("502 Bad Gateway");
  119. }
  120. if (needResponse.ok) {
  121. popularityCount += (new DOMParser().parseFromString(await needResponse.text(), 'text/html')).querySelectorAll('.card-show__owner').length;
  122. }
  123. }
  124. }
  125. }
  126.  
  127. // Очистка старой информации
  128. element.querySelector('.link-icon')?.remove();
  129.  
  130. // Добавление новой информации
  131. const icon = document.createElement('div');
  132. icon.className = 'link-icon';
  133. icon.style.position = 'absolute';
  134. icon.style.top = '10px';
  135. icon.style.right = '10px';
  136. icon.style.backgroundColor = 'rgba(0, 0, 0, 0.6)';
  137. icon.style.color = '#05ed5b';
  138. icon.style.padding = '5px';
  139. icon.style.borderRadius = '5px';
  140. icon.style.fontSize = '8px';
  141. icon.innerHTML = `Ранг: ${rankText}<br>Уже имеют: ${popularityCount}<br>Хотят получить: ${needCount}<br>Готовы поменять: ${tradeCount}`;
  142.  
  143. element.style.position = 'relative';
  144. element.appendChild(icon);
  145.  
  146. console.log(cardId, '- ok');
  147.  
  148. } catch (error) {
  149. console.error(`Ошибка обработки карты ${cardId}:`, error);
  150. // Остановка выполнения скриптов
  151. throw error;
  152. }
  153. }
  154.  
  155. function removeAllLinkIcons() {
  156. const linkIcons = document.querySelectorAll('.link-icon');
  157. linkIcons.forEach(icon => icon.remove());
  158. }
  159.  
  160. async function processCards() {
  161. removeMatchingWatchlistItems();
  162. removeAllLinkIcons();
  163.  
  164. const cards = Array.from(
  165. document.querySelectorAll('.lootbox__card, .anime-cards__item, .trade__inventory-item, .trade__main-item, .card-filter-list__card, .deck__item, .history__body-item, .history__body-item, .card-show__placeholder')
  166. ).filter(card => card.offsetParent !== null);
  167.  
  168. if (cards.length) {
  169. console.log(cards.length, 'cards found');
  170. DLEPush?.info('Обновляю инфу по ' + cards.length + ' картам');
  171. } else {
  172. DLEPush?.error('Карты не найдены на странице');
  173. return;
  174. }
  175.  
  176. for (const card of cards) {
  177.  
  178. if (card.classList.contains('trade__inventory-item--lock')) {
  179. console.log('Пропускаем карту с классом trade__inventory-item--lock');
  180. continue; // Пропускаем эту карту
  181. }
  182.  
  183. let cardId = card.getAttribute('card-id') || card.getAttribute('data-card-id') || card.getAttribute('data-id');
  184. const href = card.getAttribute('href');
  185.  
  186. if (href) {
  187. let cardIdMatch = href.match(/\/cards\/(\d+)\/users\//);
  188. console.log(cardIdMatch);
  189. if (cardIdMatch) {
  190. cardId = cardIdMatch[1];
  191. }
  192. }
  193. if (cardId) {
  194. await updateCardInfo(cardId, card).catch(error => {
  195. console.error("Остановка из-за критической ошибки:", error.message);
  196. return;
  197. });
  198. } else {
  199. console.log(cardId, 'cardId not found');
  200. console.log(card);
  201. }
  202.  
  203. if (card.classList.contains('lootbox__card')) {
  204. card.addEventListener('click', removeAllLinkIcons);
  205. }
  206. }
  207. DLEPush?.info('Информация обновлена');
  208. }
  209.  
  210. function removeMatchingWatchlistItems() {
  211. const watchlistItems = document.querySelectorAll('.watchlist__item');
  212. if (watchlistItems.length == 0) {
  213. return;
  214. }
  215. watchlistItems.forEach(item => {
  216. const episodesText = item.querySelector('.watchlist__episodes')?.textContent.trim();
  217. if (episodesText) {
  218. const matches = episodesText.match(/[\d]+/g);
  219. if (matches) {
  220. const currentEpisode = parseInt(matches[0], 10);
  221. const totalEpisodes = parseInt(matches.length === 4 ? matches[3] : matches[1], 10);
  222. if (currentEpisode === totalEpisodes) {
  223. item.remove();
  224. console.log(`Удалён блок: ${item}`);
  225. }
  226. }
  227. }
  228. });
  229.  
  230. if (watchlistItems.length) {
  231. DLEPush?.info('Из списка удалены просмотренные аниме. В списке осталось ' + document.querySelectorAll('.watchlist__item').length + ' записей.');
  232. }
  233. }
  234.  
  235. function addUpdateButton() {
  236. if (!document.querySelector('#fetchLinksButton')) {
  237. const button = document.createElement('button');
  238. button.id = 'fetchLinksButton';
  239.  
  240. // Стили кнопки
  241. button.style.position = 'fixed';
  242. button.style.top = '37%';
  243. button.style.right = '1%';
  244. button.style.zIndex = '1000';
  245. button.style.backgroundColor = '#007bff';
  246. button.style.color = '#fff';
  247. button.style.border = 'none';
  248. button.style.borderRadius = '5px';
  249. button.style.padding = '10px 15px';
  250. button.style.cursor = 'pointer';
  251. button.style.boxShadow = '0 2px 5px rgba(0, 0, 0, 0.2)';
  252. // button.style.transform = 'rotate(90deg)';
  253.  
  254. // Добавляем иконку внутрь кнопки
  255. const icon = document.createElement('span');
  256. icon.className = 'fal fa-rocket';
  257. icon.style.display = 'inline-block';
  258. // icon.style.animation = 'rotateIcon 2s linear infinite'; // Анимация вращения
  259.  
  260. button.appendChild(icon);
  261.  
  262. // Обработчик клика
  263. button.addEventListener('click', processCards);
  264.  
  265. document.body.appendChild(button);
  266. }
  267. }
  268.  
  269. // Анимация вращения в CSS
  270. const style = document.createElement('style');
  271. style.textContent = `
  272. @keyframes rotateIcon {
  273. 0% {
  274. transform: rotate(0deg);
  275. }
  276. 100% {
  277. transform: rotate(360deg);
  278. }
  279. }
  280.  
  281. .fal.fa-skull {
  282. animation: rotateIcon 2s linear infinite;
  283. }
  284. `;
  285. document.head.appendChild(style);
  286.  
  287. function clearIcons() {
  288. $('.card-notification')?.first()?.click();
  289. checkGiftCard();
  290. }
  291.  
  292. function checkGiftCard() {
  293. var button = $('#gift-icon');
  294. if (button.length === 0) {
  295. return;
  296. }
  297. var gift_code = button.attr('data-code');
  298. if ( !gift_code ) return false;
  299. $.ajax({
  300. url: '/engine/ajax/controller.php?mod=gift_code_game',
  301. data:{code: gift_code, user_hash: dle_login_hash},
  302. dataType: 'json',
  303. cache: false,
  304. type: 'post',
  305. success: function(data) {
  306. if ( data.status == 'ok' ) {
  307. DLEPush.info( data.text );
  308. button.remove();
  309. }
  310. }
  311. });
  312. }
  313.  
  314. function startPing() {
  315. setInterval(() => {
  316. // Получаем значение из глобальной переменной
  317. const userHash = window.dle_login_hash;
  318.  
  319. if (!userHash) {
  320. console.error("Переменная dle_login_hash не определена.");
  321. return;
  322. }
  323.  
  324. // Определяем текущий домен
  325. const currentDomain = window.location.origin;
  326.  
  327. // Формируем URL с учетом userHash
  328. const url = `${currentDomain}/engine/ajax/controller.php?mod=user_count_timer&user_hash=${userHash}`;
  329.  
  330. // Выполняем GET-запрос
  331. fetch(url)
  332. .then(response => {
  333. if (!response.ok) {
  334. throw new Error(`HTTP error! Status: ${response.status}`);
  335. }
  336. return response.json(); // Если ответ в формате JSON
  337. })
  338. .then(data => {
  339. console.log("Данные получены:", data); // Обрабатываем полученные данные
  340. })
  341. .catch(error => {
  342. console.error("Ошибка при выполнении запроса:", error);
  343. });
  344. }, 31000); // Интервал проверки — 31 сек
  345. }
  346.  
  347. function checkCard() {
  348. setInterval(() => {
  349. const currentDateTime = new Date();
  350. const localStorageKey = `checkCardStopped`; // Формат YYYY-MM-DDTHH
  351.  
  352. if (localStorage.getItem(localStorageKey) === currentDateTime.toISOString().slice(0, 13)) {
  353. console.log("Проверка карты уже остановлена на текущий час.");
  354. return;
  355. }
  356.  
  357. // Получаем значение из глобальной переменной
  358. const userHash = window.dle_login_hash;
  359.  
  360. if (!userHash) {
  361. console.error("Переменная dle_login_hash не определена.");
  362. return;
  363. }
  364.  
  365. // Определяем текущий домен
  366. const currentDomain = window.location.origin;
  367.  
  368. // Формируем URL с учетом userHash
  369. const url = `${currentDomain}/engine/ajax/controller.php?mod=reward_card&action=check_reward&user_hash=${userHash}`;
  370.  
  371. // Выполняем GET-запрос
  372. fetch(url)
  373. .then(response => {
  374. if (!response.ok) {
  375. throw new Error(`HTTP error! Status: ${response.status}`);
  376. }
  377. return response.json(); // Если ответ в формате JSON
  378. })
  379. .then(data => {
  380. if (data.stop_reward === "yes") {
  381. console.log("Проверка карт остановлена на текущий час:", data.reason);
  382. localStorage.setItem(localStorageKey, currentDateTime.toISOString().slice(0, 13));
  383. return;
  384. }
  385. if (!data.cards || !data.cards.owner_id) {
  386. return;
  387. }
  388. const ownerId = data.cards.owner_id;
  389. console.log("owner_id получен:", ownerId); // Выводим owner_id
  390.  
  391. if ( data.cards.name ) {
  392. DLEPush?.info('Получена новая карта "' + data.cards.name + '"');
  393. }
  394.  
  395. const url = `${currentDomain}/engine/ajax/controller.php?mod=cards_ajax`;
  396.  
  397. // Подготавливаем параметры запроса
  398. const postData = new URLSearchParams({
  399. action: "take_card",
  400. owner_id: ownerId
  401. });
  402.  
  403. // Выполняем POST-запрос
  404. fetch(url, {
  405. method: "POST",
  406. headers: {
  407. "Content-Type": "application/x-www-form-urlencoded"
  408. },
  409. body: postData.toString() // Передаём параметры в виде строки
  410. })
  411. .then(response => {
  412. if (!response.ok) {
  413. throw new Error(`HTTP error! Status: ${response.status}`);
  414. }
  415. return response.json(); // Если ответ в формате JSON
  416. })
  417. .then(data => {
  418. console.log("Данные получены:", data); // Обрабатываем полученные данные
  419. })
  420. .catch(error => {
  421. console.error("Ошибка при выполнении запроса:", error);
  422. });
  423. })
  424. .catch(error => {
  425. console.error("Ошибка при выполнении запроса:", error);
  426. });
  427.  
  428. }, 10000); // Интервал проверки — 10 сек
  429. }
  430.  
  431. Object.defineProperty(window, "loadPacks", {
  432. get: function () {
  433. return function () {
  434. console.log("Нахуй шепот!");
  435. };
  436. },
  437. set: function () {
  438. console.log("Хуй тебе а не шепот");
  439. }
  440. });
  441.  
  442.  
  443. (function() {
  444. 'use strict';
  445.  
  446. setInterval(clearIcons, 2000);
  447. startPing();
  448. checkCard();
  449.  
  450. sound_notifications = 0;
  451. addUpdateButton();
  452. $('#tg-banner').remove();
  453. localStorage.setItem('notify18', 'closed');
  454. localStorage.setItem('theme','dark');
  455. localStorage.setItem('hideTelegramAs', 'true');
  456. })();