Pornolab Enhancer

Improves User Experience

  1. // ==UserScript==
  2. // @name Pornolab Enhancer
  3. // @version 1.12.3
  4. // @description Improves User Experience
  5. // @namespace https://github.com/nikolay-borzov
  6. // @author nikolay-borzov
  7. // @license MIT
  8. // @icon https://raw.githubusercontent.com/nikolay-borzov/user-scripts/master/pornolab-enhancer/resources/icon.png
  9. // @homepageURL https://github.com/nikolay-borzov/user-scripts
  10. // @homepage https://github.com/nikolay-borzov/user-scripts
  11. // @supportURL https://github.com/nikolay-borzov/user-scripts/issues
  12. // @match *://pornolab.net/*
  13. // @match *://pornolab.lib/*
  14. // @noframes
  15. // @run-at document-start
  16. // @grant GM_addStyle
  17. // @grant GM_xmlhttpRequest
  18. // @grant GM.xmlHttpRequest
  19. // @grant GM_setValue
  20. // @grant GM.setValue
  21. // @grant GM_getValue
  22. // @grant GM.getValue
  23. // ==/UserScript==
  24.  
  25. ;(function () {
  26. const GM_METHOD_MAP = {
  27. GM_addStyle: 'addStyle',
  28. GM_deleteValue: 'deleteValue',
  29. GM_getResourceURL: 'getResourceUrl',
  30. GM_getValue: 'getValue',
  31. GM_listValues: 'listValues',
  32. GM_notification: 'notification',
  33. GM_openInTab: 'openInTab',
  34. GM_registerMenuCommand: 'registerMenuCommand',
  35. GM_setClipboard: 'setClipboard',
  36. GM_setValue: 'setValue',
  37. GM_xmlhttpRequest: 'xmlHttpRequest',
  38. GM_getResourceText: 'getResourceText',
  39. }
  40.  
  41. function getGM4PolyfilledMethod(methodName) {
  42. const gm4MethodName = GM_METHOD_MAP[methodName]
  43.  
  44. if (GM !== undefined && gm4MethodName in GM) {
  45. return GM[gm4MethodName]
  46. } else if (methodName in window) {
  47. return function (...arguments_) {
  48. return new Promise((resolve, reject) => {
  49. try {
  50. // eslint-disable-next-line unicorn/no-null
  51. resolve(window[methodName].apply(null, arguments_))
  52. } catch (error) {
  53. reject(error)
  54. }
  55. })
  56. }
  57. }
  58.  
  59. return async function () {
  60. throw new Error(`Method ${methodName} is not available. Missing @grant?`)
  61. }
  62. }
  63.  
  64. let addStyle = (css) => {
  65. addStyle =
  66. 'GM_addStyle' in window
  67. ? GM_addStyle // eslint-disable-line camelcase
  68. : (css) => {
  69. const head = document.querySelectorAll('head')[0]
  70. const style = document.createElement('style')
  71.  
  72. style.innerHTML = css
  73. head.append(style)
  74.  
  75. return style
  76. }
  77.  
  78. return addStyle(css)
  79. }
  80.  
  81. const store = {
  82. getValue: (name, defaultValue) => {
  83. store.getValue = getGM4PolyfilledMethod('GM_getValue')
  84.  
  85. return store.getValue(name, defaultValue)
  86. },
  87.  
  88. setValue: (name, value) => {
  89. store.setValue = getGM4PolyfilledMethod('GM_setValue')
  90.  
  91. return store.setValue(name, value)
  92. },
  93.  
  94. async patch(name, value) {
  95. const oldValue = await store.getValue(name)
  96.  
  97. store.setValue(name, {
  98. ...oldValue,
  99. ...value,
  100. })
  101. },
  102. }
  103.  
  104. /* global Bliss */
  105. // eslint-disable-next-line -- blissfuljs v1.0.6 Shy https://blissfuljs.com/
  106. !function(){function e(o,i,t){return i=void 0===i?1:i,(t=t||i+1)-i<=1?function(){if(arguments.length<=i||"string"===c.type(arguments[i]))return o.apply(this,arguments);var t,e,n=arguments[i];for(e in n){var r=Array.prototype.slice.call(arguments);r.splice(i,1,e,n[e]),t=o.apply(this,r);}return t}:e(e(o,i+1,t),i,t-1)}function s(e,n,t){var r=a(t);if("string"===r){var o=Object.getOwnPropertyDescriptor(n,t);!o||o.writable&&o.configurable&&o.enumerable&&!o.get&&!o.set?e[t]=n[t]:(delete e[t],Object.defineProperty(e,t,o));}else if("array"===r)t.forEach(function(t){t in n&&s(e,n,t);});else for(var i in n)t&&("regexp"===r&&!t.test(i)||"function"===r&&!t.call(n,i))||s(e,n,i);return e}function a(t){if(null===t)return "null";if(void 0===t)return "undefined";var e=(Object.prototype.toString.call(t).match(/^\[object\s+(.*?)\]$/)[1]||"").toLowerCase();return "number"==e&&isNaN(t)?"nan":e}var c=self.Bliss=s(function(t,e){return 2==arguments.length&&!e||!t?null:"string"===c.type(t)?(e||document).querySelector(t):t||null},self.Bliss);s(c,{extend:s,overload:e,type:a,property:c.property||"_",listeners:new(self.WeakMap?WeakMap:Map),original:{addEventListener:(self.EventTarget||Node).prototype.addEventListener,removeEventListener:(self.EventTarget||Node).prototype.removeEventListener},sources:{},noop:function(){},$:function(t,e){return t instanceof Node||t instanceof Window?[t]:2!=arguments.length||e?Array.prototype.slice.call("string"==typeof t?(e||document).querySelectorAll(t):t||[]):[]},defined:function(){for(var t=0;t<arguments.length;t++)if(void 0!==arguments[t])return arguments[t]},create:function(t,e){return t instanceof Node?c.set(t,e):(1===arguments.length&&(e="string"===c.type(t)?{}:(t=(e=t).tag,c.extend({},e,function(t){return "tag"!==t}))),c.set(document.createElement(t||"div"),e))},each:function(t,e,n){for(var r in n=n||{},t)n[r]=e.call(t,r,t[r]);return n},ready:function(e,t,n){if("function"!=typeof e||t||(t=e,e=void 0),e=e||document,t&&("loading"!==e.readyState?t():c.once(e,"DOMContentLoaded",function(){t();})),!n)return new Promise(function(t){c.ready(e,t,!0);})},Class:function(t){var e,n,r=["constructor","extends","abstract","static"].concat(Object.keys(c.classProps)),o=t.hasOwnProperty("constructor")?t.constructor:c.noop;2==arguments.length?(n=arguments[0],t=arguments[1]):((n=function(){if(this.constructor.__abstract&&this.constructor===n)throw new Error("Abstract classes cannot be directly instantiated.");n.super&&!e&&n.super.apply(this,arguments),o.apply(this,arguments);}).super=t.extends||null,!n.super||(e=0===(n.super+"").indexOf("class "))&&console.error(`You are using $.Class() to create a fake function-based class that extends a native JS class. This will not work. You should convert your code to use native JS classes too. You can still pass a class into $.Class() to use its conveniences.`),n.prototype=c.extend(Object.create(n.super?n.super.prototype:Object),{constructor:n}),n.prototype.super=n.super?n.super.prototype:null,n.__abstract=!!t.abstract);function i(t){return this.hasOwnProperty(t)&&-1===r.indexOf(t)}if(t.static)for(var s in c.extend(n,t.static,i),c.classProps)s in t.static&&c.classProps[s](n,t.static[s]);for(s in c.extend(n.prototype,t,i),c.classProps)s in t&&c.classProps[s](n.prototype,t[s]);return n},classProps:{lazy:e(function(t,e,n){return Object.defineProperty(t,e,{get:function(){var t=n.call(this);return Object.defineProperty(this,e,{value:t,configurable:!0,enumerable:!0,writable:!0}),t},set:function(t){Object.defineProperty(this,e,{value:t,configurable:!0,enumerable:!0,writable:!0});},configurable:!0,enumerable:!0}),t}),live:e(function(t,n,r){return "function"===c.type(r)&&(r={set:r}),Object.defineProperty(t,n,{get:function(){var t=this["_"+n],e=r.get&&r.get.call(this,t);return void 0!==e?e:t},set:function(t){var e=this["_"+n],e=r.set&&r.set.call(this,t,e);this["_"+n]=void 0!==e?e:t;},configurable:r.configurable,enumerable:r.enumerable}),t})},include:function(){var n=arguments[arguments.length-1],t=2===arguments.length&&arguments[0],r=document.createElement("script");return t?Promise.resolve():new Promise(function(t,e){c.set(r,{async:!0,onload:function(){t(r),r.parentNode&&r.parentNode.removeChild(r);},onerror:function(){e(r);},src:n,inside:document.head});})},load:function t(r,e){e=e?new URL(e,location.href):location.href,r=new URL(r,e);e=t.loading=t.loading||{};return e[r+""]||(/\.css$/.test(r.pathname)?e[r+""]=new Promise(function(t,e){var n=c.create("link",{href:r,rel:"stylesheet",inside:document.head,onload:function(){t(n);},onerror:function(){e(n);}});}):e[r+""]=c.include(r))},fetch:function(t,e){if(!t)throw new TypeError("URL parameter is mandatory and cannot be "+t);var n,r=s({url:new URL(t,location),data:"",method:"GET",headers:{},xhr:new XMLHttpRequest},e);for(n in r.method=r.method.toUpperCase(),c.hooks.run("fetch-args",r),"GET"===r.method&&r.data&&(r.url.search+=r.data),document.body.setAttribute("data-loading",r.url),r.xhr.open(r.method,r.url.href,!1!==r.async,r.user,r.password),e)if("upload"===n)r.xhr.upload&&"object"==typeof e[n]&&c.extend(r.xhr.upload,e[n]);else if(n in r.xhr)try{r.xhr[n]=e[n];}catch(t){self.console&&console.error(t);}var o,t=Object.keys(r.headers).map(function(t){return t.toLowerCase()});for(o in "GET"!==r.method&&-1===t.indexOf("content-type")&&r.xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"),r.headers)void 0!==r.headers[o]&&r.xhr.setRequestHeader(o,r.headers[o]);t=new Promise(function(t,e){r.xhr.onload=function(){document.body.removeAttribute("data-loading"),0===r.xhr.status||200<=r.xhr.status&&r.xhr.status<300||304===r.xhr.status?t(r.xhr):e(c.extend(Error(r.xhr.statusText),{xhr:r.xhr,get status(){return this.xhr.status}}));},r.xhr.onerror=function(){document.body.removeAttribute("data-loading"),e(c.extend(Error("Network Error"),{xhr:r.xhr}));},r.xhr.ontimeout=function(){document.body.removeAttribute("data-loading"),e(c.extend(Error("Network Timeout"),{xhr:r.xhr}));},r.xhr.send("GET"===r.method?null:r.data);});return t.xhr=r.xhr,t},value:function(t){var e="string"!=typeof t;return c.$(arguments).slice(+e).reduce(function(t,e){return t&&t[e]},e?t:self)}}),c.Hooks=new c.Class({add:function(t,e,n){if("string"==typeof arguments[0])(Array.isArray(t)?t:[t]).forEach(function(t){this[t]=this[t]||[],e&&this[t][n?"unshift":"push"](e);},this);else for(var t in arguments[0])this.add(t,arguments[0][t],e);},run:function(t,e){this[t]=this[t]||[],this[t].forEach(function(t){t.call(e&&e.context?e.context:e,e);});}}),c.hooks=new c.Hooks;c.property;c.Element=function(t){this.subject=t,this.data={},this.bliss={};},c.Element.prototype={set:e(function(t,e){t in c.setProps?c.setProps[t].call(this,e):t in this?this[t]=e:this.setAttribute(t,e);},0),transition:function(o,i){return new Promise(function(t,e){var n,r;"transition"in this.style&&0!==i?(n=c.extend({},this.style,/^transition(Duration|Property)$/),c.style(this,{transitionDuration:(i||400)+"ms",transitionProperty:Object.keys(o).join(", ")}),c.once(this,"transitionend",function(){clearTimeout(r),c.style(this,n),t(this);}),r=setTimeout(t,i+50,this),c.style(this,o)):(c.style(this,o),t(this));}.bind(this))},fire:function(t,e){var n=document.createEvent("HTMLEvents");return n.initEvent(t,!0,!0),this.dispatchEvent(c.extend(n,e))},bind:e(function(t,n){var e;1<arguments.length&&("function"===c.type(n)||n.handleEvent)&&(e=n,(n="object"===c.type(arguments[2])?arguments[2]:{capture:!!arguments[2]}).callback=e);var r=c.listeners.get(this)||{};t.trim().split(/\s+/).forEach(function(t){var e;-1<t.indexOf(".")&&(e=(t=t.split("."))[1],t=t[0]),r[t]=r[t]||[],0===r[t].filter(function(t){return t.callback===n.callback&&t.capture==n.capture}).length&&r[t].push(c.extend({className:e},n)),c.original.addEventListener.call(this,t,n.callback,n);},this),c.listeners.set(this,r);},0),unbind:e(function(t,i){var e;i&&("function"===c.type(i)||i.handleEvent)&&(e=i,i=arguments[2]),(i=(i="boolean"==c.type(i)?{capture:i}:i)||{}).callback=i.callback||e;var s=c.listeners.get(this);(t||"").trim().split(/\s+/).forEach(function(t){var e,n;if(-1<t.indexOf(".")&&(e=(t=t.split("."))[1],t=t[0]),!s)return t&&i.callback?c.original.removeEventListener.call(this,t,i.callback,i.capture):void 0;for(n in s)if(!t||n===t)for(var r,o=0;r=s[n][o];o++)e&&e!==r.className||i.callback&&i.callback!==r.callback||!!i.capture!=!!r.capture&&(t||i.callback||void 0!==i.capture)||(s[n].splice(o,1),c.original.removeEventListener.call(this,n,r.callback,r.capture),o--);},this);},0),when:function(r,o){var t=this;return new Promise(function(n){t.addEventListener(r,function t(e){o&&!o.call(this,e)||(this.removeEventListener(r,t),n(e));});})},toggleAttribute:function(t,e,n){(n=arguments.length<3?null!==e:n)?this.setAttribute(t,e):this.removeAttribute(t);}},c.setProps={style:function(t){for(var e in t)e in this.style?this.style[e]=t[e]:this.style.setProperty(e,t[e]);},attributes:function(t){for(var e in t)this.setAttribute(e,t[e]);},properties:function(t){c.extend(this,t);},events:function(t){if(1!=arguments.length||!t||!t.addEventListener)return c.bind.apply(this,[this].concat(c.$(arguments)));var e,n=this;if(c.listeners){var r,o=c.listeners.get(t);for(r in o)o[r].forEach(function(t){c.bind(n,r,t.callback,t.capture);});}for(e in t)0===e.indexOf("on")&&(this[e]=t[e]);},once:e(function(t,e){function n(){return c.unbind(r,t,n),e.apply(r,arguments)}var r=this;c.bind(this,t,n,{once:!0});},0),delegate:e(function(t,e,n){c.bind(this,t,function(t){t.target.closest(e)&&n.call(this,t);});},0,2),contents:function(t){!t&&0!==t||(Array.isArray(t)?t:[t]).forEach(function(t){var e=c.type(t);/^(string|number)$/.test(e)?t=document.createTextNode(t+""):"object"===e&&(t=c.create(t)),t instanceof Node&&this.appendChild(t);},this);},inside:function(t){t&&t.appendChild(this);},before:function(t){t&&t.parentNode.insertBefore(this,t);},after:function(t){t&&t.parentNode.insertBefore(this,t.nextSibling);},start:function(t){t&&t.insertBefore(this,t.firstChild);},around:function(t){t&&t.parentNode&&c.before(this,t),this.appendChild(t);}},c.Array=function(t){this.subject=t;},c.Array.prototype={all:function(t){var e=c.$(arguments).slice(1);return this[t].apply(this,e)}},c.add=e(function(r,n,o,t){o=c.extend({$:!0,element:!0,array:!0},o),"function"==c.type(n)&&(!o.element||r in c.Element.prototype&&t||(c.Element.prototype[r]=function(){return this.subject&&c.defined(n.apply(this.subject,arguments),this.subject)}),!o.array||r in c.Array.prototype&&t||(c.Array.prototype[r]=function(){var e=arguments;return this.subject.map(function(t){return t&&c.defined(n.apply(t,e),t)})}),o.$&&(c.sources[r]=c[r]=n,(o.array||o.element)&&(c[r]=function(){var t=[].slice.apply(arguments),e=t.shift(),n=o.array&&Array.isArray(e)?"Array":"Element";return c[n].prototype[r].apply({subject:e},t)})));},0),c.add(c.Array.prototype,{element:!1}),c.add(c.Element.prototype),c.add(c.setProps),c.add(c.classProps,{element:!1,array:!1});var n=document.createElement("_");c.add(c.extend({},HTMLElement.prototype,function(t){return "function"===c.type(n[t])}),null,!0);}();
  107. // eslint-disable-next-line
  108. const $ = Bliss;
  109. // eslint-disable-next-line
  110. Bliss.$;
  111.  
  112. const css_248z$4 =
  113. ':root{--color-active:#345da4;--color-active-1:#930;--color-border:#cacaca;--color-border-1:#92a3a4;--color-bkg:#efefef;--color-bkg-1:#e7e7e7;--color-bkg-2:#b5bec3;--color-bkg-3:#d1d7dc;--color-bkg-4:#d6d6d6;--color-bkg-5:#ccc;--color-bkg-6:#f5f5f5}.config-menu-link{background:url(//static.pornolab.lib/templates/default/images/menu_open_1.gif) no-repeat 100%;font-weight:700;padding-right:12px}.config-form{background-color:#fff;border:1px solid #92a3a4;display:none;padding:1px;position:absolute;z-index:1000}.config-form__footer{background-color:#b5bec3;padding:5px 0;text-align:center}.config-form__label{align-items:center;background-color:#e7e7e7;display:flex;padding:7px;transition:all .3s ease}.config-form__label:hover{background-color:#d1d7dc;color:#930}.config-form__checkbox{margin:0 7px 0 0}'
  114.  
  115. /* global Menu */
  116.  
  117. const FEATURES_DEFAULT = {
  118. tags: true,
  119. similar: true,
  120. pager: true,
  121. download: true,
  122. }
  123.  
  124. async function initConfig() {
  125. const features = {
  126. ...FEATURES_DEFAULT,
  127. ...(await store.getValue('features')),
  128. }
  129.  
  130. await $.ready()
  131.  
  132. addStyle(css_248z$4)
  133. createMenuLink(features)
  134.  
  135. return features
  136. }
  137.  
  138. function createMenuLink(features) {
  139. document.body.append(createConfigForm(features))
  140.  
  141. const container = $('#main-nav td')
  142.  
  143. const menuLink = $.create('a', {
  144. className: 'config-menu-link',
  145. textContent: 'PLE',
  146. href: '#config-form',
  147. })
  148.  
  149. $.contents(container, menuLink)
  150.  
  151. const $menuLink = jQuery(menuLink)
  152.  
  153. $menuLink
  154. .click((event) => {
  155. event.preventDefault()
  156. Menu.clicked(jQuery(menuLink))
  157. })
  158. .hover(
  159. () => Menu.hovered($menuLink),
  160. () => Menu.unhovered($menuLink)
  161. )
  162. }
  163.  
  164. function createConfigForm(features) {
  165. const button = {
  166. tag: 'input',
  167. type: 'button',
  168. value: 'Apply',
  169. events: {
  170. click: (event) => {
  171. document.location.reload()
  172. Menu.hide(event)
  173. },
  174. },
  175. }
  176.  
  177. return $.create('div', {
  178. id: 'config-form',
  179. className: 'config-form',
  180. contents: [
  181. getRow('Tags', 'tags', features.tags),
  182. getRow('Find similar', 'similar', features.similar),
  183. getRow('Pager', 'pager', features.pager),
  184. getRow('Download', 'download', features.download),
  185. {
  186. tag: 'div',
  187. className: 'config-form__label',
  188. contents: {
  189. tag: 'a',
  190. target: '_blank',
  191. href: 'https://github.com/nikolay-borzov/user-scripts#image-viewer',
  192. contents: 'Try Image Viewer',
  193. },
  194. },
  195. {
  196. tag: 'div',
  197. className: 'config-form__footer',
  198. contents: button,
  199. },
  200. ],
  201. delegate: {
  202. change: {
  203. '.js-config-checkbox': async ({ target: { value, checked } }) => {
  204. await store.patch('features', {
  205. [value]: checked,
  206. })
  207. },
  208. },
  209. },
  210. events: {
  211. mousedown: (event) => event.stopPropagation(),
  212. },
  213. })
  214. }
  215.  
  216. function getRow(label, storeKey, checked) {
  217. return $.create('label', {
  218. className: 'config-form__label',
  219. contents: [
  220. {
  221. tag: 'input',
  222. type: 'checkbox',
  223. className: 'config-form__checkbox js-config-checkbox',
  224. checked,
  225. value: storeKey,
  226. },
  227. label,
  228. ],
  229. })
  230. }
  231.  
  232. const css_248z$3 =
  233. ":root{--color-active:#345da4;--color-active-1:#930;--color-border:#cacaca;--color-border-1:#92a3a4;--color-bkg:#efefef;--color-bkg-1:#e7e7e7;--color-bkg-2:#b5bec3;--color-bkg-3:#d1d7dc;--color-bkg-4:#d6d6d6;--color-bkg-5:#ccc;--color-bkg-6:#f5f5f5}.quick-download{background-color:#efefef;border:1px solid #cacaca;border-radius:0 0 10px 10px;box-shadow:0 1px 3px #0000001f,0 1px 2px #0000003d;color:#000!important;height:65px;overflow:hidden;position:fixed;right:25%;text-align:center;text-decoration:none;top:0;transform:translateY(-90%);transition:all .3s cubic-bezier(.25,.8,.25,1);width:65px}.quick-download:hover{border-color:#345da4;color:#000!important;text-decoration:none!important;transform:translateY(0)}.quick-download:after{background:#345da440;border-radius:100%;content:\"\";height:5px;left:0;opacity:0;position:absolute;right:0;top:0;transform:scale(1);transform-origin:50% 50%;width:100%}.quick-download:focus:not(:active):after{animation:ripple 1s ease-out}.quick-download__icon{background:url(\"data:image/svg+xml;charset=utf-8,%3Csvg height='24' width='24' xmlns='http://www.w3.org/2000/svg' fill='%23345da4'%3E%3Cpath d='M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z'/%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E\") no-repeat 50%;background-size:contain;display:block;height:45px}@keyframes ripple{0%{opacity:1;transform:scale(0)}20%{opacity:1;transform:scale(25)}to{opacity:0;transform:scale(40)}}"
  234.  
  235. const ENABLE_ON_PATH = '/forum/viewtopic.php'
  236.  
  237. async function initDownload() {
  238. await $.ready()
  239.  
  240. if (location.pathname !== ENABLE_ON_PATH) {
  241. return
  242. }
  243.  
  244. const downloadLink = $('.dl-link')
  245.  
  246. if (!downloadLink) {
  247. return
  248. }
  249.  
  250. addStyle(css_248z$3)
  251.  
  252. createDownloadLink(downloadLink)
  253. }
  254.  
  255. function createDownloadLink(downloadLink) {
  256. const link = $.create('a', {
  257. className: 'quick-download',
  258. href: '#',
  259.  
  260. events: {
  261. click: (event) => {
  262. event.preventDefault()
  263.  
  264. triggerEvent(
  265. downloadLink,
  266. jQuery.browser.opera ? 'mouseover' : 'mousedown'
  267. )
  268. triggerEvent(downloadLink, 'click')
  269. },
  270. },
  271.  
  272. contents: [
  273. {
  274. tag: 'span',
  275. className: 'quick-download__icon',
  276. },
  277.  
  278. {
  279. tag: 'span',
  280. textContent: document
  281. .querySelector('.attach')
  282. ?.querySelector('.row1:nth-child(5) td:nth-child(2)')?.textContent,
  283. },
  284. ],
  285. })
  286.  
  287. document.body.append(link)
  288. }
  289.  
  290. function triggerEvent(element, eventName) {
  291. const event = new MouseEvent(eventName, {
  292. bubbles: true,
  293. cancelable: true,
  294. })
  295.  
  296. element.dispatchEvent(event)
  297. }
  298.  
  299. const regExp = {
  300. getMatchGroups(regExp, string) {
  301. const matches = []
  302. let match
  303.  
  304. while ((match = regExp.exec(string)) !== null) {
  305. if (match.index === regExp.lastIndex) {
  306. regExp.lastIndex++
  307. }
  308.  
  309. const groups = match.slice(1)
  310.  
  311. if (groups.some(Boolean)) {
  312. matches.push(groups)
  313. }
  314. }
  315.  
  316. return matches
  317. },
  318.  
  319. getFirstMatchGroup(regExp, string) {
  320. const match = regExp.exec(string)
  321.  
  322. return match ? match[1] : undefined
  323. },
  324. }
  325.  
  326. const css_248z$2 =
  327. ":root{--color-active:#345da4;--color-active-1:#930;--color-border:#cacaca;--color-border-1:#92a3a4;--color-bkg:#efefef;--color-bkg-1:#e7e7e7;--color-bkg-2:#b5bec3;--color-bkg-3:#d1d7dc;--color-bkg-4:#d6d6d6;--color-bkg-5:#ccc;--color-bkg-6:#f5f5f5}.find-similar-link{border:1px solid #0000;display:inline-block;height:25px;margin-left:10px;position:relative;vertical-align:middle;width:25px}.find-similar-link:before{background:url(\"data:image/svg+xml;charset=utf-8,%3Csvg fill='%23345da4' height='24' width='24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M3 5H1v16c0 1.1.9 2 2 2h16v-2H3V5zm18-4H7c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 16H7V3h14v14z'/%3E%3C/svg%3E\") no-repeat 50%;background-size:contain;box-sizing:border-box;content:\"\";height:17px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:17px}.find-similar-link:hover{background-color:#efefef;border-color:#345da4}"
  328.  
  329. const TOPIC_PATH$1 = '/forum/viewtopic.php'
  330. const TAGS_REGEX = /\[[^\]]+]/g
  331.  
  332. const WORDS_REGEX = /([\w'\u0400-\u04FF-]+)/g
  333. const REMOVE_CHARS_REGEX = /^[\d-.]+$/
  334. const SEARCH_TERM_MAX_LENGTH = 61
  335.  
  336. async function initFindSimilar() {
  337. await $.ready()
  338.  
  339. if (location.pathname === TOPIC_PATH$1) {
  340. addStyle(css_248z$2)
  341. createFindSimilarLink()
  342. }
  343. }
  344.  
  345. function createFindSimilarLink() {
  346. const titleElement = $('.maintitle')
  347. const titleLink = titleElement.children[0]
  348.  
  349. const rawTitle = titleLink.textContent.replace(TAGS_REGEX, '').trim()
  350. const words = regExp.getMatchGroups(WORDS_REGEX, rawTitle)
  351.  
  352. let searchTerm = words
  353. .filter(([word]) => !REMOVE_CHARS_REGEX.test(word))
  354. .join(' ')
  355.  
  356. if (searchTerm.length > SEARCH_TERM_MAX_LENGTH) {
  357. searchTerm = searchTerm.slice(0, SEARCH_TERM_MAX_LENGTH - 1)
  358. searchTerm = searchTerm.slice(0, Math.max(0, searchTerm.lastIndexOf(' ')))
  359. }
  360.  
  361. $.create('a', {
  362. className: 'find-similar-link',
  363. href: `/forum/tracker.php?nm=${searchTerm}#search_opt`,
  364. target: '_blank',
  365. title: 'Find similar',
  366. after: titleLink,
  367. })
  368. }
  369.  
  370. const css_248z$1 =
  371. ':root{--color-active:#345da4;--color-active-1:#930;--color-border:#cacaca;--color-border-1:#92a3a4;--color-bkg:#efefef;--color-bkg-1:#e7e7e7;--color-bkg-2:#b5bec3;--color-bkg-3:#d1d7dc;--color-bkg-4:#d6d6d6;--color-bkg-5:#ccc;--color-bkg-6:#f5f5f5}.nav .menu-root,.small>b>.menu-root,a.pg{background-color:#efefef;border:1px solid #cacaca;display:inline-block;padding:.5em .7em;text-decoration:none}a.pg{margin-right:.1em}.nav .menu-root,.small>b>.menu-root{background-position:95% 50%;background-repeat:no-repeat;padding-right:20px}.nav .menu-root:hover,.small>b>.menu-root:hover,a.pg:hover{border-color:#345da4;color:#345da4;text-decoration:none!important}.menu-root~b{border:1px solid #0000;display:inline-block;margin-right:.1em;padding:.5em .7em}'
  372.  
  373. const css_248z =
  374. ":root{--color-active:#345da4;--color-active-1:#930;--color-border:#cacaca;--color-border-1:#92a3a4;--color-bkg:#efefef;--color-bkg-1:#e7e7e7;--color-bkg-2:#b5bec3;--color-bkg-3:#d1d7dc;--color-bkg-4:#d6d6d6;--color-bkg-5:#ccc;--color-bkg-6:#f5f5f5}.tags-row{padding:3px 0 0}.tags-row-tag{background-color:#efefef;border:1px solid #cacaca;border-radius:5px;display:inline-block;margin:2px 5px;padding:5px;position:relative;text-decoration:none}.tags-row-tag:hover{border-color:#345da4;color:#345da4;text-decoration:none!important}.tags-row-tag:nth-child{margin-left:0}.tag-with-icon{padding-left:25px}.tag-with-icon:before{background-position:50%;background-repeat:no-repeat;background-size:contain;border:1px solid #cacaca;border-radius:100%;box-sizing:border-box;content:\"\";height:16px;left:5px;position:absolute;top:50%;transform:translateY(-50%);width:16px}.icon-en:before{background-image:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Ccircle cx='256' cy='256' r='256' fill='%23F0F0F0'/%3E%3Cpath d='M52.92 100.142c-20.11 26.163-35.272 56.318-44.1 89.077h133.177L52.92 100.14zm450.26 89.078c-8.828-32.76-23.992-62.914-44.1-89.077l-89.075 89.076H503.18zM8.82 322.784c8.83 32.758 23.992 62.913 44.1 89.075l89.074-89.076H8.82zM411.858 52.92c-26.163-20.108-56.317-35.27-89.076-44.1v133.176l89.076-89.075zM100.142 459.08c26.163 20.108 56.318 35.27 89.076 44.1V370.006l-89.076 89.074zM189.217 8.82c-32.758 8.83-62.913 23.992-89.075 44.1l89.075 89.075V8.82zm133.566 494.36c32.758-8.83 62.913-23.992 89.075-44.1l-89.075-89.075V503.18zm47.222-180.396 89.075 89.076c20.108-26.162 35.272-56.318 44.1-89.076H370.006z' fill='%230052B4'/%3E%3Cg fill='%23D80027'%3E%3Cpath d='M509.833 222.61h-220.44V2.166a258.478 258.478 0 0 0-66.783.001v220.44H2.166a258.478 258.478 0 0 0 .001 66.783h220.44v220.443a258.335 258.335 0 0 0 66.783 0v-220.44h220.443A258.583 258.583 0 0 0 512 256c0-11.317-.744-22.46-2.167-33.39z'/%3E%3Cpath d='M322.783 322.784 437.02 437.02a256.914 256.914 0 0 0 15.047-16.435l-97.802-97.802h-31.482zm-133.566 0h-.002L74.98 437.02a256.914 256.914 0 0 0 16.435 15.047l97.802-97.804v-31.48zm0-133.564v-.003L74.98 74.98a256.914 256.914 0 0 0-15.047 16.435l97.803 97.803h31.48zm133.566 0L437.02 74.98a256.605 256.605 0 0 0-16.435-15.046l-97.802 97.803v31.482z'/%3E%3C/g%3E%3C/svg%3E\")}.icon-ja:before{background-image:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Ccircle cx='256' cy='256' r='256' fill='%23F0F0F0'/%3E%3Ccircle cx='256' cy='256' r='111.304' fill='%23D80027'/%3E%3C/svg%3E\")}.icon-ru:before{background-image:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Ccircle cx='256' cy='256' r='256' fill='%23F0F0F0'/%3E%3Cpath d='M496.077 345.043C506.367 317.31 512 287.313 512 256s-5.632-61.31-15.923-89.043H15.923C5.633 194.69 0 224.687 0 256s5.633 61.31 15.923 89.043L256 367.303l240.077-22.26z' fill='%230052B4'/%3E%3Cpath d='M256 512c110.07 0 203.906-69.472 240.077-166.957H15.923C52.093 442.528 145.93 512 256 512z' fill='%23D80027'/%3E%3C/svg%3E\")}.icon-zh:before{background-image:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-49 141 512 512'%3E%3Ccircle cx='207' cy='397' r='256' style='fill:%23d80027'/%3E%3Cpath d='m91.1 296.8 22.1 68h71.5l-57.8 42.1 22.1 68-57.9-42-57.9 42 22.2-68-57.9-42.1H69zm163.4 240.7-16.9-20.8-25 9.7 14.5-22.5-16.9-20.9 25.9 6.9 14.6-22.5 1.4 26.8 26 6.9-25.1 9.6zm33.6-61 8-25.6-21.9-15.5 26.8-.4 7.9-25.6 8.7 25.4 26.8-.3-21.5 16 8.6 25.4-21.9-15.5zm45.3-147.6L321.6 353l19.2 18.7-26.5-3.8-11.8 24-4.6-26.4-26.6-3.8 23.8-12.5-4.6-26.5 19.2 18.7zm-78.2-73-2 26.7 24.9 10.1-26.1 6.4-1.9 26.8-14.1-22.8-26.1 6.4 17.3-20.5-14.2-22.7 24.9 10.1z' style='fill:%23ffda44'/%3E%3C/svg%3E\")}.icon-es:before{background-image:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M0 256c0 31.314 5.633 61.31 15.923 89.043L256 367.303l240.077-22.26C506.367 317.31 512 287.313 512 256s-5.633-61.31-15.923-89.043L256 144.697l-240.077 22.26C5.633 194.69 0 224.687 0 256z' fill='%23FFDA44'/%3E%3Cpath d='M496.077 166.957C459.907 69.473 366.07 0 256 0S52.094 69.473 15.923 166.957h480.154zM15.923 345.043C52.093 442.527 145.93 512 256 512s203.906-69.473 240.077-166.957H15.923z' fill='%23D80027'/%3E%3C/svg%3E\")}.icon-pt:before{background-image:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M0 256c0 110.07 69.472 203.905 166.955 240.076L189.217 256 166.955 15.922C69.472 52.095 0 145.93 0 256z' fill='%236DA544'/%3E%3Cpath d='M512 256C512 114.616 397.384 0 256 0c-31.314 0-61.31 5.633-89.045 15.923v480.154C194.69 506.367 224.685 512 256 512c141.384 0 256-114.616 256-256z' fill='%23D80027'/%3E%3Ccircle cx='166.957' cy='256' r='89.043' fill='%23FFDA44'/%3E%3Cpath d='M116.87 211.478v55.652c0 27.662 22.424 50.087 50.087 50.087s50.087-22.424 50.087-50.087v-55.652H116.87z' fill='%23D80027'/%3E%3Cpath d='M166.957 283.826c-9.206 0-16.696-7.49-16.696-16.696v-22.26h33.392v22.26c0 9.206-7.49 16.696-16.695 16.696z' fill='%23F0F0F0'/%3E%3C/svg%3E\")}.icon-de:before{background-image:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M15.923 345.043C52.093 442.527 145.93 512 256 512s203.906-69.473 240.077-166.957L256 322.783l-240.077 22.26z' fill='%23FFDA44'/%3E%3Cpath d='M256 0C145.93 0 52.094 69.472 15.923 166.957L256 189.217l240.077-22.26C459.907 69.47 366.07 0 256 0z'/%3E%3Cpath d='M15.923 166.957C5.633 194.69 0 224.687 0 256s5.633 61.31 15.923 89.043h480.155C506.368 317.31 512 287.313 512 256s-5.632-61.31-15.923-89.043H15.923z' fill='%23D80027'/%3E%3C/svg%3E\")}.icon-fr:before{background-image:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Ccircle cx='256' cy='256' r='256' fill='%23f0f0f0'/%3E%3Cpath d='M512 256c0-110.071-69.472-203.906-166.957-240.077v480.155C442.528 459.906 512 366.071 512 256z' fill='%23d80027'/%3E%3Cpath d='M0 256c0 110.071 69.473 203.906 166.957 240.077V15.923C69.473 52.094 0 145.929 0 256z' fill='%230052b4'/%3E%3C/svg%3E\")}.icon-ko:before{background-image:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Ccircle cx='256' cy='256' r='256' fill='%23f0f0f0'/%3E%3Cpath d='M345.043 256c0 22.261-39.866 77.913-89.043 77.913S166.957 278.261 166.957 256c0-49.178 39.866-89.043 89.043-89.043s89.043 39.865 89.043 89.043z' fill='%23d80027'/%3E%3Cpath d='M345.043 256c0 49.178-39.866 89.043-89.043 89.043S166.957 305.178 166.957 256' fill='%230052b4'/%3E%3Cpath d='m350.442 334.705 23.61-23.61 15.741 15.74-23.61 23.61zm-39.357 39.355 23.61-23.612 15.741 15.741-23.61 23.611zm86.585 7.857 23.611-23.61 15.74 15.74-23.61 23.61zm-39.356 39.361 23.61-23.61 15.741 15.74-23.61 23.611zm15.741-62.965 23.61-23.61 15.741 15.74-23.61 23.61zm-39.346 39.354 23.61-23.61 15.741 15.74-23.61 23.611zm62.969-220.377-62.963-62.963 15.741-15.74 62.962 62.962zm-62.965-15.732-23.61-23.61 15.74-15.74 23.61 23.61zm39.347 39.349-23.61-23.611 15.74-15.74 23.61 23.61zm7.855-86.571-23.61-23.611 15.74-15.741 23.61 23.61zm39.368 39.352-23.611-23.61 15.74-15.741 23.612 23.61zm-330.56 204.63 62.962 62.962-15.74 15.74-62.963-62.961zm62.957 15.732 23.611 23.611-15.74 15.74-23.61-23.61zm-39.35-39.347 23.611 23.611-15.74 15.741-23.611-23.61zm23.613-23.612 62.962 62.963-15.74 15.74-62.963-62.962zM153.684 90.72 90.72 153.683l-15.74-15.741 62.962-62.963zm23.603 23.605-62.963 62.963-15.74-15.741 62.962-62.962zm23.625 23.622-62.962 62.962-15.74-15.74 62.962-62.962z'/%3E%3C/svg%3E\")}.icon-in-progress:before{background-image:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='500' height='500'%3E%3Cdefs%3E%3CclipPath clipPathUnits='userSpaceOnUse' id='a'%3E%3Cpath style='fill:%23262425' d='M0 100h500v100H0z'/%3E%3C/clipPath%3E%3CclipPath clipPathUnits='userSpaceOnUse' id='b'%3E%3Cpath style='fill:%23262425' d='M0 300h500v100H0z'/%3E%3C/clipPath%3E%3C/defs%3E%3Ccircle cy='353.553' r='250' style='fill:%23ebb531' transform='rotate(-45)'/%3E%3Ccircle cx='250' cy='250' r='250' style='fill:%23262425' clip-path='url(%23a)' transform='rotate(-45 250 250)'/%3E%3Ccircle cx='250' cy='250' r='250' style='fill:%23262425' clip-path='url(%23b)' transform='rotate(-45 250 250)'/%3E%3C/svg%3E\")}.icon-dimension:before{background-image:url(\"data:image/svg+xml;charset=utf-8,%3Csvg height='24' width='24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M18 3v2h-2V3H8v2H6V3H4v18h2v-2h2v2h8v-2h2v2h2V3h-2zM8 17H6v-2h2v2zm0-4H6v-2h2v2zm0-4H6V7h2v2zm10 8h-2v-2h2v2zm0-4h-2v-2h2v2zm0-4h-2V7h2v2z'/%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E\");border-width:0}.icon-cen:before{background-image:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAA9AAAAPQAUrNa1AAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTnU1rJkAAAAT0lEQVQ4T2P4fW6uAzJ+Mav6CD6Mrn44GPDr3JzDyPjLvLr/KHguKkZXPxwN+NBX/h8F96JidPXDwQD0hPF9RfcxFLy0CwWjqx/yBsx1AAAIrOl/m8CdZwAAAABJRU5ErkJggg==\")}.icon-uncen:before{background-image:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 58 58'%3E%3Ccircle cx='29' cy='29' r='29' fill='%23fbce9d'/%3E%3Cpath d='M43.993 37.703c.004-.135.006-.271.007-.405.005-1.052-.495-2.022-1.239-2.765-1.245-1.243-1.678-3.17-1.298-4.89.194-.879-.007-1.794-.452-2.577-2.198-3.868-5.215-7.903-7.674-10.962a5.55 5.55 0 0 0-8.659-.003c-2.485 3.088-5.539 7.176-7.741 11.095-.437.777-.533 1.673-.387 2.552.279 1.681-.2 3.51-1.438 4.68a3.545 3.545 0 0 0-1.089 2.508l-.002.179c-.008 1.28.582 2.542 1.647 3.251 1.682 1.121 2.345 3.278 1.992 5.219a3.703 3.703 0 0 0 .784 3.025C20.8 51.443 24.219 54.267 29.01 57c5.142-2.933 8.708-5.97 11.071-9.012.639-.823.985-1.868.856-2.902-.208-1.666.319-3.439 1.581-4.552.835-.736 1.442-1.718 1.475-2.831z' fill='%23f98d85'/%3E%3Cpath d='M24.679 16.101c2.228-2.769 6.432-2.767 8.658.003 1.515 1.884 3.24 4.14 4.856 6.498C38.912 10.427 29.011 1 29.011 1s-9.896 9.422-9.183 21.593a106.439 106.439 0 0 1 4.851-6.492z' fill='%23ea6248'/%3E%3Cpath d='M31.853 14.812A4 4 0 1 0 25.011 12c0 1.095.442 2.086 1.155 2.808a5.564 5.564 0 0 1 5.687.004z' fill='%23c64646'/%3E%3Cpath d='M29.011 18s-20.75 19.75 0 39c20.75-19.25 0-39 0-39z' fill='%23ea6248'/%3E%3Cpath d='m31.171 48.395-.956 1.148a1.58 1.58 0 0 1-2.429 0l-.956-1.148A12.203 12.203 0 0 1 24 40.581V35.16A3.16 3.16 0 0 1 27.16 32h3.681a3.16 3.16 0 0 1 3.16 3.16v5.421a12.214 12.214 0 0 1-2.83 7.814z' fill='%23bf5a45'/%3E%3Cpath d='M29 40c-2.109 0-3.91 1.438-4.644 3.471a12.195 12.195 0 0 0 2.473 4.924l.956 1.148a1.58 1.58 0 0 0 2.429 0l.956-1.148a12.195 12.195 0 0 0 2.473-4.924C32.91 41.438 31.109 40 29 40z' fill='%23f98d85'/%3E%3C/svg%3E\")}.icon-ptcen:before{background-image:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAA9AAAAPQAUrNa1AAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTnU1rJkAAABqElEQVQ4T5WTSy8DURTHx0fpxjeRImHBxmOBikeipSvxqBShlWqpjUbTJiRlw05YeWzEhpadxIaFdKFCVDLTubP4u+eYmc5UJbX4Tf5zXvfec89VALio3KebjXx20bjLHmun6yWCNNnIVxvv/GkS+WzQKGRVCcR1Cm9TXQxpspGPYijWyrOTjULmxAxiPpN+PHR7GdJOH8VaRbgAVfV4PPgP5k4UPnO9gEagXIWaU8/ZCLK5YYU77DqfbOB+AlpkHq/DbQxpkUu4YhiZq0hRdBkvUtATq/iY6serr5UhTTZxbt+GRfFXAXGUhEqry8SXoR9Iq5E56dtyJhOyQM0R9O01fIUCeBr04rKvhSH9NT8BPR1zJptHoKmzDDcZ6FsRlGfH8ThQLUC6PDMGfTPCMY4C4Z/RNaePEIdJuZofz752lJamGdK0A3GwUU2WOXyN1iDZjqsdaNEFlEY6oMaWGdJaNARxVm2iPUj0kbhGWezG8T7Zi2JwgHkP9EDsxWHcWtuvGWWriLkTVfYFldwaSqOdDGmz+J+PyYZ7Yj5nNbdSJvim6j5nKN+A2Me46jRxowAAAABJRU5ErkJggg==\")}"
  375.  
  376. const TOPIC_PATH = '/forum/viewtopic.php'
  377.  
  378. const TITLE_REGEX = /(?:\[([^[\]]+)]+)?([^[]*)?/g
  379. const TAGS_SEPARATOR_REGEX = /,\s?|;|•|\/|\+/
  380. const TAGS_GROUP_SEPARATOR = ' | '
  381.  
  382. const DIMENSIONS = [
  383. '240p',
  384. '360p',
  385. '480p',
  386. '540p',
  387. '544p',
  388. '576p',
  389. '640p',
  390. '720p',
  391. '1080p',
  392. '1080i',
  393. '1440p',
  394. '2160p',
  395. ]
  396. const DIMENSION_ICON_NAME = 'dimension'
  397.  
  398. const TAG_ICON_MAP = {
  399. eng: 'en',
  400. jap: 'ja',
  401. rus: 'ru',
  402. ru: 'ru',
  403. chi: 'zh',
  404. cn: 'zh',
  405. spa: 'es',
  406. es: 'es',
  407. por: 'pt',
  408. ger: 'de',
  409. de: 'de',
  410. fr: 'fr',
  411. korean: 'ko',
  412. cen: 'cen',
  413. uncen: 'uncen',
  414. ptcen: 'ptcen',
  415. inprogress: 'in-progress',
  416. }
  417.  
  418. for (const dimensions of DIMENSIONS) {
  419. TAG_ICON_MAP[dimensions] = DIMENSION_ICON_NAME
  420. }
  421.  
  422. async function initTags() {
  423. await $.ready()
  424.  
  425. if (location.pathname === TOPIC_PATH) {
  426. createPostTags()
  427. }
  428. }
  429.  
  430. function createPostTags() {
  431. const titleElement = $('.maintitle')
  432. const titleLink = titleElement.children[0]
  433. const title = titleLink.textContent
  434.  
  435. const titleParts = tokenizeTitle(title)
  436. const hasTagBefore = titleParts.tagGroupsBefore.length > 0
  437. const hasTagsAfter = titleParts.tagGroupsAfter.length > 0
  438.  
  439. if (!hasTagBefore && !hasTagsAfter) {
  440. return
  441. }
  442.  
  443. addStyle(css_248z)
  444.  
  445. $.set(titleLink, {
  446. textContent: titleParts.title,
  447. title,
  448. })
  449.  
  450. if (hasTagBefore) {
  451. $.before(createTagsRow(titleParts.tagGroupsBefore), titleElement)
  452. }
  453.  
  454. if (hasTagsAfter) {
  455. $.after(createTagsRow(titleParts.tagGroupsAfter), titleElement)
  456. }
  457. }
  458.  
  459. function tokenizeTitle(titleRaw) {
  460. const tagGroupsBefore = []
  461. const titleParts = []
  462.  
  463. const tagGroupsAfter = []
  464.  
  465. for (const groups of regExp.getMatchGroups(TITLE_REGEX, titleRaw)) {
  466. let tags = []
  467.  
  468. if (groups[0]) {
  469. tags = groups[0].split(TAGS_SEPARATOR_REGEX)
  470. }
  471.  
  472. if (tags.length > 0) {
  473. ;(titleParts.length > 0 ? tagGroupsAfter : tagGroupsBefore).push(tags)
  474. }
  475.  
  476. if (groups[1]) {
  477. titleParts.push(groups[1])
  478. }
  479. }
  480.  
  481. return {
  482. tagGroupsBefore,
  483. title: titleParts.join('').trim(),
  484. tagGroupsAfter,
  485. }
  486. }
  487.  
  488. function createTagsRow(tagGroups) {
  489. const tags = tagGroups.reduce((result, tagsGroup, index) => {
  490. result.push(...createTagLinks(tagsGroup))
  491.  
  492. if (index + 1 !== tagGroups.length) {
  493. result.push(TAGS_GROUP_SEPARATOR)
  494. }
  495.  
  496. return result
  497. }, [])
  498.  
  499. return $.create('div', {
  500. className: 'tags-row',
  501. contents: tags,
  502. })
  503. }
  504.  
  505. function createTagLinks(tags) {
  506. return tags
  507. .filter((tag) => tag.length)
  508. .map((tag) => {
  509. let className = 'tags-row-tag'
  510.  
  511. tag = tag.trim()
  512.  
  513. const tagkey = tag.toLowerCase()
  514.  
  515. if (Object.hasOwn(TAG_ICON_MAP, tagkey)) {
  516. className = `${className} tag-with-icon icon-${TAG_ICON_MAP[tagkey]}`
  517. }
  518.  
  519. return $.create('a', {
  520. className,
  521. textContent: tag,
  522. href: `/forum/tracker.php?nm=${tag}`,
  523. target: '_blank',
  524. })
  525. })
  526. }
  527.  
  528. initConfig().then(async (config) => {
  529. if (config.tags) {
  530. await initTags()
  531. }
  532.  
  533. if (config.pager) {
  534. addStyle(css_248z$1)
  535. }
  536.  
  537. if (config.download) {
  538. await initDownload()
  539. }
  540.  
  541. if (config.similar) {
  542. await initFindSimilar()
  543. }
  544. })
  545. })()