Drive2 Old Auto UnSubscriber

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

当前为 2025-01-29 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Drive2 Old Auto UnSubscriber
// @namespace    drive2.ru
// @version      0.74
// @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;

console.log('myCars', myCars);

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);

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

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';

const updateStats = () => {
    statsDiv.innerHTML = `<div>
            Всего страниц: ${stats.pages}<br>
            Всего блоков: ${stats.totalBlocks}<br>
            Обработано: ${stats.processedBlocks}<br>
            Удалено: ${stats.removedBlocks}<br>
            Отписались: ${stats.unsubscribedBlocks}<br>
            Подписан на старые авто: ${stats.oldSubscribedBlocks}
        </div>`;
    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, 2000));
        processBlocks();

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

checkButton.addEventListener('click', clickMoreButton);

const unsubscribeCar = async (id) => {
    const url = '/ajax/subscription';
    const data = {
        _: 'unsubscribe',
        type: 'car',
        id: id, // Используем переданный параметр
        '.FCTX': '_wfqzlwoyisgAAUdQnJ1LldlYi4xOjg2NDY5MTEyODQ1NTEzODkzNTMBE9aV1TTAfio19mv_lNB3SPb24bE'
    };

    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(); // Если сервер вернул 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();
    myCars

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

        // Если блок уже подписан на старую машину, пропускаем его
        if (titleElement.classList.contains('x-secondary-color')) {
            stats.oldSubscribedBlocks++;
            stats.processedBlocks++;
            updateStats();
            continue;
        }

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

        // Делаем 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); // Убираем null
        const myCarIds = myCars.map(car => car.id);
        const hasMyCar = followedCarIds ? followedCarIds.some(carId => myCarIds.includes(carId)) : false;

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

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

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

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

        console.log('userId:', tail);
        console.log('FCTX:', fctx);
    } else {
        alert('обновите версию скрипта!');
        return;
    }
}

init_me();