您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Various search filters and user experience enhancers
当前为
// ==UserScript== // @name PH - Search & UI Tweaks // @namespace brazenvoid // @version 1.9.4 // @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=658367 // @grant GM_addStyle // @run-at document-idle // ==/UserScript== // Settings & Defaults let settings = { blacklist: [ // case-insensitive '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 }, rating: { minimum: 80, maximum: 0 }, views: { minimum: 0, maximum: 0 }, hideSDVideos: true, hidePrivateVideos: 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 filters = new Filters(statistics) filters.blacklist = settings.blacklist filters.sanitizationRules = settings.sanitize filters.init() // Local Store Events let refreshUI = function () { let store = this.get() document.getElementById(selectorGenerator.getSettingsInputSelector('Min Duration')).value = store.duration.minimum document.getElementById(selectorGenerator.getSettingsInputSelector('Min Rating')).value = store.rating.minimum document.getElementById(selectorGenerator.getSettingsInputSelector('Min Views')).value = store.views.minimum } 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 duration = videoItem.querySelector('.duration').textContent.split(':') duration = (parseInt(duration[0]) * 60) + parseInt(duration[1]) return filters.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 } // -- Private video validation let validatePrivateVideo = function (videoItem) { let validationCheck = true if (settings.hidePrivateVideos) { validationCheck = videoItem.querySelector('.privateOverlay .fanOnlyVideoWidget ') === null logger.logValidation('Private 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('%', '')) validationCheck = filters.validateRange('Rating', rating, [settings.rating.minimum, settings.rating.maximum]) } } return validationCheck } // -- Video name sanitation let sanitizeVideoPage = function () { let videoTitle = document.querySelector('.inlineFree') if (videoTitle !== null) { let sanitizedVideoName = filters.sanitize(videoTitle.textContent) videoTitle.textContent = sanitizedVideoName document.title = sanitizedVideoName } } let sanitizeVideoItem = function (videoItem, videoName) { videoItem.querySelector('.title > a').textContent = filters.sanitize(videoName) } // -- 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 filters.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('.watchedVideoOverlay') === 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').textContent logger.logVideoCheck(videoName) videoComplies = validatePrivateVideo(videoItem) && validateWatchStatus(videoItem) && validateHD(videoItem) && validateRating(videoItem) && filters.validateBlackList(videoName) && validateDuration(videoItem) && validateViews(videoItem) 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', '200px', [ uiGenerator.createSettingsFormGroup('Min Duration', settings.duration.minimum), uiGenerator.createSettingsFormGroup('Min Rating', settings.rating.minimum), uiGenerator.createSettingsFormGroup('Min Views', settings.views.minimum), uiGenerator.createFormButton('Apply', function () { let videoLists = document.querySelectorAll('.videos') settings.duration.minimum = document.getElementById(selectorGenerator.getSettingsInputSelector('Min Duration')).value settings.rating.minimum = document.getElementById(selectorGenerator.getSettingsInputSelector('Min Rating')).value settings.views.minimum = document.getElementById(selectorGenerator.getSettingsInputSelector('Min Views')).value statistics.reset() for (let videoList of videoLists) { complianceCallback(videoList) } statistics.updateUI() }), uiGenerator.createSeparator(), uiGenerator.createStoreUpdateButton(storage), uiGenerator.createStoreReloadButton(storage), uiGenerator.createStoreResetButton(storage), uiGenerator.createStoreDeleteButton(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.createFormButton('Hide', function () { document.getElementById(selectorGenerator.getSelector('settings')).style.display = 'none' }), ]) uiGenerator.appendToBody(section) uiGenerator.appendToBody(uiGenerator.createSettingShowButton('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 let videoItemsObserver = new ChildObserver(complianceCallback) let videoLists = document.querySelectorAll('ul.videos') for (let videoList of videoLists) { videoItemsObserver.observe(videoList, true) } sanitizeVideoPage() logger.logTaskCompletion('Initial run and observer attachment.') // -- IFrames Removal let removePHIframes = function () { let iframes = document.getElementsByTagName('milktruck') for (let iframe of iframes) { iframe.parentNode.remove() } return iframes.length } if (settings.removeIFrames) { filters.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.') }