XNXX - Search Filters

Various search filters

Устаревшая версия за 15.12.2019. Перейдите к последней версии.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

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

GM_addStyle(`
    section.form-section div.form-group { 
        margin-bottom: 5px;
    }
`)

// 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 UI = new UIGenerator(settings.showUIAlways, selectorGenerator)

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

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

// Local Store Events

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

    UI.setSettingsRangeInputValue('Duration', store.duration.minimum, store.duration.maximum)
    UI.setSettingsRangeInputValue('Rating', store.rating.minimum, store.rating.maximum)
    UI.setSettingsRangeInputValue('Views', store.views.minimum, store.views.maximum)
    UI.setSettingsInputValue('Min Quality', store.resolution)
    UI.setSettingsInputCheckedStatus('Always Show UI', store.showUIAlways)
}
storage.onDefaultsLoaded = refreshUI
storage.onRetrieval = refreshUI
storage.onUpdated = refreshUI

// Validators
// -- 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 validator.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 validator.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
}

// -- View count validation

let validateViews = function (views) {

    let validationCheck = true

    if (settings.views.minimum > 0 || settings.views.maximum > 0) {
        validationCheck = validator.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)')
        logger.logVideoCheck(videoName.textContent)

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

        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 = UI.createSection('settings', '#ffa31a', '250px', '250px', [
    UI.createFormRangeInputGroup('Duration', 'number', [
        settings.duration.minimum,
        settings.duration.maximum,
    ]),
    UI.createFormRangeInputGroup('Rating', 'number', [
        settings.rating.minimum,
        settings.rating.maximum,
    ]),
    UI.createFormRangeInputGroup('Views', 'number', [
        settings.views.minimum,
        settings.views.maximum,
    ]),
    UI.createSettingsDropDownFormGroup('Min Quality', [
        ['All', 'Show All'], ['360', 'SD 360p'], ['480', 'SD 480p'], ['720', 'HD 720p'], ['1080', 'HD 1080p'],
    ], settings.resolution.toString()),
    UI.createFormInputGroup('Always Show UI', 'checkbox', settings.showUIAlways),
    UI.createSeparator(),
    UI.createSettingsFormActions(storage, function () {

        settings.duration.minimum = UI.getSettingsRangeInputValue('Duration', true)
        settings.duration.maximum = UI.getSettingsRangeInputValue('Duration', false)
        settings.rating.minimum = UI.getSettingsRangeInputValue('Rating', true)
        settings.rating.maximum = UI.getSettingsRangeInputValue('Rating', false)
        settings.views.minimum = UI.getSettingsRangeInputValue('Views', true)
        settings.views.maximum = UI.getSettingsRangeInputValue('Views', false)
        settings.resolution = UI.getSettingsInputValue('Min Quality')
        settings.showUIAlways = UI.getSettingsInputCheckedStatus('Always Show UI')

        statistics.reset()
        complianceCallback(getVideoList())
    }),
    UI.createSeparator(),
    UI.createStoreFormSection(storage),
    UI.createSeparator(),
    UI.createStatisticsFormGroup('Resolution', 'Low Res'),
    UI.createStatisticsFormGroup('Duration', 'Short'),
    UI.createStatisticsFormGroup('Rating', 'Low Rated'),
    UI.createStatisticsFormGroup('Views', 'Low Views'),
    UI.createStatisticsFormGroup('Blacklist', 'Blacklisted'),
    UI.createStatisticsFormGroup('Total'),
    UI.createSettingsHideButton('settings'),
])
UIGenerator.appendToBody(section)
UI.getSettingsRangeInput('Views', false).parentNode.style.marginBottom = '10px'

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

// -- Settings Button

let controlButton = UI.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)
validator.sanitizeVideoPage('.clear-infobar > strong:nth-child(1)')

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