XNXX - Search Filters

Various search filters

As of 2019-12-01. See the latest version.

// ==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.')