您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Остальные полезные скрипты - https://zelenka.guru/threads/5310268/
// ==UserScript== // @name Автоап + автозакреп объявлений на маркете // @namespace http://tampermonkey.net/ // @version 0.1 // @description Остальные полезные скрипты - https://zelenka.guru/threads/5310268/ // @author Jack // @match https://zelenka.guru/* // @match https://lzt.market/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // ==/UserScript== const time = 6; // Время в часах между поднятием объявлений, согласно вашим правам const limit = 8; // Максимальное число объявлений, согласно вашим правам const sticky = 3; // Максимальное число объявлений которые можно закрепить, согласно вашим правам const method = 1; // Выберите метод, по которому будут подниматься товары. 1 - Дешевые, 2 - Дорогие, 3 - Старые (по заливу) const methodS = 2; // Тоже самое, только для закрепа const _xfToken = document.querySelector('input[name="_xfToken"]').value; function getUrlByMethod(method) { switch(method) { case 1: return 'https://lzt.market/user/items?category_id=0&show=active&order_by=price_to_up'; case 2: return 'https://lzt.market/user/items?category_id=0&show=active&order_by=price_to_down'; case 3: return 'https://lzt.market/user/items?category_id=0&show=active&order_by=pdate_to_up_upload'; } } async function getData(url = '') { return new Promise(function (resolve, reject) { GM_xmlhttpRequest({ method: 'GET', url: url, headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json, text/html, application/xhtml+xml, application/xml;q=0.9, image/avif, image/webp, image/apng, */*;q=0.8, application/signed-exchange;v=b3;q=0.7', 'Accept-Charset': 'UTF-8', }, onload: function (response) { if (response.status >= 200 && response.status < 300) { resolve(response.responseText); } else { reject(new Error(`HTTP error ${response.status}`)); } }, onerror: function (error) { reject(new Error(`Network error: ${error}`)); }, }); }); } async function bumpAd(id) { const url = `https://lzt.market/${id}/bump?&_xfRequestUri=%2F${id}%2F&_xfNoRedirect=1&_xfToken=${_xfToken}&_xfResponseType=json`; try { await getData(url); XenForo.alert('Объявление поднято', '', 5000); } catch (error) { console.error(`Ошибка при попытке поднять объявление ${id}: `, error); } } async function stickAd(id) { const url = `https://lzt.market/${id}/stick-unstick?&_xfRequestUri=%2F${id}%2F&_xfNoRedirect=1&_xfToken=${_xfToken}&_xfResponseType=json`; try { await getData(url); XenForo.alert('Объявление закреплено', '', 5000); } catch (error) { console.error(`Ошибка при попытке закрепить объявление ${id}: `, error); } } function shouldBump(id) { const bumpData = GM_getValue("bumpData", {}); const lastUp = bumpData[id]?.lastUp || 0; if (lastUp === 0) { return true; } const elapsedTime = (Date.now() - lastUp) / 1000 / 60 / 60; return elapsedTime >= (6 + (1 / 60)); } function shouldStick(id) { const stickyData = GM_getValue("stickyData", {}); const currentStickedCount = Object.values(stickyData).filter(item => item.sticky === "yes").length; return stickyData[id]?.sticky !== "yes" && currentStickedCount < sticky; } async function BumpGoods(ids) { for (const id of ids) { if (shouldBump(id)) { await bumpAd(id); const bumpData = GM_getValue("bumpData", {}); bumpData[id].lastUp = Date.now(); GM_setValue("bumpData", bumpData); } } } async function StickGoods(ids) { for (const id of ids) { if (shouldStick(id)) { await stickAd(id); const stickyData = GM_getValue("stickyData", {}); stickyData[id].sticky = "yes"; GM_setValue("stickyData", stickyData); } } } function getTimeLeft(id) { const bumpData = GM_getValue("bumpData", {}); const lastUpTime = bumpData[id] ? bumpData[id].lastUp : 0; const elapsedTime = (Date.now() - lastUpTime) / 1000 / 60 / 60; const timeLeft = (time + (1 / 60)) - elapsedTime; return timeLeft; } async function getInfoB(method, limit) { const parser = new DOMParser(); let bumpData = GM_getValue("bumpData", {}); let idsForBump = Object.keys(bumpData); for (let id of idsForBump) { const timeLeft = getTimeLeft(id); if (timeLeft <= 0) { const htmlAccountData = await getData(`https://lzt.market/${id}/`); const docAccount = parser.parseFromString(htmlAccountData, 'text/html'); const statusElement = docAccount.querySelector('.marketIndexItem--helpfulIcons span'); if (statusElement) { const accountStatus = statusElement.getAttribute('title'); if (['Аккаунт продан', 'Объявление закрыто и не показывается в поиске другим пользователям.', 'Удалено'].includes(accountStatus)) { delete bumpData[id]; console.log(`Аккаунт ${id} был продан, удален или закрыт. Он был удален из очереди.`); } else { bumpData[id].lastUp = Date.now(); console.log(`Обновлено время последнего поднятия для аккаунта ${id}`); } } } } if (Object.keys(bumpData).length < limit) { const urlMethod = getUrlByMethod(method); const htmlDataMethod = await getData(urlMethod); const docMethod = parser.parseFromString(htmlDataMethod, 'text/html'); const itemsMethod = Array.from(docMethod.querySelectorAll('.marketIndexItem')); for (let item of itemsMethod) { const id = item.id.replace('marketItem--', ''); if (!bumpData[id]) { bumpData[id] = { lastUp: Date.now(), method: 'A' }; console.log(`Добавлен новый аккаунт ${id}`); if (Object.keys(bumpData).length >= limit) break; } } } idsForBump = Object.keys(bumpData).sort((a, b) => bumpData[a].lastUp - bumpData[b].lastUp); for (let id of idsForBump) { const timeLeft = getTimeLeft(id); if (timeLeft <= 0) { console.log(`Следующее поднятие аккаунта ${id} через ${Math.abs(timeLeft).toFixed(2)} ч.`); BumpGoods([id]); bumpData[id].lastUp = Date.now(); console.log(`Аккаунт ${id} поднят.`); } else { console.log(`Следующее поднятие аккаунта ${id} через ${timeLeft.toFixed(2)} ч.`); } } GM_setValue("bumpData", bumpData); } async function getInfoS(methodS, sticky) { const stickyData = GM_getValue("stickyData", {}); const currentTime = new Date().getTime(); const lastCheckTime = stickyData.lastCheckTime || 0; if (currentTime - lastCheckTime > 30 * 60 * 1000) { const htmlDataStickied = await getData("https://lzt.market/user/items?category_id=0&show=stickied"); const parser = new DOMParser(); const docStickied = parser.parseFromString(htmlDataStickied, 'text/html'); const itemsStickied = Array.from(docStickied.querySelectorAll('.marketIndexItem')); stickyData.lastCheckTime = currentTime; const newStickyItems = {}; itemsStickied.forEach(item => { const id = item.id.replace('marketItem--', ''); newStickyItems[id] = { lastUp: 0, sticky: "yes" }; }); for (let id in stickyData) { if (id !== 'lastCheckTime' && !newStickyItems.hasOwnProperty(id)) { delete stickyData[id]; } } Object.assign(stickyData, newStickyItems); GM_setValue("stickyData", stickyData); } const urlMethodS = getUrlByMethod(methodS); if (Object.values(stickyData).filter(item => item.sticky === "yes").length < sticky) { const htmlDataMethodS = await getData(urlMethodS); const parser = new DOMParser(); const docMethodS = parser.parseFromString(htmlDataMethodS, 'text/html'); const itemsMethodS = Array.from(docMethodS.querySelectorAll('.marketIndexItem')); let idsForStick = itemsMethodS.slice(0, sticky).map(item => item.id.replace('marketItem--', '')); await Promise.all(idsForStick.map(async id => { if (id !== 'lastCheckTime' && shouldStick(id)) { await stickAd(id, stickyData); stickyData[id] = { lastUp: 0, sticky: "yes" }; } })); GM_setValue("stickyData", stickyData); } let idsForStick = Object.keys(stickyData).filter(id => id !== 'lastCheckTime' && stickyData[id].sticky !== "yes").slice(0, sticky); StickGoods(idsForStick); } function addButtonAfterTagButton() { setTimeout(function() { let tagButton = document.querySelector('.itemTags'); if (!tagButton) return; let loginDataText = document.querySelector('.market--titleBar.market--spec--titleBar')?.innerText; if (!loginDataText || !loginDataText.includes('Показать арбитрам данные для входа')) return; let newButton = document.createElement('a'); let icon = document.createElement('i'); newButton.setAttribute('class', 'button buttonWithIcon'); newButton.style.display = 'inline-flex'; newButton.style.alignItems = 'center'; newButton.style.justifyContent = 'center'; newButton.style.width = '39px'; newButton.style.marginLeft = '10px'; icon.setAttribute('class', 'far fa-arrow-to-top'); newButton.appendChild(icon); newButton.addEventListener('click', function () { const id = document.querySelector(".Editable").dataset.saveUrl.split('/')[0]; addIdToBumpData(id); }); tagButton.parentNode.insertBefore(newButton, tagButton.nextSibling); }, 200); } function addIdToBumpData(id) { const bumpData = GM_getValue("bumpData", {}); const idsForBump = Object.keys(bumpData); if (idsForBump.includes(id)) { XenForo.alert('Объявление уже есть в списке.', '', 5000); return; } const manualIds = idsForBump.filter(id => bumpData[id].method === 'M'); if (manualIds.length >= 8) { XenForo.alert('Нет свободных слотов. Максимальное число объявлений, добавляемых вручную - 8', '', 5000); return; } bumpData[id] = { lastUp: 0, method: 'M' }; GM_setValue("bumpData", bumpData); XenForo.alert('Объявление было добавлено в список.', '', 5000); } window.addEventListener('load', addButtonAfterTagButton, false); function init() { getInfoB(method, limit); setInterval(() => getInfoB(method, limit), time * 60 * 60 * 1000); getInfoS(methodS, sticky); setInterval(() => getInfoS(methodS, sticky), time * 60 * 60 * 1000); } init();