// ==UserScript==
// @name Base Resource
// @namespace brazenvoid
// @version 1.6.6
// @author brazenvoid
// @license GPL-3.0-only
// @description Base library for my scripts
// @grant GM_addStyle
// @run-at document-end
// ==/UserScript==
GM_addStyle(`
button.form-button {
padding: 0 5px;
width: 100%;
}
button.show-settings {
background-color: #ffa31a;
border: 0;
margin: 2px 5px;
padding: 2px 5px;
width: 100%;
}
button.show-settings.fixed {
color: black;
font-size: 14px;
left: 0;
margin: 0;
padding: 15px 0px;
position: fixed;
top: 250px;
width: 30px;
writing-mode: sideways-lr;
z-index: 999;
}
div.form-actions {
text-align: center;
}
div.form-actions button + button {
margin-left: 10px;
}
div.form-actions button.form-button {
padding: 0 15px;
width: auto
}
div.form-actions-wrapper {
display: inline-flex;
}
div.form-actions-wrapper > div.form-group + * {
margin-left: 15px;
}
div.form-group {
min-height: 15px;
padding: 5px 0;
}
div.form-group.form-range-input-group > input {
padding: 0 5px;
width: 70px;
}
div.form-group.form-range-input-group > input + input {
margin-right: 5px;
}
div.form-section {
text-align: center;
}
div.form-section button + button {
margin-left: 5px;
}
div.form-section label.title {
display: block;
height: 20px;
width: 100%;
}
div.form-section button.form-button {
width: auto;
}
hr {
margin: 3px;
}
input.form-input {
height: 18px;
text-align: center;
}
input.form-input.check-radio-input {
float: left;
margin-right: 5px;
}
input.form-input.regular-input {
float: right;
width: 100px;
}
label.form-label {
padding: 2px 0;
}
label.form-label.regular-input {
float: left;
}
label.form-label.check-radio-input {
float: right;
}
label.form-stat-label {
float: right;
padding: 2px 0;
}
section.form-section {
color: black;
font-size: 12px;
font-weight: bold;
position: fixed;
left: 0;
padding: 5px 10px;
z-index: 1000;
}
select.form-dropdown {
float: right;
height: 18px;
text-align: center;
width: 100px
}
`)
/**
* @param milliseconds
* @return {Promise<*>}
*/
const sleep = (milliseconds) => {
return new Promise(resolve => setTimeout(resolve, milliseconds))
}
/**
* @param {string} classes
* @return {RegExp}
* @private
*/
function _generateClassesIdentificationRegex (classes)
{
return new RegExp('(\\s|^)' + classes + '(\\s|$)')
}
/**
* @param {Element} node
* @param {string} classes
* @return {Element}
*/
function addClasses (node, classes)
{
if (!hasClasses(node, classes)) {
if (node.className !== '') {
node.className += ' '
}
node.className += classes
}
return node
}
/**
* @param {Element} node
* @param {string} classes
* @return {boolean}
*/
function hasClasses (node, classes)
{
return !!node.className.match(_generateClassesIdentificationRegex(classes))
}
/**
* @param {Element} node
* @param {string} classes
* @return {Element}
*/
function removeClasses (node, classes)
{
if (hasClasses(node, classes)) {
node.className = node.className.replace(_generateClassesIdentificationRegex(classes), ' ')
}
return node
}
class CaseConverters
{
/**
* @param {string} text
* @return {string}
*/
static toCamel (text)
{
return text.replace(/(?:^\w|[A-Z]|\b\w)/g, function (letter, index) {
return index === 0 ? letter.toLowerCase() : letter.toUpperCase()
}).replace(/\s+/g, '')
}
/**
* @param {string} text
* @return {string}
*/
static toKebab (text)
{
return text.toLowerCase().replace(' ', '-')
}
/**
* @param {string} text
* @return {string}
*/
static toKebabFromSnake (text)
{
return text.replace('_', '-')
}
/**
* @param {string} text
* @return {string}
*/
static toNormalFromKebab (text)
{
return text.replace('-', ' ')
}
/**
* @param {string} text
* @return {string}
*/
static toNormalFromSnake (text)
{
return text.replace('_', ' ')
}
/**
* @param {string} text
* @return {string}
*/
static toSnake (text)
{
return text.toLowerCase().replace(' ', '_')
}
}
class ChildObserver
{
/**
* @callback observerMutationHandler
* @param {Node} target
*/
/**
* @param {Element|Element[]} nodes
* @param {observerMutationHandler} handler
* @param {boolean} doInitialRun
* @return {ChildObserver}
*/
static observe (nodes, handler, doInitialRun = false)
{
let instance = new ChildObserver(handler)
instance.observeNodes(nodes, doInitialRun)
return instance
}
/**
* @param {observerMutationHandler} handler
*/
constructor (handler)
{
/**
* @type {{subtree: boolean, attributes: boolean, childList: boolean}}
* @private
*/
this._config = {
attributes: false,
childList: true,
subtree: false,
}
/**
* @type {observerMutationHandler}
* @private
*/
this._handler = handler
/**
* @type {MutationObserver}
* @private
*/
this._observer = new MutationObserver(function (mutations) {
for (let mutation of mutations) {
handler(mutation.target)
}
})
}
/**
* @param {Element|Element[]} nodes
* @param {boolean} doInitialRun
*/
observeNodes (nodes, doInitialRun = false)
{
nodes = (Array.isArray(nodes) || nodes instanceof NodeList) ? nodes : [nodes]
for (let node of nodes) {
if (doInitialRun) {
this._handler(node)
}
this._observer.observe(node, this._config)
}
}
}
class LocalStore
{
/**
* @callback storeEventHandler
* @param {Object} store
*/
/**
* @param {string} key
* @param {Object} defaultStore
*/
constructor (key, defaultStore)
{
/**
* @type {string}
* @private
*/
this._key = key
/**
* @type {Object}
* @private
*/
this._store = {}
/**
* @type {string}
* @private
*/
this._defaultStore = this._toJSON(defaultStore)
/**
* @type {storeEventHandler}
*/
this.onDefaultsLoaded = null
/**
* @type {storeEventHandler}
*/
this.onRetrieval = null
/**
* @type {storeEventHandler}
*/
this.onUpdated = null
}
/**
* @param {string} json
* @return {Object}
* @private
*/
_fromJSON (json)
{
/** @type {{arrays: Object, objects: Object, properties: Object}} */
let parsedJSON = JSON.parse(json)
let arrayObject = {}
let store = {}
for (let property in parsedJSON.arrays) {
arrayObject = JSON.parse(parsedJSON.arrays[property])
store[property] = []
for (let key in arrayObject) {
store[property].push(arrayObject[key])
}
}
for (let property in parsedJSON.objects) {
store[property] = this._fromJSON(parsedJSON.objects[property])
}
for (let property in parsedJSON.properties) {
store[property] = parsedJSON.properties[property]
}
return store
}
/**
* @return {string}
* @private
*/
_getStore ()
{
return window.localStorage.getItem(this._key)
}
/**
* @return {Object}
* @private
*/
_getDefaults ()
{
return this._fromJSON(this._defaultStore)
}
/**
* @param {Object} store
* @return {string}
* @private
*/
_toJSON (store)
{
let arrayToObject = {}
let json = {arrays: {}, objects: {}, properties: {}}
for (let property in store) {
if (typeof store[property] === 'object') {
if (Array.isArray(store[property])) {
for (let key in store[property]) {
arrayToObject[key] = store[property][key]
}
json.arrays[property] = JSON.stringify(arrayToObject)
} else {
json.objects[property] = this._toJSON(store[property])
}
} else {
json.properties[property] = store[property]
}
}
return JSON.stringify(json)
}
/**
* @return {LocalStore}
*/
delete ()
{
window.localStorage.removeItem(this._key)
return this
}
/**
* @return {Object}
*/
get ()
{
return this._store
}
/**
* @return {LocalStore}
*/
restoreDefaults ()
{
this._store = this._getDefaults()
if (this.onDefaultsLoaded !== null) {
this.onDefaultsLoaded(this._store)
}
return this
}
/**
* @return {LocalStore}
*/
retrieve ()
{
let storedStore = this._getStore()
if (storedStore === null) {
this.restoreDefaults()
} else {
this._store = this._fromJSON(storedStore)
}
if (this.onRetrieval !== null) {
this.onRetrieval(this._store)
}
return this
}
/**
* @return {LocalStore}
*/
save ()
{
window.localStorage.setItem(this._key, this._toJSON(this._store))
if (this.onUpdated !== null) {
this.onUpdated(this._store)
}
return this
}
/**
* @return {boolean}
*/
isPurged ()
{
return this._getStore() === null
}
}
class Logger
{
/**
* @param {boolean} enableDebugging
*/
constructor (enableDebugging)
{
/**
* @type {boolean}
* @private
*/
this._enableDebugging = enableDebugging
}
/**
* @param {string} message
* @private
*/
_log (message)
{
if (this._enableDebugging) {
console.log(message)
}
}
/**
* @param {string} task
*/
logTaskCompletion (task)
{
this._log('Completed: ' + task)
this.logSeparator()
}
logSeparator ()
{
this._log('------------------------------------------------------------------------------------')
}
/**
* @param {string} filterName
* @param {boolean} validationResult
*/
logValidation (filterName, validationResult)
{
this._log('Satisfies ' + filterName + ' Filter: ' + (validationResult ? 'true' : 'false'))
}
/**
* @param {string} videoName
*/
logVideoCheck (videoName)
{
this._log('Checking Video: ' + videoName)
}
}
class SelectorGenerator
{
/**
* @param {string} selectorPrefix
*/
constructor (selectorPrefix)
{
/**
* @type {string}
* @private
*/
this._prefix = selectorPrefix
}
/**
* @param {string} selector
* @return {string}
*/
getSelector (selector)
{
return this._prefix + selector
};
/**
* @param {string} settingName
* @return {string}
*/
getSettingsInputSelector (settingName)
{
return this.getSelector(CaseConverters.toKebab(settingName) + '-setting')
}
/**
* @param {string} settingName
* @param {boolean} getMinInputSelector
* @return {string}
*/
getSettingsRangeInputSelector (settingName, getMinInputSelector)
{
return this.getSelector(
CaseConverters.toKebab(settingName) + (getMinInputSelector ? '-min' : '-max') + '-setting')
}
/**
* @param {string} statisticType
* @return {string}
*/
getStatLabelSelector (statisticType)
{
return this.getSelector(CaseConverters.toKebab(statisticType) + '-stat')
};
}
class StatisticsRecorder
{
/**
* @param {Logger} logger
* @param {SelectorGenerator} selectorGenerator
*/
constructor (logger, selectorGenerator)
{
/**
* @type {Logger}
* @private
*/
this._logger = logger
/**
* @type {SelectorGenerator}
* @private
*/
this._selectorGenerator = selectorGenerator
/**
* @type {{Total: number}}
* @private
*/
this._statistics = {Total: 0}
}
/**
* @param {string} statisticType
* @param {boolean} validationResult
* @param {number} value
* @param {boolean} log
*/
record (statisticType, validationResult, value = 1, log = true)
{
if (!validationResult) {
if (typeof this._statistics[statisticType] !== 'undefined') {
this._statistics[statisticType] += value
} else {
this._statistics[statisticType] = value
}
this._statistics.Total += value
}
if (log) {
this._logger.logValidation(statisticType, validationResult)
}
}
reset ()
{
for (const statisticType in this._statistics) {
this._statistics[statisticType] = 0
}
}
updateUI ()
{
let label, labelSelector
for (const statisticType in this._statistics) {
labelSelector = this._selectorGenerator.getStatLabelSelector(statisticType)
label = document.getElementById(labelSelector)
if (label !== null) {
label.textContent = this._statistics[statisticType]
}
}
}
}
class UIGenerator
{
/**
* @param {Element|Node} node
*/
static appendToBody (node)
{
document.getElementsByTagName('body')[0].appendChild(node)
}
/**
* @param {Element} node
* @param {Element[]} children
* @return {Element}
*/
static populateChildren (node, children)
{
for (let child of children) {
node.appendChild(child)
}
return node
}
/**
* @param {boolean} showUI
* @param {SelectorGenerator} selectorGenerator
*/
constructor (showUI, selectorGenerator)
{
/**
* @type {*}
* @private
*/
this._buttonBackroundColor = null
/**
* @type {SelectorGenerator}
* @private
*/
this._selectorGenerator = selectorGenerator
/**
* @type {boolean}
* @private
*/
this._showUI = showUI
}
/**
* @param {Element[]} children
* @return {HTMLDivElement}
*/
createFormActions (children)
{
let wrapperDiv = document.createElement('div')
wrapperDiv.classList.add('form-actions-wrapper')
UIGenerator.populateChildren(wrapperDiv, children)
let formActionsDiv = document.createElement('div')
formActionsDiv.classList.add('form-actions')
formActionsDiv.appendChild(wrapperDiv)
return formActionsDiv
}
/**
* @param {string} caption
* @param onClick
* @return {HTMLButtonElement}
*/
createFormButton (caption, onClick)
{
let button = document.createElement('button')
button.classList.add('form-button')
button.textContent = caption
button.addEventListener('click', onClick)
if (this._buttonBackroundColor !== null) {
button.style.backgroundColor = this._buttonBackroundColor
}
return button
}
/**
* @param {Element[]} children
* @return {Element}
*/
createFormGroup (children)
{
let divFormGroup = document.createElement('div')
divFormGroup.classList.add('form-group')
return UIGenerator.populateChildren(divFormGroup, children)
}
/**
* @param {string} id
* @param {Array} keyValuePairs
* @param {*} defaultValue
* @return {HTMLSelectElement}
*/
createFormGroupDropdown (id, keyValuePairs, defaultValue = null)
{
let dropdown = document.createElement('select'), item
dropdown.id = id
dropdown.classList.add('form-dropdown')
for (let [key, value] of keyValuePairs) {
item = document.createElement('option')
item.textContent = value
item.value = key
dropdown.appendChild(item)
}
dropdown.value = defaultValue === null ? keyValuePairs[0][0] : defaultValue
return dropdown
}
/**
* @param {string} id
* @param {string} type
* @param {*} defaultValue
* @return {HTMLInputElement}
*/
createFormGroupInput (id, type, defaultValue = null)
{
let inputFormGroup = document.createElement('input')
inputFormGroup.id = id
inputFormGroup.classList.add('form-input')
inputFormGroup.type = type
switch (type) {
case 'number':
case 'text':
inputFormGroup.classList.add('regular-input')
if (defaultValue !== null) {
inputFormGroup.value = defaultValue
}
break
case 'radio':
case 'checkbox':
inputFormGroup.classList.add('check-radio-input')
if (defaultValue !== null) {
inputFormGroup.checked = defaultValue
}
break
}
return inputFormGroup
}
/**
* @param {string} label
* @param {string} inputID
* @param {string} inputType
* @return {HTMLLabelElement}
*/
createFormGroupLabel (label, inputID = '', inputType = '')
{
let labelFormGroup = document.createElement('label')
labelFormGroup.classList.add('form-label')
labelFormGroup.textContent = label
if (inputID !== '') {
labelFormGroup.setAttribute('for', inputID)
}
if (inputType !== '') {
switch (inputType) {
case 'number':
case 'text':
labelFormGroup.classList.add('regular-input')
labelFormGroup.textContent += ': '
break
case 'radio':
case 'checkbox':
labelFormGroup.classList.add('check-radio-input')
break
}
}
return labelFormGroup
}
/**
* @param {string} statisticType
* @return {HTMLLabelElement}
*/
createFormGroupStatLabel (statisticType)
{
let labelFormGroup = document.createElement('label')
labelFormGroup.id = this._selectorGenerator.getStatLabelSelector(statisticType)
labelFormGroup.classList.add('form-stat-label')
labelFormGroup.textContent = '0'
return labelFormGroup
}
/**
* @param {string} label
* @param {string} inputType
* @param {*} defaultValue
* @return {Element}
*/
createFormInputGroup (label, inputType = 'text', defaultValue = null)
{
let divFormInputGroup
let inputID = this._selectorGenerator.getSettingsInputSelector(label)
let labelFormGroup = this.createFormGroupLabel(label, inputType, inputID)
let inputFormGroup = this.createFormGroupInput(inputID, inputType, defaultValue)
switch (inputType) {
case 'number':
case 'text':
divFormInputGroup = this.createFormGroup([labelFormGroup, inputFormGroup])
break
case 'radio':
case 'checkbox':
divFormInputGroup = this.createFormGroup([inputFormGroup, labelFormGroup])
break
}
return divFormInputGroup
}
/**
* @param {string} label
* @param {string} inputsType
* @param {*} defaultValues
* @return {Element}
*/
createFormRangeInputGroup (label, inputsType = 'text', defaultValues = null)
{
let divFormInputGroup = this.createFormGroup([
this.createFormGroupLabel(label, null, inputsType),
this.createFormGroupInput(
this._selectorGenerator.getSettingsRangeInputSelector(label, false),
inputsType,
defaultValues === null ? null : defaultValues[1],
),
this.createFormGroupInput(
this._selectorGenerator.getSettingsRangeInputSelector(label, true),
inputsType,
defaultValues === null ? null : defaultValues[0],
),
])
divFormInputGroup.classList.add('form-range-input-group')
return divFormInputGroup
}
/**
* @param {string} title
* @param {Element[]} children
* @return {Element}
*/
createFormSection (title, children)
{
let sectionDiv = document.createElement('div')
sectionDiv.classList.add('form-section')
let sectionTitle = document.createElement('label')
sectionTitle.textContent = title
sectionTitle.classList.add('title')
UIGenerator.populateChildren(sectionDiv, [sectionTitle])
return UIGenerator.populateChildren(sectionDiv, children)
}
/**
* @param {string} caption
* @param {string} tooltip
* @param onClick
* @return {HTMLButtonElement}
*/
createFormSectionButton (caption, tooltip, onClick)
{
let button = this.createFormButton(caption, onClick)
button.title = tooltip
return button
}
/**
* @param {string} IDSuffix
* @param {*} backgroundColor
* @param {*} top
* @param {*} width
* @param {Element[]} children
* @return {Element}
*/
createSection (IDSuffix, backgroundColor, top, width, children)
{
let section = document.createElement('section')
section.id = this._selectorGenerator.getSelector(IDSuffix)
section.classList.add('form-section')
section.style.display = this._showUI ? 'block' : 'none'
section.style.top = top
section.style.width = width
section.style.backgroundColor = backgroundColor
return UIGenerator.populateChildren(section, children)
}
/**
* @return {HTMLHRElement}
*/
createSeparator ()
{
return document.createElement('hr')
}
/**
* @param {LocalStore} localStore
* @param onClick
* @param {boolean} addTopPadding
* @return {HTMLDivElement}
*/
createSettingsFormActions (localStore, onClick, addTopPadding = false)
{
let divFormActions = this.createFormActions([
this.createFormButton('Apply', onClick),
this.createFormButton('Reset', function () {
localStore.retrieve()
onClick()
}),
])
if (addTopPadding) {
divFormActions.style.paddingTop = '10px'
}
return divFormActions
}
/**
* @param {string} label
* @param {Array} keyValuePairs
* @param {*} defaultValue
* @return {Element}
*/
createSettingsDropDownFormGroup (label, keyValuePairs, defaultValue = null)
{
let dropdownID = this._selectorGenerator.getSettingsInputSelector(label)
return this.createFormGroup([
this.createFormGroupLabel(label, 'text', dropdownID),
this.createFormGroupDropdown(dropdownID, keyValuePairs, defaultValue),
])
}
/**
* @param {string} settingsSectionIDSuffix
* @return {HTMLButtonElement}
*/
createSettingsHideButton (settingsSectionIDSuffix)
{
let settingsSectionID = this._selectorGenerator.getSelector(settingsSectionIDSuffix)
return this.createFormButton('Hide', function () {
document.getElementById(settingsSectionID).style.display = 'none'
})
}
/**
* @param {string} caption
* @param {Element} settingsSection
* @param {boolean} fixed
* @return {HTMLButtonElement}
*/
createSettingsShowButton (caption, settingsSection, fixed = true)
{
let controlButton = document.createElement('button')
controlButton.textContent = caption
controlButton.classList.add('show-settings')
if (fixed) {
controlButton.classList.add('fixed')
}
controlButton.addEventListener('click', function () {
let settingsUI = document.getElementById(settingsSection.id)
settingsUI.style.display = settingsUI.style.display === 'none' ? 'block' : 'none'
})
return controlButton
}
/**
* @param {string} statisticsType
* @param {string} label
* @return {Element}
*/
createStatisticsFormGroup (statisticsType, label = null)
{
if (label === null) {
label = statisticsType
}
return this.createFormGroup([
this.createFormGroupLabel('Filtered ' + label + ' Videos'),
this.createFormGroupStatLabel(statisticsType),
])
}
/**
* @param {LocalStore} localStore
* @return {Element}
*/
createStoreFormSection (localStore)
{
return this.createFormSection('Store', [
this.createFormActions([
this.createFormSectionButton('Update', 'Save UI settings in store', function () {
localStore.save()
}),
this.createFormSectionButton(
'Reset',
'Reset store values to user defaults',
function () {
localStore.restoreDefaults()
},
),
this.createFormSectionButton('Purge', 'Purge store', function () {
localStore.delete()
}),
]),
])
}
/**
* @param {string} label
* @return {HTMLElement}
*/
getSettingsInput (label)
{
return document.getElementById(this._selectorGenerator.getSettingsInputSelector(label))
}
/**
* @param {string} label
* @return {boolean}
*/
getSettingsInputCheckedStatus (label)
{
return this.getSettingsInput(label).checked
}
/**
* @param {string} label
* @param {boolean} lowerBound
* @return {*}
*/
getSettingsInputValue (label)
{
return this.getSettingsInput(label).value
}
/**
* @param {string} label
* @param {boolean} getMinInput
* @return {HTMLElement}
*/
getSettingsRangeInput (label, getMinInput)
{
return document.getElementById(this._selectorGenerator.getSettingsRangeInputSelector(label, getMinInput))
}
/**
* @param {string} label
* @param {boolean} getMinInputValue
* @return {*}
*/
getSettingsRangeInputValue (label, getMinInputValue)
{
return this.getSettingsRangeInput(label, getMinInputValue).value
}
/**
* @param {string} label
* @param {boolean} bool
*/
setSettingsInputCheckedStatus (label, bool)
{
this.getSettingsInput(label).checked = bool
}
/**
* @param {string} label
* @param {*} value
*/
setSettingsInputValue (label, value)
{
this.getSettingsInput(label).value = value
}
/**
* @param {string} label
* @param {number} lowerBound
* @param {number} upperBound
*/
setSettingsRangeInputValue (label, lowerBound, upperBound)
{
this.getSettingsRangeInput(label, true).value = lowerBound
this.getSettingsRangeInput(label, false).value = upperBound
}
}
class Validator
{
static iFramesRemover ()
{
GM_addStyle(' iframe { display: none !important; } ')
}
/**
* @param {StatisticsRecorder} statisticsRecorder
*/
constructor (statisticsRecorder)
{
/**
* @type {Array}
* @private
*/
this._blacklist = []
/**
* @type {Array}
* @private
*/
this._filters = []
/**
* @type {RegExp}
* @private
*/
this._optimizedBlacklist = null
/**
* @type {Object}
* @private
*/
this._optimizedSanitizationRules = {}
/**
* @type {Object}
* @private
*/
this._sanitizationRules = []
/**
* @type {StatisticsRecorder}
* @private
*/
this._statisticsRecorder = statisticsRecorder
}
_buildWholeWordMatchingRegex (words)
{
let patternedWords = []
for (let i = 0; i < words.length; i++) {
patternedWords.push('\\b' + words[i] + '\\b')
}
return new RegExp('(' + patternedWords.join('|') + ')', 'gi')
}
/**
* @param {string[]} blacklistedWords
* @return {Validator}
*/
addBlacklistFilter (blacklistedWords)
{
this._blacklist = blacklistedWords
return this
}
/**
* @param {Object} sanitizationRules
* @return {Validator}
*/
addSanitizationFilter (sanitizationRules)
{
this._sanitizationRules = sanitizationRules
return this
}
/**
* @return {Validator}
*/
optimize ()
{
this._optimizedBlacklist = this._buildWholeWordMatchingRegex(this._blacklist)
for (const substitute in this._sanitizationRules) {
this._optimizedSanitizationRules[substitute] =
this._buildWholeWordMatchingRegex(this._sanitizationRules[substitute])
}
return this
}
/**
* @param {string} text
* @return {string}
*/
sanitize (text)
{
for (const substitute in this._optimizedSanitizationRules) {
text = text.replace(this._optimizedSanitizationRules[substitute], substitute)
}
return text.trim()
}
/**
* @param {Element} videoNameNode
* @return {Validator}
*/
sanitizeVideoItem (videoNameNode)
{
videoNameNode.textContent = this.sanitize(videoNameNode.textContent)
return this
}
/**
* @param {string} videoNameNodeSelector
* @return {Validator}
*/
sanitizeVideoPage (videoNameNodeSelector)
{
let videoNameNode = document.querySelector(videoNameNodeSelector)
if (videoNameNode !== null) {
let sanitizedVideoName = this.sanitize(videoNameNode.textContent)
videoNameNode.textContent = sanitizedVideoName
document.title = sanitizedVideoName
}
return this
}
/**
* @param {string} text
* @return {boolean}
*/
validateBlackList (text)
{
let validationCheck = true
if (this._optimizedBlacklist !== null) {
validationCheck = text.match(this._optimizedBlacklist) === null
this._statisticsRecorder.record('Blacklist', validationCheck)
}
return validationCheck
}
/**
* @param {string} name
* @param {number} value
* @param {number[]} bounds
* @return {boolean}
*/
validateRange (name, value, bounds)
{
let validationCheck = true
if (bounds[0] > 0 && bounds[1] > 0) {
validationCheck = value >= bounds[0] && value <= bounds[1]
} else {
if (bounds[0] > 0) {
validationCheck = value >= bounds[0]
}
if (bounds[1] > 0) {
validationCheck = value <= bounds[1]
}
}
this._statisticsRecorder.record(name, validationCheck)
return validationCheck
}
/**
* @param {string} name
* @param {number} lowerBound
* @param {number} upperBound
* @param getValueCallback
* @return {boolean}
*/
validateRangeFilter (name, lowerBound, upperBound, getValueCallback)
{
if (lowerBound > 0 || upperBound > 0) {
return this.validateRange(name, getValueCallback(), [lowerBound, upperBound])
}
return true
}
}