Greasy Fork is available in English.

Drive2 Old Auto UnSubscriber

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

As of 2021-10-21. See the latest version.

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

// ==/UserScript==

// находим секретные ключи для автоматических запросов
var FCTX = document.querySelectorAll("input")[0].value;
var tail = __d2_env.userId;

var pages = 1; // количество проверенных страниц
var checked_cars = 0;

// методы для автоматических запросов
var ajax = {};
ajax.x = function () {
    if (typeof XMLHttpRequest !== 'undefined') {
        return new XMLHttpRequest();
    }
    var versions = [
        "MSXML2.XmlHttp.6.0",
        "MSXML2.XmlHttp.5.0",
        "MSXML2.XmlHttp.4.0",
        "MSXML2.XmlHttp.3.0",
        "MSXML2.XmlHttp.2.0",
        "Microsoft.XmlHttp"
    ];

    var xhr;
    for (var i = 0; i < versions.length; i++) {
        try {
            xhr = new ActiveXObject(versions[i]);
            break;
        } catch (e) {
        }
    }
    return xhr;
};

var ajax_status = 0;
var request_in_process = false;

ajax.send = function (url, callback, method, data, async) {
    if (async === undefined) {
        async = true;
    }
    var x = ajax.x();
    x.open(method, url, async);
    x.onreadystatechange = function () {
        if (x.readyState == 4) {
            callback(x.responseText)
        }
    };
    if (method == 'POST') {
        x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    }

    x.onload = function () {
        ajax_status = x.status;
    };

    x.send(data)
};

ajax.get = function (url, data, callback, async) {
    var query = [];
    for (var key in data) {
        query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
    }
    ajax.send(url + (query.length ? '?' + query.join('&') : ''), callback, 'GET', null, async)
};

ajax.post = function (url, data, callback, async) {
    var query = [];
    for (var key in data) {
        query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
    }
    sleep(1000);
    ajax.send(url, callback, 'POST', query.join('&'), async)
};

// ищем кнопки "страниц" и открываем их все пока получается
function clickNext(){
    var nextClicked = false;
    var nextbutton = document.querySelectorAll("button.c-block__more");

    if(nextbutton.length > 0){
        sleep(1000);
        document.querySelectorAll("button.c-block__more")[0].click();
        nextClicked = true;
        pages++;
    } else {
        console.log('not found - next btn');
    }

    if (!nextClicked)
    {
        clearInterval(nIntervId);
        console.log('all pages opened');
    }

    show_status();

    ButtonClickAction();
}



// паузы
function sleep(milliseconds) {
    let timeStart = new Date().getTime();
    while (true) {
        let elapsedTime = new Date().getTime() - timeStart;
        if (elapsedTime > milliseconds) {
            break;
        }
    }
}

var cars_unsubscribed = 0;
var car_ids = []; // тут собираем ID машин которые отмечены как "бывшие"
var check_users = [];
var found_cars_count = 0;

var sIntervId = false;
var cIntervId = false;

// отписаться от машинки
function unsubscribe_car(car_id)
{
    ajax.post('/ajax/subscription', {'_': "unsubscribe", 'type': "car", 'id': car_id, '.FCTX': FCTX}, function() {
        cars_unsubscribed++;
        console.log('cars unSubscribed: ' + cars_unsubscribed + ' / ' + found_cars_count);
        request_in_process = false;

        // переотправляем в очередь запрос который не прошел
        if (ajax_status == 403)
        {
            car_ids.push(car_id);
            return;
        }
        show_status();
    });
}

// рисуем статистику
function show_status()
{
    console.log('... [очередь: проверить на взаимность ' + check_users.length + ' машин, отписаться от ' + car_ids.length + ' машин] [проверено: ' + pages + ' страниц, ' + checked_cars + ' машин]');

    if (document.getElementById('in-check-query') === null)
    {
        var infoBoxDiv = document.createElement ('div');
        infoBoxDiv.innerHTML = 'В очереди проверить на взаимность: <span id="in-check-query">0</span><br>'
                + 'В очереди на отписаться: <span id="in-subscribe-query">0</span><br>'
                + 'проверено: <span id="pages-in-work">0</span><br>'
                + 'отписались от: <span id="unsubs-done-count">0</span>';
        infoBoxDiv.setAttribute ('class', 'infoBoxDiv');
        document.querySelectorAll(".x-title-header")[0].appendChild (infoBoxDiv);
        sleep(1000);
    }

    document.getElementById('in-check-query').innerHTML = check_users.length;
    document.getElementById('in-subscribe-query').innerHTML = car_ids.length;
    document.getElementById('unsubs-done-count').innerHTML = cars_unsubscribed;
    document.getElementById('pages-in-work').innerHTML = '[' + pages + ' страниц, ' + checked_cars + ' машин]';

    if (car_ids.length > 0 && sIntervId == false)
    {
        sIntervId = setInterval(unSubs, 1000);
        console.log('запуск отписок от машин в крон');
    }

    if (check_users.length > 0 && cIntervId == false)
    {
        cIntervId = setInterval(check_user, 1000);
        console.log('запуск проверок юзеров в крон');
    }

    if (car_ids.length == 0 && sIntervId)
    {
        clearInterval(sIntervId); // завершаем цикл
        sIntervId = false;
        console.log('остановка отписок от машин в крон');
    }

    if (check_users.length == 0 && cIntervId)
    {
        clearInterval(cIntervId);
        cIntervId = false;
        console.log('остановка проверок юзеров в крон');
    }
}

