data-manager

handles loaded html, takes care of data, applying filters

当前为 2024-08-19 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name data-manager
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.2.6
  5. // @license MIT
  6. // @description handles loaded html, takes care of data, applying filters
  7. // @author smartacephale
  8. // @match *://*/*
  9. // ==/UserScript==
  10. /* globals LazyImgLoader stringToWords GM_addStyle */
  11.  
  12. class DataManager {
  13. constructor(rules, state) {
  14. this.rules = rules;
  15. this.state = state;
  16. this.data = new Map();
  17. this.setupFilters();
  18. this.lazyImgLoader = LazyImgLoader.create((target) => !this.isFiltered(target));
  19. }
  20.  
  21. dataFilters = {
  22. filterPublic: {
  23. tag: 'filtered-public',
  24. createFilter() {
  25. return (v) => [this.tag, !this.rules.IS_PRIVATE(v.element) && this.state.filterPublic];
  26. }
  27. },
  28. filterPrivate: {
  29. tag: 'filtered-private',
  30. createFilter() {
  31. return (v) => [this.tag, this.rules.IS_PRIVATE(v.element) && this.state.filterPrivate];
  32. }
  33. },
  34. filterDuration: {
  35. tag: 'filtered-duration',
  36. createFilter() {
  37. return (v) => {
  38. const notInRange = v.duration < this.state.filterDurationFrom || v.duration > this.state.filterDurationTo;
  39. return [this.tag, this.state.filterDuration && notInRange];
  40. }
  41. }
  42. },
  43. filterExclude: {
  44. tag: 'filtered-exclude',
  45. createFilter() {
  46. const tags = this.filterDSLToRegex(this.state.filterExcludeWords);
  47. return (v) => {
  48. const containTags = tags.some(tag => tag.test(v.title));
  49. return [this.tag, this.state.filterExclude && containTags];
  50. }
  51. }
  52. },
  53. filterInclude: {
  54. tag: 'filtered-include',
  55. createFilter() {
  56. const tags = this.filterDSLToRegex(this.state.filterIncludeWords);
  57. return (v) => {
  58. const containTagsNot = tags.some(tag => !tag.test(v.title));
  59. return [this.tag, this.state.filterInclude && containTagsNot];
  60. }
  61. }
  62. }
  63. }
  64.  
  65. filterDSLToRegex(str) {
  66. const toFullWord = w => `(^|\ )${w}($|\ )`;
  67. const str_ = str.replace(/f\:(\w+)/g, (_, w) => toFullWord(w));
  68. return stringToWords(str_).map(expr => new RegExp(expr, 'i'));
  69. }
  70.  
  71. setupFilters() {
  72. Object.keys(this.dataFilters).forEach(k => {
  73. if (!Object.hasOwn(this.state, k)) {
  74. delete this.dataFilters[k];
  75. }
  76. });
  77.  
  78. const tags = Object.keys(this.dataFilters).map(k => `.${this.dataFilters[k].tag}`).join(',');
  79. GM_addStyle(`${tags} { display: none !important; }`);
  80.  
  81. Object.values(this.dataFilters).forEach(f => {
  82. f.state = this.state;
  83. f.rules = this.rules;
  84. f.filterDSLToRegex = this.filterDSLToRegex;
  85. });
  86. }
  87.  
  88. isFiltered(el) {
  89. return el.className.includes('filtered');
  90. }
  91.  
  92. filter_ = (filters, offset = 0) => {
  93. const filtersToApply = Object.keys(filters)
  94. .filter(k => Object.hasOwn(this.dataFilters, k))
  95. .map(k => this.dataFilters[k].createFilter());
  96.  
  97. if (filtersToApply.length === 0) return;
  98.  
  99. let offset_counter = 1;
  100. for (const v of this.data.values()) {
  101. if (++offset_counter > offset) {
  102. for (const f of filtersToApply) {
  103. const [tag, condition] = f(v);
  104. v.element.classList.toggle(tag, condition);
  105. }
  106. }
  107. }
  108. }
  109.  
  110. filterAll = (offset) => {
  111. const applyFilters = Object.assign({}, ...Object.keys(this.dataFilters).map(f => ({ [f]: this.state[f] })));
  112. this.filter_(applyFilters, offset);
  113. }
  114.  
  115. handleLoadedHTML = (html, container, removeDuplicates = false, shouldLazify = true) => {
  116. const thumbs = this.rules.GET_THUMBS(html);
  117. const data_offset = this.data.size;
  118.  
  119. for (const thumbElement of thumbs) {
  120. const url = this.rules.THUMB_URL(thumbElement);
  121. if (!url || this.data.has(url)) {
  122. if (removeDuplicates) thumbElement.remove();
  123. continue;
  124. }
  125.  
  126. const { title, duration } = this.rules.THUMB_DATA(thumbElement);
  127. this.data.set(url, { element: thumbElement, duration, title });
  128.  
  129. if (shouldLazify) {
  130. const { img, imgSrc } = this.rules.THUMB_IMG_DATA(thumbElement);
  131. this.lazyImgLoader.lazify(thumbElement, img, imgSrc);
  132. }
  133.  
  134. const parent = container || this.rules.CONTAINER;
  135. if (!parent.contains(thumbElement)) parent.appendChild(thumbElement);
  136. }
  137.  
  138. this.filterAll(data_offset);
  139. };
  140. }

QingJ © 2025

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