Hitomi - Search & UI Tweaks

Various search filters and user experience enhancers

Ajankohdalta 6.5.2024. Katso uusin versio.

  1. // ==UserScript==
  2. // @name Hitomi - Search & UI Tweaks
  3. // @namespace brazenvoid
  4. // @version 6.1.2
  5. // @author brazenvoid
  6. // @license GPL-3.0-only
  7. // @description Various search filters and user experience enhancers
  8. // @match https://hitomi.la/*
  9. // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js
  10. // @require https://update.greasyfork.org/scripts/375557/1244990/Base%20Brazen%20Resource.js
  11. // @require https://update.greasyfork.org/scripts/416104/1371950/Brazen%20UI%20Generator.js
  12. // @require https://update.greasyfork.org/scripts/418665/1245040/Brazen%20Configuration%20Manager.js
  13. // @require https://update.greasyfork.org/scripts/429587/1244644/Brazen%20Item%20Attributes%20Resolver.js
  14. // @require https://update.greasyfork.org/scripts/416105/1300196/Brazen%20Base%20Search%20Enhancer.js
  15. // @grant GM_addStyle
  16. // @run-at document-end
  17. // ==/UserScript==
  18.  
  19. GM_addStyle(
  20. `#settings-wrapper{min-width:400px;width:400px}.disliked-tag{background-color:lightcoral !important}.disliked-tag:hover{background-color:indianred !important}.disliked-tag.favourite-tag{background-color:orange !important}.disliked-tag.favourite-tag:hover{background-color:darkorange !important}.favourite-tag{background-color:mediumseagreen !important}.favourite-tag:hover{background-color:forestgreen !important}`)
  21.  
  22. const IS_GALLERY_PAGE = $('#dl-button').length
  23.  
  24. const FILTER_GALLERY_TYPES = 'Show Gallery Types'
  25. const FILTER_PAGES = 'Pages'
  26. const FILTER_LANGUAGES = 'Languages'
  27.  
  28. const OPTION_REMOVE_RELATED_GALLERIES = 'Remove Related Galleries'
  29.  
  30. const UI_FAVOURITE_TAGS = 'Favourite Tags'
  31. const UI_DISLIKED_TAGS = 'Disliked Tags'
  32. const UI_SHOW_ALL_TAGS = 'Show All Gallery Tags'
  33.  
  34. const ITEM_GALLERY_TYPE = 'Gallery Type'
  35. const ITEM_LANGUAGE = 'Language'
  36.  
  37. class HitomiSearchAndUITweaks extends BrazenBaseSearchEnhancer
  38. {
  39. constructor()
  40. {
  41. super({
  42. isUserLoggedIn: false,
  43. itemDeepAnalysisSelector: '',
  44. itemLinkSelector: '',
  45. itemListSelectors: '.gallery-content',
  46. itemNameSelector: 'h1.lillie a',
  47. itemSelectors: '.anime,.acg,.dj,.cg,.imageset,.manga',
  48. requestDelay: 0,
  49. scriptPrefix: 'hitomi-sui-',
  50. tagSelectorGenerator: (tag) => {
  51. let selector
  52. tag = encodeURIComponent(tag.trim()).replace('-', '%2D')
  53.  
  54. if (tag.startsWith('artist%3A')) {
  55. selector = 'a[href="/artist/' + tag.replace('artist%3A', '') + '-all.html"]'
  56. } else if (tag.startsWith('series%3A')) {
  57. selector = 'a[href="/series/' + tag.replace('series%3A', '') + '-all.html"]'
  58. } else {
  59. selector = 'a[href="/tag/' + tag + '-all.html"]'
  60. }
  61. return selector
  62. },
  63. })
  64. this._setupFeatures()
  65. this._setupUI()
  66. this._setupEvents()
  67. }
  68.  
  69. /**
  70. * @private
  71. */
  72. _setupEvents()
  73. {
  74. if (IS_GALLERY_PAGE) {
  75.  
  76. this._onBeforeUIBuild.push(() => this._performComplexOperation(
  77. FILTER_PAGES,
  78. (range) => !this._getConfig(OPTION_DISABLE_COMPLIANCE_VALIDATION) && this._configurationManager.generateValidationCallback(FILTER_PAGES)(range),
  79. (range) => {
  80. let navPages = $('.simplePagerNav li').length
  81. let pageCount = navPages > 0 ? navPages * 50 : $('.simplePagerPage1').length
  82. if (!Validator.isInRange(pageCount, range.minimum, range.maximum)) {
  83. top.close()
  84. }
  85. }),
  86. )
  87.  
  88. this._onBeforeUIBuild.push(() => this._performOperation(
  89. OPTION_REMOVE_RELATED_GALLERIES, () => $('.gallery-content').remove()))
  90. }
  91.  
  92. this._onAfterUIBuild.push(() => this._uiGen.getSelectedSection()[0].userScript = this)
  93.  
  94. this._onFirstHitAfterCompliance.push((item) => {
  95. this._performComplexOperation(UI_SHOW_ALL_TAGS, (flag) => flag && !IS_GALLERY_PAGE, () => {
  96. let tags = item.find('.relatedtags > ul > li')
  97. let lastTag = tags.last()
  98. if (lastTag.text() === '...') {
  99. lastTag.remove()
  100. tags.filter('.hidden-list-item').removeClass('hidden-list-item')
  101. }
  102. })
  103. })
  104. }
  105.  
  106. /**
  107. * @private
  108. */
  109. _setupFeatures()
  110. {
  111. this._configurationManager
  112. .addCheckboxesGroup(FILTER_GALLERY_TYPES, [
  113. ['Anime', 'anime'],
  114. ['Artist CG', 'acg'],
  115. ['Doujinshi', 'dj'],
  116. ['Game CG', 'cg'],
  117. ['Image Set', 'imageset'],
  118. ['Manga', 'manga'],
  119. ], 'Show only selected gallery types.')
  120. .addCheckboxesGroup(FILTER_LANGUAGES, [
  121. ['N/A', 'not-applicable'],
  122. ['Japanese', 'japanese'],
  123. ['Chinese', 'chinese'],
  124. ['English', 'english'],
  125. ['Albanian', 'albanian'],
  126. ['Arabic', 'arabic'],
  127. ['Bulgarian', 'bulgarian'],
  128. ['Catalan', 'catalan'],
  129. ['Cebuano', 'cebuano'],
  130. ['Czech', 'czech'],
  131. ['Danish', 'danish'],
  132. ['Dutch', 'dutch'],
  133. ['Esperanto', 'esperanto'],
  134. ['Estonian', 'estonian'],
  135. ['Finnish', 'finnish'],
  136. ['French', 'french'],
  137. ['German', 'german'],
  138. ['Greek', 'greek'],
  139. ['Hebrew', 'hebrew'],
  140. ['Hungarian', 'hungarian'],
  141. ['Indonesian', 'indonesian'],
  142. ['Italian', 'italian'],
  143. ['Korean', 'korean'],
  144. ['Latin', 'latin'],
  145. ['Mongolian', 'mongolian'],
  146. ['Norwegian', 'norwegian'],
  147. ['Persian', 'persian'],
  148. ['Polish', 'polish'],
  149. ['Portuguese', 'portuguese'],
  150. ['Romanian', 'romanian'],
  151. ['Russian', 'russian'],
  152. ['Slovak', 'slovak'],
  153. ['Spanish', 'spanish'],
  154. ['Swedish', 'swedish'],
  155. ['Tagalog', 'tagalog'],
  156. ['Thai', 'thai'],
  157. ['Turkish', 'turkish'],
  158. ['Ukrainian', 'ukrainian'],
  159. ['Unspecified', 'unspecified'],
  160. ['Vietnamese', 'vietnamese'],
  161. ], 'Select languages to show')
  162. .addFlagField(OPTION_REMOVE_RELATED_GALLERIES, 'Remove related galleries section from gallery pages.')
  163. .addFlagField(UI_SHOW_ALL_TAGS, 'Show all gallery tags in search results.')
  164. .addRangeField(FILTER_PAGES, 0, Infinity, 'Close gallery pages that don\'t satisfy these page limits. Only works on galleries opened in new tabs.')
  165.  
  166. this._itemAttributesResolver
  167. .addAttribute(ITEM_GALLERY_TYPE, (item) => item.attr('class'))
  168. .addAttribute(ITEM_LANGUAGE, (item) => {
  169. let link = item.find('tr:nth-child(3) > td:nth-child(2) a')
  170. if (link.length) {
  171. return link.attr('href').replace('/index-', '').replace('.html', '')
  172. }
  173. return 'not-applicable'
  174. })
  175.  
  176. this._addItemComplianceFilter(FILTER_LANGUAGES, ITEM_LANGUAGE)
  177. this._addItemComplianceFilter(FILTER_GALLERY_TYPES, ITEM_GALLERY_TYPE)
  178.  
  179. let otherTagSections = IS_GALLERY_PAGE ? $('.tags') : null
  180.  
  181. this._addItemTagHighlights(UI_FAVOURITE_TAGS, otherTagSections, 'favourite-tag', 'Specify favourite tags to highlight. "&" "|" can be used.')
  182. this._addItemTagHighlights(UI_DISLIKED_TAGS, otherTagSections, 'disliked-tag', 'Specify disliked tags to highlight. "&" "|" can be used.')
  183. this._addItemTagBlacklistFilter(8)
  184. }
  185.  
  186. /**
  187. * @private
  188. */
  189. _setupUI()
  190. {
  191. this._userInterface = [
  192. this._uiGen.createTabsSection(['Filters', 'Highlights', 'Languages', 'Global', 'Stats'], [
  193. this._uiGen.createTabPanel('Filters', true).append([
  194. this._configurationManager.createElement(FILTER_GALLERY_TYPES),
  195. this._uiGen.createSeparator(),
  196. this._configurationManager.createElement(FILTER_PAGES),
  197. this._uiGen.createSeparator(),
  198. this._configurationManager.createElement(OPTION_ENABLE_TAG_BLACKLIST),
  199. this._configurationManager.createElement(FILTER_TAG_BLACKLIST),
  200. ]),
  201. this._uiGen.createTabPanel('Highlights').append([
  202. this._configurationManager.createElement(UI_FAVOURITE_TAGS),
  203. this._configurationManager.createElement(UI_DISLIKED_TAGS),
  204. ]),
  205. this._uiGen.createTabPanel('Languages').append([
  206. this._configurationManager.createElement(FILTER_LANGUAGES),
  207. ]),
  208. this._uiGen.createTabPanel('Global').append([
  209. this._configurationManager.createElement(UI_SHOW_ALL_TAGS),
  210. this._configurationManager.createElement(OPTION_ALWAYS_SHOW_SETTINGS_PANE),
  211. this._uiGen.createSeparator(),
  212. this._createSettingsBackupRestoreFormActions(),
  213. ]),
  214. this._uiGen.createTabPanel('Stats').append([
  215. this._uiGen.createStatisticsFormGroup(FILTER_GALLERY_TYPES),
  216. this._uiGen.createStatisticsFormGroup(FILTER_LANGUAGES),
  217. this._uiGen.createStatisticsFormGroup(FILTER_TAG_BLACKLIST),
  218. this._uiGen.createSeparator(),
  219. this._uiGen.createStatisticsTotalsGroup(),
  220. ]),
  221. ]),
  222. this._configurationManager.createElement(OPTION_DISABLE_COMPLIANCE_VALIDATION),
  223. this._uiGen.createSeparator(),
  224. this._createSettingsFormActions(),
  225. this._uiGen.createSeparator(),
  226. this._uiGen.createStatusSection(),
  227. ]
  228. }
  229. }
  230.  
  231. (new HitomiSearchAndUITweaks).init()