// проверяем взаимную подписку у владельца
function check_user()
{
    var first = car_ids.length == 0;

    if (request_in_process)
    {
        console.log('check_user - запросы заняты');
        return;
    }

    var item = check_users.pop(); //{'user_type':user_type, 'user_id':user_id, 'car_id': car_id});
    if (!item)
    {
        console.log('check_user - пусто в очереди');
        return;
    }

    console.log('check_user - ' + item.user_id);

    request_in_process = true;

    ajax.get('/ajax/info/', {'type': item.user_type, 'id': item.user_id, 'tail': tail}, function(response) {

        request_in_process = false;
        checked_cars++;

        if (ajax_status != 200)
        {
            // глюки, проверим в другой раз значит
            return;
        }

        var data = typeof response === 'string' ? JSON.parse(response) : response;

        var user_not_subscribed = typeof data.html !== 'undefined' // с запросом вс ОК
           && (data.html.indexOf("назад") > -1 || data.html.indexOf("Сейчас") > -1) // на странице есть слово "назад" или "Сейчас" (когда последний раз был владелец)
           && data.html.indexOf("Подписан") === -1; // на странице нет слова "Подписан"

        if (user_not_subscribed)
        {
            // не подписан, отписываемся от такого
            console.log('нет взаимной подписки', item.car_id);
            car_ids.push(item.car_id);

            if (first && sIntervId == false)
            {
                sIntervId = setInterval(unSubs, 1000);
                console.log('запуск отписок от машин в крон');
            }
        } else {
            console.log('взаимная подписка имеется', item.car_id);
        }

        show_status();
    });
}

// собираем все машинки от которых нужно отписаться
function ButtonClickAction ()
{

    console.log('ButtonClickAction');

    var old; // признак что авто - бывшее
    var user;
    var user_type;
    var user_id;
    var car_id;
    var container;

    var first = check_users.length == 0;

    // собираем все контейнеры
    var list = document.querySelectorAll(".c-darkening-hover-container");
    var i = false;
    if (list.length > 0)
    {
        for(var c = 0; c < list.length; c++)
        {
            container = list[c];

            i = container.querySelectorAll("button.c-button")[0];

            if (i)
            {
                car_id = i.getAttribute('data-id');

                // ищем не являемтся ли данные авто "бывшим"
                old = container.querySelectorAll(".c-car-title.c-link.c-link--gray")
                if (old.length)
                {
                    // сразу отписываемся от авто
                    console.log('обнаружена подписка на бывшее авто', car_id);
                    car_ids.push(car_id);
                    checked_cars++;
                } else {
                    // проверяем взаимную подписку у владельца
                    user = container.querySelectorAll("a.c-username")[0];
                    //car_id = container.querySelectorAll("button.c-button--subs")[0].getAttribute('data-id');
                    //check_user(user, car_id);

                    user_type = user.getAttribute('data-ihc-type');
                    user_id = user.getAttribute('data-ihc-id');
 
                    check_users.push({'user_type':user_type, 'user_id':user_id, 'car_id': car_id});
                    console.log('ставим на проверку юзера ' + user_id + ' с машинкой ' + car_id);
                }
            }

            // чистим страничку для загрузки новых данных и чтоб DOM дерево не разрасталось
            container.remove();
        }
    }

    found_cars_count = car_ids.length;
    show_status();
}

// отписываемся от них
function unSubs()
{
    if (request_in_process)
    {
        console.log('unSubs - занято в очереди');
        return;
    }

    var car_id = car_ids.pop();
    if (car_id)
    {
        console.log('unSubs - ' + car_id);
        request_in_process = true;
        unsubscribe_car(car_id);
    } else {
        console.log('unSubs - пусто в очереди');
    }

    show_status();
}

console.log('next btn search start');
var nIntervId = setInterval(clickNext, 3000); // открываем все страницы и обрабатываем их

check_user();
unSubs();