Drive2 Old Auto UnSubscriber

работает на стренице подписок на сашины. проврка на бывшие авто и взаимные подписки, автоматически отписывается от бывших авто и от машин чьи владельцы не во взаимной подписке.

目前為 2025-01-29 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Drive2 Old Auto UnSubscriber
// @namespace    drive2.ru
// @version      0.77
// @description  работает на стренице подписок на сашины. проврка на бывшие авто и взаимные подписки, автоматически отписывается от бывших авто и от машин чьи владельцы не во взаимной подписке.
// @author       drive2 lover
// @match        https://www.drive2.ru/*/carsfollowing
// @match        https://www.drive2.com/*/carsfollowing
// @license MIT
// @grant        none

// ==/UserScript==
let tail = '';
let fctx = '';

const MY_CARS_KEY = 'my_cars';
const myCars = localStorage.getItem(MY_CARS_KEY) ? JSON.parse(localStorage.getItem(MY_CARS_KEY)) : false;

// Создаем блок статистики
const statsDiv = document.createElement('div');
statsDiv.style.position = 'fixed';
statsDiv.style.top = '0';
statsDiv.style.left = '0';
statsDiv.style.backgroundColor = '#333';
statsDiv.style.color = '#fff';
statsDiv.style.padding = '10px';
statsDiv.style.zIndex = '1000';
document.body.appendChild(statsDiv);

// Создаем чекбоксы
const unsubscribeCheckboxDiv = document.createElement('div');
const unsubscribeCheckbox = document.createElement('input');
unsubscribeCheckbox.type = 'checkbox';
unsubscribeCheckbox.checked = true;
const unsubscribeLabel = document.createElement('label');
unsubscribeLabel.textContent = ' Отписываться от авто';
unsubscribeLabel.style.marginRight = '10px';

const hideOldCarsCheckboxDiv = document.createElement('div');
const hideOldCarsCheckbox = document.createElement('input');
hideOldCarsCheckbox.type = 'checkbox';
hideOldCarsCheckbox.checked = true;
const hideOldCarsLabel = document.createElement('label');
hideOldCarsLabel.textContent = ' Скрывать старые авто';
hideOldCarsLabel.style.marginRight = '10px';

// Кнопка проверки
const checkButton = document.createElement('button');
checkButton.innerText = 'Проверить';
checkButton.style.marginTop = '10px';
checkButton.style.padding = '5px 10px';
checkButton.style.backgroundColor = '#007bff';
checkButton.style.color = '#fff';
checkButton.style.border = 'none';
checkButton.style.borderRadius = '5px';
checkButton.style.cursor = 'pointer';

// Добавляем чекбоксы и кнопку в statsDiv
unsubscribeCheckboxDiv.appendChild(unsubscribeCheckbox);
unsubscribeCheckboxDiv.appendChild(unsubscribeLabel);
statsDiv.appendChild(unsubscribeCheckboxDiv);
hideOldCarsCheckboxDiv.appendChild(hideOldCarsCheckbox);
hideOldCarsCheckboxDiv.appendChild(hideOldCarsLabel);
statsDiv.appendChild(hideOldCarsCheckboxDiv);
statsDiv.appendChild(checkButton);

let stats = {
    pages: 0,
    totalBlocks: 0,
    processedBlocks: 0,
    removedBlocks: 0,
    unsubscribedBlocks: 0,
    oldSubscribedBlocks: 0
};

const updateStats = () => {
    statsDiv.innerHTML = `<div>
        Страниц пройдено: ${stats.pages}<br>
        Иконок авто в очереди: ${stats.totalBlocks}<br>
        Обработано: ${stats.processedBlocks}<br>
        Отписались автоматом: ${stats.unsubscribedBlocks}<br>
        Подписан на старые авто: ${stats.oldSubscribedBlocks}
    </div>`;
    statsDiv.appendChild(unsubscribeCheckbox);
    statsDiv.appendChild(unsubscribeLabel);
    statsDiv.appendChild(hideOldCarsCheckbox);
    statsDiv.appendChild(hideOldCarsLabel);
    statsDiv.appendChild(checkButton);
};

