PornoLab Hider-Fixer

Allows to hide unwanted categories everywhere and remember tracker search options, fixes some things

  1. // ==UserScript==
  2. // @name PornoLab Hider-Fixer
  3. // @namespace copyMister
  4. // @version 1.1
  5. // @description Allows to hide unwanted categories everywhere and remember tracker search options, fixes some things
  6. // @description:ru Позволяет скрывать ненужные категории отовсюду и запоминать настройки поиска по трекеру, исправляет некоторые вещи
  7. // @author copyMister
  8. // @license MIT
  9. // @match https://pornolab.net/forum/*
  10. // @match https://pornolab.cc/forum/*
  11. // @match https://pornolab.biz/forum/*
  12. // @match https://pornolab.lib/forum/*
  13. // @require https://cdn.jsdelivr.net/npm/@github/check-all@0.3.0/dist/check-all.umd.js
  14. // @icon https://www.google.com/s2/favicons?sz=64&domain=pornolab.net
  15. // @run-at document-body
  16. // @grant GM_addStyle
  17. // @grant GM_getValue
  18. // @grant GM_setValue
  19. // @homepageURL https://pornolab.net/forum/viewtopic.php?t=2714164
  20. // ==/UserScript==
  21.  
  22. var hiddenCats = JSON.parse(GM_getValue('hiddenCats', '[]'));
  23. var torrentCats = [36,38,60,284,508,509,512,553,555,883,902,903,997,1110,1111,1112,1124,1143,1296,1450,1451,1644,1646,1671,1673,1675,1676,1678,1679,1680,1681,1682,1683,1685,1689,1691,1692,1707,1711,1712,1713,1715,1718,1719,1720,1726,1728,1729,1731,1733,1734,1735,1740,1741,1750,1752,1754,1755,1756,1757,1758,1760,1762,1763,1765,1767,1768,1769,1775,1777,1780,1781,1784,1785,1787,1788,1789,1790,1791,1792,1793,1797,1798,1801,1802,1803,1804,1805,1815,1818,1819,1820,1823,1825,1826,1827,1828,1829,1830,1831,1834,1836,1837,1842,1843,1845,1846,1847,1849,1851,1853,1856,1857,1859,1861,1862,1863,1864,1865,1867,1868,1869,1870,1872,1873];
  24. var adsCats = [1753, 1761, 1821];
  25.  
  26. var menuFields = ['tracker_torrent', 'tracker_hide', 'tracker_less',
  27. 'tracker_params', 'tracker_forums', 'tracker_focus', 'tracker_second',
  28. 'link_exclude', 'link_forums', 'link_params',
  29. 'search_topics', 'search_msgs', 'search_hide',
  30. 'other_qsearch', 'other_buttons', 'mode_edit', 'mode_cats'];
  31.  
  32. var menuDefaults = [true, true, true,
  33. false, false, true, true,
  34. false, false, false,
  35. true, true, true,
  36. true, true, true, true];
  37.  
  38. var options = JSON.parse(GM_getValue('options', null));
  39. if (!options) {
  40. options = defaultOptions();
  41. }
  42.  
  43. function defaultOptions() {
  44. var obj = {};
  45. menuFields.forEach(function(item, ind) {
  46. obj[item] = menuDefaults[ind];
  47. });
  48. return obj;
  49. }
  50.  
  51. function saveOptions(custom) {
  52. GM_setValue('options', JSON.stringify(custom ? custom : options));
  53. }
  54.  
  55. function menuHtml(title, id) {
  56. var disabled = (id === 'link_exclude' && options.link_forums) ||
  57. (id === 'link_forums' && options.link_exclude);
  58.  
  59. return `<label><input id="hfix_${id}" type="checkbox"
  60. ${options[id] ? 'checked' : ''}
  61. ${disabled ? 'disabled' : ''}
  62. >${title}</label>`;
  63. }
  64.  
  65. function closeMenu() {
  66. document.querySelector('#hfix-btn').click();
  67. }
  68.  
  69. function addCheckbox(elem, isItem) {
  70. var forumId = parseInt(elem.lastElementChild.href.split('=')[1]);
  71. var isChecked = hiddenCats.includes(forumId);
  72.  
  73. elem.insertAdjacentHTML(
  74. 'beforeend',
  75. `<input class="hide-cbox" type="checkbox" title="Скрывать" ${isChecked ? 'checked' : ''}
  76. ${isItem ? 'data-check-all-item' : 'data-check-all'}>`
  77. );
  78. }
  79.  
  80. (function() {
  81. 'use strict';
  82.  
  83. var cssCode = [
  84. '#hfix-menu .menu-header { position: relative; }',
  85. '#hfix-menu .menu-btn { position: absolute; bottom: 3px; height: 19.33px; }',
  86. '#hfix-menu label { user-select: none; }',
  87. '#hfix-menu > table, #hfix-menu fieldset { border-collapse: collapse; height: 100%; }',
  88. '#hfix-reload { width: 50%; }',
  89. '#hfix-menu td { padding: 4px; }',
  90. '#hfix-res-opt { left: 3px; }',
  91. '#hfix-res-cat { right: 3px; }',
  92. '.forums tr[id^="f-"]:not(:has(a[href*="viewforum.php"])) { display: none; }',
  93. '#fs optgroup:not(:has(> option)) { display: none; }',
  94. ].join('\n');
  95.  
  96. if (options.mode_edit) {
  97. cssCode += [
  98. '.hide-cbox { float: left; margin: 2px 7px 0 0 !important; }',
  99. ':is(.forumlink, .subforums > .sf_title):has(> .hide-cbox:checked) { filter: grayscale(1); }',
  100. ].join('\n');
  101. }
  102.  
  103. if (options.other_buttons) {
  104. cssCode += [
  105. 'a.menu-root[href="#pg-jump"] ~ :is(b, a) { padding: 4px 7px; margin-right: 1px; border: 1px solid #969696; border-radius: 4px; text-decoration: none; }',
  106. 'a.menu-root[href="#pg-jump"] ~ :is(b, a:hover) { background-color: rgba(124, 190, 255, .3); text-decoration: none !important; }',
  107. '.bottom_info .nav, #pagination .nav { padding: 1em 6px; margin: 0; }',
  108. ].join('\n');
  109. }
  110.  
  111. GM_addStyle(cssCode);
  112.  
  113. $.holdReady(true);
  114.  
  115. document.addEventListener('DOMContentLoaded', function() {
  116. document.querySelector('#main-nav td').insertAdjacentHTML(
  117. 'beforeend',
  118. '<a href="#hfix-menu" id="hfix-btn" class="menu-root bold">Hider-Fixer</a>'
  119. );
  120.  
  121. document.body.insertAdjacentHTML(
  122. 'beforeend',
  123. `<div class="menu-sub" id="hfix-menu">
  124. <table>
  125. <tr>
  126. <th colspan="2" class="menu-header pad_6">Опции юзерскрипта Hider-Fixer
  127. <input id="hfix-res-opt" class="menu-btn" type="submit" value="🔄 опции" title="Вернуть опции по умолчанию">
  128. <input id="hfix-res-cat" class="menu-btn" type="submit" value="🔄 форумы" title="Снять отметки со всех форумов">
  129. </th>
  130. </tr>
  131. <tr><td rowspan="2"><fieldset>
  132. <legend>Трекер</legend>
  133. <div class="pad_4">
  134. ${menuHtml('Скрывать торренты', 'tracker_torrent')}
  135. ${menuHtml('Убирать скрытые форумы', 'tracker_hide')}
  136. ${menuHtml('Убирать лишние категории', 'tracker_less')}
  137. ${menuHtml('Запоминать выбранные форумы', 'tracker_forums')}
  138. ${menuHtml('Запоминать параметры', 'tracker_params')}
  139. ${menuHtml('Фокус на поле поиска', 'tracker_focus')}
  140. ${menuHtml('Вторая строка поиска', 'tracker_second')}
  141. </div>
  142. </fieldset></td>
  143. <td><fieldset>
  144. <legend>Ссылка на Трекер</legend>
  145. <div class="pad_4">
  146. ${menuHtml('Исключать скрытые форумы', 'link_exclude')}
  147. ${menuHtml('Добавлять выбранные форумы', 'link_forums')}
  148. ${menuHtml('Добавлять параметры', 'link_params')}
  149. </div>
  150. </fieldset></td></tr>
  151. <tr><td><fieldset>
  152. <legend>Поиск</legend>
  153. <div class="pad_4">
  154. ${menuHtml('Скрывать темы', 'search_topics')}
  155. ${menuHtml('Скрывать сообщения', 'search_msgs')}
  156. ${menuHtml('Убирать скрытые форумы', 'search_hide')}
  157. </div>
  158. </fieldset></td></tr>
  159. <tr><td><fieldset>
  160. <legend>Главная</legend>
  161. <div class="pad_4">
  162. ${menuHtml('Режим редактирования', 'mode_edit')}
  163. ${menuHtml('Скрывать форумы (вне режима)', 'mode_cats')}
  164. </div>
  165. </fieldset></td>
  166. <td><fieldset>
  167. <legend>Разное</legend>
  168. <div class="pad_4">
  169. ${menuHtml('Запоминать тип быстрого поиска', 'other_qsearch')}
  170. ${menuHtml('Номера страниц в виде кнопок', 'other_buttons')}
  171. </div>
  172. </fieldset></td></tr>
  173. <tr><th colspan="2" class="pad_4">
  174. <input id="hfix-reload" type="submit" value="Обновить страницу" title="Для применения опций">
  175. </th></tr>
  176. </table>
  177. </div>`
  178. );
  179.  
  180. document.querySelector('#hfix-res-opt').addEventListener('click', function() {
  181. saveOptions(defaultOptions());
  182. closeMenu();
  183. });
  184.  
  185. document.querySelector('#hfix-res-cat').addEventListener('click', function() {
  186. GM_setValue('hiddenCats', '[]');
  187. closeMenu();
  188. });
  189.  
  190. document.querySelector('#hfix-reload').addEventListener('click', function() {
  191. window.location.reload();
  192. });
  193.  
  194. menuFields.forEach(function(item) {
  195. document.querySelector(`#hfix_${item}`).addEventListener('change', function() {
  196. if (this.id === 'hfix_link_exclude') {
  197. document.querySelector(`#hfix_link_forums`).disabled = this.checked;
  198. } else if (this.id === 'hfix_link_forums') {
  199. document.querySelector(`#hfix_link_exclude`).disabled = this.checked;
  200. }
  201. options[item] = this.checked;
  202. saveOptions();
  203. });
  204. });
  205.  
  206. var quickSearch = document.querySelector('#search-action');
  207. if (quickSearch) {
  208. if (options.other_qsearch && options.qsearch_type) {
  209. quickSearch.value = options.qsearch_type;
  210. }
  211.  
  212. quickSearch.addEventListener('change', function() {
  213. options.qsearch_type = this.value;
  214. saveOptions();
  215. });
  216. }
  217.  
  218. var trackerLink = document.querySelector('#main-nav a[href^="tracker.php"]');
  219. if (trackerLink) {
  220. var href = 'tracker.php?';
  221.  
  222. if (options.link_exclude && hiddenCats.length > 0) {
  223. href += 'fn=1&f=';
  224. hiddenCats.forEach(function(fid) {
  225. if (torrentCats.includes(fid)) {
  226. href += fid + ',';
  227. }
  228. });
  229. } else if (options.link_forums && options.tracker_selected && options.tracker_selected.length > 0) {
  230. href += 'f=';
  231. options.tracker_selected.forEach(function(fid) {
  232. href += fid + ',';
  233. });
  234. }
  235.  
  236. if (options.link_params && options.tracker_options) {
  237. if (href.endsWith(',')) {
  238. href = href.slice(0, -1);
  239. href += '&';
  240. }
  241. Object.keys(options.tracker_options).forEach(function(key) {
  242. if (key === 'fn' && options.link_exclude) {
  243. return;
  244. }
  245. href += `${key}=${options.tracker_options[key]}&`;
  246. });
  247. }
  248.  
  249. href = href.slice(0, -1);
  250. trackerLink.href = href;
  251. }
  252.  
  253. if (document.querySelector('.forumlink')) {
  254. if (options.mode_edit) {
  255. document.querySelectorAll('.subforums > .sf_title').forEach(function(forum) {
  256. addCheckbox(forum, true);
  257. })
  258.  
  259. document.querySelectorAll('.forumlink').forEach(function(category) {
  260. if (category.firstElementChild.href.startsWith('https://pornolab')) {
  261. addCheckbox(category, false);
  262. checkAll.default(category.parentElement);
  263. }
  264. });
  265.  
  266. document.querySelectorAll('.hide-cbox').forEach(function(cbox) {
  267. cbox.addEventListener('change', function() {
  268. var forumId = parseInt(cbox.previousElementSibling.href.split('=')[1]);
  269. var found = hiddenCats.indexOf(forumId);
  270. if (this.checked && found === -1) {
  271. hiddenCats.push(forumId);
  272. }
  273. if (!this.checked && found !== -1) {
  274. hiddenCats.splice(found, 1);
  275. }
  276. GM_setValue('hiddenCats', JSON.stringify(hiddenCats));
  277. });
  278. });
  279. } else if (options.mode_cats) {
  280. hiddenCats.forEach(function(fid) {
  281. var forum = document.querySelector(`:is(.forumlink, .subforums) a[href$="f=${fid}"]`);
  282. if (forum) {
  283. if (forum.parentElement.classList.contains('forumlink')) {
  284. forum.closest('tr').remove();
  285. } else {
  286. forum.closest('span').remove();
  287. }
  288. }
  289. });
  290. }
  291. }
  292.  
  293. if (options.search_topics && document.querySelector('.topictitle') && !document.querySelector('.dl-chbox, #show-edit-btn')) {
  294. hiddenCats.forEach(function(fid) {
  295. var rows = document.querySelectorAll(`.forumline a[href$="f=${fid}"]`);
  296. if (rows.length > 0) {
  297. rows.forEach(function(td) {
  298. td.closest('tr').remove();
  299. });
  300. }
  301. });
  302. }
  303.  
  304. if (options.search_msgs && document.querySelector('.cat.nav')) {
  305. hiddenCats.forEach(function(fid) {
  306. var cats = document.querySelectorAll(`.cat.nav > a[href$="f=${fid}"]`);
  307. if (cats.length > 0) {
  308. cats.forEach(function(cat) {
  309. var root = cat.closest('tr');
  310. var msg = root.nextElementSibling;
  311. while (msg.hasAttribute('class')) {
  312. var nextMsg = msg.nextElementSibling;
  313. msg.remove();
  314. msg = nextMsg;
  315. }
  316. root.remove();
  317. });
  318. }
  319. });
  320. }
  321.  
  322. if (options.search_hide && document.querySelector('form[action="search.php"] #fs')) {
  323. document.querySelectorAll('select[name="f[]"] > optgroup > option[id^="fs-"]').forEach(function(opt) {
  324. if (hiddenCats.concat(adsCats).includes(parseInt(opt.value))) {
  325. opt.remove();
  326. }
  327. });
  328. }
  329.  
  330. var trackerForm = document.querySelector('#tr-form');
  331. if (trackerForm) {
  332. if (options.tracker_torrent) {
  333. document.querySelectorAll('#tor-tbl .gen.f').forEach(function(link) {
  334. if (hiddenCats.includes(parseInt(link.href.split('=')[1]))) {
  335. link.closest('tr').remove();
  336. }
  337. });
  338. }
  339.  
  340. if (options.tracker_less) {
  341. document.querySelectorAll('#fs-main > optgroup:not([label$="Releases"])').forEach(function(cat) {
  342. cat.remove();
  343. });
  344. }
  345.  
  346. if (options.tracker_hide) {
  347. document.querySelectorAll('#fs-main option').forEach(function(opt) {
  348. if (hiddenCats.includes(parseInt(opt.value))) {
  349. opt.remove();
  350. }
  351. });
  352. }
  353.  
  354. if (options.tracker_forums) {
  355. if (options.tracker_selected && options.tracker_selected.length > 0) {
  356. document.querySelectorAll('#fs-main option').forEach(function(opt) {
  357. opt.selected = options.tracker_selected.includes(opt.value);
  358. });
  359. }
  360.  
  361. trackerForm.addEventListener('submit', function() {
  362. options.tracker_selected = [];
  363. document.querySelectorAll('#fs-main option').forEach(function(opt) {
  364. if (opt.selected && opt.value !== '-1' && torrentCats.includes(parseInt(opt.value))) {
  365. options.tracker_selected.push(opt.value);
  366. }
  367. });
  368. saveOptions();
  369. });
  370. }
  371.  
  372. if (options.tracker_params) {
  373. var inputs = '.fieldsets fieldset:not([id="fs"]) :is(input, select)';
  374.  
  375. if (options.tracker_options) {
  376. document.querySelectorAll(inputs).forEach(function(elem) {
  377. if (options.tracker_options[elem.name]) {
  378. if (elem.type === 'select-one') {
  379. elem.value = options.tracker_options[elem.name];
  380. } else if (elem.value === options.tracker_options[elem.name]) {
  381. elem.checked = true;
  382. }
  383. }
  384. });
  385. }
  386.  
  387. trackerForm.addEventListener('submit', function() {
  388. options.tracker_options = {};
  389. document.querySelectorAll(inputs).forEach(function(elem) {
  390. if (!['hidden', 'text', 'search'].includes(elem.type) && !elem.disabled) {
  391. if (elem.type === 'select-one' || elem.checked) {
  392. options.tracker_options[elem.name] = elem.value;
  393. }
  394. }
  395. });
  396. saveOptions();
  397. });
  398. }
  399.  
  400. var titleSearch = document.querySelector('#title-search');
  401. if (options.tracker_focus) {
  402. titleSearch.focus();
  403. }
  404.  
  405. if (options.tracker_second) {
  406. var secondValue = options.second_search ?? '';
  407.  
  408. if (secondValue) {
  409. titleSearch.value = titleSearch.value.replace(secondValue, '');
  410. }
  411.  
  412. titleSearch.parentElement.insertAdjacentHTML(
  413. 'afterend',
  414. `<p class="input">
  415. <input id="second-search" style="width: 95%;" type="search" size="50" value="${secondValue.replaceAll('"', '&quot;')}">
  416. <a id="second-icon" class="med" href="#" style="font-size: 0.9rem;" title="Вторая строка с запоминанием и автоматической подстановкой; нажмите для вставки заготовки">
  417. <i class="fas fa-question-circle"></i>
  418. </a>
  419. </p>`
  420. );
  421.  
  422. var secondSearch = document.querySelector('#second-search');
  423. document.querySelector('#second-icon').addEventListener('click', function(e) {
  424. e.preventDefault();
  425. secondSearch.focus();
  426. secondSearch.value = '-transex* -transsex* -=trans -shemale -scat -defecation -cbt -strapon -="strap-on" -yaoi -futanari -=futa';
  427. });
  428.  
  429. trackerForm.addEventListener('submit', function(e) {
  430. e.preventDefault();
  431. secondSearch.value = secondSearch.value.trim();
  432.  
  433. if (secondSearch.value) {
  434. titleSearch.value = titleSearch.value.trim() + ' ' + secondSearch.value;
  435. }
  436.  
  437. options.second_search = secondSearch.value;
  438. saveOptions();
  439. secondSearch.value = '';
  440. trackerForm.submit();
  441. });
  442. }
  443. }
  444.  
  445. $.holdReady(false);
  446. });
  447. })();