您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Various search filters
当前为
// ==UserScript== // @name XNXX - Search Filters // @namespace brazenvoid // @version 2.5.1 // @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=758353 // @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.')