E-Hentai - UX Tweaks

Complex tag highlights and blacklisting

Version vom 26.09.2023. Aktuellste Version

  1. // ==UserScript==
  2. // @name E-Hentai - UX Tweaks
  3. // @namespace brazenvoid
  4. // @version 1.2.1
  5. // @author brazenvoid
  6. // @license GPL-3.0-only
  7. // @description Complex tag highlights and blacklisting
  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://greasyfork.org/scripts/375557-base-brazen-resource/code/Base%20Brazen%20Resource.js?version=1244990
  12. // @require https://greasyfork.org/scripts/416104-brazen-ui-generator/code/Brazen%20UI%20Generator.js?version=1245460
  13. // @require https://greasyfork.org/scripts/418665-brazen-configuration-manager/code/Brazen%20Configuration%20Manager.js?version=1245040
  14. // @require https://greasyfork.org/scripts/429587-brazen-item-attributes-resolver/code/Brazen%20Item%20Attributes%20Resolver.js?version=1244644
  15. // @require https://greasyfork.org/scripts/416105-brazen-base-search-enhancer/code/Brazen%20Base%20Search%20Enhancer.js?version=1245401
  16. // @grant GM_addStyle
  17. // @run-at document-end
  18. // ==/UserScript==
  19.  
  20. GM_addStyle(
  21. `#settings-wrapper{min-width:270px;width:270px}.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_SMALL_WINDOW = $('.stuffbox').length
  25.  
  26. const UI_FAVOURITE_TAGS = 'Favourite Tags'
  27. const UI_DISLIKED_TAGS = 'Disliked Tags'
  28. const UI_VISITED_HIGHLIGHT = 'Highlight Visited'
  29. const UI_AUTO_NEXT_ON_OPEN_ALL_IMAGES = 'Auto Next Page'
  30.  
  31. class EHentaiSearchAndUITweaks extends BrazenBaseSearchEnhancer
  32. {
  33. constructor()
  34. {
  35. super({
  36. isUserLoggedIn: false,
  37. itemDeepAnalysisSelector: '',
  38. itemLinkSelector: 'td.gl3m.glname > a, td.gl3c.glname > a, div.gl2e > div > a, a',
  39. itemListSelectors: 'table.itg, div.itg',
  40. itemNameSelector: 'td.gl3m.glname > a > div.glink, td.gl3c.glname > a > div.glink, div.gl4e.glname > div.glink, div.gl4t.glname.glink',
  41. itemSelectors: 'td.gl2e, div.gl1t',
  42. requestDelay: 0,
  43. scriptPrefix: 'e-hentai-ux-',
  44. tagSelectorGenerator: (tag) => {
  45. tag = tag.trim()
  46. if (IS_GALLERY_PAGE) {
  47. return 'div[id="td_' + tag.replace(' ', '_') + '"]'
  48. }
  49. return 'div.gt[title="' + tag + '"], div.gtl[title="' + tag + '"]'
  50. },
  51. })
  52. this._setupFeatures()
  53. this._setupUI()
  54. this._setupEvents()
  55. }
  56.  
  57. _setupEvents()
  58. {
  59. this._onValidateInit = () => !IS_SMALL_WINDOW
  60.  
  61. this._onBeforeUIBuild.push(() => this._performOperation(
  62. UI_VISITED_HIGHLIGHT, () => GM_addStyle(`td.gl2e > div > a:visited > .glname > .glink {color: black;}`)))
  63.  
  64. this._onAfterUIBuild.push(() => this._uiGen.getSelectedSection()[0].userScript = this)
  65.  
  66. this._onItemHide = (item) => {
  67. if (item.is('td.gl2e')) {
  68. item.parent().addClass('noncompliant-item')
  69. item.parent().hide()
  70. } else {
  71. item.removeClass('noncompliant-item')
  72. item.hide()
  73. }
  74. }
  75.  
  76. this._onItemShow = (item) => {
  77. if (item.is('td.gl2e')) {
  78. item.parent().removeClass('noncompliant-item')
  79. item.parent().show()
  80. } else {
  81. item.removeClass('noncompliant-item')
  82. item.show()
  83. }
  84. }
  85. }
  86.  
  87. /**
  88. * @private
  89. */
  90. _setupFeatures()
  91. {
  92. this._configurationManager
  93. .addFlagField(UI_AUTO_NEXT_ON_OPEN_ALL_IMAGES, 'Automatically navigates to the next page after opening all images.')
  94. .addFlagField(UI_VISITED_HIGHLIGHT, 'Colours the visited gallery links black, to make them distinct.')
  95.  
  96. let otherTagSections = IS_GALLERY_PAGE ? $('#taglist') : null
  97.  
  98. this._addItemTagHighlights(UI_FAVOURITE_TAGS, otherTagSections, 'favourite-tag', 'Specify favourite tags to highlight.', 10)
  99. this._addItemTagHighlights(UI_DISLIKED_TAGS, otherTagSections, 'disliked-tag', 'Specify disliked tags to highlight.', 10)
  100. this._addItemTagBlacklistFilter(20)
  101. }
  102.  
  103. /**
  104. * @private
  105. */
  106. _setupUI()
  107. {
  108. let openGalleryPages = []
  109. if (IS_GALLERY_PAGE) {
  110. openGalleryPages = [
  111. this._uiGen.createSeparator(),
  112. this._uiGen.createFormButton(
  113. 'Open Gallery Images',
  114. 'Opens all images on current page of this gallery.',
  115. () => {
  116.  
  117. let images = $('div.gdtl a > img, div.gdtm a > img')
  118. let firstPage = images.first().attr('alt')
  119. let firstPageNumber = Number(firstPage)
  120. let paddedPageLength = firstPage.length
  121. let maxPages = firstPageNumber + images.length - 1
  122.  
  123. for (let page = maxPages; page >= firstPageNumber; page--) {
  124.  
  125. let paddedPage = page.toString().padStart(paddedPageLength, '0')
  126. window.open(images.filter('[alt="' + paddedPage + '"]').parent().attr('href'))
  127. }
  128.  
  129. if (this._getConfig(UI_AUTO_NEXT_ON_OPEN_ALL_IMAGES)) {
  130.  
  131. let page = window.location.href.split('=')[1] || 0
  132. let pageNavs = $('.ptt td')
  133. let maxPages = Number.parseInt(pageNavs.eq(pageNavs.length - 2).children('a').attr('href').split('=')[1]) || 1
  134.  
  135. if (maxPages > 1 && page < maxPages) {
  136.  
  137. let uri = window.location.href
  138. if (page === 0) {
  139. uri += '?p=1'
  140. } else {
  141. uri = uri.replace('?p=' + page++, '?p=' + page)
  142. }
  143. window.location = uri
  144. }
  145. }
  146. }),
  147. this._uiGen.createBreakSeparator(),
  148. this._configurationManager.createElement(UI_AUTO_NEXT_ON_OPEN_ALL_IMAGES),
  149. ]
  150. }
  151.  
  152. this._userInterface = [
  153. this._uiGen.createTabsSection(['Filters', 'Highlights', 'Global'], [
  154. this._uiGen.createTabPanel('Filters', true).append([
  155. this._configurationManager.createElement(OPTION_ENABLE_BLACKLIST),
  156. this._configurationManager.createElement(FILTER_TAG_BLACKLIST),
  157. // this._uiGen.createSeparator(),
  158. // this._configurationManager.createElement(OPTION_DISABLE_COMPLIANCE_VALIDATION),
  159. ]),
  160. this._uiGen.createTabPanel('Highlights').append([
  161. this._configurationManager.createElement(UI_FAVOURITE_TAGS),
  162. this._configurationManager.createElement(UI_DISLIKED_TAGS),
  163. ]),
  164. this._uiGen.createTabPanel('Global').append([
  165. this._configurationManager.createElement(UI_VISITED_HIGHLIGHT),
  166. this._configurationManager.createElement(OPTION_ALWAYS_SHOW_SETTINGS_PANE),
  167. this._uiGen.createSeparator(),
  168. this._createSettingsBackupRestoreFormActions(),
  169. ]),
  170. ]),
  171. this._uiGen.createStatisticsFormGroup(FILTER_TAG_BLACKLIST),
  172. ...openGalleryPages,
  173. this._uiGen.createSeparator(),
  174. // this._uiGen.createStatisticsTotalsGroup(),
  175. this._createSettingsFormActions(),
  176. this._uiGen.createSeparator(),
  177. this._uiGen.createStatusSection(),
  178. ]
  179. }
  180. }
  181.  
  182. (new EHentaiSearchAndUITweaks).init()