// ==UserScript==
// @name SpankBang - Search and UI Enhancer
// @namespace brazenvoid
// @version 1.2.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 = 'a.n';
const SCRIPT_PREFIX = 'sb-sui-';
// Configuration
const FILTER_VIDEOS_RESOLUTION = 'Resolution';
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_AD_BOX_VIDEO_LISTS = 'Remove Ad in Video Lists';
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 = 'scriptDuration';
const ITEM_RATING = 'scriptRating';
const ITEM_RESOLUTION = 'scriptResolution';
const ITEM_VIEWS = 'scriptViews';
class SpankBangSearchAndUIEnhancer extends BrazenBaseSearchEnhancer
{
constructor()
{
super(SCRIPT_PREFIX, ITEM_CLASSES);
this._configurationManager.
addFlagField(UI_REMOVE_AD_BOX_VIDEO_LISTS, 'Removes the ad box found in the first row of videos lists.').
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.').
addRadiosGroup(FILTER_VIDEOS_RESOLUTION, [
['All', 'All'],
['Only SD', 'Only SD'],
['Only HD 720p', 'Only HD 720p'],
['Only HD 1080p', 'Only HD 1080p'],
['Only HD 4K', 'Only HD 4K'],
['Minimum HD 720p', 'Minimum HD 720p'],
['Minimum HD 1080p', 'Minimum HD 1080p'],
], 'Filter videos by resolution.').
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.');
this._setupUI();
this._setupCompliance();
this._setupComplianceFilters();
}
_analyseItem(item)
{
let durationBadge = item.find('span.l')
item[0][ITEM_DURATION] = durationBadge.length ? parseInt(durationBadge.text().replace('m', '')) : null;
let resolutionBadge = item.find('span.h')
item[0][ITEM_RESOLUTION] = resolutionBadge.length ? resolutionBadge.text() : 'SD';
let stats = item.find('div.stats > .v.d');
if (stats.length) {
stats = stats.html().trim().split(' ')
item[0][ITEM_VIEWS] = stats[0];
item[0][ITEM_RATING] = stats[1];
} else {
item[0][ITEM_RATING] = null;
item[0][ITEM_VIEWS] = null;
}
}
/**
* @private
*/
_redirectSubscriptionsLink()
{
if (this._configurationManager.getValue(UI_REDIRECT_SUBSCRIPTIONS_LINK)) {
$('a[href="/users/social"]').attr('href', '/users/social?sort=new');
}
}
_removeAdBoxInVideoLists()
{
if (this._configurationManager.getValue(UI_REMOVE_AD_BOX_VIDEO_LISTS)) {
$(ITEM_CLASSES + ' ins').parent().remove();
}
}
/**
* @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_RESOLUTION, (item, value) => {
if (value === 'All') {
return true
}
let resolutionSpan = item.find('span.h')
if (resolutionSpan.length === 0) {
return value === 'Only SD'
} else if (value === 'Minimum HD 720p') {
return true
} else if (value === 'Only SD') {
return false
}
let resolution = resolutionSpan.text().trim()
switch (value) {
case 'Only HD 720p':
return resolution === '720p'
case 'Only HD 1080p':
return resolution === '1080p'
case 'Only HD 4K':
return resolution === '4k'
case 'Minimum HD 1080p':
return resolution === '1080p' || resolution === '4k'
}
return true
});
this._addItemBlacklistFilter('Hide videos with specified phrases in their names. Separate the phrases with line breaks.');
}
/**
* @private
*/
_setupUI()
{
this._onBeforeUIBuild = () => {
this._redirectSubscriptionsLink();
this._removeLiveModelSections();
this._removeAdBoxInVideoLists();
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._uiGen.createSeparator(),
this._configurationManager.createElement(FILTER_VIDEOS_RESOLUTION),
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_REMOVE_AD_BOX_VIDEO_LISTS),
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_RESOLUTION),
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();