// ==UserScript==
// @name Video Celebs Search And UI Tweaks
// @version 1.1.4
// @namespace brazenvoid
// @author brazenvoid
// @license GPL-3.0-only
// @description Video filters and UI manipulations
// @include https://videocelebs.net/*
// @require https://greasyfork.org/scripts/375557-base-resource/code/Base%20Resource.js?version=869038
// @grant GM_addStyle
// @run-at document-end
// ==/UserScript==
GM_addStyle(
`.form-group{display:flex;align-items:center}label.form-label{flex-grow:1}input.form-input{height:auto}input.form-input.check-radio-input{width:auto;margin:0 5px 1px 0}label.form-label{padding: 0}label.title{margin: 0}div.form-group.form-range-input-group>input+input{margin-left: 5px;margin-right:0}`)
const PAGE_PATH_NAME = window.location.pathname
const IS_VIDEO_PAGE = PAGE_PATH_NAME.endsWith('.html')
const FILTER_RATING_VIDEOS_KEY = 'Rating'
const FILTER_VIDEOS_YEAR_KEY = 'Year'
const OPTION_ALWAYS_SHOW_UI = 'Always Show This Settings Pane'
const OPTION_DISABLE_VIDEO_FILTERS = 'Disable All Video Filters'
const OPTION_MOVE_VIDEO_ATTRIBUTES_SECTION_KEY = 'Reposition Attributes Section'
const OPTION_REMOVE_COMMENTS_SECTION_KEY = 'Remove Comments Section'
const OPTION_REMOVE_IFRAME_SECTION_KEY = 'Remove Iframe Share Section'
const OPTION_REMOVE_RELATED_VIDEOS_SECTION_KEY = 'Remove Related Videos Section'
const PAGINATOR_THRESHOLD = 'Pagination Threshold'
function getLastPageUrl ()
{
if (IS_VIDEO_PAGE) {
return window.location.href
} else {
let lastPaginationElement = $('.wp-pagenavi a:last')
return lastPaginationElement.length ? lastPaginationElement.attr('href') : window.location.href
}
}
class VideoCelebsSearchAndUITweaks extends BaseHandler
{
/**
* @typedef {{disableItemComplianceValidation: boolean, rating: {maximum: number, minimum: number}, year: {maximum: number, minimum: number},
* moveVideoAttributesBelowDescription: boolean, removeCommentsSection: boolean, removeIFrameSection: boolean, removeRelatedVideosSection: boolean, showUIAlways: boolean
* paginationThreshold: number}} VideoCelebsSearchAndUITweaksSettings
*/
static initialize ()
{
return (new VideoCelebsSearchAndUITweaks).init()
}
constructor ()
{
super({
scriptPrefix: 'vc-sui-',
itemClasses: 'item.big',
paginator: {
enable: !IS_VIDEO_PAGE,
listSelector: '.midle_div',
lastPageUrl: getLastPageUrl(),
getPageNo: (url) => url.includes('/page/') ? parseInt(url.split('/').pop()) : 1,
getPageUrl: (newPageNo) => {
let currentUrl = window.location.href
if (currentUrl.includes('/page/')) {
let currentUrlFragments = currentUrl.split('/')
currentUrlFragments.pop()
currentUrl = currentUrlFragments.join('/')
} else {
currentUrl += '/page'
}
return currentUrl + '/' + newPageNo
},
afterPagination: (paginator) => {
let currentPaginationElement = $('.wp-pagenavi span.current')
currentPaginationElement.text(paginator.currentPageNo + '-' + paginator.paginatedPageNo)
let paginatorLinksAfterCurrent = $('.wp-pagenavi span.current ~ a')
if (paginator.paginatedPageNo === paginator.lastPageNo) {
paginatorLinksAfterCurrent.remove()
} else {
paginatorLinksAfterCurrent.each((index, element) => {
let paginationLink = $(element)
if (paginator.getPageNo($(element).attr('href')) <= paginator.paginatedPageNo) {
paginationLink.remove()
}
})
let nextPageUrl = paginator.getPageUrl(paginator.paginatedPageNo + 1)
let nextPageLink = $('.wp-pagenavi a[href="'+ nextPageUrl +'"]')
if (nextPageLink.length === 0) {
let lastPageLink = $('.wp-pagenavi a:last')
lastPageLink.clone().insertAfter(currentPaginationElement).
text(paginator.paginatedPageNo + 1).removeClass('last').attr('href', nextPageUrl)
}
}
}
},
configDefaults: {
rating: {
minimum: 0,
maximum: 0,
},
year: {
minimum: 0,
maximum: 0,
},
moveVideoAttributesBelowDescription: false,
removeCommentsSection: false,
removeIFrameSection: false,
removeRelatedVideosSection: false,
},
})
// UI Events
this._onBeforeUIBuild = () => {
if (IS_VIDEO_PAGE) {
this._moveVideoAttributesBelowDescription()
this._removeCommentsSection()
this._removeIFrameSection()
this._removeRelatedVideosSection()
}
}
this._onUIBuild = () =>
this._uiGen.createSection('settings', '#ffa31a', '15vh', '250px').addSectionChildren([
this._uiGen.createTabsSection(['Filters', 'UI', 'Stats'], [
this._uiGen.createTabPanel('Filters', [
this._createFormRangeInputGroup(FILTER_RATING_VIDEOS_KEY, 'number'),
this._createFormRangeInputGroup(FILTER_VIDEOS_YEAR_KEY, 'number'),
this._uiGen.createSeparator(),
this._uiGen.createFormInputGroup(OPTION_DISABLE_VIDEO_FILTERS, 'checkbox', 'Disables all video filters.'),
this._uiGen.createSeparator(),
this._createSettingsFormActions(),
this._uiGen.createSeparator(),
this._uiGen.createStoreFormSection(this._settingsStore),
]),
this._uiGen.createTabPanel('UI', [
this._uiGen.createFormInputGroup(OPTION_MOVE_VIDEO_ATTRIBUTES_SECTION_KEY, 'checkbox',
'Move the video attributes section from below the screenshot area to under the description.'),
this._uiGen.createFormInputGroup(OPTION_REMOVE_COMMENTS_SECTION_KEY, 'checkbox', 'Remove comments area on video pages.'),
this._uiGen.createFormInputGroup(OPTION_REMOVE_IFRAME_SECTION_KEY, 'checkbox', 'Remove iframe share section under video player.'),
this._uiGen.createFormInputGroup(OPTION_REMOVE_RELATED_VIDEOS_SECTION_KEY, 'checkbox', 'Remove related videos section on video pages.'),
this._uiGen.createSeparator(),
this._uiGen.createFormInputGroup(PAGINATOR_THRESHOLD, 'number', 'Merges results from later pages to satisfy the defined minimum.'),
this._uiGen.createFormInputGroup(OPTION_ALWAYS_SHOW_UI, 'checkbox', 'Always show this interface.'),
this._uiGen.createSeparator(),
this._createSettingsFormActions(),
this._uiGen.createSeparator(),
this._uiGen.createStoreFormSection(this._settingsStore),
]),
this._uiGen.createTabPanel('Stats', [
this._uiGen.createStatisticsFormGroup(FILTER_RATING_VIDEOS_KEY),
this._uiGen.createStatisticsFormGroup(FILTER_VIDEOS_YEAR_KEY),
this._uiGen.createSeparator(),
this._uiGen.createStatisticsTotalsGroup(),
]),
]),
this._uiGen.createStatusSection(),
])
this._onAfterUIBuild = () => {
this._uiGen.getSelectedSection().userScript = this
}
// Compliance Events
this._onGetItemLists = () => document.querySelectorAll('.midle_div,.list_videos')
this._complianceFilters = [
(videoItem) => this._validateRating(videoItem),
(videoItem) => this._validateYear(videoItem),
]
// Store Events
this._onSettingsStoreUpdate = () => {
/** @type {VideoCelebsSearchAndUITweaksSettings} */
let store = this._settingsStore.get()
this._uiGen.setSettingsInputCheckedStatus(OPTION_ALWAYS_SHOW_UI, store.showUIAlways)
this._uiGen.setSettingsInputCheckedStatus(OPTION_DISABLE_VIDEO_FILTERS, store.disableItemComplianceValidation)
this._uiGen.setSettingsInputCheckedStatus(OPTION_MOVE_VIDEO_ATTRIBUTES_SECTION_KEY, store.moveVideoAttributesBelowDescription)
this._uiGen.setSettingsInputCheckedStatus(OPTION_REMOVE_COMMENTS_SECTION_KEY, store.removeCommentsSection)
this._uiGen.setSettingsInputCheckedStatus(OPTION_REMOVE_IFRAME_SECTION_KEY, store.removeIFrameSection)
this._uiGen.setSettingsInputCheckedStatus(OPTION_REMOVE_RELATED_VIDEOS_SECTION_KEY, store.removeRelatedVideosSection)
this._uiGen.setSettingsInputValue(PAGINATOR_THRESHOLD, store.paginationThreshold)
this._uiGen.setSettingsRangeInputValue(FILTER_RATING_VIDEOS_KEY, store.rating.minimum, store.rating.maximum)
this._uiGen.setSettingsRangeInputValue(FILTER_VIDEOS_YEAR_KEY, store.year.minimum, store.year.maximum)
}
this._onSettingsApply = () => {
/** @type {VideoCelebsSearchAndUITweaksSettings} */
let settings = this._settings
settings.disableItemComplianceValidation = this._uiGen.getSettingsInputCheckedStatus(OPTION_DISABLE_VIDEO_FILTERS)
settings.moveVideoAttributesBelowDescription = this._uiGen.getSettingsInputCheckedStatus(OPTION_MOVE_VIDEO_ATTRIBUTES_SECTION_KEY)
settings.paginationThreshold = this._uiGen.getSettingsInputValue(PAGINATOR_THRESHOLD)
settings.rating.minimum = this._uiGen.getSettingsRangeInputValue(FILTER_RATING_VIDEOS_KEY, true)
settings.rating.maximum = this._uiGen.getSettingsRangeInputValue(FILTER_RATING_VIDEOS_KEY, false)
settings.removeCommentsSection = this._uiGen.getSettingsInputCheckedStatus(OPTION_REMOVE_COMMENTS_SECTION_KEY)
settings.removeIFrameSection = this._uiGen.getSettingsInputCheckedStatus(OPTION_REMOVE_IFRAME_SECTION_KEY)
settings.removeRelatedVideosSection = this._uiGen.getSettingsInputCheckedStatus(OPTION_REMOVE_RELATED_VIDEOS_SECTION_KEY)
settings.showUIAlways = this._uiGen.getSettingsInputCheckedStatus(OPTION_ALWAYS_SHOW_UI)
settings.year.minimum = this._uiGen.getSettingsRangeInputValue(FILTER_VIDEOS_YEAR_KEY, true)
settings.year.maximum = this._uiGen.getSettingsRangeInputValue(FILTER_VIDEOS_YEAR_KEY, false)
}
}
_moveVideoAttributesBelowDescription ()
{
if (this._settings.moveVideoAttributesBelowDescription) {
let videoInfoBlock = document.querySelector('.entry-utility')
videoInfoBlock.parentNode.insertBefore(videoInfoBlock, videoInfoBlock.previousSibling.previousSibling)
}
}
_removeCommentsSection ()
{
if (this._settings.removeCommentsSection) {
$('.comments-area').remove()
}
}
_removeIFrameSection ()
{
if (this._settings.removeIFrameSection) {
$('#tab_share').remove()
}
}
_removeRelatedVideosSection ()
{
if (this._settings.removeRelatedVideosSection) {
$('.related').remove()
}
}
/**
* Validate video source release year
* @param {Node|HTMLElement} videoItem
* @return {boolean}
* @private
*/
_validateRating (videoItem)
{
if (this._settings.rating.minimum > 0 || this._settings.rating.maximum > 0) {
let rating = parseInt(videoItem.querySelector('.rating').textContent.trim().replace('%', ''))
return this._validator.validateRange(FILTER_RATING_VIDEOS_KEY, rating, [this._settings.rating.minimum, this._settings.rating.maximum])
}
return true
}
/**
* Validate video view count
* @param {Node|HTMLElement} videoItem
* @return {boolean}
* @private
*/
_validateYear (videoItem)
{
if (this._settings.year.minimum > 0 || this._settings.year.maximum > 0) {
let yearFragments = videoItem.querySelector('.title a').textContent.trim().split('(')
let year = parseInt(yearFragments[yearFragments.length - 1].replace(')', ''))
return this._validator.validateRange(FILTER_VIDEOS_YEAR_KEY, year, [this._settings.year.minimum, this._settings.year.maximum])
}
return true
}
/**
* @param {string} label
* @param {string} inputsType
*
* @return {HTMLElement}
* @private
*/
_createFormRangeInputGroup (label, inputsType = 'text')
{
let maxInputSelector = this._uiGen._selectorGenerator.getSettingsRangeInputSelector(label, false)
let minInputSelector = this._uiGen._selectorGenerator.getSettingsRangeInputSelector(label, true)
let divFormInputGroup = this._uiGen.createFormGroup([
this._uiGen.createFormGroupLabel(label, '', inputsType),
this._uiGen.createFormGroupInput(minInputSelector, inputsType),
this._uiGen.createFormGroupInput(maxInputSelector, inputsType),
])
divFormInputGroup.classList.add('form-range-input-group')
return divFormInputGroup
}
}
VideoCelebsSearchAndUITweaks.initialize()