E-Hentai - UX Tweaks

Numerous features to enrich your browsing experience

  1. // ==UserScript==
  2. // @name E-Hentai - UX Tweaks
  3. // @namespace brazenvoid
  4. // @version 1.9.1
  5. // @author brazenvoid
  6. // @license GPL-3.0-only
  7. // @description Numerous features to enrich your browsing experience
  8. // @match https://e-hentai.org/*
  9. // @match https://exhentai.org/*
  10. // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js
  11. // @require https://update.greasyfork.org/scripts/375557/1244990/Base%20Brazen%20Resource.js
  12. // @require https://update.greasyfork.org/scripts/416104/1498249/Brazen%20UI%20Generator.js
  13. // @require https://update.greasyfork.org/scripts/418665/1481350/Brazen%20Configuration%20Manager.js
  14. // @require https://update.greasyfork.org/scripts/429587/1244644/Brazen%20Item%20Attributes%20Resolver.js
  15. // @require https://update.greasyfork.org/scripts/416105/1478692/Brazen%20Base%20Search%20Enhancer.js
  16. // @grant GM_addStyle
  17. // @run-at document-end
  18. // ==/UserScript==
  19.  
  20. GM_addStyle(
  21. `#settings-wrapper{min-width:310px;width:310px}.bv-section{font-size:1.25rem}.disliked-tag{background-color:lightcoral !important;color:white !important}.disliked-tag:hover{background-color:indianred !important}.disliked-tag > a{color:white !important}.disliked-tag.favourite-tag{background-color:orange !important}.disliked-tag.favourite-tag:hover{background-color:darkorange !important}.favourite-tag{background-color:mediumseagreen !important;color:white !important}.favourite-tag:hover{background-color:forestgreen !important}.favourite-tag > a{color:white !important}`)
  22.  
  23. const IS_GALLERY_PAGE = $('#gdt').length
  24. const IS_IMAGE_PAGE = window.location.pathname.startsWith('/s/')
  25. const IS_SEARCH_PAGE = $('#f_search').length
  26. const IS_SMALL_WINDOW = $('.stuffbox').length
  27. const IS_TAG_SEARCH_PAGE = window.location.pathname.startsWith('/tag')
  28. const IS_UPLOADER_SEARCH_PAGE = window.location.pathname.startsWith('/uploader')
  29. const IS_WATCHED_PAGE = document.querySelectorAll('.ido > div > p.ip')?.length > 0
  30.  
  31. const IS_EXTENDED_LAYOUT = IS_SEARCH_PAGE && $('table.itg.glte').length > 0
  32. const IS_MINIMAL_LAYOUT = !IS_EXTENDED_LAYOUT && $('table.itg.gltm').length > 0
  33. const IS_COMPACT_LAYOUT = !IS_MINIMAL_LAYOUT && $('table.itg.gltc').length > 0
  34. const IS_THUMBNAIL_LAYOUT = !IS_COMPACT_LAYOUT && $('div.itg.gld').length > 0
  35.  
  36. const ITEM_RATED_BLUE = 'ratedBlue'
  37. const ITEM_RATED_GREEN = 'ratedGreen'
  38. const ITEM_RATED_RED = 'ratedRed'
  39. const ITEM_TAGS = 'tags'
  40. const ITEM_WATCHED = 'watched'
  41.  
  42. const FILTER_WATCHED_FROM_SEARCH = 'Hide Watched Galleries'
  43. const FILTER_RATED_VIDEOS = 'Hide Rated Galleries'
  44.  
  45. const STYLE_GALLERY_HIGHLIGHT = 'gallery-highlight'
  46.  
  47. const UI_DEFAULTS_PAGE_RANGE = 'Page Range'
  48. const UI_DEFAULTS_PAGE_RANGE_ENABLE = 'Enable Page Range Filter'
  49. const UI_DEFAULTS_RATING = 'Rating'
  50. const UI_DEFAULTS_RATING_ENABLE = 'Enable Rating Filter'
  51. const UI_DEFAULTS_TAGS = 'Tags'
  52. const UI_DEFAULTS_TAGS_ENABLE = 'Enable Default Tags'
  53.  
  54. const UI_OPEN_GALLERY_PAGES_AUTO_NEXT = 'Auto Next Page'
  55. const UI_OPEN_GALLERY_PAGES_CHUNK_SIZE = 'Chunk Size'
  56. const UI_OPEN_GALLERY_PAGES_DELAY = 'Delay'
  57. const UI_DISLIKED_TAGS = 'Disliked Tags'
  58. const UI_FAVOURITE_TAGS = 'Favourite Tags'
  59. const UI_EMBED_TORRENTS = 'Embed Torrent Downloads'
  60. const UI_VISITED_HIGHLIGHT = 'Highlight Visited'
  61. const UI_GALLERY_HIGHLIGHTS = 'Gallery Highlights'
  62. const UI_GALLERY_HIGHLIGHTS_COlOUR = 'Highlight Colour'
  63.  
  64. let selectorItem = '', selectorItemLink = '', selectorItemList = '', selectorItemName = ''
  65. if (IS_EXTENDED_LAYOUT) {
  66. selectorItem = 'tr'
  67. selectorItemLink = 'div.gl2e > div > a'
  68. selectorItemList = 'table.itg.glte > tbody'
  69. selectorItemName = 'div.gl4e.glname > div.glink'
  70. } else if (IS_COMPACT_LAYOUT) {
  71. selectorItem = 'tr'
  72. selectorItemLink = 'td.gl3c.glname > a'
  73. selectorItemList = 'table.itg.gltc > tbody'
  74. selectorItemName = 'td.gl3c.glname > a > div.glink'
  75. } else if (IS_MINIMAL_LAYOUT) {
  76. selectorItem = 'tr'
  77. selectorItemLink = 'td.gl3m.glname > a'
  78. selectorItemList = 'table.itg.gltm > tbody'
  79. selectorItemName = 'td.gl3m.glname > a > div.glink'
  80. } else if (IS_THUMBNAIL_LAYOUT) {
  81. selectorItem = 'div.gl1t'
  82. selectorItemLink = 'div.gl3t > a'
  83. selectorItemList = 'div.itg.gld'
  84. selectorItemName = 'div.gl4t.glname'
  85. }
  86.  
  87. class EHentaiSearchAndUITweaks extends BrazenBaseSearchEnhancer
  88. {
  89. constructor()
  90. {
  91. super({
  92. isUserLoggedIn: false,
  93. itemDeepAnalysisSelector: 'div.gm',
  94. itemLinkSelector: selectorItemLink,
  95. itemListSelectors: selectorItemList,
  96. itemNameSelector: selectorItemName,
  97. itemSelectors: selectorItem,
  98. itemSelectionMethod: 'children',
  99. requestDelay: 0,
  100. scriptPrefix: 'e-hentai-ux-',
  101. tagSelectorGenerator: (tag) => {
  102. tag = tag.trim()
  103. if (IS_GALLERY_PAGE) {
  104. let tagAttribute = tag.replaceAll(' ', '_')
  105. return 'div[id="td_' + tagAttribute + '"], a[id="ta_' + tagAttribute + '"]'
  106. }
  107. return 'div.gt[title="' + tag + '"], div.gtl[title="' + tag + '"]'
  108. },
  109. })
  110. this._setupFeatures()
  111. this._setupUI()
  112. this._setupEvents()
  113. }
  114.  
  115. /**
  116. * @param {string} tag
  117. * @return {string}
  118. * @private
  119. */
  120. _formatTag(tag)
  121. {
  122. if (tag.includes(':') && !tag.includes('"') && (tag.includes(' ') || tag.includes('+'))) {
  123. tag = tag.replace(':', ':"') + '"'
  124. }
  125. return tag
  126. }
  127.  
  128. /**
  129. *
  130. * @param {JQuery} item
  131. * @return {string[]}
  132. * @private
  133. */
  134. _gatherItemTags(item)
  135. {
  136. let tags = []
  137. let tagElements = item.find('.gt,.gtl')
  138. if (IS_EXTENDED_LAYOUT) {
  139. tagElements.each((_i, e) => {
  140. tags.push($(e).attr('title'))
  141. })
  142. } else {
  143. tagElements.each((_i, e) => {
  144. let tagID = $(e).find('a').attr('id')
  145. if (tagID.startsWith('ta_')) {
  146. tagID = tagID.replace('ta_', '')
  147. }
  148. if (tagID.startsWith('td_')) {
  149. tagID = tagID.replace('td_', '')
  150. }
  151. tags.push(tagID.replace('_', ' '))
  152. })
  153. }
  154. return tags
  155. }
  156.  
  157. /**
  158. * @param {{}} range
  159. * @param {URLSearchParams} queryParams
  160. * @private
  161. */
  162. _handleDefaultPageRangeFilter(range, queryParams)
  163. {
  164. if (range.minimum > 0) {
  165. queryParams.set('f_spf', range.minimum)
  166. }
  167. if (range.maximum > 0) {
  168. queryParams.set('f_spt', range.maximum)
  169. }
  170. }
  171.  
  172. /**
  173. * @param {string} rating
  174. * @param {URLSearchParams} queryParams
  175. * @private
  176. */
  177. _handleDefaultRatingsFilter(rating, queryParams)
  178. {
  179. queryParams.set('f_srdd', rating)
  180. }
  181.  
  182. /**
  183. * @param {string[]} tags
  184. * @param {URLSearchParams} queryParams
  185. * @private
  186. */
  187. _handleDefaultTags(tags, queryParams)
  188. {
  189. let existingTags = queryParams.get('f_search')
  190. let updatedTags = existingTags
  191. let include = true
  192.  
  193. for (let tag of tags) {
  194. if (!existingTags.includes(tag)) {
  195. updatedTags += '+' + this._formatTag(tag)
  196. } else {
  197. include = false
  198. break
  199. }
  200. }
  201.  
  202. if (include) {
  203. queryParams.set('f_search', updatedTags)
  204. }
  205. }
  206.  
  207. /**
  208. * @private
  209. */
  210. _handleDefaults()
  211. {
  212. let queryParams = new URLSearchParams(window.location.search)
  213. let existingParams = queryParams.toString()
  214.  
  215. if (!queryParams.has('next') &&
  216. (this._getConfig(UI_DEFAULTS_PAGE_RANGE_ENABLE) || this._getConfig(UI_DEFAULTS_RATING_ENABLE) ||
  217. this._getConfig(UI_DEFAULTS_TAGS_ENABLE))) {
  218.  
  219. if (!queryParams.has('f_search')) {
  220.  
  221. let existingTag = ''
  222. let urlSegments = window.location.pathname.split('/')
  223.  
  224. if (IS_TAG_SEARCH_PAGE) {
  225. existingTag = urlSegments.pop().trim()
  226. } else if (IS_UPLOADER_SEARCH_PAGE) {
  227. existingTag = 'uploader:' + urlSegments.pop().trim()
  228. }
  229. queryParams.set('f_search', existingTag.length ? this._formatTag(existingTag) : '')
  230. }
  231.  
  232. if (!queryParams.has('advsearch')) {
  233. queryParams.set('advsearch', '1')
  234. }
  235.  
  236. let validatePageRange = (range, defaultValidator) => defaultValidator(range) && !queryParams.has('f_spf') &&
  237. !queryParams.has('f_spt')
  238.  
  239. this._performTogglableComplexOperation(UI_DEFAULTS_PAGE_RANGE_ENABLE, UI_DEFAULTS_PAGE_RANGE, validatePageRange,
  240. (range) => {
  241. this._handleDefaultPageRangeFilter(range, queryParams)
  242. })
  243.  
  244. let validateRatingFilter = (range, defaultValidator) => defaultValidator(range) && !queryParams.has('f_srdd')
  245.  
  246. this._performTogglableComplexOperation(UI_DEFAULTS_RATING_ENABLE, UI_DEFAULTS_RATING, validateRatingFilter,
  247. (rating) => {
  248. this._handleDefaultRatingsFilter(rating, queryParams)
  249. })
  250.  
  251. this._performTogglableOperation(UI_DEFAULTS_TAGS_ENABLE, UI_DEFAULTS_TAGS, (tags) => {
  252. this._handleDefaultTags(tags, queryParams)
  253. })
  254.  
  255. let updatedParams = queryParams.toString().replaceAll('%2B', '+')
  256. if (updatedParams !== existingParams) {
  257. if (IS_TAG_SEARCH_PAGE || IS_UPLOADER_SEARCH_PAGE) {
  258. window.location = window.location.origin + '?' + updatedParams
  259. } else {
  260. window.location = window.location.origin + window.location.pathname + '?' + updatedParams
  261. }
  262. }
  263. }
  264. }
  265.  
  266. /**
  267. * @param {JQuery} item
  268. * @private
  269. */
  270. _handleGalleryHighlights(item)
  271. {
  272. let mode = this._getConfig(UI_GALLERY_HIGHLIGHTS)
  273. let itemHasHighlight = item.hasClass(STYLE_GALLERY_HIGHLIGHT)
  274.  
  275. if (mode !== 'Disabled') {
  276.  
  277. let itemTags = this._get(item, ITEM_TAGS), doHighlight, tag
  278. if (itemTags) {
  279.  
  280. for (let rule of this._configurationManager.getField(UI_FAVOURITE_TAGS).optimized) {
  281.  
  282. doHighlight = true
  283. for (let tagSelector of rule) {
  284.  
  285. tag = tagSelector.split('"], div.gtl[title="').pop().replace('"]', '')
  286.  
  287. if ((mode === 'All' && !itemTags.includes(tag)) ||
  288. (mode === 'Source' && ((!tag.startsWith('artist:') && !tag.startsWith('group:')) || !itemTags.includes(tag)))) {
  289. doHighlight = false
  290. break
  291. }
  292. }
  293.  
  294. if (doHighlight) {
  295. if (!itemHasHighlight) {
  296. item.addClass(STYLE_GALLERY_HIGHLIGHT)
  297. }
  298. break
  299. }
  300. }
  301.  
  302. if (!doHighlight && itemHasHighlight) {
  303. item.removeClass(STYLE_GALLERY_HIGHLIGHT)
  304. }
  305. }
  306.  
  307. } else if (itemHasHighlight) {
  308. item.removeClass(STYLE_GALLERY_HIGHLIGHT)
  309. }
  310. }
  311.  
  312. /**
  313. * @private
  314. */
  315. async _handleOpenGalleryImages()
  316. {
  317. let chunkSize = this._getConfig(UI_OPEN_GALLERY_PAGES_CHUNK_SIZE)
  318. let delay = this._getConfig(UI_OPEN_GALLERY_PAGES_DELAY)
  319. let images = $('#gdt > a')
  320. let iteration = 0
  321. let firstPageNumber = images.first().attr('href').split('-').pop()
  322. let maxPages = firstPageNumber + images.length - 1
  323.  
  324. for (let page = images.length - 1; page >= 0; page--) {
  325.  
  326. window.open(images.eq(page).attr('href'))
  327.  
  328. if (chunkSize && delay) {
  329.  
  330. iteration++
  331.  
  332. if (iteration === chunkSize && page !== 0) {
  333. iteration = 0
  334. await Utilities.sleep(delay * 1000)
  335. }
  336. }
  337. }
  338.  
  339. if (this._getConfig(UI_OPEN_GALLERY_PAGES_AUTO_NEXT)) {
  340.  
  341. let page = window.location.href.split('=')[1] || 0
  342. let pageNavs = $('.ptt td')
  343.  
  344. maxPages = Number.parseInt(pageNavs.eq(pageNavs.length - 2).children('a').text()) - 1
  345. if (page < maxPages) {
  346.  
  347. let uri = window.location.href
  348. if (page === 0) {
  349. uri += '?p=1'
  350. } else {
  351. uri = uri.replace('?p=' + page++, '?p=' + page)
  352. }
  353. window.location = uri
  354. }
  355. }
  356. }
  357.  
  358. /**
  359. * @param {JQuery} item
  360. * @param {string} option
  361. * @private
  362. */
  363. _handleRatedGalleries(item, option)
  364. {
  365. let doesntComply
  366. switch (option) {
  367. case 'Blue':
  368. doesntComply = this._get(item, ITEM_RATED_BLUE)
  369. break
  370. case 'Green':
  371. doesntComply = this._get(item, ITEM_RATED_GREEN)
  372. break
  373. case 'Red':
  374. doesntComply = this._get(item, ITEM_RATED_RED)
  375. break
  376. case 'All':
  377. doesntComply = this._get(item, ITEM_RATED_BLUE) || this._get(item, ITEM_RATED_GREEN) || this._get(item, ITEM_RATED_RED)
  378. break
  379. }
  380. return !doesntComply
  381. }
  382.  
  383. /**
  384. * @private
  385. */
  386. _handleTorrentDownloadsEmbedding()
  387. {
  388. let link = $('#gd5 > .g2 > a').eq(1)
  389. if (!link.text().endsWith('(0)')) {
  390.  
  391. let container = $('<div class="gm"></div>').insertBefore('#cdiv')
  392. container.load(link.attr('onclick').replace('return popUp(\'', '').replace('\',610,590)', '') + ' form', () => {
  393. container.prepend('<h1 style="font-size:10pt; font-weight:bold; margin:3px; text-align:center">Torrents</h1>')
  394. link.parent().remove()
  395. })
  396. }
  397. }
  398.  
  399. /**
  400. * @private
  401. */
  402. _setupEvents()
  403. {
  404. this._onValidateInit = () => !IS_SMALL_WINDOW
  405.  
  406. this._onBeforeUIBuild.push(() => {
  407.  
  408. this._performOperation(UI_VISITED_HIGHLIGHT, () => {
  409. GM_addStyle(`td.gl2e > div > a:visited > .glname > .glink {color: black;}`)
  410. })
  411.  
  412. if (IS_SEARCH_PAGE) {
  413. this._handleDefaults()
  414. GM_addStyle('.gallery-highlight{background-color:' + this._getConfig(UI_GALLERY_HIGHLIGHTS_COlOUR) + ' !important;border:whitesmoke 2px solid}')
  415. }
  416. })
  417.  
  418. this._onAfterUIBuild.push(() => {
  419.  
  420. this._uiGen.getSelectedSection()[0].userScript = this
  421.  
  422. if (IS_GALLERY_PAGE) {
  423. this._performOperation(UI_EMBED_TORRENTS, () => this._handleTorrentDownloadsEmbedding())
  424. }
  425. })
  426.  
  427. this._onItemHide = (item) => {
  428. if (item.is('td.gl2e')) {
  429. item.parent().addClass('noncompliant-item')
  430. item.parent().hide()
  431. } else {
  432. item.removeClass('noncompliant-item')
  433. item.hide()
  434. }
  435. }
  436.  
  437. this._onItemShow.push((item) => {
  438. if (item.is('td.gl2e')) {
  439. item.parent().removeClass('noncompliant-item')
  440. item.parent().show()
  441. } else {
  442. item.removeClass('noncompliant-item')
  443. item.show()
  444. }
  445. })
  446.  
  447. if (IS_SEARCH_PAGE) {
  448. this._onItemShow.push((item) => this._handleGalleryHighlights(item))
  449. }
  450. }
  451.  
  452. /**
  453. * @private
  454. */
  455. _setupFeatures()
  456. {
  457. this._configurationManager.
  458. addFlagField(
  459. FILTER_WATCHED_FROM_SEARCH,
  460. 'Hides watched galleries from searches initiated other than the watched page.').
  461. addFlagField(
  462. UI_OPEN_GALLERY_PAGES_AUTO_NEXT, 'Automatically navigates to the next page after opening all images.').
  463. addFlagField(
  464. UI_DEFAULTS_PAGE_RANGE_ENABLE,
  465. 'Always set these page limits in searches. Ignored if you set your own values on the page.').
  466. addFlagField(
  467. UI_DEFAULTS_RATING_ENABLE, 'Enable default rating filter in searches').
  468. addFlagField(
  469. UI_DEFAULTS_TAGS_ENABLE, 'Enable default tags in searches.').
  470. addFlagField(
  471. UI_EMBED_TORRENTS, 'Embed torrent downloads in gallery pages.').
  472. addFlagField(
  473. UI_VISITED_HIGHLIGHT, 'Colours the visited gallery links black, to make them distinct.').
  474. addNumberField(
  475. UI_OPEN_GALLERY_PAGES_CHUNK_SIZE, 0, 1000, 'Number of pages to open in one go. Set 0 to open all.').
  476. addNumberField(
  477. UI_OPEN_GALLERY_PAGES_DELAY, 0, 60, 'The delay between chunks in seconds. Set 0 to disable.').
  478. addRadiosGroup(
  479. FILTER_RATED_VIDEOS,
  480. [
  481. ['Disabled', 'Disabled'],
  482. ['Red', 'Red'],
  483. ['Blue', 'Blue'],
  484. ['Green', 'Green'],
  485. ['All', 'All'],
  486. ],
  487. 'Hides galleries rated by you with the colour set in site settings or all.').
  488. addRadiosGroup(
  489. UI_DEFAULTS_RATING,
  490. [
  491. ['2 stars', '2'],
  492. ['3 stars', '3'],
  493. ['4 stars', '4'],
  494. ['5 stars', '5'],
  495. ],
  496. 'Always set this rating filter in searches. Ignored if you set your own value on the page.').
  497. addRadiosGroup(
  498. UI_GALLERY_HIGHLIGHTS,
  499. [
  500. ['Disabled', 'Disabled'],
  501. ['All Favourite Tags', 'All'],
  502. ['Only Group / Artist Tags', 'Source'],
  503. ],
  504. 'Highlights favourite galleries in search results with at least one matching tag.').
  505. addRangeField(
  506. UI_DEFAULTS_PAGE_RANGE, 0, 2000, 'Enable default page range filter in searches.').
  507. addRulesetField(
  508. UI_DEFAULTS_TAGS,
  509. 3,
  510. 'Always add the following tags in search. Can be overridden with at least one tag present.').
  511. addTextField(
  512. UI_GALLERY_HIGHLIGHTS_COlOUR, 'Colour to highlight the galleries with. Requires refresh to change.', 'mediumaquamarine')
  513.  
  514. this._addItemTagAttribute(ITEM_TAGS, !IS_EXTENDED_LAYOUT, false, (item) => this._gatherItemTags(item))
  515.  
  516. this._itemAttributesResolver.
  517. addAttribute(ITEM_WATCHED, (item) => item.find('.gt[style],.gtl[style]').length > 0).
  518. addAttribute(ITEM_RATED_BLUE, (item) => item.find('.irb').length > 0).
  519. addAttribute(ITEM_RATED_GREEN, (item) => item.find('.irg').length > 0).
  520. addAttribute(ITEM_RATED_RED, (item) => item.find('.irr').length > 0)
  521.  
  522. let otherTagSections = IS_GALLERY_PAGE ? $('#taglist') : null
  523.  
  524. this._addItemComplexComplianceFilter(
  525. FILTER_RATED_VIDEOS,
  526. (option) => option !== 'Disabled',
  527. (item, option) => this._handleRatedGalleries(item, option))
  528.  
  529. this._addItemComplexComplianceFilter(
  530. FILTER_WATCHED_FROM_SEARCH,
  531. (enabled) => !IS_GALLERY_PAGE && !IS_WATCHED_PAGE && enabled,
  532. (item) => !this._get(item, ITEM_WATCHED))
  533.  
  534. this._addItemTagHighlights(
  535. UI_FAVOURITE_TAGS,
  536. otherTagSections,
  537. 'favourite-tag',
  538. 'Specify favourite tags to highlight.',
  539. 10,
  540. 'disliked-tag')
  541.  
  542. this._addItemTagHighlights(
  543. UI_DISLIKED_TAGS,
  544. otherTagSections,
  545. 'disliked-tag',
  546. 'Specify disliked tags to highlight.',
  547. 10,
  548. 'favourite-tag')
  549.  
  550. this._addItemTagBlacklistFilter(ITEM_TAGS, false, 20)
  551. }
  552.  
  553. /**
  554. * @private
  555. */
  556. _setupUI()
  557. {
  558. let galleryOptions = []
  559. let statistics = []
  560.  
  561. if (IS_GALLERY_PAGE) {
  562. galleryOptions = [
  563. this._uiGen.createSeparator(),
  564. this._uiGen.createFormButton(
  565. 'Open Gallery Images',
  566. 'Opens all images on current page of this gallery.',
  567. () => this._handleOpenGalleryImages(),
  568. ),
  569. ]
  570. } else {
  571. statistics = [
  572. this._uiGen.createStatisticsFormGroup(FILTER_TAG_BLACKLIST),
  573. this._uiGen.createStatisticsFormGroup(FILTER_RATED_VIDEOS),
  574. IS_WATCHED_PAGE ? '' : this._uiGen.createStatisticsFormGroup(FILTER_WATCHED_FROM_SEARCH),
  575. ]
  576. }
  577.  
  578. this._userInterface = [
  579. this._uiGen.createTabsSection(['Filters', 'Filters 2', 'Galleries', 'Tag Highlights', 'Search Defaults', 'UI', 'Backup'], [
  580. this._uiGen.createTabPanel('Filters', true).append([
  581. this._configurationManager.createElement(FILTER_WATCHED_FROM_SEARCH),
  582. this._configurationManager.createElement(OPTION_ENABLE_TAG_BLACKLIST),
  583. this._configurationManager.createElement(FILTER_TAG_BLACKLIST),
  584. this._configurationManager.createElement(OPTION_DISABLE_COMPLIANCE_VALIDATION),
  585. ]),
  586. this._uiGen.createTabPanel('Filters 2').append([
  587. this._configurationManager.createElement(FILTER_RATED_VIDEOS),
  588. ]),
  589. this._uiGen.createTabPanel('Galleries').append([
  590. this._uiGen.createTitle('Open Images'),
  591. this._configurationManager.createElement(UI_OPEN_GALLERY_PAGES_AUTO_NEXT),
  592. this._configurationManager.createElement(UI_OPEN_GALLERY_PAGES_CHUNK_SIZE),
  593. this._configurationManager.createElement(UI_OPEN_GALLERY_PAGES_DELAY),
  594. this._uiGen.createSeparator(),
  595. this._configurationManager.createElement(UI_GALLERY_HIGHLIGHTS),
  596. this._uiGen.createBreakSeparator(),
  597. this._uiGen.createBreakSeparator(),
  598. this._configurationManager.createElement(UI_GALLERY_HIGHLIGHTS_COlOUR),
  599. ]),
  600. this._uiGen.createTabPanel('Tag Highlights').append([
  601. this._configurationManager.createElement(UI_FAVOURITE_TAGS),
  602. this._configurationManager.createElement(UI_DISLIKED_TAGS),
  603. ]),
  604. this._uiGen.createTabPanel('Search Defaults').append([
  605. this._configurationManager.createElement(UI_DEFAULTS_PAGE_RANGE_ENABLE),
  606. this._configurationManager.createElement(UI_DEFAULTS_PAGE_RANGE),
  607. this._uiGen.createSeparator(),
  608. this._configurationManager.createElement(UI_DEFAULTS_RATING),
  609. this._uiGen.createBreakSeparator(),
  610. this._configurationManager.createElement(UI_DEFAULTS_RATING_ENABLE),
  611. this._uiGen.createSeparator(),
  612. this._configurationManager.createElement(UI_DEFAULTS_TAGS_ENABLE),
  613. this._configurationManager.createElement(UI_DEFAULTS_TAGS),
  614. ]),
  615. this._uiGen.createTabPanel('UI').append([
  616. this._configurationManager.createElement(UI_EMBED_TORRENTS),
  617. this._configurationManager.createElement(UI_VISITED_HIGHLIGHT),
  618. this._configurationManager.createElement(OPTION_ALWAYS_SHOW_SETTINGS_PANE),
  619. ]),
  620. this._uiGen.createTabPanel('Backup').append([
  621. this._createSettingsBackupRestoreFormActions(),
  622. ]),
  623. ]),
  624. ...statistics,
  625. ...galleryOptions,
  626. this._uiGen.createSeparator(),
  627. this._createSettingsFormActions(),
  628. this._uiGen.createSeparator(),
  629. this._uiGen.createStatusSection(),
  630. ]
  631. }
  632. }
  633.  
  634. if (!IS_IMAGE_PAGE) {
  635. (new EHentaiSearchAndUITweaks).init()
  636. }