XHamster - Search Filters

Various search filters

Versione datata 26/02/2019. Vedi la nuova versione l'ultima versione.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name          XHamster - Search Filters
// @namespace     brazenvoid
// @version       1.0.0
// @author        brazenvoid
// @license       GPL-3.0-only
// @description   Various search filters
// @include       https://xhamster.com/*
// @require       https://greasyfork.org/scripts/375557-brazenvoid-s-base-resource/code/Brazenvoid's%20Base%20Resource.js?version=673754
// @run-at        document-idle
// ==/UserScript==

// Settings & Defaults

let settings = {
  blacklist: [ // case-insensitive
    'urin',
    'arab',
    'muslim',
    'desi',
    'squirt',
    'fake',
    'pregnant',
    'pee',
  ],
  sanitize: { // Substitutes values with key (case-insensitive)
    ' ': ['neighbor', 'step'],
    Boyfriend: ['brother', 'bro', 'daddy', 'dad'],
    Girlfriend: ['daughter', 'mom', 'mother', 'sister', 'sis']
  },
  duration: { // In Seconds
    minimum: 120,
    maximum: 0
  },
  rating: {
    minimum: 80,
    maximum: 0
  },
  views: {
    minimum: 0,
    maximum: 0
  },
  hideSDVideos: true,
  showUIAlways: false, // Desktop
  debugLogging: false
}

// Base Resources Initialization

const scriptPrefix = 'xh-sui-'

let storage = new LocalStore(scriptPrefix + 'settings', settings)
settings = storage.retrieve().get()

let logger = new Logger(settings.debugLogging)
let selectorGenerator = new SelectorGenerator(scriptPrefix)
let statistics = new StatisticsRecorder(logger, selectorGenerator)

let uiGenerator = new UIGenerator(settings.showUIAlways, selectorGenerator)
uiGenerator.buttonBackroundColor = 'rgb(218, 218, 218)'

let validator = new Validator(statistics)
validator.addBlacklistFilter(settings.blacklist).addSanitizationFilter(settings.sanitize).optimize()

function getVideoLists () {
  return document.querySelectorAll('div.thumb-list')
}

// Local Store Events

let refreshUI = function () {
  let store = this.get()

  uiGenerator.setSettingsInputValue('Min Duration', store.duration.minimum)
  uiGenerator.setSettingsInputValue('Min Rating', store.rating.minimum)
  uiGenerator.setSettingsInputValue('Min Views', store.views.minimum)
}
storage.onDefaultsLoaded = refreshUI
storage.onRetrieval = refreshUI
storage.onUpdated = refreshUI

// Validators
// -- Duration validation

let validateDuration = function (videoItem) {

  if (settings.duration.minimum > 0 || settings.duration.maximum > 0) {

    let duration = videoItem.querySelector('div.thumb-image-container__duration').textContent.split(':')
    duration = (parseInt(duration[0]) * 60) + parseInt(duration[1])

    return validator.validateRange('Duration', duration, [settings.duration.minimum, settings.duration.maximum])
  }
  return true
}

// -- High definition validation

let validateHD = function (videoItem) {

  let validationCheck = true

  if (settings.hideSDVideos) {

    validationCheck = videoItem.querySelector('i.thumb-image-container__icon--hd') !== null

    logger.logValidation('HD', validationCheck)
  }
  return validationCheck
}

// -- Rating validation

let validateRating = function (videoItem) {

  let validationCheck = true

  if (settings.rating.minimum > 0 || settings.rating.maximum > 0) {

    let rating = videoItem.querySelector('i.video-thumb-info__rating')

    if (rating !== null) {
      rating = parseInt(rating.textContent.replace('%', ''))
      validationCheck = validator.validateRange('Rating', rating, [settings.rating.minimum, settings.rating.maximum])
    }
  }
  return validationCheck
}

// -- View count validation

let validateViews = function (videoItem) {
  if (settings.views.minimum > 0 || settings.views.maximum > 0) {
    return validator.validateRange('Views', videoItem.querySelector('i.video-thumb-info__views').textContent, [settings.views.minimum, settings.views.maximum])
  }
  return true
}

// -- Compliance logic

let complianceCallback = function (target) {

  let videoItems = target.querySelectorAll('div.thumb-list__item')
  let videoName, videoComplies

  for (let videoItem of videoItems) {

    videoName = videoItem.querySelector('a.video-thumb-info__name')
    logger.logVideoCheck(videoName.textContent)


    videoComplies =
      validateHD(videoItem) &&
      validateRating(videoItem) &&
      validator.validateBlackList(videoName.textContent) &&
      validateDuration(videoItem) &&
      validateViews(videoItem)

    if (videoComplies) {
      videoItem.style.display = 'inline-block'
      validator.sanitizeVideoItem(videoName)
    } else {
      videoItem.style.display = 'none'
    }

    logger.logSeparator()
  }
  statistics.updateUI()
}

// UI Composition
// -- Control Panel

let section = uiGenerator.createSection('settings', '#ffa31a', '150px', '220px', [
  uiGenerator.createSettingsFormGroup('Min Duration', 'number', settings.duration.minimum),
  uiGenerator.createSettingsFormGroup('Min Rating', 'number', settings.rating.minimum),
  uiGenerator.createSettingsFormGroup('Min Views', 'number', settings.views.minimum),
  uiGenerator.createSettingsFormActions(storage, function () {

    settings.duration.minimum = uiGenerator.getSettingsInputValue('Min Duration')
    settings.rating.minimum = uiGenerator.getSettingsInputValue('Min Rating')
    settings.views.minimum = uiGenerator.getSettingsInputValue('Min Views')

    statistics.reset()
    for (let videoList of getVideoLists()) {
      complianceCallback(videoList)
    }
  }, true),
  uiGenerator.createSeparator(),
  uiGenerator.createStoreControlPanel(storage),
  uiGenerator.createSeparator(),
  uiGenerator.createStatisticsFormGroup('Duration', 'Short'),
  uiGenerator.createStatisticsFormGroup('Rating', 'Low Rated'),
  uiGenerator.createStatisticsFormGroup('Views', 'By Views'),
  uiGenerator.createStatisticsFormGroup('Blacklist', 'Blacklisted'),
  uiGenerator.createStatisticsFormGroup('Total'),
  uiGenerator.createSettingsHideButton('settings'),
])
uiGenerator.appendToBody(section)
uiGenerator.appendToBody(uiGenerator.createSettingsShowButton('Search & Tweaks', section))

logger.logTaskCompletion('Building UI')

// Script run
// -- Initial compliance run & observer attachment

ChildObserver.observe(getVideoLists(), complianceCallback, true)
validator.sanitizeVideoPage('h1.entity-info-container__title')

logger.logTaskCompletion('Initial run and observer attachment.')