Drive2 Old Auto UnSubscriber

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

目前为 2021-10-19 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Drive2 Old Auto UnSubscriber
  3. // @namespace drive2.ru
  4. // @version 0.511
  5. // @description работает на стренице подписок на сашины. проврка на бывшие авто и взаимные подписки, автоматически отписывается от бывших авто и от машин чьи владельцы не во взаимной подписке.
  6. // @author joker ivan
  7. // @match https://www.drive2.ru/*/carsfollowing
  8. // @grant none
  9.  
  10. // ==/UserScript==
  11.  
  12. // находим секретные ключи для автоматических запросов
  13. var FCTX = document.querySelectorAll("input")[0].value;
  14. var tail = __d2_env.userId;
  15.  
  16. var pages = 1; // количество проверенных страниц
  17. var checked_cars = 0;
  18.  
  19. // методы для автоматических запросов
  20. var ajax = {};
  21. ajax.x = function () {
  22. if (typeof XMLHttpRequest !== 'undefined') {
  23. return new XMLHttpRequest();
  24. }
  25. var versions = [
  26. "MSXML2.XmlHttp.6.0",
  27. "MSXML2.XmlHttp.5.0",
  28. "MSXML2.XmlHttp.4.0",
  29. "MSXML2.XmlHttp.3.0",
  30. "MSXML2.XmlHttp.2.0",
  31. "Microsoft.XmlHttp"
  32. ];
  33.  
  34. var xhr;
  35. for (var i = 0; i < versions.length; i++) {
  36. try {
  37. xhr = new ActiveXObject(versions[i]);
  38. break;
  39. } catch (e) {
  40. }
  41. }
  42. return xhr;
  43. };
  44.  
  45. var ajax_status = 0;
  46. var request_in_process = false;
  47.  
  48. ajax.send = function (url, callback, method, data, async) {
  49. if (async === undefined) {
  50. async = true;
  51. }
  52. var x = ajax.x();
  53. x.open(method, url, async);
  54. x.onreadystatechange = function () {
  55. if (x.readyState == 4) {
  56. callback(x.responseText)
  57. }
  58. };
  59. if (method == 'POST') {
  60. x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
  61. }
  62.  
  63. x.onload = function () {
  64. ajax_status = x.status;
  65. };
  66.  
  67. x.send(data)
  68. };
  69.  
  70. ajax.get = function (url, data, callback, async) {
  71. var query = [];
  72. for (var key in data) {
  73. query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
  74. }
  75. ajax.send(url + (query.length ? '?' + query.join('&') : ''), callback, 'GET', null, async)
  76. };
  77.  
  78. ajax.post = function (url, data, callback, async) {
  79. var query = [];
  80. for (var key in data) {
  81. query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
  82. }
  83. sleep(1000);
  84. ajax.send(url, callback, 'POST', query.join('&'), async)
  85. };
  86.  
  87. // ищем кнопки "страниц" и открываем их все пока получается
  88. function clickNext(){
  89. var nextClicked = false;
  90. var nextbutton = document.querySelectorAll("button.c-block__more");
  91. if(nextbutton.length > 0){
  92. sleep(1000);
  93. document.querySelectorAll("button.c-block__more")[0].click();
  94. nextClicked = true;
  95. pages++;
  96. } else {
  97. console.log('not found - next btn');
  98. }
  99.  
  100. if (!nextClicked)
  101. {
  102. clearInterval(nIntervId);
  103. console.log('all pages opened');
  104. }
  105.  
  106. if (car_ids.length > 0 && sIntervId == false)
  107. {
  108. sIntervId = setInterval(unSubs, 1000);
  109. }
  110.  
  111. ButtonClickAction();
  112. }
  113.  
  114. // паузы
  115. function sleep(milliseconds) {
  116. let timeStart = new Date().getTime();
  117. while (true) {
  118. let elapsedTime = new Date().getTime() - timeStart;
  119. if (elapsedTime > milliseconds) {
  120. break;
  121. }
  122. }
  123. }
  124.  
  125. var cars_unsubscribed = 0;
  126. var car_ids = []; // тут собираем ID машин которые отмечены как "бывшие"
  127. var check_users = [];
  128. var found_cars_count = 0;
  129.  
  130. // отписаться от машинки
  131. function unsubscribe_car(car_id)
  132. {
  133. ajax.post('/ajax/subscription', {'_': "unsubscribe", 'type': "car", 'id': car_id, '.FCTX': FCTX}, function() {
  134. cars_unsubscribed++;
  135. console.log('cars unSubscribed: ' + cars_unsubscribed + ' / ' + found_cars_count);
  136. request_in_process = false;
  137.  
  138. // переотправляем в очередь запрос который не прошел
  139. if (ajax_status == 403)
  140. {
  141. car_ids.push(car_id);
  142. return;
  143. }
  144. show_status();
  145. });
  146. }
  147.  
  148. // рисуем статистику
  149. function show_status()
  150. {
  151. console.log('... [очередь: проверить на взаимность ' + check_users.length + ' машин, отписаться от ' + car_ids.length + ' машин] [проверено: ' + pages + ' страниц, ' + checked_cars + ' машин]');
  152.  
  153. if (document.getElementById('in-check-query') === null)
  154. {
  155. var infoBoxDiv = document.createElement ('div');
  156. infoBoxDiv.innerHTML = 'В очереди проверить на взаимность: <span id="in-check-query">0</span><br>'
  157. + 'В очереди на отписаться: <span id="in-subscribe-query">0</span><br>'
  158. + 'обработано: <span id="pages-in-work">0</span><br>';
  159. infoBoxDiv.setAttribute ('class', 'infoBoxDiv');
  160. document.querySelectorAll(".l-page-header")[0].appendChild (infoBoxDiv);
  161. sleep(1000);
  162. }
  163.  
  164. document.getElementById('in-check-query').innerHTML = check_users.length;
  165. document.getElementById('in-subscribe-query').innerHTML = car_ids.length;
  166. document.getElementById('pages-in-work').innerHTML = '[' + pages + ' страниц, ' + checked_cars + ' машин]';
  167.  
  168. if (car_ids.length > 0 && sIntervId == false)
  169. {
  170. sIntervId = setInterval(unSubs, 1000);
  171. }
  172.  
  173. if (check_users.length > 0 && cIntervId == false)
  174. {
  175. cIntervId = setInterval(check_user, 1000);
  176. }
  177. }
  178.  
  179. // проверяем взаимную подписку у владельца
  180. function check_user()
  181. {
  182. if (request_in_process)
  183. {
  184. return;
  185. }
  186.  
  187. var item = check_users.pop(); //{'user_type':user_type, 'user_id':user_id, 'car_id': car_id});
  188. if (!item)
  189. {
  190. return;
  191. }
  192.  
  193. request_in_process = true;
  194. ajax.get('/ajax/info/', {'type': item.user_type, 'id': item.user_id, 'tail': tail}, function(response) {
  195.  
  196. request_in_process = false;
  197. checked_cars++;
  198.  
  199. if (ajax_status != 200)
  200. {
  201. // глюки, проверим в другой раз значит
  202. return;
  203. }
  204.  
  205. var data = typeof response === 'string' ? JSON.parse(response) : response;
  206.  
  207. var user_not_subscribed = typeof data.html !== 'undefined' // с запросом вс ОК
  208. && (data.html.indexOf("назад") > -1 || data.html.indexOf("Сейчас") > -1) // на странице есть слово "назад" или "Сейчас" (когда последний раз был владелец)
  209. && data.html.indexOf("Подписан") === -1; // на странице нет слова "Подписан"
  210.  
  211. if (user_not_subscribed)
  212. {
  213. // не подписан, отписываемся от такого
  214. console.log('нет взаимной подписки', item.car_id);
  215. car_ids.push(item.car_id);
  216. }
  217.  
  218. show_status();
  219. });
  220. }
  221.  
  222. // собираем все машинки от которых нужно отписаться
  223. function ButtonClickAction () {
  224.  
  225. var old; // признак что авто - бывшее
  226. var user;
  227. var user_type;
  228. var user_id;
  229. var car_id;
  230. var container;
  231.  
  232. // собираем все контейнеры
  233. var list = document.querySelectorAll(".c-darkening-hover-container");
  234. var i = false;
  235. if (list.length > 0)
  236. {
  237. for(var c = 0; c < list.length; c++)
  238. {
  239. container = list[c];
  240.  
  241. i = container.querySelectorAll(".c-car-card-sa__subscribe button");
  242.  
  243. if (i.length > 0)
  244. {
  245. car_id = i.getAttribute('data-id');
  246.  
  247. // ищем не являемтся ли данные авто "бывшим"
  248. old = container.querySelectorAll(".c-car-title.c-link.c-link--gray")
  249. if (old.length)
  250. {
  251. // сразу отписываемся от авто
  252. console.log('обнаружена подписка на бывшее авто', car_id);
  253. car_ids.push(car_id);
  254. checked_cars++;
  255. } else {
  256. // проверяем взаимную подписку у владельца
  257. user = container.querySelectorAll(".c-username")[0];
  258. car_id = container.querySelectorAll(".c-car-card-sa__subscribe button")[0].getAttribute('data-id');
  259. //check_user(user, car_id);
  260.  
  261. user_type = user.getAttribute('data-ihc-type');
  262. user_id = user.getAttribute('data-ihc-id');
  263. check_users.push({'user_type':user_type, 'user_id':user_id, 'car_id': car_id});
  264. }
  265. }
  266.  
  267. // чистим страничку для загрузки новых данных и чтоб DOM дерево не разрасталось
  268. container.remove();
  269. }
  270. }
  271.  
  272. found_cars_count = car_ids.length;
  273.  
  274. if (car_ids.length > 0 && sIntervId == false)
  275. {
  276. sIntervId = setInterval(unSubs, 1000);
  277. }
  278.  
  279. }
  280.  
  281. // отписываемся от них
  282. function unSubs()
  283. {
  284. if (request_in_process)
  285. {
  286. return;
  287. }
  288.  
  289. request_in_process = true;
  290. var car_id = car_ids.pop();
  291. if (car_id)
  292. {
  293. unsubscribe_car(car_id);
  294. } else { // если закончился список на отписку
  295. if (check_users.length < 1) { // а также список на проверку
  296. if (sIntervId)
  297. {
  298. clearInterval(sIntervId); // завершаем цикл
  299. }
  300. if (cIntervId)
  301. {
  302. clearInterval(cIntervId);
  303. }
  304. }
  305. }
  306. }
  307.  
  308. console.log('next btn search start');
  309. var nIntervId = setInterval(clickNext, 3000); // открываем все страницы и обрабатываем их
  310. var sIntervId = false;
  311. var cIntervId = setInterval(check_user, 1000);