Hitomi - Language & Tag Filtering

Search Filters & UI Manipulations

Versión del día 26/01/2019. Echa un vistazo a la versión más reciente.

  1. // ==UserScript==
  2. // @name Hitomi - Language & Tag Filtering
  3. // @namespace brazenvoid
  4. // @version 2.6.0
  5. // @author brazenvoid
  6. // @license GPL-3.0-only
  7. // @description Search Filters & UI Manipulations
  8. // @include https://hitomi.la/*
  9. // @run-at document-idle
  10. // ==/UserScript==
  11.  
  12. // Define languages to keep and tags to exclude here
  13.  
  14. let settings = {
  15. allowedGalleryTypes: [
  16. 'artist cg',
  17. 'doujinshi',
  18. 'game cg',
  19. 'manga',
  20. ],
  21. allowedLanguages: [
  22. 'japanese',
  23. 'korean',
  24. 'english'
  25. ],
  26. excludedTags: [
  27. 'anthology',
  28. 'female:daughter',
  29. 'female:females only',
  30. 'female:mother',
  31. 'sample',
  32. 'male:father',
  33. 'male:son',
  34. 'male:yaoi',
  35. ],
  36. excludedTagGroups: [
  37. ['female:loli', 'female:sole female'],
  38. ['male:shota', 'male:sole male'],
  39. ],
  40. removeRelatedGalleries: true,
  41. }
  42.  
  43. // Translate gallery types to css selectors
  44.  
  45. let allowedGallerySelectors = [], allowedGalleryTypeSelector
  46.  
  47. for (let allowedGalleryType of settings.allowedGalleryTypes) {
  48. switch (allowedGalleryType) {
  49. case 'anime':
  50. allowedGalleryTypeSelector = 'anime'
  51. break
  52. case 'artist cg':
  53. allowedGalleryTypeSelector = 'acg'
  54. break
  55. case 'doujinshi':
  56. allowedGalleryTypeSelector = 'dj'
  57. break
  58. case 'game cg':
  59. allowedGalleryTypeSelector = 'cg'
  60. break
  61. case 'manga':
  62. allowedGalleryTypeSelector = 'manga'
  63. break
  64. default:
  65. continue
  66. }
  67. allowedGallerySelectors.push(allowedGalleryTypeSelector)
  68. }
  69.  
  70. // Formatting filters
  71.  
  72. let formatFilters = function (filters, prefix, suffix, join) {
  73.  
  74. let formatFilter = function (filter) {
  75. return '[href="' + prefix + encodeURIComponent(filter) + suffix + '.html"]'
  76. }
  77. let index2
  78. for (let index = 0; index < filters.length; index++) {
  79. if (Array.isArray(filters[index])) {
  80. for (index2 = 0; index2 < filters[index].length; index2++) {
  81. filters[index][index2] = formatFilter(filters[index][index2])
  82. }
  83. filters[index] = filters[index].join(', ')
  84. } else {
  85. filters[index] = formatFilter(filters[index])
  86. }
  87. }
  88. return join ? filters.join(', ') : filters
  89. }
  90.  
  91. let languageFiltersSelector = formatFilters(settings.allowedLanguages, '/index-', '-1', true)
  92. let tagFiltersSelector = formatFilters(settings.excludedTags, '/tag/', '-all-1', true)
  93. let tagGroupFiltersSelectors = formatFilters(settings.excludedTagGroups, '/tag/', '-all-1', false)
  94.  
  95. // Filtration logic
  96.  
  97. let validateLanguage = function (gallery) {
  98.  
  99. let validationCheck = true
  100.  
  101. if (settings.allowedLanguages.length > 0) {
  102.  
  103. let languageTD = gallery.querySelector('tr:nth-child(3) > td:nth-child(2)')
  104. if (languageTD.querySelector('a') !== null) {
  105. validationCheck = languageTD.querySelectorAll(languageFiltersSelector).length > 0
  106. }
  107. }
  108. return validationCheck
  109. }
  110.  
  111. let validateTags = function (gallery) {
  112.  
  113. let validationCheck = true
  114.  
  115. if (settings.excludedTags.length > 0) {
  116. validationCheck = gallery.querySelectorAll(tagFiltersSelector).length === 0
  117. }
  118. if (validationCheck && settings.excludedTagGroups.length > 0) {
  119. for (let tagGroupFilterSelector of tagGroupFiltersSelectors) {
  120. validationCheck = gallery.querySelectorAll(tagGroupFilterSelector).length < tagGroupFilterSelector.length
  121. if (!validationCheck) {
  122. break
  123. }
  124. }
  125. }
  126. return validationCheck
  127. }
  128.  
  129. let validateType = function (gallery) {
  130. return allowedGallerySelectors.includes(gallery.className)
  131. }
  132.  
  133. let complianceCallback = function (target) {
  134.  
  135. let galleries = target.querySelectorAll('.anime, .manga, .dj, .acg, .cg')
  136. let validationCheck
  137.  
  138. for (let gallery of galleries) {
  139.  
  140. validationCheck = validateType(gallery) && validateLanguage(gallery) && validateTags(gallery)
  141.  
  142. if (!validationCheck) {
  143. gallery.remove()
  144. }
  145. }
  146. }
  147.  
  148. // Script Run
  149.  
  150. let galleriesList = document.querySelector('.gallery-content')
  151. let isGalleryPage = document.getElementById('dl-button') !== null
  152.  
  153. if (isGalleryPage && settings.removeRelatedGalleries) {
  154.  
  155. galleriesList.remove()
  156.  
  157. } else {
  158.  
  159. let observerConfig = {
  160. attributes: false,
  161. childList: true,
  162. subtree: false
  163. }
  164. complianceCallback(galleriesList)
  165.  
  166. // Adding observer to check compliance of galleries
  167.  
  168. let observer = new MutationObserver(function (mutations) {
  169. for (let mutation of mutations) {
  170. complianceCallback(mutation.target)
  171. }
  172. })
  173. observer.observe(galleriesList, observerConfig)
  174. }