您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Various search filters
当前为
// ==UserScript== // @name XHamster Search and UI Improvements // @namespace brazenvoid // @version 2.2.0 // @author brazenvoid // @license GPL-3.0-only // @description Various search filters // @include https://xhamster.com/* // @match https://*.xhamster.com/* // @match https://xhamster2.com/* // @match https://*.xhamster2.com/* // @match https://xhamster3.com/* // @match https://*.xhamster3.com/* // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js // @require https://greasyfork.org/scripts/375557-base-resource/code/Base%20Resource.js?version=899286 // @require https://greasyfork.org/scripts/416104-brazen-ui-generator/code/Brazen%20UI%20Generator.js?version=899448 // @require https://greasyfork.org/scripts/418665-brazen-configuration-manager/code/Brazen%20Configuration%20Manager.js?version=892799 // @require https://greasyfork.org/scripts/416105-brazen-base-search-enhancer/code/Brazen%20Base%20Search%20Enhancer.js?version=899428 // @grant GM_addStyle // @run-at document-idle // ==/UserScript== GM_addStyle( `#settings-wrapper{top:5vh;width:270px}#settings-wrapper .check-radio-input{display:block}#settings-wrapper .form-button{border:revert}.font-primary{color:white}.tab-button:hover:not(.active){color:black}.tab-button:not(.active){color:white}.bg-brand{background-color:#3a3a3a}`) const PAGE_PATH_NAME = window.location.pathname const IS_PROFILE_TREE_PAGE = PAGE_PATH_NAME.startsWith('/users') const IS_PROFILE_VIDEOS_PAGE = IS_PROFILE_TREE_PAGE && PAGE_PATH_NAME.includes('/videos') const IS_PROFILE_PAGE = IS_PROFILE_TREE_PAGE && !IS_PROFILE_VIDEOS_PAGE const IS_VIDEO_PAGE = PAGE_PATH_NAME.startsWith('/videos') const FILTER_HD_VIDEOS = 'Show only HD Videos' const FILTER_VIDEOS_VIEWS = 'Views' const SCRIPT_PREFIX = 'xh-sui-' const SELECTOR_ITEM = '.thumb-list__item' const SELECTOR_ITEM_LIST = 'div.thumb-list' const SELECTOR_ITEM_NAME = 'a.video-thumb-info__name' class XHamsterSearchAndUITweaks extends BrazenBaseSearchEnhancer { constructor () { super(SCRIPT_PREFIX, SELECTOR_ITEM) this._configurationManager. addFlagField(FILTER_HD_VIDEOS, 'Hides videos of less than 720p resolution.'). addRangeField(FILTER_VIDEOS_VIEWS, 0, 10000000, 'Filter videos by view count.') if (!IS_VIDEO_PAGE) { let paginationSection = $('.pager-container ul') let nextPageNode = paginationSection.find('li.next') let lastPageUrl = nextPageNode.length ? nextPageNode.prev().find('a').attr('href') : window.location.href this._paginator = BrazenPaginator.create(paginationSection, '.thumb-list:not(.thumb-list--related):first', SELECTOR_ITEM, lastPageUrl). onGetPageNoFromUrl((url) => { let lastSegment = parseInt(url.split('/').pop()) return isNaN(lastSegment) ? 1 : lastSegment }). onGetPageUrlFromPageNo((newPageNo) => { let currentUrl = window.location.href let currentUrlFragments = currentUrl.split('/') if (newPageNo === 1) { if (!isNaN(parseInt(currentUrlFragments[currentUrl.length - 1]))) { currentUrlFragments.pop() } } else { if (isNaN(parseInt(currentUrlFragments[currentUrl.length - 1]))) { currentUrlFragments.push(newPageNo.toString()) } else { currentUrlFragments[currentUrl.length - 1] = newPageNo.toString() } } return currentUrlFragments.join('/') }). onGetPaginationElementForPageNo((pageNo, paginator) => paginator.getPaginationWrapper(). find(pageNo === paginator.getCurrentPageNo() ? 'a.xh-paginator-button.active' : 'a.xh-paginator-button[data-page=' + pageNo + ']'). parent(), ) } this._addPaginationConfiguration() this._setupUI() this._setupCompliance() this._setupComplianceFilters() } /** * @private */ _markAllVisited() { let current_url = window.location.href $('a.video-thumb-info__name').each((_i, element) => { history.replaceState({}, '', element.href) }) history.replaceState({}, '', current_url) } /** * @private */ _setupCompliance () { this._onGetItemLists = () => $(SELECTOR_ITEM_LIST) this._onGetItemName = (item) => item.find(SELECTOR_ITEM_NAME).text() this._onFirstHitBeforeCompliance = (item) => { Validator.sanitizeTextNode(item.find(SELECTOR_ITEM_NAME), this._configurationManager.getFieldOrFail(FILTER_TEXT_SANITIZATION).optimized) } } /** * @private */ _setupComplianceFilters () { this._addItemTextSanitizationFilter( 'Censor video names by substituting offensive phrases. Each rule in separate line with comma separated target phrases. Example Rule: boyfriend=stepson,stepdad') this._addItemWhitelistFilter('Show videos with specified phrases in their names. Separate the phrases with line breaks.') this._addItemTextSearchFilter() this._addItemPercentageRatingRangeFilter('div.rating span.metric-text') this._addItemDurationRangeFilter('div.thumb-image-container__duration') this._addItemComplianceFilter(FILTER_VIDEOS_VIEWS, (item, range) => { let viewsCount = 0 let viewsCountNode = item.find('div.views span.metric-text') if (viewsCountNode.length) { viewsCount = parseInt(viewsCountNode.text().replace(',', '')) if (isNaN(viewsCount)) { viewsCount = 0 } } return Validator.isInRange(viewsCount, range.minimum, range.maximum) }) this._addItemComplianceFilter( FILTER_HD_VIDEOS, (item) => !Validator.isChildMissing(item, 'i.thumb-image-container__icon--hd,i.thumb-image-container__icon--uhd')) this._addItemBlacklistFilter('Hide videos with specified phrases in their names. Separate the phrases with line breaks.') } /** * @private */ _setupUI () { this._onBeforeUIBuild = () => { if (IS_VIDEO_PAGE) { Validator.sanitizeNodeOfSelector( 'main > div.width-wrap.with-player-container > h1:first', this._configurationManager.getFieldOrFail(FILTER_TEXT_SANITIZATION).optimized) } } this._onUIBuild = () => this._uiGen.createSettingsSection().append([ this._uiGen.createTabsSection(['Filters', 'Text Based', 'Global'], [ this._uiGen.createTabPanel('Filters', true).append([ this._configurationManager.createElement(FILTER_DURATION_RANGE), this._configurationManager.createElement(FILTER_PERCENTAGE_RATING_RANGE), this._configurationManager.createElement(FILTER_VIDEOS_VIEWS), this._uiGen.createBreakSeparator(), this._configurationManager.createElement(FILTER_HD_VIDEOS), this._configurationManager.createElement(FILTER_UNRATED), this._uiGen.createSeparator(), this._configurationManager.createElement(OPTION_DISABLE_COMPLIANCE_VALIDATION), this._uiGen.createFormButton('Mark All Videos Viewed', 'Makes the browset believe you have seen all videos on the page.', () => this._markAllVisited()), ]), this._uiGen.createTabPanel('Text Based').append([ this._configurationManager.createElement(FILTER_TEXT_SEARCH), this._configurationManager.createElement(FILTER_TEXT_BLACKLIST), this._configurationManager.createElement(FILTER_TEXT_WHITELIST), this._configurationManager.createElement(FILTER_TEXT_SANITIZATION), ]), this._uiGen.createTabPanel('Global').append([ this._uiGen.createSeparator(), this._configurationManager.createElement(CONFIG_PAGINATOR_THRESHOLD), this._configurationManager.createElement(CONFIG_PAGINATOR_LIMIT), this._configurationManager.createElement(OPTION_ALWAYS_SHOW_SETTINGS_PANE), this._uiGen.createSeparator(), this._createSettingsBackupRestoreFormActions(), ]), ]), this._createSettingsFormActions(), this._uiGen.createSeparator(), this._uiGen.createStatisticsFormGroup(FILTER_TEXT_BLACKLIST), this._uiGen.createStatisticsFormGroup(FILTER_TEXT_WHITELIST), this._uiGen.createStatisticsFormGroup(FILTER_DURATION_RANGE), this._uiGen.createStatisticsFormGroup(FILTER_HD_VIDEOS, 'High Definition'), this._uiGen.createStatisticsFormGroup(FILTER_TEXT_SEARCH), this._uiGen.createStatisticsFormGroup(FILTER_PERCENTAGE_RATING_RANGE), this._uiGen.createStatisticsFormGroup(FILTER_DURATION_RANGE, 'Unrated'), this._uiGen.createStatisticsFormGroup(FILTER_VIDEOS_VIEWS), this._uiGen.createSeparator(), this._uiGen.createStatisticsTotalsGroup(), this._uiGen.createSeparator(), this._uiGen.createStatusSection(), ]) this._onAfterUIBuild = () => { this._uiGen.getSelectedSection()[0].userScript = this } } } (new XHamsterSearchAndUITweaks).init()