// ==UserScript== // @name Versions 4pda // @namespace http://4pda.to/forum/index.php // @version 1.6.2 // @description:ru Вывод версий приложений в Избранном 4pda, показ обновленных приложений // @author Azat-777 (Ник на 4pda: Azat-777, mail: aflitonovazat@gmail.com) // @icon http://s.4pda.to/kkRM7z1nbI3gbG5E7r0a561qtdKnE2GlKhz1ipnv.png // @match http*://4pda.to/forum/index.php?act=fav* // @match http*://4pda.to/forum/index.php?showtopic=* // @grant GM_xmlhttpRequest // @license MIT // @history:ru когда-то давно: первый релиз // @history:ru 26.07.2017: допиливание мелочей // @history:ru 31.07.2017: расширение функционала скрипта: подробная информация о каждом пользователе в топиках // @history:ru 04.08.2017: добавлено мигание 'NEW' (скрыто) // @history:ru 02.01.2018: небольшие правки кода // @history:ru 10.05.2018: изменение списка обновленных приложений // @history:ru 11.05.2018: мелкие правки и исправления // @history:ru 20.05.2018: добавлено удаление пробелов в начале и конце названий версий, чтобы из-за пробелов версия не определялась как новая // @history:ru 16.08.2018: теперь обновления не исчезают с обновлением страницы, для ручного скрытия обновлений добавлена кнопка // @history:ru 17.08.2018: правка вчерашних ошибок, добавление мелочей (title и переход к последнему непрочитанному сообщению в теме // @history:ru обновленного приложения); реализация скрытия обновлений по одному: убрад мигание NEW для обновлений, т.к. уже неактуально // @history:ru 20.08.2018: починен показ кнопки скрытия отдельного обновления; в консоли выводится объем загруженого XHR-запросами траффика // @history:ru 06.05.2019: кроме слова 'версия' другой текст, если он был, не удалялся, поправлено // @history:ru 01.06.2019: слово 'версия' не заменялось на 'v.', если после него не было пробела. Недоработка в регулярках. Поправлено // @history:ru 02.06.2019: добавлена функция отключения проверки обновлений для выбранных приложений (могут быть ошибки) // @history:ru 14.02.2020: исправлена ошибка, при которой выводился текст на месте версии // @history:ru 05.07.2022: исправлена ошибка в коде, из-за которой таблица с обновленными версиями приложений появлялась снова после скрытия // @history:ru 09.06.2023: мелкие и незначительные правки для обеспечения полной работоспособности скрипта, наверное... // @history:ru 25.05.2025: в таблицу обновлений (в том числе и в таблицу ЧС) добавлен столбец с датами последнего обновления приложения/игры; // @history:ru убрал в таблице для версий приставку 'v.' за ненадобностью // @history:ru ВНИМАНИЕ: некоторые приложения, относящие к VPN, не будут подгружаться в таблицу обновлений и показывать версии, // @history:ru т.к. могут быть проблемы с доступом к этим темам без включенного VPN // @description Вывод версий приложений в Избранном 4pda, показ обновленных приложений // @downloadURL none // ==/UserScript== (function() { 'use strict'; //============================================================ // получение ссылки текущей страницы var URL = window.document.URL; //log(URL); //============================================================ // удаляем рекламу и центрируем логотип 4pda var tbody = document.getElementsByTagName('tbody')[0], td = tbody.getElementsByTagName('td'); td[1].remove(); td[0].align = 'center'; //============================================================ var favURL = '4pda.to/forum/index.php?act=fav', i, head = document.getElementsByTagName('head')[0]; //var topicURL = 'http://4pda.to/forum/index.php?showtopic='; // спойлер с объявлениями всегда скрыт if(document.querySelector('#gc_1, #go_1')) { document.querySelector('#go_1').style.display = 'none'; document.querySelector('#gc_1').style.display = 'none'; } var l = 0, // счетчик totalKB = 0, totalMB = 0; function log(text) { return console.log(text); } // Избранное if (~URL.indexOf(favURL)) { //localStorage //localStorage.clear(); //============================================================ // модифицирование встроенной функции модерации тем в своем избранном var savedIDs, form = document.querySelector('#fav-sel-form'), select = form.querySelector('select'), option = document.createElement('option'), values = ''; option.value = 'not_show_updates'; option.innerHTML = 'Не уведомлять об обновлениях (mod)'; select.insertBefore(option, select.firstChild); // сохранение IDов выбранных тем в localStorage option.onclick = function() { checkSavedIDs(); if(savedIDs == '-1') { values = form.querySelector('input').value; } else { values = savedIDs + ',' + form.querySelector('input').value; } values = values.split(','); values = unique(values); localStorage.setItem('savedIDs', values); checkBan(); } // удаление из массива одинаковых IDов function unique(arr) { var obj = {}; for (var i = 0; i < arr.length; i++) { var str = arr[i]; obj[str] = true; // запомнить строку в виде свойства объекта } return Object.keys(obj); // или собрать ключи перебором для IE8- } checkSavedIDs(); function checkSavedIDs() { if(localStorage.getItem('savedIDs') === null) { localStorage.setItem('savedIDs', '-1'); } savedIDs = localStorage.getItem('savedIDs'); savedIDs = savedIDs.split(','); } // добавление в строке названий приложений их версий var ver; // находим таблицу var tbl = document.getElementsByClassName('ipbtable')[0]; var tbody2 = tbl.getElementsByTagName('tbody')[0]; var _tr = tbody2.getElementsByTagName('tr'); // запихиваем в tr нужные нам строки таблицы var tr = [], id; for(i=0; i<_tr.length; i++) { if (_tr[i].hasAttribute('data-item-fid')) { // отсортировываем из таблицы только темы tr.push(_tr[i]); // запихиваем в массив tr } } var trLength = tr.length var name = []; // названия тем for (i=0; i `; var _span = document.createElement('span'); _span.style.color = 'black'; var _span2 = document.createElement('span'); _span2.style.color = 'black'; var navstrip = document.getElementById('navstrip'); //===================================================== var app_name, saveToHideName = [], saveToHideVer = []; /*_new = ' NEW',*/ function getVersion(link, i, id) { var XHR = ("onload" in new XMLHttpRequest()) ? XMLHttpRequest : XDomainRequest; var xhr = new XHR(); xhr.open('GET', link, true); xhr.send(); xhr.onload = function() { if(this.readyState === 4) { if (this.status === 200) { var response = xhr.responseText; var parser = new DOMParser(); var doc = parser.parseFromString(response, 'text/html'); var tbl = doc.getElementsByClassName('ipbtable'); for (var j=0; j')) { replace_ver = replace_ver.toLowerCase().replace(/[А-Яа-я\s]*верси[ия]:[\s]*/, 'v.').replace(/<[\/]*b[r]*>/g, '').trim(); if(~replace_ver.indexOf('v.')) { alt_ver = replace_ver; } else { alt_ver = '---'; } var alt_name; alt_name = name[i].innerHTML.replace(/<[\/]*strong>/g, ''); // если приложение в списке игнорируемых, т.е. не проходит проверку на обновления t = true; for(var l=0; l[А-Яа-я\s]*верси[ия]:[\s]*/, 'v.').replace(/<[\/]*b>/g, '').trim(); if(~replace_ver.indexOf('v.')) { alt_ver = replace_ver; } else { alt_ver = '---'; } // если приложение в списке игнорируемых, т.е. не проходит проверку на обновления t = true; for(l=0; l>N ' app_name = goto + ''+alt_name + ''; saveToHideName.push(alt_name); saveToHideVer.push(alt_ver); showUpdates(app_name, alt_ver, date); } // если replace_ver содержит готовый шаблон "v.xxx", добавляем его к названию приложения if(~replace_ver.indexOf('v.')) { replace_ver = ' ' + replace_ver + ''; // добавление цвета для наглядности name[i].innerHTML += replace_ver; } } break; } } break; } } } } }; xhr.onerror = function() { log('onerror'); alert('Ошибка'); }; xhr.onloadend = function(event) { //log('onloadend'); totalKB += (event.loaded/1024); // подсчет загруженного траффика totalMB += (event.loaded/1024/1024); if(++l === trLength) { addEvent(); // вешаем обработчик событий строки (появление/скрытие кноки "Скрыть") hideApp(); // скрытие строки с обновленным приложением console.log('Скачано XHR-запросами:', totalKB.toFixed(2), 'КБ |', totalMB.toFixed(2), 'МБ'); // вывод объема скачанного } }; xhr.onprogress = function(event) { //log('onprogress'); }; } // переопределяем стиль для кнопок var btnStyle = document.createElement('style'); btnStyle.type = 'text/css'; var _s = ` .myBtn { display: inline-block; font-family: arial,sans-serif; font-size: 10px; font-weight: bold; color: rgb(68,68,68); text-decoration: none; user-select: none; padding: .1em 1.2em; outline: none; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; background: rgb(245,245,245) linear-gradient(#f4f4f4, #f1f1f1); transition: all .218s ease 0s; } .myBtn:hover { color: rgb(24,24,24); border: 1px solid rgb(198,198,198); background: #f7f7f7 linear-gradient(#f7f7f7, #f1f1f1); box-shadow: 0 1px 2px rgba(0,0,0,.1); } .myBtn:active { color: rgb(51,51,51); border: 1px solid rgb(204,204,204); background: rgb(238,238,238) linear-gradient(rgb(238,238,238), rgb(224,224,224)); box-shadow: 0 1px 2px rgba(0,0,0,.1) inset; }`; var _st = document.createTextNode(_s); btnStyle.appendChild(_st); head.appendChild(btnStyle); //navstrip.appendChild(_span); navstrip.appendChild(main_tbl); var one = document.querySelector('#main_tbl #one'), two = document.querySelector('#main_tbl #two'); one.appendChild(_span); two.appendChild(_span2); _span.innerHTML = 'Обновлений: ' + count + '
' + `
# Название Версия Дата обновления
`; var _tbl = document.querySelector('._tbl'), _tbody = _tbl.querySelector('tbody'), _cnt = document.querySelector('#_cnt'), n = 0; _tbl.style.display = 'none'; var tblStyle = document.createElement('style'); tblStyle.type = 'text/css'; var s = ` ._tbl th { color: brown; background-color: white; text-align: center; padding: 2px; letter-spacing: 0px; } ._tbl td { font-size: 10px; padding: 0 5px; } ._tbl .brown-right-line { border-right: 1px solid; } ._tbl .date { padding-left: 5px; padding-right: 5px; } ._tbl .black-right-line { border-right: 1px solid; }`; var st = document.createTextNode(s); tblStyle.appendChild(st); head.appendChild(tblStyle); // кнопка скрытия обновлений вручную var hideBtn = document.querySelector('#hideBtn'); hideBtn.onclick = function() { hideBtn.style.display = 'none'; // сразу сохраняем обновленные версии в память, чтобы при следующем обновлении не всплыли в таблице обновлений for(var i=0; i 0;) { _tbl.deleteRow(1); } } _span2.innerHTML = '
' + ``; checkBan(); function checkBan() { var tb = document.querySelector('#tbody2'); if(savedIDs.length > 0 && savedIDs[0] !== '-1') { _span2.style.display = ''; } else { _span2.style.display = 'none'; } } var showBanList = document.querySelector('#showBanList'), clearBanList = document.querySelector('#clearBanList'), ban_tbl = document.querySelector('#ban_tbl'); showBanList.onclick = function() { if(ban_tbl.style.display == 'none') { ban_tbl.style.display = 'block'; showBanList.value = 'Скрыть ЧС'; clearBanList.disabled = false; clearBanList.style.textDecoration = ''; } else { ban_tbl.style.display = 'none'; showBanList.value = 'Показать ЧС'; clearBanList.disabled = true; clearBanList.style.textDecoration = 'line-through'; //clearBanList.style.setProperty("text-decoration", "line-through"); } } clearBanList.style.textDecoration = 'line-through'; clearBanList.onclick = function() { localStorage.setItem('savedIDs', '-1'); checkSavedIDs(); //log(savedIDs); } // добавлению в таблицу скрытых приложений, их версии и id их темы var num = 0; function getBannedApps(app_name, ver, id, date) { num++; ver = ver.replace('v.', ''); var _tbody2 = document.querySelector('#tbody2'); var row =_tbody2.insertRow(-1), cell1 = row.insertCell(-1), // # cell2 = row.insertCell(-1), // Название cell3 = row.insertCell(-1), // Версия cell4 = row.insertCell(-1), // ID темы cell5 = row.insertCell(-1), // Дата обновления cell6 = row.insertCell(-1); // Скрыть row.className = 'myTr'; cell1.className = 'black-right-line one'; cell2.className = 'black-right-line'; cell3.className = 'black-right-line'; cell4.className = 'black-right-line'; cell1.innerHTML = num; cell2.innerHTML = app_name; cell3.innerHTML = ver; cell4.innerHTML = id; cell5.innerHTML = date; cell6.innerHTML = ''; } // показ количества обновлений и вывод их в таблице function showUpdates(app_name, ver, date) { _tbl.style.display = 'block'; n++; ver = ver.replace('v.', ''); var row = _tbody.insertRow(-1), cell1 = row.insertCell(-1), // # cell2 = row.insertCell(-1), // Название cell3 = row.insertCell(-1), // Версия cell4 = row.insertCell(-1), // Дата обновления cell5 = row.insertCell(-1); // Скрыть row.className = 'myTr'; cell1.className = 'black-right-line one'; cell2.className = 'black-right-line'; cell3.className = 'black-right-line'; cell1.innerHTML = n; _cnt.innerHTML = count; cell2.innerHTML = app_name; cell3.innerHTML = ver; cell4.innerHTML = date; cell5.innerHTML = ''; } function addEvent() { var myTr = document.querySelectorAll('.myTr'); for(var i=0; i center'), userLink = document.getElementsByClassName('normalname'), link = [], // собираем все ссылки на профили ulLength = userLink.length; for (i=0; i]+>/g,'').replace(/(Город:)/, '$1 ').replace(/(юзера:)/, '$1 ').replace(/(рождения:)/, '$1 ') + '
'; } insertData(tt, i); } } }; xhr.onerror = function() { log('error'); alert('Ошибка'); }; xhr.onloadend = function(event) { //log('onloadend'); totalKB += (event.loaded/1024); // подсчет загруженного траффика totalMB += (event.loaded/1024/1024); if(++l === ulLength) { log('Скачано XHR-запросами:', totalKB.toFixed(2), 'КБ |', totalMB.toFixed(2), 'МБ'); // вывод объема скачанного } }; } //========================================================================== function insertData(data0, i) { div.innerHTML = data0; post[i].appendChild(div.cloneNode(true)); } } })();