// ==UserScript== // @name AdvForum // @namespace https://github.com/MyRequiem/comfortablePlayingInGW // @description Звуковые и визуальные оповещения при появлении новых тем или смене верхней темы, новых сообщений в темах, скрытие закрытых тем и прикрепленок, отметка закрытых тем, скрытие ненужных веток форума. // @id comfortablePlayingInGW@MyRequiem // @updateURL https://raw.githubusercontent.com/MyRequiem/comfortablePlayingInGW/master/separatedScripts/AdvForum/advForum.meta.js // @downloadURL https://raw.githubusercontent.com/MyRequiem/comfortablePlayingInGW/master/separatedScripts/AdvForum/advForum.user.js // @include https://*gwars*/threads.php?fid=* // @include https://*gwars*/messages.php?fid=* // @include https://*gwars*/forum.php // @grant none // @license MIT // @version 2.34-120522 // @author MyRequiem [https://www.gwars.io/info.php?id=2095458] // ==/UserScript== /*global unsafeWindow */ /*jslint browser: true, maxlen: 80, regexp: true, vars: true, plusplus: true, continue: true, nomen: true, devel: true */ /*eslint-env browser */ /*eslint no-useless-escape: 'warn', linebreak-style: ['error', 'unix'], quotes: ['error', 'single'], semi: ['error', 'always'], eqeqeq: 'error', curly: 'error' */ /*jscs:disable requireMultipleVarDecl, requireVarDeclFirst */ /*jscs:disable disallowKeywords, disallowDanglingUnderscores */ /*jscs:disable validateIndentation */ (function () { 'use strict'; /** * @class General * @constructor */ var General = function () { /** * @property root * @type {Object} */ this.root = this.getRoot(); /** * @property doc * @type {Object} */ this.doc = this.root.document; /** * @property loc * @type {String} */ this.loc = this.root.location.href; /** * @property st * @type {Object} */ this.st = this.root.localStorage; /** * @property STORAGENAME * @type {String} */ this.STORAGENAME = 'advForum'; /** * @property imgPath * @type {String} */ this.imgPath = 'https://raw.githubusercontent.com/MyRequiem/' + 'comfortablePlayingInGW/master/imgs/'; /** * @property myID * @type {String} */ this.myID = /(^|;) ?uid=([^;]*)(;|$)/.exec(this.doc.cookie)[2]; /** * @property domain * @type {String} */ this.domain = this.doc.domain; }; /** * @lends General.prototype */ General.prototype = { /** * @method getRoot * @return {Object} */ getRoot: function () { var rt = typeof unsafeWindow; return rt !== 'undefined' ? unsafeWindow : window; }, /** * @method setData * @param {Array} data */ setData: function (data) { this.st.setItem(this.STORAGENAME, data.join('|')); }, /** * @method getData * @return {Array} */ getData: function () { var stData = this.st.getItem(this.STORAGENAME); if (stData) { return stData.split('|'); } /** localStorage * [0] - отмечать закрытые темы * [1] - звук при появлении новой темы * [2] - интервал перезагрузки страниц с темами форума (сек) * [3] - не показывать закрытые темы * [4] - не показывать прикрепленки * [5] - ветки, где скрипт работать не будет * [6] - список включения/отключения показа форумов * [7] - данные веток форума: * { * 'fid': { * 'tid': { * d: str // дата первого просмотра темы * l: str // id последнего сообщения * с: str // номер последнего сообщения * }, * ... * }, * ... * } * [8] - {'fid': id_последней темы, ...} */ stData = ['1', '', '', '', '', '1,5,7,11,15,24,34,35,36,37,' + '41,42,44,46,47,48,54', '1,1,1,1,1,1,1,1,1,1,1,1,' + '1,1,1,1,1,1,1,1,1,1,1', '{}', '{}']; this.setData(stData); return stData; }, /** * @method $ * @param {String} id * @return {HTMLElement|null} */ $: function (id) { return this.doc.querySelector('#' + id); } }; var general = new General(); /** * @class PlaySound * @constructor */ var PlaySound = function () { /** * @method init * @param {int|String} sound */ this.init = function (sound) { if (sound && sound !== '0') { var audio = general.$('cpingw_audio'); if (!audio) { audio = general.doc.createElement('audio'); audio.setAttribute('id', 'cpingw_audio'); var divAudio = general.doc.createElement('div'); divAudio.setAttribute('style', 'display: none;'); divAudio.appendChild(audio); general.doc.body.appendChild(divAudio); } audio.volume = 0.3; audio.src = 'https://raw.githubusercontent.com/MyRequiem/' + 'comfortablePlayingInGW/master/sounds/' + sound + '.ogg'; // noinspection JSIgnoredPromiseFromCall audio.play(); } }; }; /** * @class GetSelectSound * @constructor */ var GetSelectSound = function () { /** * @method init * @param {String} id * @return {String} */ this.init = function (id) { var sounds = [ 'Без звука', 'Перезарядка', 'Выстрел дробовика', 'Открытие двери', 'Взрыв бочки', 'Выстрел BFG', 'Радио-зуммер', 'Подтверждение цели', 'Ion Cannon Ready!', 'Select target!', 'Звук тревоги', 'I`m alive!', 'Орки смеются', 'Unholy Armor', 'We`ve been attacked!', 'Кот мяукает', 'Кот мяукает #2', 'Take cover!', 'Stupid!', 'Hello!', 'hehehehe!', 'Chimes', 'Ding', 'Ошибка', 'Отказ оборудования', 'А, вот эти ребята', 'Не-не-не-не!', 'нет, Девид Блейн, нет!', 'Я делаю особую магию ', 'Prepare for battle!', 'Pick up your weapons' ], str = ' ' + ''; }; }; /** * @class AdvForum * @constructor */ var AdvForum = function () { /** * @property lifeTime * @type {int} */ this.lifeTime = 3 * 24 * 60 * 60 * 1000; /** * @property parseLoc * @type {Array|null} */ this.parseLoc = /\?fid=(\d+)(&tid=(\d+))?/.exec(general.loc); /** * @method getForumTable * @return {HTMLElement} */ this.getForumTable = function () { return general.doc.querySelector('center+br+center+table'); }; /** * @method processingThemesList */ this.processingThemesList = function () { var table = this.getForumTable(), tableContent = table.innerHTML, fid = this.toHex(this.parseLoc[1]); // настройки this.setSettins(table, fid); var stData = general.getData(), json = JSON.parse(stData[7]), json1 = JSON.parse(stData[8]), trs = table.querySelectorAll('tr'), lastTheme = true, themeDataStorage, themeLink, imgClosed, imgEyes, tid, i; for (i = 1; i < trs.length; i++) { trs[i].style.display = ''; themeLink = trs[i].querySelector('td>a'); // прикрепленки пропускаем или скрываем, не отслеживаем if (themeLink.firstElementChild) { if (stData[4]) { trs[i].style.display = 'none'; } continue; } tid = this.toHex(+/&tid=(\d+)/.exec(themeLink.href)[1]); // верхняя тема на первой странице if (/\?fid=\d+(&page_id=0)?$/.test(general.loc) && lastTheme) { lastTheme = false; // id первой темы в хранилище не равен id первой // темы на странице - играем звук, запоминаем тему if (json1[fid] !== tid) { // если не первый раз заходим в данную ветку if (json1[fid]) { new PlaySound().init(stData[1]); } json1[fid] = tid; stData[8] = JSON.stringify(json1); general.setData(stData); } } // закрытые темы if (/тема закрыта/.test(trs[i]. querySelector('td:last-child').innerHTML)) { // скрытие закрытой темы if (stData[3]) { trs[i].style.display = 'none'; continue; } // отметка скрытой темы if (stData[0]) { imgClosed = general.doc.createElement('img'); imgClosed.setAttribute('style', 'height: 10px; ' + 'width: 10px; margin-right: 3px;'); imgClosed.title = 'Тема закрыта'; imgClosed.src = general.imgPath + 'AdvForum/closed.png'; themeLink.parentNode.insertBefore(imgClosed, themeLink); } } // есть отслеживаемые темы в текущей ветке форума if (json[fid]) { themeDataStorage = json[fid][tid]; // текущая тема отслеживается if (themeDataStorage) { imgEyes = general.doc.createElement('img'); imgEyes.setAttribute('style', 'margin-right: ' + '3px; height: 12px; width: 12px; cursor: ' + 'pointer;'); imgEyes.setAttribute('title', 'Отменить отслеживание темы'); themeLink.parentNode. insertBefore(imgEyes, themeLink); imgEyes.src = general.imgPath + 'AdvForum/'; imgEyes.addEventListener('click', this.cleanStorage(fid, tid, tableContent), false); // появилось новое сообщение if (themeDataStorage.c !== /\d+/.exec(trs[i]. querySelectorAll('td')[2].innerHTML)[0]) { imgEyes.src += 'eyesPlus.png'; } else { imgEyes.src += 'eyes.png'; } } } } var tm = +stData[2]; if (tm) { general.root.setTimeout(function () { general.root.location.reload(); }, tm * 1000); } }; /** * @method cleanStorage * @param {String} f * @param {String} t * @param {String} tableHTML * @return {Function} */ this.cleanStorage = function (f, t, tableHTML) { var _this = this; return function () { var stData = general.getData(), json = JSON.parse(stData[7]), tmp = {}, fid, tid; for (fid in json) { if (json.hasOwnProperty(fid)) { // удаляется ветка форума if (f && !t && fid === f && general.root. confirm('Удалить все данные ветки?')) { continue; } for (tid in json[fid]) { if (json[fid].hasOwnProperty(tid)) { // удаляется тема форума if (f && t && fid === f && t === tid && general.root. confirm('Не отслеживать тему?')) { continue; } if (_this.toDec(json[fid][tid].d) + _this.lifeTime > new Date().getTime()) { if (!tmp[fid]) { tmp[fid] = {}; } tmp[fid][tid] = json[fid][tid]; } } } } } stData[7] = JSON.stringify(tmp); general.setData(stData); if (tableHTML) { _this.getForumTable().innerHTML = tableHTML; _this.processingThemesList(); } }; }; /** * @method toDec * @param {String} hex * @return {int} */ this.toDec = function (hex) { return parseInt(hex, 16); }; /** * @method toHex * @param {int} dec * @return {String} */ this.toHex = function (dec) { return Number(dec).toString(16); }; /** * @method showHideForum */ this.showHideForum = function () { return function () { var stData = general.getData(), f = stData[6].split(','), _this = this, ind = /\d+/.exec(_this.id)[0]; f[ind] = _this.checked ? '1' : ''; stData[6] = f.join(','); general.setData(stData); }; }; /** * @method setSettins * @param {HTMLElement} table * @param {String} fid */ this.setSettins = function (table, fid) { // кнопка настройки var tableContent = table.innerHTML, imgSettins = general.doc.createElement('img'); imgSettins.src = 'https://images.' + general.domain.replace('www.', '') + '/i/home/properties.gif'; imgSettins.setAttribute('style', 'cursor: pointer; ' + 'margin-left: 10px;'); imgSettins.setAttribute('title', 'Настройки'); // кнопка сброса всех данных ветки var imgReset = general.doc.createElement('img'); imgReset.src = 'https://images.' + general.domain.replace('www.', '') + '/i/home/questlog.gif'; imgReset.setAttribute('style', 'cursor: pointer; ' + 'margin-left: 10px;'); imgReset.setAttribute('title', 'Сбросить все данные ветки'); imgReset.addEventListener('click', this.cleanStorage(fid, '', tableContent), false); var td = table.querySelector('td'); td.appendChild(imgSettins); td.appendChild(imgReset); var _this = this; imgSettins.addEventListener('click', function () { var themes = [ ['Официальные объявления', '1'], ['Вопросы и помощь в игре', '49'], ['Общий Форум', '27'], ['Идеи и предложения', '2'], ['Форум для неигровых тем', '22'], ['Клуб Нытиков', '55'], ['Объявления синдикатов', '38'], ['Вступлю в синдикат', '56'], ['Конкурсы', '3'], ['Благодарности и поздравления', '4'], ['Offline встречи', '6'], ['Креатив', '23'], ['Официальные объявления налоговой инспекции', '24'], ['Официальные объявления суда', '11'], ['Зал суда', '12'], ['Зал бракосочетаний', '29'], ['Дворец Бракосочетания', '50'], ['Техническая поддержка', '17'], ['Баги и глюки (общее)', '18'], ['Баги и глюки (финансовые вопросы)', '19'], ['Проблемы с боями', '20'], ['Проблемы с персонажами', '33'], ['Respect Hill', '25'] ], stData = general.getData(), f = stData[6].split(','), str = '', i; for (i = 0; i < themes.length; i++) { str += '
Отмечать закрытые ' + 'темы | ' + ' |
Не показывать закрытые темы | ' + '|
Не показывать прикрепленки | ' + ' |
Интервал перезагрузки страниц с темами форума ' + '(> 4) | сек (0 или пустое ' + 'поле - без перезагрузки) |
Звук при ' + 'появлении новой темы | ' + new GetSelectSound().init('sound') + ' |
Номера исключенных веток форума ' + '(параметр fid=xxx в ссылке на форум) | ' + ' |
<< Назад | |
' + 'Показывать ветки форума на ' + 'этой странице: |