您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
card helper
当前为
// ==UserScript== // @name Card Helper AStars | AnimeStars | ASStars // @namespace animestars.org // @version 6.7 // @description card helper // @author bmr // @match https://astars.club/* // @match https://asstars1.astars.club/* // @match https://animestars.org/* // @match https://as1.astars.club/* // @match https://asstars.tv/* // @license MIT // @grant none // ==/UserScript== const DELAY = 40; const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); let cardCounter = 0; const cardClasses = '.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-pack__card'; function getCurrentDomain() { const hostname = window.location.hostname; const protocol = window.location.protocol; return `${protocol}//${hostname}`; } async function getCount(cardId, type) { const currentDomain = getCurrentDomain(); let count = 0; let needResponse = await fetch(`${currentDomain}/cards/${cardId}/users/${type}/`); if (needResponse.status === 502) { throw new Error("502 Bad Gateway"); } let needHtml = ''; let needDoc = ''; if (needResponse.ok) { needHtml = await needResponse.text(); needDoc = new DOMParser().parseFromString(needHtml, 'text/html'); count = needDoc.querySelectorAll('.profile__friends-item').length; } else { return count; } const pagination = needDoc.querySelector('.pagination__pages'); if (pagination && count >= 50) { const lastPageNum = pagination.querySelector('a:last-of-type'); const totalPages = lastPageNum ? parseInt(lastPageNum.innerText, 10) : 1; if (totalPages > 1) { count = (totalPages - 1) * 50; } needResponse = await fetch(`${currentDomain}/cards/${cardId}/users/${type}/page/${totalPages}`); if (needResponse.status === 502) { throw new Error("502 Bad Gateway"); } if (needResponse.ok) { needHtml = await needResponse.text(); needDoc = new DOMParser().parseFromString(needHtml, 'text/html'); count += needDoc.querySelectorAll('.profile__friends-item').length; } } return count; } async function loadCard(cardId) { const cacheKey = 'cardId: ' + cardId; let card = await getCard(cacheKey) ?? {}; if (Object.keys(card).length) { return card; } const currentDomain = getCurrentDomain(); await sleep(DELAY); let needCount = await getCount(cardId, 'need'); await sleep(DELAY); let tradeCount = await getCount(cardId, 'trade'); await sleep(DELAY); let popularityCount = 0; const popularityResponse = await fetch(`${currentDomain}/cards/${cardId}/users/`); if (popularityResponse.ok) { const popularityHtml = await popularityResponse.text(); const popularityDoc = new DOMParser().parseFromString(popularityHtml, 'text/html'); const pagination = popularityDoc.querySelector('.pagination__pages'); if (pagination) { const lastPageNum = pagination.querySelector('a:last-of-type'); const totalPages = lastPageNum ? parseInt(lastPageNum.innerText, 10) : 1; if (totalPages > 1) { popularityCount = (totalPages - 1) * 40; await sleep(DELAY); const lastPageResponse = await fetch(`${currentDomain}/cards/${cardId}/users/page/${totalPages}`); if (lastPageResponse.ok) { const lastPageHtml = await lastPageResponse.text(); const lastPageDoc = new DOMParser().parseFromString(lastPageHtml, 'text/html'); const lastPageCount = lastPageDoc.querySelectorAll('.card-show__owner').length; popularityCount += lastPageCount; } } else { popularityCount = popularityDoc.querySelectorAll('.card-show__owner').length; } } else { popularityCount = popularityDoc.querySelectorAll('.card-show__owner').length; } } card = {popularityCount, needCount, tradeCount}; await cacheCard(cacheKey, card); return card; } async function updateCardInfo(cardId, element) { if (!cardId || !element) { return; } try { const card = await loadCard(cardId); let statsContainer = document.querySelector('.card-stats-container'); if (!statsContainer) { statsContainer = document.createElement('div'); statsContainer.className = 'card-stats-container'; document.body.appendChild(statsContainer); } const oldStats = element.querySelector('.card-stats'); if (oldStats) { oldStats.remove(); } const stats = document.createElement('div'); stats.className = 'card-stats'; stats.innerHTML = ` <span title="Владельцев"> <i class="fas fa-users"></i> ${card.popularityCount} </span> <span title="Хотят получить"> <i class="fas fa-heart"></i> ${card.needCount} </span> <span title="Готовы обменять"> <i class="fas fa-sync-alt"></i> ${card.tradeCount} </span> `; element.appendChild(stats); } catch (error) { throw error; } } function clearMarkFromCards() { cleanByClass('div-marked'); } function removeAllLinkIcons() { cleanByClass('link-icon'); } function cleanByClass(className) { const list = document.querySelectorAll('.' + className); list.forEach(item => item.remove()); } function getCardsOnPage() { return Array.from( document.querySelectorAll(cardClasses) ).filter(card => card.offsetParent !== null); } async function processCards() { if (isCardRemeltPage()) { const storedData = JSON.parse(localStorage.getItem('animeCardsData')) || {}; if (Object.keys(storedData).length < 1) { await readyRemeltCards(); return; } } removeMatchingWatchlistItems(); removeAllLinkIcons(); clearMarkFromCards(); const cards = getCardsOnPage(); let counter = cards.length; if (!counter) { return; } let buttonId = 'processCards'; startAnimation(buttonId); updateButtonCounter(buttonId, counter); showNotification('Проверяю спрос на ' + counter + ' карточек'); for (const card of cards) { if (card.classList.contains('trade__inventory-item--lock') || card.classList.contains('remelt__inventory-item--lock')) { continue; } card.classList.add('processing-card'); let cardId = await getCardId(card); if (cardId) { await updateCardInfo(cardId, card).catch(error => { return; }); counter--; updateButtonCounter(buttonId, counter); } card.classList.remove('processing-card'); if (card.classList.contains('lootbox__card')) { card.addEventListener('click', removeAllLinkIcons); } } showNotification('Проверка спроса завершена'); stopAnimation(buttonId); } function removeMatchingWatchlistItems() { const watchlistItems = document.querySelectorAll('.watchlist__item'); if (watchlistItems.length == 0) { return; } watchlistItems.forEach(item => { const episodesText = item.querySelector('.watchlist__episodes')?.textContent.trim(); if (episodesText) { const matches = episodesText.match(/[\d]+/g); if (matches) { const currentEpisode = parseInt(matches[0], 10); const totalEpisodes = parseInt(matches.length === 4 ? matches[3] : matches[1], 10); if (currentEpisode === totalEpisodes) { item.remove(); } } } }); if (watchlistItems.length) { showNotification('Из списка удалены просмотренные аниме. В списке осталось ' + document.querySelectorAll('.watchlist__item').length + ' записей.'); } } function startAnimation(id) { $('#' + id + ' span:first').css('animation', 'pulseIcon 1s ease-in-out infinite'); } function stopAnimation(id) { $('#' + id + ' span:first').css('animation', ''); } function getButton(id, className, percent, text, clickFunction) { const button = document.createElement('button'); button.id = id; button.style.position = 'fixed'; button.style.top = percent + '%'; button.style.right = '1%'; button.style.zIndex = '1000'; button.style.backgroundColor = '#6c5ce7'; button.style.color = '#fff'; button.style.border = 'none'; button.style.borderRadius = '50%'; button.style.width = '45px'; button.style.height = '45px'; button.style.padding = '0'; button.style.cursor = 'pointer'; button.style.boxShadow = '0 2px 5px rgba(0, 0, 0, 0.2)'; button.style.transition = 'all 0.3s ease'; let tooltipTimeout; button.onmouseover = function() { this.style.backgroundColor = '#5f51e3'; tooltip.style.opacity = '1'; tooltip.style.transform = 'translateX(0)'; if (tooltipTimeout) { clearTimeout(tooltipTimeout); } }; button.onmouseout = function() { this.style.backgroundColor = '#6c5ce7'; tooltip.style.opacity = '0'; tooltip.style.transform = 'translateX(10px)'; }; const icon = document.createElement('span'); icon.className = 'fal fa-' + className; icon.style.display = 'inline-block'; icon.style.fontSize = '20px'; button.appendChild(icon); const tooltip = document.createElement('div'); tooltip.style.cssText = ` position: fixed; right: calc(1% + 55px); background-color: #2d3436; color: #fff; padding: 8px 12px; border-radius: 4px; font-size: 14px; opacity: 0; transition: all 0.3s ease; white-space: nowrap; top: ${percent}%; transform: translateX(10px); z-index: 999; pointer-events: none; `; switch(id) { case 'processCards': tooltip.textContent = 'Узнать спрос'; break; case 'readyToCharge': tooltip.textContent = 'Отметить всё как "Готов обменять"'; break; case 'readyRemeltCards': tooltip.textContent = 'Кешировать карточки'; break; default: tooltip.textContent = text; } button.addEventListener('click', function(e) { e.stopPropagation(); clickFunction(e); if (window.innerWidth <= 768) { tooltip.style.opacity = '1'; tooltip.style.transform = 'translateX(0)'; if (tooltipTimeout) { clearTimeout(tooltipTimeout); } tooltipTimeout = setTimeout(() => { tooltip.style.opacity = '0'; tooltip.style.transform = 'translateX(10px)'; }, 1000); } }); const container = document.createElement('div'); container.appendChild(tooltip); container.appendChild(button); button.classList.add('action-button'); return container; } function updateButtonCounter(id, counter) { return; } function addUpdateButton() { if (window.location.pathname.includes('/pm/') || window.location.pathname.includes('emotions.php') || window.frameElement) { return; } if (!document.querySelector('#fetchLinksButton')) { let cards = getCardsOnPage(); document.body.appendChild(getButton('processCards', 'star', 37, 'Сравнить карточки', processCards)); if (!cards.length) { return } if (isMyCardPage()) { document.body.appendChild(getButton('readyToCharge', 'handshake', 50, '"Готов поменять" на все карточки', readyToCharge)); } if (isCardRemeltPage()) { document.body.appendChild(getButton('readyRemeltCards', 'yin-yang', 50, 'закешировать карточки', readyRemeltCards)); const storedData = JSON.parse(localStorage.getItem('animeCardsData')) || {}; updateButtonCounter('readyRemeltCards', Object.keys(storedData).length); } } } function isMyCardPage() { return (/^\/user\/(.*)\/cards(\/page\/\d+\/)?/).test(window.location.pathname) } function isCardRemeltPage() { return (/^\/cards_remelt\//).test(window.location.pathname) } async function readyRemeltCards() { showNotification('Кеширую все карты так как иначе на этой странице не получится их определить рейтинги'); const linkElement = document.querySelector('a.button.button--left-icon.mr-3'); const href = linkElement ? linkElement.href : null; if (!href) { return; } removeMatchingWatchlistItems(); removeAllLinkIcons(); clearMarkFromCards(); const cards = getCardsOnPage(); let counter = cards.length; if (!counter) { return; } let buttonId = 'readyRemeltCards'; startAnimation(buttonId); await scrapeAllPages(href, buttonId); stopAnimation(buttonId); } async function scrapeAllPages(firstPageHref, buttonId) { const response = await fetch(firstPageHref); if (!response.ok) { throw new Error(`Ошибка HTTP: ${response.status}`); } const firstPageDoc = new DOMParser().parseFromString(await response.text(), 'text/html'); const pagination = firstPageDoc.querySelector('#pagination'); if (!pagination) { return; } const progressBar = createProgressBar(); let totalCards = 0; let processedCards = 0; let storedData = JSON.parse(localStorage.getItem('animeCardsData')) || {}; const titleElement = firstPageDoc.querySelector('h1.secondary-title.text-center'); if (titleElement) { const match = titleElement.textContent.match(/\((\d+)\s*шт\.\)/); totalCards = match ? parseInt(match[1], 10) : -1; if (totalCards == Object.keys(storedData).length) { showNotification('На данный момент в кеше карточек ровно столько же сколько в профиле пользователя'); return; } } async function processCardsToLocalstorage(doc) { const cards = doc.querySelectorAll('.anime-cards__item'); for (let i = 0; i < cards.length; i += 5) { const cardGroup = Array.from(cards).slice(i, i + 5); for (const card of cardGroup) { const cardId = card.getAttribute('data-id'); const ownerId = card.getAttribute('data-owner-id'); const name = card.getAttribute('data-name'); const rank = card.getAttribute('data-rank'); const animeLink = card.getAttribute('data-anime-link'); const image = card.getAttribute('data-image'); const ownerKey = 'o_' + ownerId; if (!ownerId || !cardId) continue; if (!storedData[ownerKey]) { storedData[ownerKey] = []; } storedData[ownerKey].push({ cardId, name, rank, animeLink, image, ownerId }); processedCards++; if (totalCards > 0) { progressBar.update(processedCards, totalCards); } } await sleep(10); } } async function fetchPage(url) { try { const response = await fetch(url); if (!response.ok) throw new Error(`Ошибка загрузки страницы ${url}`); return await response.text(); } catch (error) { return null; } } await processCardsToLocalstorage(firstPageDoc); const lastPageLink = pagination.querySelector('a:last-of-type'); if (lastPageLink) { const lastPageNumber = parseInt(lastPageLink.textContent.trim(), 10); if (!isNaN(lastPageNumber) && lastPageNumber > 1) { const parser = new DOMParser(); for (let i = 2; i <= lastPageNumber; i++) { const pageUrl = lastPageLink.href.replace(/page\/\d+/, `page/${i}`); const pageHTML = await fetchPage(pageUrl); if (pageHTML) { await processCardsToLocalstorage(parser.parseFromString(pageHTML, 'text/html')); } await sleep(1000); if (i % 3 === 0) { localStorage.setItem('animeCardsData', JSON.stringify(storedData)); } } } } localStorage.setItem('animeCardsData', JSON.stringify(storedData)); setTimeout(() => { progressBar.remove(); }, 1000); document.body.appendChild(getButton('processCards', 'star', 37, 'Сравнить карточки', processCards)); await processCards(); } async function getCardId(card) { let cardId = card.getAttribute('card-id') || card.getAttribute('data-card-id') || card.getAttribute('data-id'); const href = card.getAttribute('href'); if (href) { let cardIdMatch = href.match(/\/cards\/(\d+)\/users\//); if (cardIdMatch) { cardId = cardIdMatch[1]; } } if (cardId) { const cardByOwner = await getFirstCardByOwner(cardId); if (cardByOwner) { cardId = cardByOwner.cardId; } } return cardId; } async function getFirstCardByOwner(ownerId) { const storedData = JSON.parse(localStorage.getItem('animeCardsData')) || {}; const key = 'o_' + ownerId; return storedData[key] && storedData[key].length > 0 ? storedData[key][0] : null; } async function readyToCharge() { showNotification('Отмечаем все карты на странице как: "Готов обменять" кроме тех что на обмене и заблокированных'); let cards = getCardsOnPage(); let counter = cards.length; let buttonId = 'readyToCharge'; startAnimation(buttonId); updateButtonCounter(buttonId, counter); clearMarkFromCards(); const progressBar = createProgressBar(); cardCounter = 0; const totalCards = cards.filter(card => !card.classList.contains('trade__inventory-item--lock')).length; let processedCards = 0; for (const card of cards) { if (card.classList.contains('trade__inventory-item--lock')) { continue; } let cardId = await getCardId(card); if (cardId) { await readyToChargeCard(cardId); processedCards++; progressBar.update(processedCards, totalCards); counter--; updateButtonCounter(buttonId, counter); } } setTimeout(() => { progressBar.remove(); }, 1000); showNotification('Отправили на обмен ' + cardCounter + ' карточек на странице'); stopAnimation(buttonId); } const readyToChargeCard = async (cardId) => { await sleep(DELAY * 2); const url = '/engine/ajax/controller.php?mod=trade_ajax'; const data = { action: 'propose_add', type: 1, card_id: cardId, user_hash: dle_login_hash }; try { const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams(data).toString() }); if (response.status === 502) { throw new Error("502 Bad Gateway"); } if (response.ok) { const data = await response.json(); if (data.error) { if (data.error == 'Слишком часто, подождите пару секунд и повторите действие') { await readyToChargeCard(cardId); return; } } if ( data.status == 'added' ) { cardCounter++; return; } if ( data.status == 'deleted' ) { await readyToChargeCard(cardId); return; } cardCounter++; } } catch (error) { } }; const style = document.createElement('style'); style.textContent = ` @keyframes glowEffect { 0% { box-shadow: 0 0 5px #6c5ce7; } 50% { box-shadow: 0 0 20px #6c5ce7; } 100% { box-shadow: 0 0 5px #6c5ce7; } } @keyframes fadeInUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .processing-card { position: relative; } .processing-card img { position: relative; z-index: 2; } .processing-card::after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; max-height: calc(100% - 30px); border-radius: 8px; z-index: 1; animation: glowEffect 1.5s infinite; pointer-events: none; } /* Общие стили для карт */ .card-stats { position: relative; background: linear-gradient(45deg, #6c5ce7, #a367dc); padding: 8px; color: white; font-size: 12px; margin-top: 5px; border-radius: 5px; display: flex; justify-content: space-between; align-items: center; text-shadow: 1px 1px 2px rgba(0,0,0,0.3); animation: fadeInUp 0.3s ease; z-index: 0 !important; } /* Стили для истории трейдов */ .history__inner { max-width: 1200px !important; margin: 0 auto !important; padding: 15px !important; } .history__item { background: rgba(108, 92, 231, 0.05) !important; border-radius: 10px !important; padding: 20px !important; margin-bottom: 20px !important; } .history__body { display: flex !important; flex-wrap: wrap !important; gap: 15px !important; padding: 15px !important; border-radius: 8px !important; } .history__body--gained { background: rgba(46, 213, 115, 0.1) !important; margin-bottom: 10px !important; } .history__body--lost { background: rgba(255, 71, 87, 0.1) !important; } /* Увеличенные размеры для карточек в истории трейдов на ПК */ @media screen and (min-width: 769px) { .history__body-item { width: 150px !important; height: auto !important; transition: transform 0.2s !important; } .history__body-item img { width: 150px !important; height: auto !important; border-radius: 8px !important; box-shadow: 0 2px 8px rgba(0,0,0,0.1) !important; } } .history__body-item:hover { transform: scale(1.05) !important; z-index: 2 !important; } /* Мобильная версия истории трейдов */ @media screen and (max-width: 768px) { .history__body-item, .history__body-item img { width: 120px !important; } .processing-card::before { top: -1px !important; left: -1px !important; right: -1px !important; bottom: -1px !important; opacity: 0.5 !important; } } .progress-bar { position: fixed; top: 0; left: 0; width: 100%; height: 4px; background: #ddd; z-index: 10000; } .progress-bar__fill { width: 0%; height: 100%; background: linear-gradient(to right, #6c5ce7, #a367dc); transition: width 0.3s ease; position: relative; } .progress-bar__text { position: absolute; left: 50%; top: 5px; transform: translateX(-50%); color: #ffffff; font-size: 14px; font-weight: bold; background: #6c5ce7; padding: 2px 8px; border-radius: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.2); text-shadow: 1px 1px 2px rgba(0,0,0,0.3); } .card-stats span { display: flex; align-items: center; gap: 4px; } .card-stats span i { font-size: 14px; } /* Мобильная версия */ @media screen and (max-width: 768px) { .action-button { transform: scale(0.8) !important; } .action-button button { width: 35px !important; height: 35px !important; } .action-button span { font-size: 16px !important; } .action-button div { font-size: 12px !important; padding: 6px 10px !important; } .card-stats { font-size: 10px !important; padding: 4px !important; } .card-stats span i { font-size: 12px !important; } /* Исправление отображения карт на странице переплавки */ .remelt__inventory-list { grid-template-columns: repeat(2, 1fr) !important; gap: 10px !important; } .remelt__inventory-item { width: 100% !important; margin: 0 !important; } .remelt__inventory-item img { width: 100% !important; height: auto !important; } .remelt__inventory-item .card-stats { width: 100% !important; margin-top: 4px !important; } /* Уменьшение размера карт в паках */ .lootbox__card { transform: scale(0.75) !important; margin-top: -10px !important; margin-bottom: 25px !important; } .lootbox__card .card-stats { font-size: 14px !important; padding: 6px !important; } .lootbox__card .card-stats i { font-size: 14px !important; } .lootbox__list { gap: 15px !important; padding-bottom: 15px !important; } /* Уменьшение размера карт в истории */ .history__body-item { width: 100px !important; } .history__body-item img { width: 100px !important; } /* Уменьшение размера прогресс-бара */ .progress-bar { height: 3px !important; } .progress-bar__text { font-size: 12px !important; padding: 1px 6px !important; } } /* Стили для карт */ .card-stats { position: relative; background: linear-gradient(45deg, #6c5ce7, #a367dc); padding: 8px; color: white; font-size: 12px; margin-top: 5px; border-radius: 5px; display: flex; justify-content: space-between; align-items: center; text-shadow: 1px 1px 2px rgba(0,0,0,0.3); animation: fadeInUp 0.3s ease; } /* Специальные стили для карт в паках */ .lootbox__card { position: relative !important; transform: scale(0.85) !important; margin-top: -15px !important; margin-bottom: 35px !important; } .lootbox__card .card-stats { position: absolute !important; bottom: -35px !important; left: 0 !important; right: 0 !important; margin: 0; padding: 8px !important; border-radius: 5px; z-index: 9999 !important; background: linear-gradient(45deg, #6c5ce7, #a367dc) !important; font-size: 16px !important; width: 100% !important; transform: none !important; text-rendering: optimizeLegibility !important; -webkit-font-smoothing: antialiased !important; } .lootbox__card .card-stats span { color: white !important; text-shadow: 1px 1px 2px rgba(0,0,0,0.3) !important; padding: 0 8px !important; flex: 1; text-align: center; font-weight: 500 !important; } .lootbox__card .card-stats i { color: white !important; font-size: 16px !important; margin-right: 4px; } .lootbox__list { gap: 25px !important; padding-bottom: 20px !important; } /* Мобильная версия */ @media screen and (max-width: 768px) { .lootbox__card { transform: scale(0.8) !important; margin-top: -20px !important; margin-bottom: 30px !important; } } `; document.head.appendChild(style); function clearIcons() { $('.card-notification:first')?.click(); } function autoRepeatCheck() { clearIcons(); checkGiftCard(document); Audio.prototype.play = function() { return new Promise(() => {}); }; } async function checkGiftCard(doc) { const button = doc.querySelector('#gift-icon'); if (!button) return; const giftCode = button.getAttribute('data-code'); if (!giftCode) return false; try { const response = await fetch('/engine/ajax/controller.php?mod=gift_code_game', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ code: giftCode, user_hash: dle_login_hash }) }); const data = await response.json(); if (data.status === 'ok') { showNotification(data.text); button.remove(); } } catch (error) { } } function startPing() { const userHash = window.dle_login_hash; if (!userHash) { return; } const currentDomain = getCurrentDomain(); const url = `${currentDomain}/engine/ajax/controller.php?mod=user_count_timer&user_hash=${userHash}`; fetch(url) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { }) .catch(error => { }); } function checkNewCard() { let userHash = window.dle_login_hash; if (!userHash) { setTimeout(() => { userHash = window.dle_login_hash; if (userHash) { checkNewCard(); } }, 2000); return; } const currentDateTime = new Date(); const localStorageKey = 'checkCardStopped' + userHash; if (localStorage.getItem(localStorageKey) === currentDateTime.toISOString().slice(0, 13)) { return; } const currentDomain = getCurrentDomain(); const url = `${currentDomain}/engine/ajax/controller.php?mod=reward_card&action=check_reward&user_hash=${userHash}`; fetch(url) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { if (data.stop_reward === "yes") { localStorage.setItem(localStorageKey, currentDateTime.toISOString().slice(0, 13)); return; } if (!data.cards || !data.cards.owner_id) { return; } const ownerId = data.cards.owner_id; if (data.cards.name) { showNotification('Получена новая карта "' + data.cards.name + '"'); } const url = `${currentDomain}/engine/ajax/controller.php?mod=cards_ajax`; const postData = new URLSearchParams({ action: "take_card", owner_id: ownerId }); fetch(url, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: postData.toString() }) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { }) .catch(error => { }); }) .catch(error => { }); } async function setCache(key, data, ttlInSeconds) { const expires = Date.now() + ttlInSeconds * 1000; const cacheData = { data, expires }; localStorage.setItem(key, JSON.stringify(cacheData)); } async function getCache(key) { const cacheData = JSON.parse(localStorage.getItem(key)); if (!cacheData) return null; if (Date.now() > cacheData.expires) { localStorage.removeItem(key); return null; } return cacheData.data; } async function cacheCard(key, data) { await setCache(key, data, 3600); } async function getCard(key) { return await getCache(key); } function addClearButton() { const filterControls = document.querySelector('.card-filter-form__controls'); if (!filterControls) { return; } const inputField = filterControls.querySelector('.card-filter-form__search'); if (!inputField) { return; } const searchButton = filterControls.querySelector('.tabs__search-btn'); if (!searchButton) { return; } inputField.addEventListener('keydown', function (event) { if (event.key === 'Enter') { event.preventDefault(); searchButton.click(); } }); const clearButton = document.createElement('button'); clearButton.innerHTML = '<i class="fas fa-times"></i>'; clearButton.classList.add('clear-search-btn'); clearButton.style.margin = '5px'; clearButton.style.position = 'absolute'; clearButton.style.padding = '10px'; clearButton.style.background = 'red'; clearButton.style.color = 'white'; clearButton.style.border = 'none'; clearButton.style.cursor = 'pointer'; clearButton.style.boxShadow = '0 2px 5px rgba(0, 0, 0, 0.2)'; clearButton.style.fontSize = '14px'; clearButton.style.borderRadius = '5px'; clearButton.addEventListener('click', function () { inputField.value = ''; searchButton.click(); }); inputField.style.marginLeft = '30px'; inputField.parentNode.insertBefore(clearButton, inputField); } function showNotification(message) { const notification = document.createElement('div'); notification.style.cssText = ` position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background: linear-gradient(45deg, #6c5ce7, #a367dc); color: white; padding: 12px 24px; border-radius: 8px; box-shadow: 0 4px 15px rgba(0,0,0,0.2); z-index: 9999; animation: slideDown 0.5s ease, fadeOut 0.5s ease 2.5s forwards; font-size: 14px; `; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => notification.remove(), 3000); } function createProgressBar() { const progressBar = document.createElement('div'); progressBar.className = 'progress-bar'; progressBar.innerHTML = ` <div class="progress-bar__fill"></div> <div class="progress-bar__text">0%</div> `; const style = document.createElement('style'); style.textContent = ` .progress-bar { position: fixed; top: 0; left: 0; width: 100%; height: 4px; background: #ddd; z-index: 10000; } .progress-bar__fill { width: 0%; height: 100%; background: linear-gradient(to right, #6c5ce7, #a367dc); transition: width 0.3s ease; position: relative; } .progress-bar__text { position: absolute; left: 50%; top: 5px; transform: translateX(-50%); color: #ffffff; font-size: 14px; font-weight: bold; background: #6c5ce7; padding: 2px 8px; border-radius: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.2); text-shadow: 1px 1px 2px rgba(0,0,0,0.3); } `; document.head.appendChild(style); document.body.appendChild(progressBar); return { update: (current, total) => { const percentage = Math.round((current / total) * 100); progressBar.querySelector('.progress-bar__fill').style.width = percentage + '%'; progressBar.querySelector('.progress-bar__text').textContent = percentage + '%'; }, remove: () => progressBar.remove() }; } function clearCardCache() { const keys = Object.keys(localStorage); let clearedCount = 0; keys.forEach(key => { if (key.startsWith('cardId: ')) { localStorage.removeItem(key); clearedCount++; } }); showNotification(`Очищено ${clearedCount} карточек из кеша`); } function addClearCacheButton() { if (window.location.pathname.includes('/pm/') || window.location.pathname.includes('emotions.php') || window.frameElement) { return; } if (!document.querySelector('#clearCacheButton')) { const button = getButton('clearCacheButton', 'trash', 63, 'Очистить кеш карт', clearCardCache); document.body.appendChild(button); } } (function() { 'use strict'; function checkTimeAndReset() { const now = new Date(); const mskTime = new Date(now.getTime() + (now.getTimezoneOffset() + 180) * 60000); const hours = mskTime.getHours(); const today = mskTime.toISOString().split('T')[0]; const userHash = window.dle_login_hash; if (!userHash) return; const stopKey = 'checkCardStopped' + userHash; const stopValue = localStorage.getItem(stopKey); if (hours >= 0 && stopValue) { localStorage.removeItem(stopKey); console.log('Сброс ограничения сбора карт выполнен'); checkNewCard(); setTimeout(checkNewCard, 2000); setTimeout(checkNewCard, 5000); } } function initializeScript() { checkTimeAndReset(); setInterval(autoRepeatCheck, 2000); setInterval(startPing, 31000); setInterval(checkNewCard, 10000); setInterval(checkTimeAndReset, 60000); setInterval(() => { if (!document.querySelector('#processCards')) { addUpdateButton(); addClearButton(); addClearCacheButton(); } }, 500); $('#tg-banner').remove(); localStorage.setItem('notify18', 'closed'); localStorage.setItem('hideTelegramAs', 'true'); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initializeScript); } else { initializeScript(); } window.addEventListener('pageshow', initializeScript); })(); (function() { 'use strict'; let lastActiveTime = localStorage.getItem('lastCrystalTime') || "00:00"; let processedCrystals = new Set(JSON.parse(localStorage.getItem('processedCrystals') || '[]')); let workerBlob = null; let worker = null; function getCurrentTime() { const now = new Date(); return now.getHours().toString().padStart(2, '0') + ":" + now.getMinutes().toString().padStart(2, '0'); } function getCrystalId(msg) { const timeElement = msg.querySelector(".lc_chat_li_date"); const author = msg.querySelector(".lc_chat_li_autor"); if (timeElement && author) { return `${author.textContent.trim()}_${timeElement.textContent.trim()}`; } return null; } function initializeWorker() { if (worker) return; if (typeof Worker === 'undefined') { console.log('Web Workers не поддерживаются в этом браузере'); setInterval(clickOnCrystal, 1000); setInterval(preventTimeout, 2000); setInterval(detectInactiveCrystal, 4000); setInterval(() => { const now = new Date(); if (now.getHours() === 0 && now.getMinutes() === 0) { resetTimerAtMidnight(); } }, 60000); return; } try { const workerCode = ` let intervalIds = []; self.onmessage = function(e) { if (e.data.action === 'start') { clearAllIntervals(); startIntervals(); } else if (e.data.action === 'stop') { clearAllIntervals(); } }; function clearAllIntervals() { intervalIds.forEach(id => clearInterval(id)); intervalIds = []; } function startIntervals() { intervalIds.push(setInterval(() => { self.postMessage({ type: 'checkCrystal' }); }, 1000)); intervalIds.push(setInterval(() => { self.postMessage({ type: 'checkTimeout' }); }, 2000)); intervalIds.push(setInterval(() => { self.postMessage({ type: 'checkInactive' }); }, 4000)); intervalIds.push(setInterval(() => { const now = new Date(); if (now.getHours() === 0 && now.getMinutes() === 0) { self.postMessage({ type: 'midnight' }); } }, 60000)); } `; workerBlob = new Blob([workerCode], { type: 'application/javascript' }); worker = new Worker(URL.createObjectURL(workerBlob)); worker.onmessage = function(e) { switch(e.data.type) { case 'checkCrystal': clickOnCrystal(); break; case 'checkTimeout': preventTimeout(); break; case 'checkInactive': detectInactiveCrystal(); break; case 'midnight': resetTimerAtMidnight(); break; } }; worker.onerror = function(error) { console.log('Ошибка воркера:', error); setInterval(clickOnCrystal, 1000); setInterval(preventTimeout, 2000); setInterval(detectInactiveCrystal, 4000); setInterval(() => { const now = new Date(); if (now.getHours() === 0 && now.getMinutes() === 0) { resetTimerAtMidnight(); } }, 60000); }; } catch (error) { console.log('Ошибка при создании воркера:', error); setInterval(clickOnCrystal, 1000); setInterval(preventTimeout, 2000); setInterval(detectInactiveCrystal, 4000); setInterval(() => { const now = new Date(); if (now.getHours() === 0 && now.getMinutes() === 0) { resetTimerAtMidnight(); } }, 60000); } } function clickOnCrystal() { try { const chatMessages = document.querySelectorAll(".lc_chat_li"); chatMessages.forEach(msg => { const diamond = msg.querySelector("#diamonds-chat"); const timeElement = msg.querySelector(".lc_chat_li_date"); if (diamond && timeElement) { const crystalId = getCrystalId(msg); let messageTime = timeElement.textContent.trim(); if (messageTime >= lastActiveTime && !processedCrystals.has(crystalId)) { diamond.click(); lastActiveTime = messageTime; processedCrystals.add(crystalId); try { localStorage.setItem('lastCrystalTime', lastActiveTime); localStorage.setItem('processedCrystals', JSON.stringify([...processedCrystals])); } catch (e) { console.log('Ошибка сохранения в localStorage:', e); } } } }); } catch (error) { console.log('Ошибка в clickOnCrystal:', error); } } function preventTimeout() { const chatContainer = document.querySelector('.lc_chat'); if (chatContainer) { try { const moveEvent = new MouseEvent('mousemove', { bubbles: true, cancelable: true, view: window, clientX: 1, clientY: 1 }); chatContainer.dispatchEvent(moveEvent); } catch (e) {} } const timeoutButton = document.querySelector(".lc_chat_timeout_imback"); if (timeoutButton) { timeoutButton.click(); } } function detectInactiveCrystal() { const warning = document.querySelector(".DLEPush-notification.push-warning"); if (warning) { const closeButton = warning.querySelector(".DLEPush-close"); if (closeButton) { closeButton.click(); } lastActiveTime = getCurrentTime(); localStorage.setItem('lastCrystalTime', lastActiveTime); } } function resetTimerAtMidnight() { const now = new Date(); if (now.getHours() === 0 && now.getMinutes() === 0) { lastActiveTime = "00:00"; processedCrystals.clear(); localStorage.setItem('lastCrystalTime', lastActiveTime); localStorage.setItem('processedCrystals', JSON.stringify([])); } } initializeWorker(); worker.postMessage({ action: 'start' }); window.addEventListener('beforeunload', function() { if (worker) { worker.terminate(); URL.revokeObjectURL(workerBlob); } }); })();