您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Various search filters and user experience enhancers
当前为
// ==UserScript== // @name SpankBang - Search and UI Enhancer // @namespace brazenvoid // @version 1.0.0 // @author brazenvoid // @license GPL-3.0-only // @description Various search filters and user experience enhancers // @match https://spankbang.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-end // ==/UserScript== GM_addStyle(`button.show-settings{height:60vh;top:20vh}#settings-wrapper{top:20vh;width:300px}.bg-brand{background-color:#69150d}.font-primary{color:white}.font-secondary{color:black}hr{background:white}`) const PAGE_PATH_NAME = window.location.pathname const PAGE_PATH_FRAGMENTS = PAGE_PATH_NAME.split('/') const IS_HOME_PAGE = PAGE_PATH_NAME === '/' const IS_VIDEO_PAGE = PAGE_PATH_FRAGMENTS[2] === 'video' || PAGE_PATH_FRAGMENTS[2] === 'playlist' const ITEM_CLASSES = 'div.video-item' const ITEM_LISTS_SELECTOR = 'div.video-list' const ITEM_TEXT_NODE_SELECTOR = 'span.n' const SCRIPT_PREFIX = 'sb-sui-' // Configuration const FILTER_VIDEOS_SD = 'Show Only HD Videos' const FILTER_VIDEOS_DURATION = 'Duration' const FILTER_VIDEOS_MAXIMUM_AGE = 'Maximum Age' const FILTER_VIDEOS_MAXIMUM_AGE_UNIT = 'Maximum Age Unit' const FILTER_VIDEOS_MINIMUM_AGE = 'Minimum Age' const FILTER_VIDEOS_MINIMUM_AGE_UNIT = 'Minimum Age Unit' const FILTER_VIDEOS_RATING = 'Rating' const FILTER_VIDEOS_VIEWS = 'Views' const UI_REMOVE_EMBED_VIDEO_SECTION = 'Remove Embed Video Section' const UI_REMOVE_LIVE_MODEL_SECTIONS = 'Remove Live Model Sections' const UI_REDIRECT_SUBSCRIPTIONS_LINK = 'Redirect Subscriptions Link' const UI_REPOSITION_SCREENSHOTS = 'Reposition Video Screenshots' const UI_REPOSITION_VIDEO_DETAILS = 'Reposition Video Details' const UI_SWAP_RELATED_VIDEOS = 'Reposition Related Videos' // Item attributes const ITEM_AGE = 'scriptAge' const ITEM_DURATION = 'scriptAge' const ITEM_RATING = 'scriptRating' const ITEM_VIEWS = 'scriptViews' class SpankBangSearchAndUIEnhancer extends BrazenBaseSearchEnhancer { constructor () { super(SCRIPT_PREFIX, ITEM_CLASSES) this._configurationManager. addFlagField(FILTER_VIDEOS_SD, 'Filter videos of less than 720p resolution.'). addFlagField(UI_REMOVE_EMBED_VIDEO_SECTION, 'Removes embed video section on video pages.'). addFlagField(UI_REMOVE_LIVE_MODEL_SECTIONS, 'Removes live model sections from the site.'). addFlagField(UI_REDIRECT_SUBSCRIPTIONS_LINK, 'Redirects subscription videos page shortcut on user bar to new subscribed videos view.'). addFlagField(UI_REPOSITION_SCREENSHOTS, 'Move video screenshots above video player on video pages.'). addFlagField(UI_REPOSITION_VIDEO_DETAILS, 'Move video details section to the top of the right pane.'). addFlagField(UI_SWAP_RELATED_VIDEOS, 'Swaps related videos section with comments section'). addNumberField(FILTER_VIDEOS_MAXIMUM_AGE, 0, 100, 'Maximum age filter value.'). addNumberField(FILTER_VIDEOS_MINIMUM_AGE, 0, 100, 'Minimum age filter value.'). addRangeField(FILTER_VIDEOS_DURATION, 0, 100000, 'Filter videos by duration in minutes.'). addRangeField(FILTER_VIDEOS_RATING, 0, 100, 'Filter videos by duration.'). addRangeField(FILTER_VIDEOS_VIEWS, 0, 9999999999, 'Filter videos by view count.') // addSelectField(FILTER_VIDEOS_MAXIMUM_AGE_UNIT, [ // ['Minutes', 'minutes'], // ['Hours', 'hours'], // ['Days', 'days'], // ['Weeks', 'weeks'], // ['Months', 'months'], // ['Years', 'years]'], // ], 'Maximum age filter unit.'). // addSelectField(FILTER_VIDEOS_MINIMUM_AGE_UNIT, [ // ['Minutes', 'minutes'], // ['Hours', 'hours'], // ['Days', 'days'], // ['Weeks', 'weeks'], // ['Months', 'months'], // ['Years', 'years]'], // ], 'Minimum age filter unit.') // this._addPaginationConfiguration() this._setupUI() this._setupCompliance() this._setupComplianceFilters() } _analyseItem (item) { let stats = item.find('div.stats') if (stats.length) { stats = stats.text().split('%') item[0][ITEM_AGE] = stats[1] stats = stats[0].split(' ') item[0][ITEM_VIEWS] = stats[0] item[0][ITEM_RATING] = parseInt(stats[1].trim()) } else { item[0][ITEM_AGE] = null item[0][ITEM_RATING] = null item[0][ITEM_VIEWS] = null } item[0][ITEM_DURATION] = parseInt(item.find('span.l').text().replace('m', '')) } /** * @private */ _redirectSubscriptionsLink () { if (this._configurationManager.getValue(UI_REDIRECT_SUBSCRIPTIONS_LINK)) { $('a[href="/users/social"]').attr('href', '/users/social?sort=new') } } /** * @private */ _removeEmbedVideoSection () { if (this._configurationManager.getValue(UI_REMOVE_EMBED_VIDEO_SECTION)) { $('.embed').remove() } } /** * @private */ _removeLiveModelSections () { if (this._configurationManager.getValue(UI_REMOVE_EMBED_VIDEO_SECTION)) { let liveModelsSection = $('.lv_cm_cl_mx_why') if (IS_HOME_PAGE) { liveModelsSection.prev().remove() liveModelsSection.next().remove() } liveModelsSection.remove() } } /** * @return {JQuery<HTMLElement> | jQuery | HTMLElement} * @private */ _generatePseudoLeftSection () { return $('<div class="left" style="padding: 23px 0 0 0"></div>') } /** * @private */ _repositionVideoDetails () { if (this._configurationManager.getValue(UI_REPOSITION_VIDEO_DETAILS)) { let rightPane = $('div.right') let pseudoLeftSection = this._generatePseudoLeftSection() rightPane.prepend(pseudoLeftSection) pseudoLeftSection.append($('div.left section.details')) } } /** * @private */ _repositionVideoScreenshots () { if (this._configurationManager.getValue(UI_REPOSITION_SCREENSHOTS)) { $('div.left section.timeline').insertBefore('#player_wrapper_outer') } } /** * @private */ _setupCompliance () { this._onGetItemLists = () => $(ITEM_LISTS_SELECTOR) this._onGetItemName = (videoItem) => videoItem.find(ITEM_TEXT_NODE_SELECTOR).text() this._onFirstHitBeforeCompliance = (item) => this._analyseItem(item) this._onFirstHitAfterCompliance = (item) => { Validator.sanitizeTextNode(item.find(ITEM_TEXT_NODE_SELECTOR), 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._addItemComplianceFilter(FILTER_VIDEOS_RATING, (item, range) => item[0][ITEM_RATING] ? Validator.isInRange(item[0][ITEM_RATING], range.minimum, range.maximum) : true) this._addItemComplianceFilter(FILTER_VIDEOS_DURATION, (item, range) => Validator.isInRange(item[0][ITEM_DURATION], range.minimum, range.maximum)) this._addItemComplianceFilter(FILTER_VIDEOS_VIEWS, (item, range) => { let viewsString = item[0][ITEM_VIEWS] if (!viewsString) { return true } let viewsAmount = parseFloat(viewsString.replace('K', '').replace('M', '').replace('B', '')) if (viewsString.endsWith('K')) { viewsAmount *= 1000 } else if (viewsString.endsWith('M')) { viewsAmount *= 1000000 } else if (viewsString.endsWith('B')) { viewsAmount *= 1000000000 } return Validator.isInRange(viewsAmount, range.minimum, range.maximum) }) this._addItemComplianceFilter(FILTER_VIDEOS_SD, (item) => Validator.doesChildExist(item, 'span.h')) this._addItemBlacklistFilter('Hide videos with specified phrases in their names. Separate the phrases with line breaks.') } /** * @private */ _setupUI () { this._onBeforeUIBuild = () => { this._redirectSubscriptionsLink() this._removeLiveModelSections() if (IS_VIDEO_PAGE) { this._removeEmbedVideoSection() this._repositionVideoDetails() this._repositionVideoScreenshots() this._swapRelatedVideos() Validator.sanitizeNodeOfSelector('div.video > div.left > h1', this._configurationManager.getFieldOrFail(FILTER_TEXT_SANITIZATION).optimized) } } this._onUIBuild = () => this._uiGen.createSettingsSection().append([ this._uiGen.createTabsSection(['Filters', 'Text', 'UI', 'Global', 'Stats'], [ this._uiGen.createTabPanel('Filters', true).append([ this._configurationManager.createElement(FILTER_VIDEOS_DURATION), this._configurationManager.createElement(FILTER_VIDEOS_RATING), this._configurationManager.createElement(FILTER_VIDEOS_VIEWS), // this._configurationManager.createElement(FILTER_VIDEOS_MINIMUM_AGE), // this._configurationManager.createElement(FILTER_VIDEOS_MINIMUM_AGE_UNIT), // this._configurationManager.createElement(FILTER_VIDEOS_MAXIMUM_AGE), // this._configurationManager.createElement(FILTER_VIDEOS_MAXIMUM_AGE_UNIT), this._configurationManager.createElement(FILTER_VIDEOS_SD), this._uiGen.createSeparator(), this._configurationManager.createElement(OPTION_DISABLE_COMPLIANCE_VALIDATION), ]), this._uiGen.createTabPanel('Text').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('UI').append([ this._configurationManager.createElement(UI_REDIRECT_SUBSCRIPTIONS_LINK), this._configurationManager.createElement(UI_REMOVE_EMBED_VIDEO_SECTION), this._configurationManager.createElement(UI_REMOVE_LIVE_MODEL_SECTIONS), this._configurationManager.createElement(UI_SWAP_RELATED_VIDEOS), this._configurationManager.createElement(UI_REPOSITION_VIDEO_DETAILS), this._configurationManager.createElement(UI_REPOSITION_SCREENSHOTS), this._uiGen.createSeparator(), this._configurationManager.createElement(OPTION_ALWAYS_SHOW_SETTINGS_PANE), ]), this._uiGen.createTabPanel('Global').append([ this._createSettingsBackupRestoreFormActions(), ]), this._uiGen.createTabPanel('Stats').append([ this._uiGen.createStatisticsFormGroup(FILTER_VIDEOS_DURATION), this._uiGen.createStatisticsFormGroup(FILTER_VIDEOS_RATING), this._uiGen.createStatisticsFormGroup(FILTER_VIDEOS_VIEWS), this._uiGen.createStatisticsFormGroup(FILTER_VIDEOS_SD), this._uiGen.createStatisticsFormGroup(FILTER_TEXT_SEARCH), this._uiGen.createStatisticsFormGroup(FILTER_TEXT_BLACKLIST), this._uiGen.createStatisticsFormGroup(FILTER_TEXT_WHITELIST), this._uiGen.createSeparator(), this._uiGen.createStatisticsTotalsGroup(), ]), ]), this._createSettingsFormActions(), this._uiGen.createSeparator(), this._uiGen.createStatusSection(), ]) this._onAfterUIBuild = () => { this._uiGen.getSelectedSection()[0].userScript = this } } /** * @private */ _swapRelatedVideos () { if (this._configurationManager.getValue(UI_SWAP_RELATED_VIDEOS)) { let newRelatedVideosSection = $('<section class="user_uploads"></section>') newRelatedVideosSection.insertAfter('section.all_comments') newRelatedVideosSection.append('<h2>Similar Videos</h2>') newRelatedVideosSection.append($('.similar div.video-list')) $('.similar').remove() let pseudoLeftSection = this._configurationManager.getValue(UI_REPOSITION_VIDEO_DETAILS) ? $('div.right div.left') : this._generatePseudoLeftSection() pseudoLeftSection.append($('section.all_comments')) } } } (new SpankBangSearchAndUIEnhancer).init()