Greasy Fork

Brazenvoid's Base Resource

Base library for my scripts

目前为 2018-12-31 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.greasyfork.icu/scripts/375557/658367/Brazenvoid%27s%20Base%20Resource.js

// ==UserScript==
// @name          Brazenvoid's Base Resource
// @namespace     brazenvoid
// @version       1.3.0
// @author        brazenvoid
// @license       GPL-3.0-only
// @description   Base library for my scripts
// @run-at	      document-end
// ==/UserScript==

const sleep = (milliseconds) => {
  return new Promise(resolve => setTimeout(resolve, milliseconds))
}

class CaseConverters {

  toCamel (text) {
    return text.replace(/(?:^\w|[A-Z]|\b\w)/g, function (letter, index) {
      return index === 0 ? letter.toLowerCase() : letter.toUpperCase()
    }).replace(/\s+/g, '')
  }

  toKebab (text) {
    return text.toLowerCase().replace(' ', '-')
  }

  toKebabFromSnake (text) {
    return text.replace('_', '-')
  }

  toNormalFromKebab (text) {
    return text.replace('-', ' ')
  }

  toNormalFromSnake (text) {
    return text.replace('_', ' ')
  }

  toSnake (text) {
    return text.toLowerCase().replace(' ', '_')
  }
}

class ChildObserver {

  constructor (handler) {
    this.config = {
      attributes: false,
      childList: true,
      subtree: false
    }
    this.handler = handler
    this.observer = new MutationObserver(function (mutations) {
      for (let mutation of mutations) {
        handler(mutation.target)
      }
    })
  }

  observe (node, doInitialRun = false) {

    if (doInitialRun) {
      this.handler(node)
    }
    this.observer.observe(node, this.config)
    return this
  }
}

class Filters {

  constructor (statisticsRecorder) {
    this.blacklist = []
    this.sanitizationRules = []

    this._optimizedBlacklist = []
    this._optimizedSanitizationRules = {}
    this._statisticsRecorder = statisticsRecorder
  }

  init () {

    for (let i = 0; i < this.blacklist.length; i++) {
      this._optimizedBlacklist[i] = new RegExp(this.blacklist[i], 'ig')
    }

    for (const substitute in this.sanitizationRules) {
      this._optimizedSanitizationRules[substitute] = []

      for (let i = 0; i < this.sanitizationRules[substitute].length; i++) {
        this._optimizedSanitizationRules[substitute][i] = new RegExp(this.sanitizationRules[substitute][i], 'ig')
      }
    }
  }

  iFramesRemover () {

    GM_addStyle(`
      iframe {
          display: none !important;
      }
    `)
  }

  sanitize (text) {

    for (const substitute in this._optimizedSanitizationRules) {
      for (const subject of this._optimizedSanitizationRules[substitute]) {
        text = text.replace(subject, substitute)
      }
    }
    return text
  }

  validateBlackList (text) {

    let validationCheck = true

    if (this._optimizedBlacklist.length > 0) {

      for (const blacklistedWord of this._optimizedBlacklist) {

        validationCheck = text.match(blacklistedWord) === null
        if (!validationCheck) {
          break
        }
      }
      this._statisticsRecorder.record('Blacklist', validationCheck)
    }
    return validationCheck
  }

  validateRange (type, value, bounds) {

    let validationCheck = true

    if (bounds[0] > 0) {
      validationCheck = value >= bounds[0]
    }
    if (bounds[1] > 0) {
      validationCheck = value <= bounds[1]
    }
    this._statisticsRecorder.record(type, validationCheck)

    return validationCheck
  }
}

class LocalStore {

  constructor (key, defaultStore) {
    this.onDefaultsLoaded = null
    this.onRetrieval = null
    this.onUpdated = null

    this._key = key
    this._store = {}
    this._defaultStore = this._toJSON(defaultStore)
  }

  _fromJSON (json) {
    let arrayObject = {}
    let parsedJSON = JSON.parse(json)
    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
  }

  _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)
  }

  delete () {
    window.localStorage.removeItem(this._key)
    return this
  }

  get () {
    return this._store
  }

  restoreDefaults () {
    this._store = this._fromJSON(this._defaultStore)

    if (this.onDefaultsLoaded !== null) {
      this.onDefaultsLoaded(this._store)
    }
    return this
  }

  retrieve () {
    let storedStore = window.localStorage.getItem(this._key)
    if (storedStore === null) {
      this.restoreDefaults()
    } else {
      this._store = this._fromJSON(storedStore)
    }
    if (this.onRetrieval !== null) {
      this.onRetrieval(this._store)
    }
    return this
  }

  save () {
    window.localStorage.setItem(this._key, this._toJSON(this._store))

    if (this.onUpdated !== null) {
      this.onUpdated(this._store)
    }
    return this
  }
}

class Logger {

  constructor (enableDebugging) {
    this.enableDebugging = enableDebugging
  }

  _log (message) {
    if (this.enableDebugging) {
      console.log(message)
    }
  }

  logTaskCompletion (task) {
    this._log('Completed: ' + task)
    this.logSeparator()
  }

  logSeparator () {
    this._log('------------------------------------------------------------------------------------')
  }

  logValidation (filterName, validationResult = null) {
    this._log('Satisfies ' + filterName + ' Filter: ' + (validationResult ? 'true' : 'false'))
  }

  logVideoCheck (videoName) {
    this._log('Checking Video: ' + videoName)
  }
}

class SelectorGenerator {

  constructor (selectorPrefix) {
    this.prefix = selectorPrefix
  }

  getSelector (selector) {
    return this.prefix + selector
  };

  getSelectorFromName (name) {
    return CaseConverters.prototype.toKebab(name)
  }

