XNXX - Search Filters

Various search filters

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

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

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

// Settings & Defaults

let settings = {
  blacklist: [ // case-insensitive
    '360 drops of',
    '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,
  },
  resolution: '720', // All / 360 / 480 / 720 / 1080
  rating: {
    minimum: 80,
    maximum: 0,
  },
  views: {
    minimum: 0,
    maximum: 0,
  },
  showUIAlways: false, // Desktop/Tablet
  debugLogging: false
}

// Base Resources Initialization

const scriptPrefix = 'xnxx-sf-'
const isOnVideoPage = window.location.pathname.startsWith('/video-')

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)

let filters = new Filters(statistics)
filters.blacklist = settings.blacklist
filters.sanitizationRules = settings.sanitize
filters.init()

function getVideoList () {
  return document.querySelector('.mozaique')
}

// 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 Resolution', store.resolution)
  uiGenerator.setSettingsInputValue('Min Views', store.views.minimum)
}
storage.onDefaultsLoaded = refreshUI
storage.onRetrieval = refreshUI
storage.onUpdated = refreshUI

// Filters
// -- Duration validation

let validateDuration = function (duration) {

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

    let splitArray

    if (isOnVideoPage) {
      console.log(typeof duration)
      splitArray = duration.split(' ')
      duration = 0
      for (let i = 0; i < splitArray.length; i++) {
        if (splitArray[i].endsWith('min')) {
          duration += 60 * splitArray[i].replace('min', '')
        } else if (splitArray[i].endsWith('sec')) {
          duration += splitArray[i].replace('sec', '')
        }
      }
    } else {
      splitArray = duration.split('min')
      if (splitArray.length === 2) {
        duration = 60 * splitArray[0]
      } else {
        splitArray = duration.split('sec')
        if (splitArray.length === 2) {
          duration = splitArray[0]
        }
      }
    }
    return filters.validateRange('Duration', duration, [settings.duration.minimum, settings.duration.maximum])
  }
  return true
}

// -- Rating validation

let validateRating = function (rating) {

  if (settings.rating.minimum > 0 || settings.rating.maximum > 0) {
    return filters.validateRange('Rating', rating, [settings.rating.minimum, settings.rating.maximum])
  }
  return true
}

// -- Resolution validation

let validateResolution = function (resolution) {

  let validationCheck = true

  if (settings.resolution !== 'All') {
    validationCheck = parseInt(resolution.replace('p', '')) >= settings.resolution
    statistics.record('Resolution', validationCheck)
  }
  return validationCheck
}

// -- Video name sanitation

let sanitizeVideoPage = function () {

  let videoTitle = document.querySelector('.clear-infobar > strong:nth-child(1)')
  if (videoTitle !== null) {

    let sanitizedVideoName = filters.sanitize(videoTitle.textContent)
    videoTitle.textContent = sanitizedVideoName
    document.title = sanitizedVideoName
  }

}
let sanitizeVideoItem = function (videoItem, videoName) {

  videoItem.querySelector('.thumb-under > p:nth-child(1) > a:nth-child(1)').textContent = filters.sanitize(videoName)
}

// -- View count validation

let validateViews = function (views) {

  let validationCheck = true

  if (settings.views.minimum > 0 || settings.views.maximum > 0) {
    validationCheck = filters.validateRange('Duration', views, [settings.views.minimum, settings.views.maximum])
  }
  return validationCheck
}

// -- Compliance logic

let complianceCallback = function (target) {

  let videoItems = target.querySelectorAll('.thumb-block')
  let videoDuration, videoComplies, videoMetadata, videoName, videoRating, videoResolution, videoViews

  for (let videoItem of videoItems) {

    if (isOnVideoPage) {
      videoMetadata = videoItem.querySelector('.metadata').textContent.split(' ')
      videoDuration = videoMetadata[1]
      videoRating = 100
      videoResolution = videoMetadata[5]
      videoViews = videoMetadata[0]
    } else {
      videoMetadata = videoItem.querySelector('.metadata').textContent.split('\n')
      videoMetadata[1] = videoMetadata[1].split(' ')
      videoDuration = videoMetadata[2]
      videoRating = videoMetadata[1][1].replace('%', '')
      videoResolution = videoMetadata[3].replace(' -  ', '')
      videoViews = videoMetadata[1][0]
    }

    videoName = videoItem.querySelector('.thumb-under > p:nth-child(1) > a:nth-child(1)').textContent
    logger.logVideoCheck(videoName)

    videoComplies =
      validateRating(videoRating) &&
      validateResolution(videoResolution) &&
      filters.validateBlackList(videoName) &&
      validateDuration(videoDuration) &&
      validateViews(videoViews)

    if (videoComplies) {
      videoItem.style.display = 'inline-block'
      sanitizeVideoItem(videoItem, videoName)
    } else {
      videoItem.style.display = 'none'
    }
    logger.logSeparator()
  }
  statistics.updateUI()
}

// UI Composition
// -- Control Panel

let section = uiGenerator.createSection('settings', '#ffa31a', '250px', '220px', [
  uiGenerator.createSettingsFormGroup('Min Rating', 'number', settings.rating.minimum.toString()),
  uiGenerator.createSettingsFormGroup('Min Duration', 'number', settings.duration.minimum.toString()),
  uiGenerator.createSettingsDropDownFormGroup('Min Resolution', [
    ['All', 'Show All'], ['360', 'SD 360p'], ['480', 'SD 480p'], ['720', 'HD 720p'], ['1080', 'HD 1080p']
  ], settings.resolution.toString()),
  uiGenerator.createSettingsFormGroup('Min Views', 'number', settings.views.minimum.toString()),
  uiGenerator.createSettingsFormActions(storage, function () {

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

    statistics.reset()
    complianceCallback(getVideoList())
  }),
  uiGenerator.createSeparator(),
  uiGenerator.createStoreControlPanel(storage),
  uiGenerator.createSeparator(),
  uiGenerator.createStatisticsFormGroup('Duration', 'Short'),
  uiGenerator.createStatisticsFormGroup('Rating', 'Low Rated'),
  uiGenerator.createStatisticsFormGroup('Resolution', 'Low Resolution'),
  uiGenerator.createStatisticsFormGroup('Views', 'Low Views'),
  uiGenerator.createStatisticsFormGroup('Blacklist', 'Blacklisted'),
  uiGenerator.createStatisticsFormGroup('Total'),
  uiGenerator.createSettingsHideButton('settings')
])
uiGenerator.appendToBody(section)
uiGenerator.getSettingsInput('Min Views').parentNode.style.marginBottom = '10px'

let labels = section.getElementsByTagName('label')
for (let label of labels) {
  label.style.margin = '0'
}

// -- Settings Button

let controlButton = uiGenerator.createSettingsShowButton('Show Settings UI', section, false)
controlButton.style.width = 'unset'

let controlListItem = document.createElement('div')
controlListItem.appendChild(controlButton)

document.querySelector('.slogan').appendChild(controlButton)

logger.logTaskCompletion('Building UI')

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

ChildObserver.observe(getVideoList(), complianceCallback, true)
sanitizeVideoPage()

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