Hitomi - Search & UI Tweaks

Search Filters & UI Manipulations

От 08.02.2019. Виж последната версия.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         Hitomi - Search & UI Tweaks
// @namespace    brazenvoid
// @version      2.6.1
// @author       brazenvoid
// @license      GPL-3.0-only
// @description  Search Filters & UI Manipulations
// @include      https://hitomi.la/*
// @run-at       document-idle
// ==/UserScript==

// Define languages to keep and tags to exclude here

let settings = {
  allowedGalleryTypes: [
    'artist cg',
    'doujinshi',
    'game cg',
    'manga',
  ],
  allowedLanguages: [
    'japanese',
    'english'
  ],
  excludedTags: [
    'female:daughter',
    'female:mother',
    'sample',
    'male:father',
    'male:son',
    'male:yaoi'
  ],
  excludedTagGroups: [
    ['female:loli', 'female:sole female'],
    ['male:shota', 'male:sole male'],
  ],
  removeRelatedGalleries: true,
}

// Translate gallery types to css selectors

let allowedGallerySelectors = [], allowedGalleryTypeSelector

for (let allowedGalleryType of settings.allowedGalleryTypes) {
  switch (allowedGalleryType) {
    case 'anime':
      allowedGalleryTypeSelector = 'anime'
      break
    case 'artist cg':
      allowedGalleryTypeSelector = 'acg'
      break
    case 'doujinshi':
      allowedGalleryTypeSelector = 'dj'
      break
    case 'game cg':
      allowedGalleryTypeSelector = 'cg'
      break
    case 'manga':
      allowedGalleryTypeSelector = 'manga'
      break
    default:
      continue
  }
  allowedGallerySelectors.push(allowedGalleryTypeSelector)
}

// Formatting filters

let formatFilters = function (filters, prefix, suffix, join) {

  let formatFilter = function (filter) {
    return '[href="' + prefix + encodeURIComponent(filter) + suffix + '.html"]'
  }
  let index2
  for (let index = 0; index < filters.length; index++) {
    if (Array.isArray(filters[index])) {
      for (index2 = 0; index2 < filters[index].length; index2++) {
        filters[index][index2] = formatFilter(filters[index][index2])
      }
    } else {
      filters[index] = formatFilter(filters[index])
    }
  }
  return join ? filters.join(', ') : filters
}

let languageFiltersSelector = formatFilters(settings.allowedLanguages, '/index-', '-1', true)
let tagFiltersSelector = formatFilters(settings.excludedTags, '/tag/', '-all-1', true)
let tagGroupFiltersSelectors = formatFilters(settings.excludedTagGroups, '/tag/', '-all-1', false)

// Filtration logic

let validateLanguage = function (gallery) {

  let validationCheck = true

  if (settings.allowedLanguages.length > 0) {

    let languageTD = gallery.querySelector('tr:nth-child(3) > td:nth-child(2)')
    if (languageTD.querySelector('a') !== null) {
      validationCheck = languageTD.querySelectorAll(languageFiltersSelector).length > 0
    }
  }
  return validationCheck
}

let validateTags = function (gallery) {

  let validationCheck = true

  if (settings.excludedTags.length > 0) {
    validationCheck = gallery.querySelectorAll(tagFiltersSelector).length === 0
  }
  if (validationCheck && settings.excludedTagGroups.length > 0) {
    for (let tagGroupFilterSelectors of tagGroupFiltersSelectors) {
      validationCheck = gallery.querySelectorAll(tagGroupFilterSelectors.join(', ')).length < tagGroupFilterSelectors.length
      if (!validationCheck) {
        break
      }
    }
  }
  return validationCheck
}

let validateType = function (gallery) {
  return allowedGallerySelectors.includes(gallery.className)
}

let complianceCallback = function (target) {

  let galleries = target.querySelectorAll('.anime, .manga, .dj, .acg, .cg')
  let validationCheck

  for (let gallery of galleries) {

    validationCheck = validateType(gallery) && validateLanguage(gallery) && validateTags(gallery)

    if (!validationCheck) {
      gallery.remove()
    }
  }
}

// Script Run

let galleriesList = document.querySelector('.gallery-content')
let isGalleryPage = document.getElementById('dl-button') !== null

if (isGalleryPage && settings.removeRelatedGalleries) {

  galleriesList.remove()

} else {

  let observerConfig = {
    attributes: false,
    childList: true,
    subtree: false
  }
  complianceCallback(galleriesList)

  // Adding observer to check compliance of galleries

  let observer = new MutationObserver(function (mutations) {
    for (let mutation of mutations) {
      complianceCallback(mutation.target)
    }
  })
  observer.observe(galleriesList, observerConfig)
}