您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Various search filters and user experience enhancers
当前为
// ==UserScript== // @name PH - Search & UI Tweaks // @namespace brazenvoid // @version 1.10.10 // @author brazenvoid // @license GPL-3.0-only // @description Various search filters and user experience enhancers // @include https://www.pornhub.com/* // @require https://greasyfork.org/scripts/375557-brazenvoid-s-base-resource/code/Brazenvoid's%20Base%20Resource.js?version=678370 // @grant GM_addStyle // @run-at document-idle // ==/UserScript== // Settings & Defaults let settings = { blacklist: [ // case-insensitive 'urin', 'arab', 'mmd', 'muslim', 'desi', 'squirt', 'fake', 'pregnant', 'pee', ], sanitize: { // Substitutes values with key (case-insensitive) ' ': ['neighbor', 'step'], Boyfriend: ['brother', 'bro', 'dad', 'son', 'father'], 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, hideFanVideos: true, hideUnratedVideos: true, hideWatchedVideos: false, removeIFrames: true, removeLiveModelsSection: true, removePornStarsListingInSidebar: true, showUIAlways: false, // Desktop debugLogging: false } // Base Resources Initialization const scriptPrefix = 'az-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) let validator = new Validator(statistics) validator.addBlacklistFilter(settings.blacklist).addSanitizationFilter(settings.sanitize).optimize() function getVideoLists () { return document.querySelectorAll('ul.videos') } // 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) uiGenerator.setSettingsInputCheckedStatus('Only HD Videos', store.hideSDVideos) uiGenerator.setSettingsInputCheckedStatus('Hide Fan Videos', store.hideFanVideos) uiGenerator.setSettingsInputCheckedStatus('Hide Watched Videos', store.hideWatchedVideos) uiGenerator.setSettingsInputCheckedStatus('Hide Unrated Videos', store.hideUnratedVideos) } 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 durationNode = videoItem.querySelector('.duration') if (durationNode !== null) { let duration = durationNode.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('.hd-thumbnail') !== null logger.logValidation('HD', validationCheck) } return validationCheck } // -- Fan video validation let validateFanVideo = function (videoItem) { let validationCheck = true if (settings.hideFanVideos) { validationCheck = videoItem.querySelector('.fanOnlyVideoWidget') === null logger.logValidation('Fan Video', 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('.value') if (rating === null) { validationCheck = !settings.hideUnratedVideos statistics.record('Rating', validationCheck) } else { rating = parseInt(rating.textContent.replace('%', '')) if (rating === 0) { validationCheck = !settings.hideUnratedVideos; } else { 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) { let viewsCountString = videoItem.querySelector('.views').textContent.replace(' views', '') let viewsCountMultiplier = 1 let viewsCountStringLength = viewsCountString.length if (viewsCountString[viewsCountStringLength - 1] === 'K') { viewsCountMultiplier = 1000 viewsCountString = viewsCountString.replace('K', '') } else if (viewsCountString[viewsCountStringLength - 1] === 'M') { viewsCountMultiplier = 1000000 viewsCountString = viewsCountString.replace('M', '') } let viewsCount = parseFloat(viewsCountString) * viewsCountMultiplier return validator.validateRange('Views', viewsCount, [settings.views.minimum, settings.views.maximum]) } return true } // -- Watched video validation let validateWatchStatus = function (videoItem) { let validationCheck = true if (settings.hideWatchedVideos) { validationCheck = videoItem.querySelector('.watchedVideoText') === null statistics.record('Watched', validationCheck) } return validationCheck } // -- Compliance logic let complianceCallback = function (target) { let videoItems = target.querySelectorAll('.videoblock') let videoName, videoComplies for (let videoItem of videoItems) { videoName = videoItem.querySelector('.title > a') logger.logVideoCheck(videoName.textContent) videoComplies = validateFanVideo(videoItem) && validateWatchStatus(videoItem) && 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', '200px', [ 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.createSettingsFormGroup('Only HD Videos', 'checkbox', settings.hideSDVideos), uiGenerator.createSettingsFormGroup('Hide Fan Videos', 'checkbox', settings.hideFanVideos), uiGenerator.createSettingsFormGroup('Hide Watched Videos', 'checkbox', settings.hideWatchedVideos), uiGenerator.createSettingsFormGroup('Hide Unrated Videos', 'checkbox', settings.hideUnratedVideos), 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') settings.hideSDVideos = uiGenerator.getSettingsInputCheckedStatus('Only HD Videos') settings.hideFanVideos = uiGenerator.getSettingsInputCheckedStatus('Hide Fan Videos') settings.hideWatchedVideos = uiGenerator.getSettingsInputCheckedStatus('Hide Watched Videos') settings.hideUnratedVideos = uiGenerator.getSettingsInputCheckedStatus('Hide Unrated Videos') statistics.reset() for (let videoList of getVideoLists()) { complianceCallback(videoList) } }), 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('Watched', 'Watched'), uiGenerator.createStatisticsFormGroup('Total'), uiGenerator.createSettingsHideButton('settings'), ]) uiGenerator.appendToBody(section) uiGenerator.appendToBody(uiGenerator.createSettingsShowButton('Search & Tweaks', section)) logger.logTaskCompletion('Building UI') // -- Move pagination section let videosSection = document.querySelector('.nf-videos') if (videosSection !== null) { let paginationBlock = document.querySelector('.pagination3') videosSection.appendChild(paginationBlock) } // -- Fix search section div heights for (let div of document.querySelectorAll('.showingCounter, .tagsForWomen')) { div.style.height = 'auto' } // Script run // -- Initial compliance run & observer attachment ChildObserver.observe(getVideoLists(), complianceCallback, true) validator.sanitizeVideoPage('.inlineFree') logger.logTaskCompletion('Initial run and observer attachment.') // -- IFrames Removal let removePHIframes = function () { let iframes = document.getElementsByTagName('milktruck') for (let iframe of iframes) { iframe.remove() } return iframes.length } if (settings.removeIFrames) { Validator.iFramesRemover() let iframesCount; do { iframesCount = removePHIframes() } while (iframesCount); } // -- Live Models Section Removal if (settings.removeLiveModelsSection) { let liveModelStreamsSection = document.querySelector('.streamateContent') if (liveModelStreamsSection !== null) { liveModelStreamsSection.closest('.sectionWrapper').remove() } logger.logTaskCompletion('Live model section removal.') } // -- Porn stars listing in sidebar removal if (settings.removePornStarsListingInSidebar) { let pornStarsSection = document.getElementById('relatedPornstarSidebar') if (pornStarsSection !== null) { pornStarsSection.remove() } logger.logTaskCompletion('Sidebar porn start listing removal.') }