animestars Auto Helper

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

目前为 2025-02-04 提交的版本。查看 最新版本

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