  getSettingsInputSelector (settingName) {
    return this.getSelector(this.getSelectorFromName(settingName) + '-setting')
  }

  getStatLabelSelector (statisticType) {
    return this.getSelector(this.getSelectorFromName(statisticType) + '-stat')
  };
}

class StatisticsRecorder {

  constructor (logger, selectorGenerator) {
    this.logger = logger
    this.selectorGenerator = selectorGenerator
    this.statistics = {Total: 0}
  }

  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 {

  constructor (showUI, selectorGenerator) {
    this.selectorGenerator = selectorGenerator
    this.showUI = showUI
  }

  appendToBody (node) {

    let bodyTag = document.getElementsByTagName('body')[0]
    bodyTag.appendChild(node)
  }

  createFormButton (caption, onClick) {

    let button = document.createElement('button')
    button.textContent = caption
    button.style.height = '30px'
    button.style.width = '100%'
    button.addEventListener('click', onClick)

    return button
  }

  createFormGroup () {

    let divFormGroup = document.createElement('div')
    divFormGroup.style.display = 'block'
    divFormGroup.style.height = '18px'
    divFormGroup.style.marginBottom = '2px'
    divFormGroup.style.padding = '5px 0'

    return divFormGroup
  }

  createFormGroupLabel (label, inputID = null) {

    let labelFormGroup = document.createElement('label')
    labelFormGroup.style.float = 'left'
    labelFormGroup.style.padding = '2px 0'
    labelFormGroup.textContent = label + ': '

    if (inputID !== null) {
      labelFormGroup.setAttribute('for', inputID)
    }
    return labelFormGroup
  }

  createFormGroupStatLabel (statisticType) {

    let labelFormGroup = document.createElement('label')
    labelFormGroup.id = this.selectorGenerator.getStatLabelSelector(statisticType)
    labelFormGroup.style.float = 'right'
    labelFormGroup.style.padding = '2px 0'
    labelFormGroup.textContent = '0'

    return labelFormGroup
  }

  createFormGroupInput (id, defaultValue) {

    let inputFormGroup = document.createElement('input')
    inputFormGroup.id = id
    inputFormGroup.style.float = 'right'
    inputFormGroup.style.width = '100px'
    inputFormGroup.style.textAlign = 'center'

    if (defaultValue !== null) {
      inputFormGroup.value = defaultValue
    }
    return inputFormGroup
  }

  createSection (id, backgroundColor, width, children) {

    let section = document.createElement('section')
    section.id = this.selectorGenerator.getSelector(id)
    section.style.color = 'black'
    section.style.display = this.showUI ? 'block' : 'none'
    section.style.fontSize = '12px'
    section.style.fontWeight = 'bold'
    section.style.position = 'fixed'
    section.style.top = '250px'
    section.style.left = '0'
    section.style.width = width
    section.style.padding = '5px 10px'
    section.style.backgroundColor = backgroundColor
    section.style.zIndex = '1000'

    for (let child of children) {
      section.appendChild(child)
    }
    return section
  }

  createSeparator () {

    let separator = document.createElement('hr')
    separator.style.margin = '3px'

    return separator
  }

  createSettingsFormGroup (label, defaultValue = null) {

    let divFormGroup = this.createFormGroup()
    let inputID = this.selectorGenerator.getSettingsInputSelector(label)
    let labelFormGroup = this.createFormGroupLabel(label, inputID)
    let inputFormGroup = this.createFormGroupInput(inputID, defaultValue)

    divFormGroup.appendChild(labelFormGroup)
    divFormGroup.appendChild(inputFormGroup)

    return divFormGroup
  }

  createSettingShowButton (caption, settingSection, fixed = true) {

    let controlButton = document.createElement('button')
    controlButton.textContent = caption

    if (fixed) {
      controlButton.style.backgroundColor = '#ffa31a'
      controlButton.style.border = '0'
      controlButton.style.color = 'black'
      controlButton.style.fontSize = '14px'
      controlButton.style.left = '0'
      controlButton.style.padding = '15px 0px'
      controlButton.style.position = 'fixed'
      controlButton.style.writingMode = 'sideways-lr'
      controlButton.style.top = '250px'
      controlButton.style.width = '30px'
      controlButton.style.zIndex = '999'
    } else {
      controlButton.style.width = '100%'
      controlButton.style.margin = '2px 5px'
      controlButton.style.padding = '2px 5px'
      controlButton.style.backgroundColor = '#ffa31a'
      controlButton.style.border = '0'
    }
    controlButton.addEventListener('click', function () {
      let settingsUI = document.getElementById(settingSection.id)
      settingsUI.style.display = settingsUI.style.display === 'none' ? 'block' : 'none'
    })
    return controlButton
  }

  createStatisticsFormGroup (statisticsType, label = null) {

    if (label === null) {
      label = statisticsType
    }

    let divFormGroup = this.createFormGroup()
    let labelFormGroup = this.createFormGroupLabel('Filtered ' + label + ' Videos')
    let statLabelFormGroup = this.createFormGroupStatLabel(statisticsType)

    divFormGroup.appendChild(labelFormGroup)
    divFormGroup.appendChild(statLabelFormGroup)

    return divFormGroup
  }

  createStoreUpdateButton (localStore) {
    return this.createFormButton('Update Store', function () {
      localStore.save()
    })
  }

  createStoreReloadButton (localStore) {
    return this.createFormButton('Reload Store', function () {
      localStore.retrieve()
    })
  }

  createStoreResetButton (localStore) {
    return this.createFormButton('Load Defaults', function () {
      localStore.restoreDefaults()
    })
  }

  createStoreDeleteButton (localStore) {
    return this.createFormButton('Delete Store', function () {
      localStore.delete()
    })
  }
}