updateStats();

// Функция для поиска и клика по кнопке "Загрузить еще"
const clickMoreButton = async () => {
    const button = document.querySelector('button.x-box-more');

    if (button) {
        stats.pages++;
        console.log('Загружаем страницу ' + stats.pages);
        button.click();

        if (!localStorage.getItem(MY_CARS_KEY)) {
            const response = await fetch('/my/r/');
            const html = await response.text();
            const parser = new DOMParser();
            const doc = parser.parseFromString(html, 'text/html');

            const cars = [];
            doc.querySelectorAll('.c-car-draglist__item .c-car-card__caption a').forEach(car => {
                if (!car.classList.contains('x-secondary-color')) {
                    const id = car.href.match(/\/(\d+)\//)[1];
                    cars.push({
                        id,
                        name: car.textContent.trim()
                    });
                }
            });

            localStorage.setItem(MY_CARS_KEY, JSON.stringify(cars));
        }
        updateStats();

        await new Promise(resolve => setTimeout(resolve, 3000));
        processBlocks();

    } else {
        console.log('Кнопка не найдена, продолжаем проверку...');
    }
};

const unsubscribeCar = async (id) => {
    const url = '/ajax/subscription';
    const data = {
        _: 'unsubscribe',
        type: 'car',
        id: id,
        '.FCTX': fctx
    };

    try {
        const response = await fetch(url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            },
            body: new URLSearchParams(data).toString()
        });

        if (response.ok) {
            const result = await response.json();
            console.log('Ответ сервера:', result);
        } else {
            console.error('Ошибка запроса:', response.status);
        }
    } catch (error) {
        console.error('Ошибка выполнения POST-запроса:', error);
    }
};

const processBlocks = async () => {
    const blocks = document.querySelectorAll('.c-car-card-sa');
    stats.totalBlocks = blocks.length;
    updateStats();

    for (const block of blocks) {
        const titleElement = block.querySelector('.c-car-title');

        // Если чекбокс скрытия старых авто включен и блок старый – пропускаем или удаляем
        if (titleElement.classList.contains('x-secondary-color')) {
            stats.oldSubscribedBlocks++;
            stats.processedBlocks++;
            if (hideOldCarsCheckbox.checked) {
                block.remove();
                stats.removedBlocks++;
            }
            updateStats();
            continue;
        }

        const subscribeButton = block.querySelector('subscribe-button');
        const userId = block.querySelector('a.c-username')?.getAttribute('data-ihc-token');

        if (!userId) continue;

        // Делаем GET-запрос для проверки подписки
        const response = await fetch(`https://www.drive2.com/_api/hovercards/${userId}?tail=${tail}`);
        const data = await response.json();

        const followedCarIds = data?.subscriptions?.followedCars?.map(car => {
            const match = car.url.match(/\/(\d+)\//);
            return match ? match[1] : null;
        }).filter(Boolean);
        const myCarIds = myCars.map(car => car.id);
        const hasMyCar = followedCarIds ? followedCarIds.some(carId => myCarIds.includes(carId)) : false;

        if (hasMyCar) {
            console.log('Блок содержит одну из моих машин, пропускаем.');
        } else {
            console.log('Блок не содержит моих машин.');
            if (unsubscribeCheckbox.checked) {
                unsubscribeCar(subscribeButton.getAttribute('uid'));
                stats.unsubscribedBlocks++;
            }
        }

        // Удаляем блок, если он не содержит мою машину
        block.remove();
        stats.removedBlocks++;
        stats.processedBlocks++;
        updateStats();

        // Ждём 1 секунду перед обработкой следующего блока
        await new Promise(resolve => setTimeout(resolve, 2000));
    }
    clickMoreButton();
};

checkButton.addEventListener('click', processBlocks);

function init_me() {
    // находим секретные ключи для автоматических запросов
    if (window.d2Env) {
        tail = window.d2Env.userId;
        fctx = window.d2Env.formContext['.FCTX'];
    } else {
        alert('обновите версию скрипта!');
        return;
    }
}

init_me();