Base Brazen Resource Edited 2

Base library for my scripts

目前為 2023-06-17 提交的版本,檢視 最新版本

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.gf.qytechs.cn/scripts/468846/1206404/Base%20Brazen%20Resource%20Edited%202.js

  1. // ==UserScript==
  2. // @name Base Brazen Resource Edited 2
  3. // @namespace brazenvoid ItsColby
  4. // @version 3.8.0
  5. // @author brazenvoid ItsColby
  6. // @license GPL-3.0-only
  7. // @description Base library for my scripts
  8. // @grant GM.getValue
  9. // @grant GM.setValue
  10. // @grant GM.deleteValue
  11. // @run-at document-end
  12. // ==/UserScript==
  13.  
  14. const REGEX_LINE_BREAK = /\r?\n/g
  15. const REGEX_PRESERVE_NUMBERS = /[^0-9]/
  16.  
  17. class ChildObserver
  18. {
  19. /**
  20. * @callback observerOnMutation
  21. * @param {NodeList} nodes
  22. * @param {Element} previousSibling
  23. * @param {Element} nextSibling
  24. * @param {Element} target
  25. */
  26.  
  27. /**
  28. * @return {ChildObserver}
  29. */
  30. static create ()
  31. {
  32. return new ChildObserver
  33. }
  34.  
  35. /**
  36. * ChildObserver constructor
  37. */
  38. constructor ()
  39. {
  40. this._node = null
  41. this._observer = null
  42. this._onNodesAdded = null
  43. this._onNodesRemoved = null
  44. }
  45.  
  46. /**
  47. * @return {ChildObserver}
  48. * @private
  49. */
  50. _observeNodes ()
  51. {
  52. this._observer.observe(this._node, {childList: true})
  53. return this
  54. }
  55.  
  56. /**
  57. * Attach an observer to the specified node(s)
  58. * @param {Node} node
  59. * @returns {ChildObserver}
  60. */
  61. observe (node)
  62. {
  63. this._node = node
  64. this._observer = new MutationObserver((mutations) => {
  65. for (let mutation of mutations) {
  66. if (mutation.addedNodes.length && this._onNodesAdded !== null) {
  67. this._onNodesAdded(
  68. mutation.addedNodes,
  69. mutation.previousSibling,
  70. mutation.nextSibling,
  71. mutation.target,
  72. )
  73. }
  74. if (mutation.removedNodes.length && this._onNodesRemoved !== null) {
  75. this._onNodesRemoved(
  76. mutation.removedNodes,
  77. mutation.previousSibling,
  78. mutation.nextSibling,
  79. mutation.target,
  80. )
  81. }
  82. }
  83. })
  84. return this._observeNodes()
  85. }
  86.  
  87. /**
  88. * @param {observerOnMutation} eventHandler
  89. * @returns {ChildObserver}
  90. */
  91. onNodesAdded (eventHandler)
  92. {
  93. this._onNodesAdded = eventHandler
  94. return this
  95. }
  96.  
  97. /**
  98. * @param {observerOnMutation} eventHandler
  99. * @returns {ChildObserver}
  100. */
  101. onNodesRemoved (eventHandler)
  102. {
  103. this._onNodesRemoved = eventHandler
  104. return this
  105. }
  106.  
  107. pauseObservation ()
  108. {
  109. this._observer.disconnect()
  110. }
  111.  
  112. resumeObservation ()
  113. {
  114. this._observeNodes()
  115. }
  116. }
  117.  
  118. class LocalStore
  119. {
  120. /**
  121. * @callback storeEventHandler
  122. * @param {Object} store
  123. */
  124.  
  125. /**
  126. * @param {string} key
  127. * @param {Object} defaults
  128. */
  129. constructor (key, defaults)
  130. {
  131. /**
  132. * @type {Object}
  133. * @private
  134. */
  135. this._defaults = defaults
  136.  
  137. /**
  138. * @type {boolean}
  139. * @private
  140. */
  141. this._defaultsSet = false
  142.  
  143. /**
  144. * @type {string}
  145. * @private
  146. */
  147. this._key = key
  148.  
  149. // Events
  150.  
  151. /**
  152. * @type {storeEventHandler}
  153. */
  154. this._onChange = null
  155. }
  156.  
  157. _handleOnChange ()
  158. {
  159. if (this._onChange !== null) {
  160. this._onChange(this.get())
  161. }
  162. }
  163.  
  164. /**
  165. * @return {LocalStore}
  166. */
  167. delete ()
  168. {
  169. GM.deleteValue(this._key);
  170. return this
  171. }
  172.  
  173. /**
  174. * @return {*}
  175. */
  176. get ()
  177. {
  178. this._defaultsSet = false
  179. let storedStore = GM.getValue(this._key);
  180. return storedStore === null ? this.restoreDefaults() : Utilities.objectFromJSON(storedStore)
  181. }
  182.  
  183. /**
  184. * @param {storeEventHandler} handler
  185. * @return {LocalStore}
  186. */
  187. onChange (handler)
  188. {
  189. this._onChange = handler
  190. return this
  191. }
  192.  
  193. /**
  194. * @return {Object}
  195. */
  196. restoreDefaults ()
  197. {
  198. this._defaultsSet = true
  199. this.save(this._defaults)
  200. return this._defaults
  201. }
  202.  
  203. /**
  204. * @param {Object} data
  205. * @return {LocalStore}
  206. */
  207. save (data)
  208. {
  209. GM.setValue(this._key, Utilities.objectToJSON(data))
  210. this._handleOnChange()
  211. return this
  212. }
  213.  
  214. /**
  215. * @return {boolean}
  216. */
  217. wereDefaultsSet ()
  218. {
  219. return this._defaultsSet
  220. }
  221. }
  222.  
  223. class SelectorGenerator
  224. {
  225. /**
  226. * @param {string} selectorPrefix
  227. */
  228. constructor (selectorPrefix)
  229. {
  230. /**
  231. * @type {string}
  232. * @private
  233. */
  234. this._prefix = selectorPrefix
  235. }
  236.  
  237. /**
  238. * @param {string} selector
  239. * @return {string}
  240. */
  241. getSelector (selector)
  242. {
  243. return this._prefix + selector
  244. }
  245.  
  246. /**
  247. * @param {string} settingName
  248. * @return {string}
  249. */
  250. getSettingsInputSelector (settingName)
  251. {
  252. return this.getSelector(Utilities.toKebabCase(settingName) + '-setting')
  253. }
  254.  
  255. /**
  256. * @param {string} settingName
  257. * @param {boolean} getMinInputSelector
  258. * @return {string}
  259. */
  260. getSettingsRangeInputSelector (settingName, getMinInputSelector)
  261. {
  262. return this.getSelector(Utilities.toKebabCase(settingName) + (getMinInputSelector ? '-min' : '-max') + '-setting')
  263. }
  264.  
  265. /**
  266. * @param {string} statisticType
  267. * @return {string}
  268. */
  269. getStatLabelSelector (statisticType)
  270. {
  271. return this.getSelector(Utilities.toKebabCase(statisticType) + '-stat')
  272. }
  273. }
  274.  
  275. class StatisticsRecorder
  276. {
  277. /**
  278. * @param {string} selectorPrefix
  279. */
  280. constructor (selectorPrefix)
  281. {
  282. /**
  283. * @type {SelectorGenerator}
  284. * @private
  285. */
  286. this._selectorGenerator = new SelectorGenerator(selectorPrefix)
  287.  
  288. /**
  289. * @type {{Total: number}}
  290. * @private
  291. */
  292. this._statistics = {Total: 0}
  293. }
  294.  
  295. /**
  296. * @param {string} statisticType
  297. * @param {boolean} validationResult
  298. * @param {number} value
  299. */
  300. record (statisticType, validationResult, value = 1)
  301. {
  302. if (!validationResult) {
  303. if (typeof this._statistics[statisticType] !== 'undefined') {
  304. this._statistics[statisticType] += value
  305. } else {
  306. this._statistics[statisticType] = value
  307. }
  308. this._statistics.Total += value
  309. }
  310. }
  311.  
  312. reset ()
  313. {
  314. for (const statisticType in this._statistics) {
  315. this._statistics[statisticType] = 0
  316. }
  317. }
  318.  
  319. updateUI ()
  320. {
  321. let label, labelSelector
  322.  
  323. for (const statisticType in this._statistics) {
  324. labelSelector = this._selectorGenerator.getStatLabelSelector(statisticType)
  325. label = document.getElementById(labelSelector)
  326. if (label !== null) {
  327. label.textContent = this._statistics[statisticType]
  328. }
  329. }
  330. }
  331. }
  332.  
  333. class Utilities
  334. {
  335. /**
  336. * @param {string[]} words
  337. * @return {RegExp|null}
  338. */
  339. static buildWholeWordMatchingRegex (words)
  340. {
  341. if (words.length) {
  342. let patternedWords = []
  343. for (let i = 0; i < words.length; i++) {
  344. patternedWords.push('\\b' + words[i] + '\\b')
  345. }
  346. return new RegExp('(' + patternedWords.join('|') + ')', 'gi')
  347. }
  348. return null
  349. }
  350.  
  351. static callEventHandler (handler, parameters = [], defaultValue = null)
  352. {
  353. return handler ? handler(...parameters) : defaultValue
  354. }
  355.  
  356. static callEventHandlerOrFail (name, handler, parameters = [])
  357. {
  358. if (handler) {
  359. return handler(...parameters)
  360. }
  361. throw new Error('Callback "' + name + '" must be defined.')
  362. }
  363.  
  364. /**
  365. * @return {number|string}
  366. */
  367. static generateId (prefix = null)
  368. {
  369. let id = Math.trunc(Math.random() * 1000000000)
  370. return prefix ? prefix + id.toString() : id
  371. }
  372.  
  373. /**
  374. * @param {string} json
  375. * @return {Object}
  376. */
  377. static objectFromJSON (json)
  378. {
  379. /** @type {{arrays: Object, objects: Object, properties: Object}} */
  380. let parsedJSON = JSON.parse(json)
  381. let arrayObject = {}
  382. let result = {}
  383.  
  384. for (let property in parsedJSON.arrays) {
  385. arrayObject = JSON.parse(parsedJSON.arrays[property])
  386. result[property] = []
  387.  
  388. for (let key in arrayObject) {
  389. result[property].push(arrayObject[key])
  390. }
  391. }
  392. for (let property in parsedJSON.objects) {
  393. result[property] = Utilities.objectFromJSON(parsedJSON.objects[property])
  394. }
  395. for (let property in parsedJSON.properties) {
  396. result[property] = parsedJSON.properties[property]
  397. }
  398. return result
  399. }
  400.  
  401. /**
  402. * @param {Object} object
  403. * @return {string}
  404. */
  405. static objectToJSON (object)
  406. {
  407. let arrayToObject
  408. let json = {arrays: {}, objects: {}, properties: {}}
  409. for (let property in object) {
  410. if (typeof object[property] === 'object') {
  411. if (Array.isArray(object[property])) {
  412. arrayToObject = {}
  413. for (let key in object[property]) {
  414. arrayToObject[key] = object[property][key]
  415. }
  416. json.arrays[property] = JSON.stringify(arrayToObject)
  417. } else {
  418. json.objects[property] = Utilities.objectToJSON(object[property])
  419. }
  420. } else {
  421. json.properties[property] = object[property]
  422. }
  423. }
  424. return JSON.stringify(json)
  425. }
  426.  
  427. /**
  428. * @param milliseconds
  429. * @return {Promise<*>}
  430. */
  431. static sleep (milliseconds)
  432. {
  433. return new Promise(resolve => setTimeout(resolve, milliseconds))
  434. }
  435.  
  436. /**
  437. * @param {string} text
  438. * @return {string}
  439. */
  440. static toKebabCase (text)
  441. {
  442. return text.toLowerCase().replaceAll(' ', '-')
  443. }
  444.  
  445. /**
  446. * @param {string[]} strings
  447. */
  448. static trimAndKeepNonEmptyStrings (strings)
  449. {
  450. let nonEmptyStrings = []
  451. for (let string of strings) {
  452. string = string.trim()
  453. if (string !== '') {
  454. nonEmptyStrings.push(string)
  455. }
  456. }
  457. return nonEmptyStrings
  458. }
  459. }
  460.  
  461. class Validator
  462. {
  463. /**
  464. * @param {JQuery} item
  465. * @param {string} selector
  466. * @return {boolean}
  467. */
  468. static doesChildExist (item, selector)
  469. {
  470. return item.find(selector).length > 0
  471. }
  472.  
  473. static iFramesRemover ()
  474. {
  475. GM_addStyle('iframe { display: none !important; }')
  476. }
  477.  
  478. /**
  479. * @param {JQuery} item
  480. * @param {string} selector
  481. * @return {boolean}
  482. */
  483. static isChildMissing (item, selector)
  484. {
  485. return item.find(selector).length === 0
  486. }
  487.  
  488. /**
  489. * @param {number} value
  490. * @param {number} lowerBound
  491. * @param {number} upperBound
  492. * @return {boolean}
  493. */
  494. static isInRange (value, lowerBound, upperBound)
  495. {
  496. let validationCheck = true
  497.  
  498. if (lowerBound > 0 && upperBound > 0) {
  499. validationCheck = value >= lowerBound && value <= upperBound
  500. } else {
  501. if (lowerBound > 0) {
  502. validationCheck = value >= lowerBound
  503. }
  504. if (upperBound > 0) {
  505. validationCheck = value <= upperBound
  506. }
  507. }
  508. return validationCheck
  509. }
  510.  
  511. /**
  512. * @param {string} text
  513. * @param {Object} rules
  514. * @return {string}
  515. */
  516. static sanitize (text, rules)
  517. {
  518. if (rules) {
  519. for (const substitute in rules) {
  520. text = text.replace(rules[substitute], substitute)
  521. }
  522. }
  523. return text.trim()
  524. }
  525.  
  526. /**
  527. * @param {JQuery} textNode
  528. * @param {Object} rules
  529. * @return {Validator}
  530. */
  531. static sanitizeTextNode (textNode, rules)
  532. {
  533. textNode.text(Validator.sanitize(textNode.text(), rules))
  534. return this
  535. }
  536.  
  537. /**
  538. * @param {string} selector
  539. * @param {Object} rules
  540. * @return {Validator}
  541. */
  542. static sanitizeNodeOfSelector (selector, rules)
  543. {
  544. let node = $(selector)
  545. if (node.length) {
  546. let sanitizedText = Validator.sanitize(node.text(), rules)
  547. node.text(sanitizedText)
  548. document.title = sanitizedText
  549. }
  550. return this
  551. }
  552.  
  553. /**
  554. * @param {string} text
  555. * @param {Object} rules
  556. * @return {boolean}
  557. */
  558. static regexMatches (text, rules)
  559. {
  560. return rules ? text.match(rules) !== null : true
  561. }
  562.  
  563. /**
  564. * @param {string} text
  565. * @param {Object} rules
  566. * @return {boolean}
  567. */
  568. static validateTextDoesNotContain (text, rules)
  569. {
  570. return rules ? text.match(rules) === null : true
  571. }
  572. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址