// ==UserScript==
// @name animestars Auto Helper
// @namespace animestars.org
// @version 3.0
// @description хелпер который помогает определить популярность карты на сайте astars.club
// @author astars lover
// @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 = 500; // Задержка между запросами в миллисекундах (по умолчанию 0,5 секунды) не менять чтоб не делать избыточную нагрузку на сайт
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
let cardCounter = 0;
async function getCount(cardId, type) {
// Определяем текущий домен
const currentDomain = window.location.origin;
let count = 0;
let needResponse = await fetch(`${currentDomain}/cards/${cardId}/users/${type}/`);
if (needResponse.status === 502) {
console.error("Ошибка 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) {
console.error("Ошибка 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 updateCardInfo(cardId, element) {
// Определяем текущий домен
const currentDomain = window.location.origin;
if (!cardId || !element) {
console.log(cardId, 'updateCardInfo error');
return;
}
try {
console.log(`Обработка карточки с ID: ${cardId}`);
await sleep(DELAY);
// Получение количества "Желающих"
let needCount = await getCount(cardId, 'need');
await sleep(DELAY);
// Получение количества "Готовых поменять"
let tradeCount = await getCount(cardId, 'trade');
await sleep(DELAY);
// Получение популярности и ранга
const popularityResponse = await fetch(`${currentDomain}/cards/${cardId}/users/`);
if (popularityResponse.status === 502) {
console.error("Ошибка 502: Остановка выполнения скриптов.");
throw new Error("502 Bad Gateway");
}
let popularityCount = 0;
let rankText = '';
if (popularityResponse.ok) {
const popularityHtml = await popularityResponse.text();
const popularityDoc = new DOMParser().parseFromString(popularityHtml, 'text/html');
const rankElement = popularityDoc.querySelector('.anime-cards__rank');
if (rankElement) {
rankText = rankElement.textContent.trim();
}
popularityCount = popularityDoc.querySelectorAll('.card-show__owner').length;
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 >= 35) {
popularityCount = (totalPages - 1) * 35;
const needResponse = await fetch(`${currentDomain}/cards/${cardId}/users/page/${totalPages}`);
if (needResponse.status === 502) {
console.error("Ошибка 502: Остановка выполнения скриптов.");
throw new Error("502 Bad Gateway");
}
if (needResponse.ok) {
popularityCount += (new DOMParser().parseFromString(await needResponse.text(), 'text/html')).querySelectorAll('.card-show__owner').length;
}
}
}
}
// Очистка старой информации
element.querySelector('.link-icon')?.remove();
// Добавление новой информации
const icon = document.createElement('div');
icon.className = 'link-icon';
icon.style.position = 'absolute';
icon.style.top = '10px';
icon.style.right = '10px';
icon.style.backgroundColor = 'rgba(0, 0, 0, 0.6)';
icon.style.color = '#05ed5b';
icon.style.padding = '5px';
icon.style.borderRadius = '5px';
icon.style.fontSize = '8px';
icon.innerHTML = `Ранг: ${rankText}<br>имеют: ${popularityCount}<br>хотят: ${needCount}<br>не хотят: ${tradeCount}`;
element.style.position = 'relative';
element.appendChild(icon);
} catch (error) {
console.error(`Ошибка обработки карты ${cardId}:`, error);
// Остановка выполнения скриптов
throw error;
}
}
function removeAllLinkIcons() {
const linkIcons = document.querySelectorAll('.link-icon');
linkIcons.forEach(icon => icon.remove());
}
function getCardsOnPage() {
return Array.from(
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')
).filter(card => card.offsetParent !== null);
}
async function processCards() {
removeMatchingWatchlistItems();
removeAllLinkIcons();
const cards = getCardsOnPage();
let counter = cards.length;
if (!counter) {
return;
}
let buttonId = 'processCards';
startAnimation(buttonId);
updateButtonCounter(buttonId, counter);
for (const card of cards) {
if (card.classList.contains('trade__inventory-item--lock')) {
continue; // Пропускаем эту карту
}
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) {
await updateCardInfo(cardId, card).catch(error => {
console.error("Остановка из-за критической ошибки:", error.message);
return;
});
card.style.border = '2px solid ' + (card.classList.contains('anime-cards__owned-by-user') ? 'rgb(255 0 0)' : '#217412');
counter--;
updateButtonCounter(buttonId, counter);
} else {
console.log(cardId, 'cardId not found');
}
if (card.classList.contains('lootbox__card')) {
card.addEventListener('click', removeAllLinkIcons);
}
}
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();
console.log(`Удалён блок: ${item}`);
}
}
}
});
if (watchlistItems.length) {
DLEPush?.info('Из списка удалены просмотренные аниме. В списке осталось ' + document.querySelectorAll('.watchlist__item').length + ' записей.');
}
}
function startAnimation(id) {
$('#' + id + ' span:first').css('animation', 'rotateIcon 2s linear 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.title = text;
button.style.position = 'fixed';
button.style.top = percent + '%';
button.style.right = '1%';
button.style.zIndex = '1000';
button.style.backgroundColor = '#007bff';
button.style.color = '#fff';
button.style.border = 'none';
button.style.borderRadius = '5px';
button.style.padding = '10px 15px';
button.style.cursor = 'pointer';
button.style.boxShadow = '0 2px 5px rgba(0, 0, 0, 0.2)';
const icon = document.createElement('span');
icon.className = 'fal fa-' + className;
icon.style.display = 'inline-block';
button.appendChild(icon);
const info = document.createElement('span');
info.id = id + '_counter';
info.className = 'guest__notification';
info.style.display = 'none';
button.appendChild(info);
button.addEventListener('click', clickFunction);
return button;
}
function updateButtonCounter(id, counter) {
let c = $('#' + id + '_counter');
c.css('display', counter > 0 ? 'flex' : 'none');
c.text(counter);
}
function addUpdateButton() {
if (!document.querySelector('#fetchLinksButton')) {
document.body.appendChild(getButton('processCards', 'rocket', 37, 'Сравнить карточки', processCards));
let cards = getCardsOnPage();
if (cards.length) {
document.body.appendChild(getButton('readyToCharge', 'circle-check', 50, 'Готов поменять карточки', readyToCharge));
}
}
}
async function readyToCharge() {
DLEPush.info('Отмечаем все карты на странице как: "Готов обменять" кроме тех что на обмене и заблокированных');
let cards = getCardsOnPage();
DLEPush.info('Карт на странице: ' + cards.length);
let counter = cards.length;
let buttonId = 'readyToCharge';
startAnimation(buttonId);
updateButtonCounter(buttonId, counter);
cardCounter = 0;
for (const card of cards) {
if (card.classList.contains('trade__inventory-item--lock')) {
continue;
}
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) {
await readyToChargeCard(cardId);
counter--;
card.style.border = '2px solid ' + (card.classList.contains('anime-cards__owned-by-user') ? 'rgb(255 0 0)' : '#217412');
updateButtonCounter(buttonId, counter);
}
}
DLEPush.info('Отправили на обмен ' + 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) {
console.error("Ошибка 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++;
//console.log('Ответ сервера:', data);
} else {
console.error('Ошибка запроса:', response.status);
}
} catch (error) {
console.error('Ошибка выполнения POST-запроса:', error);
}
};
// Анимация вращения в CSS
const style = document.createElement('style');
style.textContent = `
@keyframes rotateIcon {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
`;
document.head.appendChild(style);
function clearIcons() {
$('.card-notification')?.first()?.click();
}
function autoRepeatCheck() {
clearIcons();
checkGiftCard();
// блочим воспроизведение звуков при получении карты
Audio.prototype.play = function() {
return new Promise(() => {}); // Возвращаем promise, чтобы не было ошибок
};
}
function checkGiftCard() {
var button = $('#gift-icon');
if (button.length === 0) {
return;
}
var gift_code = button.attr('data-code');
if ( !gift_code ) return false;
$.ajax({
url: '/engine/ajax/controller.php?mod=gift_code_game',
data:{code: gift_code, user_hash: dle_login_hash},
dataType: 'json',
cache: false,
type: 'post',
success: function(data) {
if ( data.status == 'ok' ) {
DLEPush.info( data.text );
button.remove();
}
}
});
}
function startPing() {
// Получаем значение из глобальной переменной
const userHash = window.dle_login_hash;
if (!userHash) {
console.error("Переменная dle_login_hash не определена.");
return;
}
// Определяем текущий домен
const currentDomain = window.location.origin;
// Формируем URL с учетом userHash
const url = `${currentDomain}/engine/ajax/controller.php?mod=user_count_timer&user_hash=${userHash}`;
// Выполняем GET-запрос
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json(); // Если ответ в формате JSON
})
.then(data => {
console.log("Данные получены:", data); // Обрабатываем полученные данные
})
.catch(error => {
console.error("Ошибка при выполнении запроса:", error);
});
}
function checkNewCard() {
const currentDateTime = new Date();
// Получаем значение из глобальной переменной
const userHash = window.dle_login_hash;
if (!userHash) {
console.error("Переменная dle_login_hash не определена.");
return;
}
const localStorageKey = 'checkCardStopped' + window.dle_login_hash; // Формат YYYY-MM-DDTHH
if (localStorage.getItem(localStorageKey) === currentDateTime.toISOString().slice(0, 13)) {
console.log("Проверка карты уже остановлена на текущий час.");
return;
}
// Определяем текущий домен
const currentDomain = window.location.origin;
// Формируем URL с учетом userHash
const url = `${currentDomain}/engine/ajax/controller.php?mod=reward_card&action=check_reward&user_hash=${userHash}`;
// Выполняем GET-запрос
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json(); // Если ответ в формате JSON
})
.then(data => {
if (data.stop_reward === "yes") {
console.log("Проверка карт остановлена на текущий час:", data.reason);
localStorage.setItem(localStorageKey, currentDateTime.toISOString().slice(0, 13));
return;
}
if (!data.cards || !data.cards.owner_id) {
return;
}
const ownerId = data.cards.owner_id;
console.log("owner_id получен:", ownerId); // Выводим owner_id
if ( data.cards.name ) {
DLEPush?.info('Получена новая карта "' + data.cards.name + '"');
}
const url = `${currentDomain}/engine/ajax/controller.php?mod=cards_ajax`;
// Подготавливаем параметры запроса
const postData = new URLSearchParams({
action: "take_card",
owner_id: ownerId
});
// Выполняем POST-запрос
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(); // Если ответ в формате JSON
})
.then(data => {
console.log("Данные получены:", data); // Обрабатываем полученные данные
})
.catch(error => {
console.error("Ошибка при выполнении запроса:", error);
});
})
.catch(error => {
console.error("Ошибка при выполнении запроса:", error);
});
}
(function() {
'use strict';
setInterval(autoRepeatCheck, 2000);
setInterval(startPing, 31000);
setInterval(checkNewCard, 10000);
addUpdateButton();
$('#tg-banner').remove();
localStorage.setItem('notify18', 'closed');
localStorage.setItem('hideTelegramAs', 'true');
})();