Greasy Fork 还支持 简体中文。

animestars Auto Helper

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

  1. // ==UserScript==
  2. // @name animestars Auto Helper
  3. // @namespace animestars.org
  4. // @version 3.33
  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://asstars.tv/*
  11. // @match https://asstars.astars.club/*
  12. // @match https://as1.astars.club/*
  13. // @match https://as2.astars.club/*
  14. // @match https://as3.astars.club/*
  15. // @match https://as4.astars.club/*
  16. // @match https://as5.astars.club/*
  17. // @match https://as6.astars.club/*
  18. // @match https://as7.astars.club/*
  19. // @match https://as8.astars.club/*
  20. // @match https://as9.astars.club/*
  21. // @match https://as10.astars.club/*
  22. // @match https://as11.astars.club/*
  23. // @match https://as12.astars.club/*
  24. // @match https://as13.astars.club/*
  25. // @match https://as14.astars.club/*
  26. // @match https://as15.astars.club/*
  27. // @match https://as16.astars.club/*
  28. // @match https://as17.astars.club/*
  29. // @match https://as18.astars.club/*
  30. // @match https://as18.astars.club/*
  31. // @match https://as20.astars.club/*
  32. // @match https://as21.astars.club/*
  33. // @match https://as22.astars.club/*
  34. // @match https://as23.astars.club/*
  35. // @match https://as24.astars.club/*
  36. // @match https://as25.astars.club/*
  37. // @match https://as26.astars.club/*
  38. // @match https://as27.astars.club/*
  39. // @match https://as28.astars.club/*
  40. // @match https://as29.astars.club/*
  41. // @match https://as30.astars.club/*
  42. // @match https://as31.astars.club/*
  43. // @match https://as32.astars.club/*
  44. // @match https://as33.astars.club/*
  45. // @match https://as34.astars.club/*
  46. // @match https://as35.astars.club/*
  47. // @match https://as36.astars.club/*
  48.  
  49. // @license MIT
  50. // @grant none
  51.  
  52. // ==/UserScript==
  53.  
  54. const DELAY = 50; // Задержка между запросами в миллисекундах (по умолчанию 0,5 секунды) не менять чтоб не делать избыточную нагрузку на сайт
  55.  
  56. const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
  57.  
  58. let cardCounter = 0;
  59.  
  60. const cardClasses = '.noffer__img, .remelt__inventory-item, .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';
  61.  
  62. function addCheckMark(element) {
  63. if (!element) return;
  64. const checkMark = document.createElement('i');
  65. checkMark.classList.add('fas', 'fa-check', 'div-marked');
  66. checkMark.style.position = 'absolute';
  67. checkMark.style.bottom = '5px';
  68. checkMark.style.left = '5px';
  69. checkMark.style.background = 'green';
  70. checkMark.style.color = 'white';
  71. checkMark.style.borderRadius = '50%';
  72. checkMark.style.padding = '5px';
  73. checkMark.style.fontSize = '16px';
  74. checkMark.style.width = '24px';
  75. checkMark.style.height = '24px';
  76. checkMark.style.display = 'flex';
  77. checkMark.style.alignItems = 'center';
  78. checkMark.style.justifyContent = 'center';
  79. element.classList.add('div-checked');
  80. if (window.getComputedStyle(element).position === 'static') {
  81. element.style.position = 'relative';
  82. }
  83. element.appendChild(checkMark);
  84. }
  85.  
  86. function addInCardMark(element, count) {
  87. if (!element) return;
  88. const checkMark = document.createElement('span');
  89. checkMark.classList.add('dupl-count');
  90. element.classList.add('div-checked');
  91. checkMark.title = 'Карт в корзине';
  92. if (window.getComputedStyle(element).position === 'static') {
  93. element.style.position = 'relative';
  94. }
  95. checkMark.innerText = count;
  96. element.appendChild(checkMark);
  97. }
  98.  
  99. async function iNeedCard(cardId) {
  100. await sleep(DELAY * 2);
  101. const url = '/engine/ajax/controller.php?mod=trade_ajax';
  102. const data = {
  103. action: 'propose_add',
  104. type: 0,
  105. card_id: cardId,
  106. user_hash: dle_login_hash
  107. };
  108.  
  109. try {
  110. const response = await fetch(url, {
  111. method: 'POST',
  112. headers: {
  113. 'Content-Type': 'application/x-www-form-urlencoded',
  114. },
  115. credentials: 'same-origin',
  116. body: new URLSearchParams(data).toString()
  117. });
  118. if (response.status === 502) {
  119. console.error("Ошибка 502: Остановка выполнения скриптов.");
  120. throw new Error("502 Bad Gateway");
  121. }
  122. if (response.ok) {
  123. const data = await response.json();
  124. if (data.error) {
  125. if (data.error == 'Слишком часто, подождите пару секунд и повторите действие') {
  126. await readyToChargeCard(cardId);
  127. return;
  128. } else {
  129. DLEPush?.info(data.error);
  130. }
  131. }
  132. if ( data.status == 'added' ) {
  133. cardCounter++;
  134. return;
  135. }
  136. if ( data.status == 'deleted' ) {
  137. await sleep(DELAY * 2);
  138. await iNeedCard(cardId);
  139. return;
  140. }
  141. cardCounter++;
  142. } else {
  143. console.error('Ошибка запроса:', response.status);
  144. }
  145. } catch (error) {
  146. console.error('Ошибка выполнения POST-запроса:', error);
  147. }
  148. }
  149.  
  150. async function loadCard(cardId) {
  151. const cacheKey = 'card_id: ' + cardId;
  152. let card = await getCard(cacheKey) ?? {};
  153. if (Object.keys(card).length) {
  154. // return card;
  155. }
  156.  
  157. // console.log(`Обработка карточки с ID: ${cardId}`);
  158. const currentDomain = window.location.origin;
  159. await sleep(DELAY);
  160. let rankText = '';
  161.  
  162. const popularityResponse = await fetch(`${currentDomain}/cards/users/?id=${cardId}`);
  163. if (popularityResponse.status === 502) {
  164. console.error("Ошибка 502: Остановка выполнения скриптов.");
  165. throw new Error("502 Bad Gateway");
  166. }
  167. let likes = 0;
  168. let dislikes = 0;
  169. let popularityCount = 0;
  170. let needСount = 0;
  171. let tradeСount = 0;
  172. let tradeName = '';
  173.  
  174. console.log('popularityResponse.ok', popularityResponse.ok);
  175. if (popularityResponse.ok) {
  176. const popularityHtml = await popularityResponse.text();
  177. const popularityDoc = new DOMParser().parseFromString(popularityHtml, 'text/html');
  178.  
  179. needСount = popularityDoc.querySelectorAll('.ncard__tabs-btns a span')[0].innerText;
  180. tradeСount = popularityDoc.querySelectorAll('.ncard__tabs-btns a span')[1].innerText;
  181. tradeName = popularityDoc.querySelector('meta[name="description"]').getAttribute('content').replace('Все обладатели карточки ','');
  182. rankText = popularityDoc.querySelector('.ncard__rank').innerText.replace('Редкость\n','').trim();
  183.  
  184. await checkGiftCard(popularityDoc); // ищем небесный камень заодно
  185. /*
  186. const animeUrl = popularityDoc.querySelector('.card-show__placeholder')?.href;
  187. if (animeUrl) {
  188. try {
  189. const response = await fetch(animeUrl);
  190. if (!response.ok) {
  191. throw new Error(`Ошибка HTTP: ${response.status}`);
  192. }
  193. const htmlText = await response.text();
  194. const parser = new DOMParser();
  195. const doc = parser.parseFromString(htmlText, 'text/html');
  196.  
  197. likes = parseInt(doc.querySelector('[data-likes-id]')?.textContent?.trim(), 10);
  198. dislikes = parseInt(doc.querySelector('[data-dislikes-id]')?.textContent?.trim(), 10);
  199. checkGiftCard(doc); // ищем небесный камень заодно
  200. } catch (error) {
  201. console.error('Ошибка при загрузке страницы:', error);
  202. }
  203. }
  204. popularityCount = popularityDoc.querySelectorAll('.card-show__owner').length;
  205. */
  206. popularityCount = popularityDoc.querySelector('#owners-count').innerText ?? 0;
  207. }
  208.  
  209. card = {likes: likes, dislikes: dislikes, rankText: rankText, popularityCount: popularityCount, needCount: needСount, tradeCount: tradeСount, name: tradeName};
  210.  
  211. console.log('card', card);
  212.  
  213. if (card.likes || card.dislikes) {
  214. await cacheCard(cacheKey, card)
  215. }
  216.  
  217. return card;
  218. }
  219.  
  220. async function updateCardInfo(cardId, element) {
  221. if (!cardId || !element) {
  222. console.log(cardId, 'updateCardInfo error');
  223. return;
  224. }
  225. try {
  226. const card = await loadCard(cardId);
  227. console.log(card);
  228.  
  229. element.querySelector('.link-icon')?.remove();
  230. const icon = document.createElement('div');
  231. icon.className = 'link-icon';
  232. icon.style.position = 'absolute';
  233. icon.style.top = '10px';
  234. icon.style.right = '10px';
  235. icon.style.backgroundColor = 'rgba(0, 0, 0, 0.6)';
  236. icon.style.color = '#05ed5b';
  237. icon.style.padding = '5px';
  238. icon.style.borderRadius = '5px';
  239. icon.style.fontSize = '8px';
  240. let anime = card.likes && card.dislikes ? `<br>аниме: +${card.likes} / -${card.dislikes}` : '';
  241. if (isCardsPackPage() || isTradesPage() || isTradePage())
  242. {
  243. const username = document.querySelector('a[href^="/user/"]')?.pathname.split('/')[2];
  244. let num = await getCardsCountInCart(card.name, cardId, username);
  245. anime += '<br>у меня: ' + num + ' шт';
  246. }
  247. icon.innerHTML = `Ранг: ${card.rankText}<br>имеют: ${card.popularityCount}<br>хотят: ${card.needCount}<br>отдают: ${card.tradeCount}` + anime;
  248. element.style.position = 'relative';
  249. element.appendChild(icon);
  250. } catch (error) {
  251. console.error(`Ошибка обработки карты ${cardId}:`, error);
  252. throw error;
  253. }
  254. }
  255.  
  256. function clearMarkFromCards() {
  257. cleanByClass('div-marked');
  258. }
  259.  
  260. function removeAllLinkIcons() {
  261. cleanByClass('link-icon');
  262. }
  263.  
  264. function cleanByClass(className) {
  265. const list = document.querySelectorAll('.' + className);
  266. list.forEach(item => item.remove());
  267. }
  268.  
  269. function getCardsOnPage() {
  270. return Array.from(
  271. document.querySelectorAll(cardClasses)
  272. ).filter(card => card.offsetParent !== null);
  273. }
  274.  
  275. async function processCards() {
  276.  
  277. if (isCardRemeltPage()) {
  278. const storedData = JSON.parse(localStorage.getItem('animeCardsData')) || {};
  279. if (Object.keys(storedData).length < 1) {
  280. await readyRemeltCards();
  281. return;
  282. }
  283. }
  284.  
  285. removeMatchingWatchlistItems();
  286. removeAllLinkIcons();
  287. clearMarkFromCards();
  288.  
  289. const cards = getCardsOnPage();
  290. let counter = cards.length;
  291.  
  292. if (!counter) {
  293. return;
  294. }
  295.  
  296. let buttonId = 'processCards';
  297. startAnimation(buttonId);
  298. updateButtonCounter(buttonId, counter);
  299. for (const card of cards) {
  300.  
  301. if (card.classList.contains('trade__inventory-item--lock') || card.classList.contains('remelt__inventory-item--lock')) {
  302. continue;
  303. }
  304. let cardId = await getCardId(card);
  305. if (cardId) {
  306. await updateCardInfo(cardId, card).catch(error => {
  307. console.error("Остановка из-за критической ошибки:", error.message);
  308. return;
  309. });
  310. addCheckMark(card);
  311. counter--;
  312. updateButtonCounter(buttonId, counter);
  313. } else {
  314. console.log(cardId, 'cardId not found');
  315. }
  316.  
  317. if (card.classList.contains('lootbox__card')) {
  318. card.addEventListener('click', removeAllLinkIcons);
  319. }
  320. }
  321. stopAnimation(buttonId);
  322. }
  323.  
  324. function removeMatchingWatchlistItems() {
  325. const watchlistItems = document.querySelectorAll('.watchlist__item');
  326. if (watchlistItems.length == 0) {
  327. return;
  328. }
  329. watchlistItems.forEach(item => {
  330. const episodesText = item.querySelector('.watchlist__episodes')?.textContent.trim();
  331. if (episodesText) {
  332. const matches = episodesText.match(/[\d]+/g);
  333. if (matches) {
  334. const currentEpisode = parseInt(matches[0], 10);
  335. const totalEpisodes = parseInt(matches.length === 4 ? matches[3] : matches[1], 10);
  336. if (currentEpisode === totalEpisodes) {
  337. item.remove();
  338. //console.log(`Удалён блок: ${item}`);
  339. }
  340. }
  341. }
  342. });
  343.  
  344. if (watchlistItems.length) {
  345. DLEPush?.info('Из списка удалены просмотренные аниме. В списке осталось ' + document.querySelectorAll('.watchlist__item').length + ' записей.');
  346. }
  347. }
  348.  
  349. function startAnimation(id) {
  350. $('#' + id + ' span:first').css('animation', 'rotateIcon 2s linear infinite');
  351. }
  352.  
  353. function stopAnimation(id) {
  354. $('#' + id + ' span:first').css('animation', '');
  355. }
  356.  
  357. function getButton(id, className, percent, text, clickFunction) {
  358. const button = document.createElement('button');
  359. button.id = id;
  360. button.title = text;
  361. button.style.position = 'fixed';
  362. button.style.top = percent + '%';
  363. button.style.right = '1%';
  364. button.style.zIndex = '1000';
  365. button.style.backgroundColor = '#007bff';
  366. button.style.color = '#fff';
  367. button.style.border = 'none';
  368. button.style.borderRadius = '5px';
  369. button.style.padding = '10px 15px';
  370. button.style.cursor = 'pointer';
  371. button.style.boxShadow = '0 2px 5px rgba(0, 0, 0, 0.2)';
  372. const icon = document.createElement('span');
  373. icon.className = 'fal fa-' + className;
  374. icon.style.display = 'inline-block';
  375. button.appendChild(icon);
  376. const info = document.createElement('span');
  377. info.id = id + '_counter';
  378. info.className = 'guest__notification';
  379. info.style.display = 'none';
  380. button.appendChild(info);
  381. button.addEventListener('click', clickFunction);
  382. return button;
  383. }
  384.  
  385. function updateButtonCounter(id, counter) {
  386. let c = $('#' + id + '_counter');
  387. c.css('display', counter > 0 ? 'flex' : 'none');
  388. c.text(counter);
  389. }
  390.  
  391. function addUpdateButton() {
  392. if (!document.querySelector('#fetchLinksButton')) {
  393. let cards = getCardsOnPage();
  394.  
  395. document.body.appendChild(getButton('processCards', 'rocket', 37, 'Сравнить карточки', processCards));
  396.  
  397. if (!cards.length) {
  398. return
  399. }
  400.  
  401. let myCardPage = isMyCardPage();
  402. if (myCardPage) {
  403. document.body.appendChild(getButton('readyToCharge', 'circle-check', 50, '"Готов поменять" на все карточки', readyToCharge));
  404. }
  405.  
  406. let animePage = isAnimePage();
  407. if (animePage) {
  408. document.body.appendChild(getButton('iNeedAllThisCards', 'search', 50, '"Хочу карту" на все карточки', iNeedAllThisCards));
  409. }
  410.  
  411. let cardRemeltPage = isCardRemeltPage();
  412. if (cardRemeltPage) {
  413. document.body.appendChild(getButton('readyRemeltCards', 'yin-yang', 50, 'закешировать карточки', readyRemeltCards));
  414. const storedData = JSON.parse(localStorage.getItem('animeCardsData')) || {};
  415. updateButtonCounter('readyRemeltCards', Object.keys(storedData).length);
  416. }
  417.  
  418. if (document.querySelectorAll(`[data-id][data-name]`).length) {
  419. let percent = myCardPage || cardRemeltPage || cardRemeltPage ? 63 : 50;
  420. document.body.appendChild(getButton('checkCardsCountInCart', 'suitcase', percent, 'проверить наличие в корзине', checkCardsCountInCart));
  421. }
  422. }
  423. }
  424.  
  425. async function checkCardsCountInCart() {
  426. let cardsCountInCart = document.querySelectorAll(`[data-id][data-name]`);
  427. if (cardsCountInCart.length < 1) {
  428. return;
  429. }
  430.  
  431. let buttonId = 'checkCardsCountInCart';
  432. startAnimation(buttonId);
  433. let counter = cardsCountInCart.length;
  434. updateButtonCounter(buttonId, counter);
  435. const username = document.querySelector('a[href^="/user/"]')?.pathname.split('/')[2];
  436.  
  437. for (const card of cardsCountInCart) {
  438. let name = card?.getAttribute("data-name");
  439. let id = card?.getAttribute("data-id");
  440. if (!name || !id) {
  441. continue;
  442. }
  443.  
  444. let num = await getCardsCountInCart(name, id, username);
  445. addInCardMark(card, num);
  446. counter--;
  447. updateButtonCounter(buttonId, counter);
  448. }
  449. stopAnimation(buttonId);
  450. }
  451.  
  452. function isMyCardPage() {
  453. return (/^\/user\/(.*)\/cards(\/page\/\d+\/)?/).test(window.location.pathname)
  454. }
  455.  
  456. function isCardRemeltPage() {
  457. return (/^\/cards_remelt\//).test(window.location.pathname)
  458. }
  459.  
  460. function isCardsPackPage() {
  461. return (/^\/cards\/pack\//).test(window.location.pathname)
  462. }
  463.  
  464. function isTradesPage() {
  465. return (/^\/trades\//).test(window.location.pathname)
  466. }
  467.  
  468. function isTradePage() {
  469. return (/^\/cards\/.*\/trade\//).test(window.location.pathname)
  470. }
  471.  
  472. function isAnimePage() {
  473. return document.getElementById('anime-data') !== null;
  474. }
  475.  
  476. async function readyRemeltCards() {
  477. DLEPush.info('метод пока не работает');
  478. }
  479.  
  480. async function iNeedAllThisCards() {
  481. let cards = getCardsOnPage();
  482. DLEPush.info('Отметить "Хочу карточку" на все ' + cards.length + ' карточек на странице');
  483.  
  484. let counter = cards.length;
  485. let buttonId = 'iNeedAllThisCards';
  486. startAnimation(buttonId);
  487. updateButtonCounter(buttonId, counter);
  488. clearMarkFromCards();
  489.  
  490. cardCounter = 0;
  491. for (const card of cards) {
  492. if (card.classList.contains('anime-cards__owned-by-user')) {
  493. counter--;
  494. updateButtonCounter(buttonId, counter);
  495. continue;
  496. }
  497. let cardId = await getCardId(card);
  498. if (cardId) {
  499. await iNeedCard(cardId).catch(error => {
  500. console.error("Остановка из-за критической ошибки:", error.message);
  501. return;
  502. });
  503. addCheckMark(card);
  504. counter--;
  505. updateButtonCounter(buttonId, counter);
  506. } else {
  507. console.log(cardId, 'cardId not found');
  508. }
  509. }
  510. stopAnimation(buttonId);
  511. }
  512.  
  513. async function getCardId(card) {
  514. let cardId = card.getAttribute('card-id') || card.getAttribute('data-card-id') || card.getAttribute('data-id');
  515. const href = card.getAttribute('href');
  516. if (href) {
  517. let cardIdMatch = href.match(/\/cards\/(\d+)\/users\//) || href.match(/\/cards\/users\/\?id=(\d+)/);
  518. if (cardIdMatch) {
  519. cardId = cardIdMatch[1];
  520. }
  521. }
  522. if (cardId) {
  523. // проверяем что в локально нет такого номера
  524. console.log('проверка в хранилище номера карты ' + cardId);
  525. const cardByOwner = await getFirstCardByOwner(cardId);
  526. // console.log('localStorage', cardByOwner);
  527. if (cardByOwner) {
  528. cardId = cardByOwner.cardId;
  529. }
  530. }
  531. return cardId;
  532. }
  533.  
  534. async function getCardOwnerId(card) {
  535. let cardId = card.getAttribute('data-owner-id');
  536. return cardId;
  537. }
  538.  
  539. async function getCardType(card) {
  540. return card.getAttribute('data-type') || null;
  541. }
  542.  
  543. async function getFirstCardByOwner(ownerId) {
  544. const storedData = JSON.parse(localStorage.getItem('animeCardsData')) || {};
  545. const key = 'o_' + ownerId;
  546.  
  547. return storedData[key] && storedData[key].length > 0 ? storedData[key][0] : null;
  548. }
  549.  
  550. async function readyToCharge() {
  551. DLEPush.info('Отмечаем все карты на странице как: "Готов обменять" кроме тех что на обмене и заблокированных');
  552. let cards = getCardsOnPage();
  553. // DLEPush.info('Карт на странице: ' + cards.length);
  554.  
  555. let counter = cards.length;
  556. let buttonId = 'readyToCharge';
  557. startAnimation(buttonId);
  558. updateButtonCounter(buttonId, counter);
  559. clearMarkFromCards();
  560.  
  561. cardCounter = 0;
  562. for (const card of cards) {
  563. if (card.classList.contains('trade__inventory-item--lock')) {
  564. continue;
  565. }
  566. let cardOwnerId = await getCardOwnerId(card);
  567. if (cardOwnerId) {
  568. await sleep(1000);
  569. //await readyToChargeCard(cardOwnerId);
  570. await cardProposeAdd(cardOwnerId)
  571. counter--;
  572. addCheckMark(card);
  573. updateButtonCounter(buttonId, counter);
  574. }
  575. }
  576. DLEPush.info('Отправили на обмен ' + cardCounter + ' карточек на странице');
  577. stopAnimation(buttonId);
  578. }
  579.  
  580. async function cardProposeAdd(card_id) {
  581. try {
  582. await sleep(DELAY * 3);
  583.  
  584. const data = await new Promise((resolve, reject) => {
  585. $.ajax({
  586. url: "/engine/ajax/controller.php?mod=trade_ajax",
  587. type: "post",
  588. data: {
  589. action: "propose_add",
  590. type: 1,
  591. card_id: card_id,
  592. user_hash: dle_login_hash
  593. },
  594. dataType: "json",
  595. cache: false,
  596. success: resolve,
  597. error: reject
  598. });
  599. });
  600.  
  601. if (data?.error) {
  602. if (data.error === 'Слишком часто, подождите пару секунд и повторите действие') {
  603. return await cardProposeAdd(card_id);
  604. }
  605. console.log('cardProposeAdd ' + card_id, data.error);
  606.  
  607. return false;
  608. }
  609.  
  610. if (data?.status == "added") {
  611. return true;
  612. }
  613.  
  614. if (data?.status == "deleted") {
  615. return await cardProposeAdd(card_id);
  616. }
  617.  
  618. return false;
  619.  
  620. } catch (e) {
  621. console.error("Ошибка запроса:", e);
  622. return false;
  623. }
  624. }
  625.  
  626. const readyToChargeCard = async (cardOwnerId) => {
  627. await sleep(DELAY * 2);
  628. const url = '/engine/ajax/controller.php?mod=trade_ajax';
  629. const data = {
  630. action: 'propose_add',
  631. type: 1,
  632. card_id: cardOwnerId,
  633. user_hash: dle_login_hash
  634. };
  635.  
  636. try {
  637. const response = await fetch(url, {
  638. method: 'POST',
  639. headers: {
  640. 'Content-Type': 'application/x-www-form-urlencoded',
  641. },
  642. credentials: 'same-origin',
  643. body: new URLSearchParams(data).toString()
  644. });
  645. if (response.status === 502) {
  646. console.error("Ошибка 502: Остановка выполнения скриптов.");
  647. throw new Error("502 Bad Gateway");
  648. }
  649. if (response.ok) {
  650. const data = await response.json();
  651. if (data.error) {
  652. if (data.error == 'Слишком часто, подождите пару секунд и повторите действие') {
  653. await readyToChargeCard(cardId);
  654. return;
  655. }
  656. }
  657. if ( data.status == 'added' ) {
  658. cardCounter++;
  659. return;
  660. }
  661. if ( data.status == 'deleted' ) {
  662. await readyToChargeCard(cardId);
  663. return;
  664. }
  665. cardCounter++;
  666. //console.log('Ответ сервера:', data);
  667. } else {
  668. console.error('Ошибка запроса:', response.status);
  669. }
  670. } catch (error) {
  671. console.error('Ошибка выполнения POST-запроса:', error);
  672. }
  673. };
  674.  
  675. // Анимация вращения в CSS
  676. const style = document.createElement('style');
  677. style.textContent = `
  678. @keyframes rotateIcon {
  679. 0% {
  680. transform: rotate(0deg);
  681. }
  682. 100% {
  683. transform: rotate(360deg);
  684. }
  685. }
  686. `;
  687. document.head.appendChild(style);
  688.  
  689. function clearIcons() {
  690. document.querySelector('.card-notification')?.click();
  691. }
  692.  
  693. function autoRepeatCheck() {
  694. clearIcons();
  695. checkGiftCard(document);
  696. document.querySelector('.adv_volume.volume_on')?.click();
  697.  
  698. Audio.prototype.play = function() {
  699. return new Promise(() => {});
  700. };
  701. }
  702.  
  703. async function checkGiftCard(doc) {
  704. const button = doc.querySelector('#gift-icon');
  705. if (!button) return;
  706.  
  707. const giftCode = button.getAttribute('data-code');
  708. if (!giftCode) return false;
  709.  
  710. try {
  711. const response = await fetch('/engine/ajax/controller.php?mod=gift_code_game', {
  712. method: 'POST',
  713. headers: {
  714. 'Content-Type': 'application/x-www-form-urlencoded'
  715. },
  716. credentials: 'same-origin',
  717. body: new URLSearchParams({
  718. code: giftCode,
  719. user_hash: dle_login_hash
  720. })
  721. });
  722. const data = await response.json();
  723. if (data.status === 'ok') {
  724. DLEPush.info(data.text);
  725. button.remove();
  726. }
  727. } catch (error) {
  728. console.error('Ошибка при проверке подарочной карты:', error);
  729. }
  730. }
  731.  
  732. async function startPing() {
  733. if (!dle_login_hash) {
  734. console.error("Переменная dle_login_hash не определена.");
  735. return;
  736. }
  737.  
  738. // Определяем текущий домен
  739. const currentDomain = window.location.origin;
  740.  
  741. /*
  742. try {
  743. await sleep(DELAY * 3);
  744. const user_count_timer_data = await new Promise((resolve, reject) => {
  745. $.ajax({
  746. url: "/engine/ajax/controller.php?mod=user_count_timer",
  747. type: "post",
  748. data: {
  749. user_hash: dle_login_hash
  750. },
  751. dataType: "json",
  752. cache: false,
  753. success: resolve,
  754. error: reject
  755. });
  756. });
  757. } catch (e) {
  758. console.error("Ошибка запроса:", e);
  759. return false;
  760. }
  761. */
  762. }
  763.  
  764. async function checkNewCard() {
  765.  
  766. const currentDateTime = new Date();
  767. // Получаем значение из глобальной переменной
  768. // const userHash = window.dle_login_hash;
  769.  
  770. if (!dle_login_hash) {
  771. console.error("Переменная dle_login_hash не определена.");
  772. return;
  773. }
  774.  
  775. const localStorageKey = 'checkCardStopped' + window.dle_login_hash; // Формат YYYY-MM-DDTHH
  776.  
  777. if (localStorage.getItem(localStorageKey) === currentDateTime.toISOString().slice(0, 13)) {
  778. console.log("Проверка карты уже остановлена на текущий час.");
  779. return;
  780. }
  781.  
  782. // Определяем текущий домен
  783. const currentDomain = window.location.origin;
  784.  
  785. try {
  786. await sleep(DELAY * 3);
  787.  
  788. const data = await new Promise((resolve, reject) => {
  789. $.ajax({
  790. url: "/ajax/card_for_watch/",
  791. type: "post",
  792. data: {
  793. user_hash: dle_login_hash
  794. },
  795. dataType: "json",
  796. cache: false,
  797. success: resolve,
  798. error: reject
  799. });
  800. });
  801.  
  802. if (data?.stop_reward === "yes") {
  803. console.log("Проверка карт остановлена на текущий час:", data.reason);
  804. localStorage.setItem(localStorageKey, currentDateTime.toISOString().slice(0, 13));
  805. return;
  806. }
  807.  
  808. if (!data.cards || !data.cards.owner_id) {
  809. return;
  810. }
  811.  
  812. if ( data.cards.name ) {
  813. DLEPush?.info('Получена новая карта "' + data.cards.name + '"');
  814. }
  815.  
  816. const ownerId = data.cards.owner_id;
  817. console.log("owner_id получен:", ownerId); // Выводим owner_id
  818.  
  819. /*
  820. $.ajax({
  821. url: "/engine/ajax/controller.php?mod=cards_ajax",
  822. type: "post",
  823. data: {
  824. action: "take_card",
  825. owner_id: ownerId
  826. },
  827. dataType: "json",
  828. cache: false,
  829. success: function () {},
  830. error: function () {}
  831. });
  832. */
  833.  
  834. } catch (e) {
  835. console.error("Ошибка запроса:", e);
  836. return false;
  837. }
  838.  
  839.  
  840. }
  841.  
  842. async function setCache(key, data, ttlInSeconds) {
  843. const expires = Date.now() + ttlInSeconds * 1000; // Устанавливаем срок хранения
  844. const cacheData = { data, expires };
  845. localStorage.setItem(key, JSON.stringify(cacheData));
  846. }
  847.  
  848. async function getCardsCountInCart(name, id, username) {
  849. if (!name || !id) return;
  850.  
  851. try {
  852. await sleep(DELAY * 4);
  853.  
  854. const searchUrl = `/user/cards/?name=${encodeURIComponent(username)}&search=${encodeURIComponent(name)}`;
  855. // /user/cards/?name=ishutko&search=Ёруити%20и%20Рангику
  856. const response = await fetch(searchUrl);
  857. const html = new DOMParser().parseFromString(await response.text(), 'text/html');
  858. await checkGiftCard(html); // ищем небесный камень заодно
  859. const foundCards = html.querySelectorAll(`[data-id="${id}"]`);
  860.  
  861. return foundCards.length;
  862. } catch (err) {
  863. console.error("Ошибка при запросе:", err);
  864. return "❌";
  865. }
  866. }
  867.  
  868. async function getCache(key) {
  869. const cacheData = JSON.parse(localStorage.getItem(key));
  870. if (!cacheData) return null; // Если данных нет
  871. if (Date.now() > cacheData.expires) {
  872. localStorage.removeItem(key); // Если срок истёк, удаляем
  873. return null;
  874. }
  875. return cacheData.data;
  876. }
  877.  
  878. async function cacheCard(key, data) {
  879. await setCache(key, data, 86400); // Записываем данные на 24 часа (86400 секунд)
  880. }
  881.  
  882. async function getCard(key) {
  883. return await getCache(key); // Записываем данные на 24 часа (86400 секунд)
  884. }
  885.  
  886. function addClearButton() {
  887. const filterControls = document.querySelector('.card-filter-form__controls');
  888. if (!filterControls) {
  889. return;
  890. }
  891. const inputField = filterControls.querySelector('.card-filter-form__search');
  892. if (!inputField) {
  893. return;
  894. }
  895. const searchButton = filterControls.querySelector('.tabs__search-btn');
  896. if (!searchButton) {
  897. return;
  898. }
  899. inputField.addEventListener('keydown', function (event) {
  900. if (event.key === 'Enter') {
  901. event.preventDefault();
  902. searchButton.click();
  903. }
  904. });
  905. const clearButton = document.createElement('button');
  906. clearButton.innerHTML = '<i class="fas fa-times"></i>'; // Иконка Font Awesome
  907. clearButton.classList.add('clear-search-btn'); // Добавляем класс для стилизации
  908. clearButton.style.margin = '5px';
  909. clearButton.style.position = 'absolute';
  910. clearButton.style.padding = '10px';
  911. clearButton.style.background = 'red';
  912. clearButton.style.color = 'white';
  913. clearButton.style.border = 'none';
  914. clearButton.style.cursor = 'pointer';
  915. clearButton.style.fontSize = '14px';
  916. clearButton.style.borderRadius = '5px';
  917. clearButton.addEventListener('click', function () {
  918. inputField.value = '';
  919. searchButton.click();
  920. });
  921. inputField.style.marginLeft = '30px';
  922. inputField.parentNode.insertBefore(clearButton, inputField);
  923. }
  924.  
  925. function addPromocodeBtn() {
  926. const button = document.createElement('button');
  927. button.innerText = 'Промокоды';
  928. button.style.position = 'fixed';
  929. button.style.bottom = '80px';
  930. button.style.right = '0px';
  931. button.style.zIndex = '1000';
  932. button.style.background = 'rgb(0, 123, 255)';
  933. button.style.fontSize = '8px';
  934. button.style.cursor = 'pointer';
  935. button.style.transform = 'rotateY(47deg);';
  936. button.addEventListener('click', () => {
  937. window.location.href = '/promo_codes';
  938. });
  939. document.body.appendChild(button);
  940. }
  941.  
  942. (function() {
  943. 'use strict';
  944.  
  945. setInterval(autoRepeatCheck, 2000);
  946. setInterval(startPing, 31000);
  947. setInterval(checkNewCard, 10000);
  948.  
  949. addUpdateButton();
  950. addClearButton();
  951. addPromocodeBtn();
  952.  
  953. document.getElementById('tg-banner')?.remove();
  954. localStorage.setItem('notify18', 'closed');
  955. localStorage.setItem('hideTelegramAs', 'true');
  956.  
  957. // авто открытие карт под аниме
  958. // $('div .pmovie__related a.glav-s:first')?.click()?.remove();
  959.  
  960. // немного увеличиваем карты на списках чтоб читались надписи
  961. document.querySelectorAll('.anime-cards__item-wrapper').forEach(el => {
  962. el.style.setProperty('min-width', '20.28%');
  963. });
  964.  
  965. if (isCardsPackPage()) {
  966. window.doAnimLoot = () => {};
  967. }
  968.  
  969. })();
  970.  
  971. document.addEventListener('click', function (e) {
  972. const target = e.target;
  973.  
  974. if (target.classList.contains('anime-cards__name')) {
  975. const name = target.textContent.trim();
  976. const username = document.querySelector('a[href^="/user/"]')?.pathname.split('/')[2];
  977. const currentDomain = window.location.origin;
  978. const searchUrl = `${currentDomain}/user/cards/?name=${encodeURIComponent(username)}&search=${encodeURIComponent(name)}`;
  979. window.open(searchUrl, '_blank');
  980. }
  981. });
  982.  
  983. const styleGlobal = document.createElement('style');
  984. style.textContent = `
  985. .anime-cards__name {
  986. cursor: pointer;
  987. text-decoration: underline;
  988. }
  989. `;
  990. document.head.appendChild(styleGlobal);