Skip to content

Commit 3f456aa

Browse files
authored
🔀 Merge pull request #317 from richardfrost/stats
Filtering Statistics
2 parents d23cb5f + 3f3b3c8 commit 3f456aa

File tree

13 files changed

+351
-67
lines changed

13 files changed

+351
-67
lines changed

src/script/bookmarkletFilter.ts

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,31 +30,32 @@ export default class BookmarkletFilter extends Filter {
3030
mutePage: boolean;
3131
observer: MutationObserver;
3232
processMutationTarget: boolean;
33-
processNode: (node: HTMLElement | Document | ShadowRoot, wordlistId: number, stats?: boolean) => void;
33+
processNode: (node: HTMLElement | Document | ShadowRoot, wordlistId: number, statsType?: string | null) => void;
3434
shadowObserver: MutationObserver;
35+
stats?: Statistics; // Bookmarklet: Not used
3536

3637
constructor() {
3738
super();
3839
this.extension = false;
39-
this.audioWordlistId = 0;
40+
this.audioWordlistId = Constants.ALL_WORDS_WORDLIST_ID;
4041
this.mutePage = false;
4142
this.processMutationTarget = false;
4243
}
4344

44-
advancedReplaceText(node, wordlistId: number, stats = true) {
45+
advancedReplaceText(node, wordlistId: number, statsType: string | null = Constants.STATS_TYPE_TEXT) {
4546
if (node.parentNode || node === document) {
4647
this.wordlists[wordlistId].regExps.forEach((regExp) => {
4748
// @ts-ignore: External library function
4849
findAndReplaceDOMText(node, { preset: 'prose', find: regExp, replace: (portion, match) => {
4950
if (portion.index === 0) {
50-
return this.replaceText(match[0], wordlistId, stats);
51+
return this.replaceText(match[0], wordlistId, statsType);
5152
} else {
5253
return '';
5354
}
5455
} });
5556
});
5657
} else {
57-
this.cleanText(node, wordlistId, stats);
58+
this.cleanText(node, wordlistId, statsType);
5859
}
5960
}
6061

@@ -150,31 +151,31 @@ export default class BookmarkletFilter extends Filter {
150151
}
151152
}
152153

153-
cleanChildNode(node, wordlistId: number, stats: boolean = true) {
154+
cleanChildNode(node, wordlistId: number, statsType: string | null = Constants.STATS_TYPE_TEXT) {
154155
if (node.nodeName) {
155156
if (node.textContent && node.textContent.trim() != '') {
156-
const result = this.replaceTextResult(node.textContent, wordlistId, stats);
157+
const result = this.replaceTextResult(node.textContent, wordlistId, statsType);
157158
if (result.modified) {
158159
node.textContent = result.filtered;
159160
}
160161
} else if (node.nodeName == 'IMG') {
161-
if (node.alt != '') { node.alt = this.replaceText(node.alt, wordlistId, stats); }
162-
if (node.title != '') { node.title = this.replaceText(node.title, wordlistId, stats); }
162+
if (node.alt != '') { node.alt = this.replaceText(node.alt, wordlistId, statsType); }
163+
if (node.title != '') { node.title = this.replaceText(node.title, wordlistId, statsType); }
163164
} else if (node.shadowRoot) {
164-
this.filterShadowRoot(node.shadowRoot, wordlistId, stats);
165+
this.filterShadowRoot(node.shadowRoot, wordlistId, statsType);
165166
}
166167
}
167168
}
168169

169-
cleanNode(node, wordlistId: number, stats: boolean = true) {
170+
cleanNode(node, wordlistId: number, statsType: string | null = Constants.STATS_TYPE_TEXT) {
170171
if (Page.isForbiddenNode(node)) { return false; }
171-
if (node.shadowRoot) { this.filterShadowRoot(node.shadowRoot, wordlistId, stats); }
172+
if (node.shadowRoot) { this.filterShadowRoot(node.shadowRoot, wordlistId, statsType); }
172173
if (node.childNodes.length > 0) {
173174
for (let i = 0; i < node.childNodes.length ; i++) {
174-
this.cleanNode(node.childNodes[i], wordlistId, stats);
175+
this.cleanNode(node.childNodes[i], wordlistId, statsType);
175176
}
176177
} else {
177-
this.cleanChildNode(node, this.wordlistId, stats);
178+
this.cleanChildNode(node, this.wordlistId, statsType);
178179
}
179180
}
180181

@@ -209,30 +210,30 @@ export default class BookmarkletFilter extends Filter {
209210
this.startObserving(document);
210211
}
211212

212-
cleanText(node, wordlistId: number, stats: boolean = true) {
213+
cleanText(node, wordlistId: number, statsType: string | null = Constants.STATS_TYPE_TEXT) {
213214
if (Page.isForbiddenNode(node)) { return false; }
214-
if (node.shadowRoot) { this.filterShadowRoot(node.shadowRoot, wordlistId, stats); }
215+
if (node.shadowRoot) { this.filterShadowRoot(node.shadowRoot, wordlistId, statsType); }
215216
if (node.childElementCount > 0) {
216217
const treeWalker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT);
217218
while(treeWalker.nextNode()) {
218219
if (treeWalker.currentNode.childNodes.length > 0) {
219220
treeWalker.currentNode.childNodes.forEach((childNode) => {
220-
this.cleanText(childNode, wordlistId, stats);
221+
this.cleanText(childNode, wordlistId, statsType);
221222
});
222223
} else {
223224
if (!Page.isForbiddenNode(treeWalker.currentNode)) {
224-
this.cleanChildNode(treeWalker.currentNode, wordlistId, stats);
225+
this.cleanChildNode(treeWalker.currentNode, wordlistId, statsType);
225226
}
226227
}
227228
}
228229
} else {
229-
this.cleanChildNode(node, wordlistId, stats);
230+
this.cleanChildNode(node, wordlistId, statsType);
230231
}
231232
}
232233

233-
filterShadowRoot(shadowRoot: ShadowRoot, wordlistId: number, stats: boolean = true) {
234+
filterShadowRoot(shadowRoot: ShadowRoot, wordlistId: number, statsType: string | null = Constants.STATS_TYPE_TEXT) {
234235
this.shadowObserver.observe(shadowRoot, observerConfig);
235-
this.processNode(shadowRoot, wordlistId, stats);
236+
this.processNode(shadowRoot, wordlistId, statsType);
236237
}
237238

238239
init(wordlistId: number | false = false) {

src/script/lib/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ import { upperCaseFirst } from './helper';
33

44
export default class Constants {
55
// Named Constants
6+
static readonly ALL_WORDS_WORDLIST_ID = 0;
67
static readonly DOMAIN_MODES = { NORMAL: 0, ADVANCED: 1, DEEP: 2 };
78
static readonly FILTER_METHODS = { CENSOR: 0, SUBSTITUTE: 1, REMOVE: 2 };
89
static readonly MATCH_METHODS = { EXACT: 0, PARTIAL: 1, WHOLE: 2, REGEX: 3 };
910
static readonly MUTE_METHODS = { TAB: 0, VIDEO: 1, NONE: 2 };
1011
static readonly SHOW_SUBTITLES = { ALL: 0, FILTERED: 1, UNFILTERED: 2, NONE: 3 };
12+
static readonly STATS_TYPE_AUDIO = 'audio';
13+
static readonly STATS_TYPE_TEXT = 'text';
1114

1215
// Helper Functions
1316
static filterMethodName(id: number) { return this.nameById(this.FILTER_METHODS, id); }

src/script/lib/filter.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,14 @@ export default class Filter {
6969
return false;
7070
}
7171

72-
foundMatch(word?: Word) {
72+
foundMatch(word?: Word, statsType?: string) {
7373
this.counter++;
7474
}
7575

7676
init(wordlistId: number | false = false) {
7777
this.iWhitelist = this.cfg.iWordWhitelist;
7878
this.whitelist = this.cfg.wordWhitelist;
79-
if (this.wordlistId === undefined) { this.wordlistId = this.cfg.wordlistId == null ? 0 : this.cfg.wordlistId; }
79+
if (this.wordlistId === undefined) { this.wordlistId = this.cfg.wordlistId == null ? Constants.ALL_WORDS_WORDLIST_ID : this.cfg.wordlistId; }
8080
this.buildWordlist(wordlistId);
8181
}
8282

@@ -102,7 +102,7 @@ export default class Filter {
102102
});
103103
}
104104

105-
replaceText(str: string, wordlistId: number | false = false, stats: boolean = true): string {
105+
replaceText(str: string, wordlistId: number | false = false, statsType: string | null = Constants.STATS_TYPE_TEXT): string {
106106
wordlistId = this.buildWordlist(wordlistId);
107107
const wordlist = this.wordlists[wordlistId];
108108

@@ -112,7 +112,7 @@ export default class Filter {
112112
str = str.replace(regExp, (originalMatch, ...args): string => {
113113
const { word, string, match, matchStartIndex, captureGroups, internalCaptureGroups } = this.matchData(wordlist, index, originalMatch, args);
114114
if (this.checkWhitelist(match, string, matchStartIndex, word)) { return match; } // Check for whitelisted match
115-
if (stats) { this.foundMatch(word); }
115+
if (statsType) { this.foundMatch(word, statsType); }
116116

117117
// Filter
118118
let censoredString = '';
@@ -138,7 +138,7 @@ export default class Filter {
138138
str = str.replace(regExp, (originalMatch, ...args): string => {
139139
const { word, string, match, matchStartIndex, captureGroups, internalCaptureGroups } = this.matchData(wordlist, index, originalMatch, args);
140140
if (this.checkWhitelist(match, string, matchStartIndex, word)) { return match; } // Check for whitelisted match
141-
if (stats) { this.foundMatch(word); }
141+
if (statsType) { this.foundMatch(word, statsType); }
142142

143143
// Filter
144144
let sub = word.sub || this.cfg.defaultSubstitution;
@@ -166,7 +166,7 @@ export default class Filter {
166166
str = str.replace(regExp, (originalMatch, ...args): string => {
167167
const { word, string, match, matchStartIndex, captureGroups, internalCaptureGroups } = this.matchData(wordlist, index, originalMatch, args);
168168
if (this.checkWhitelist(match.trim(), string, matchStartIndex, word)) { return match; } // Check for whitelisted match
169-
if (stats) { this.foundMatch(word); }
169+
if (statsType) { this.foundMatch(word, statsType); }
170170

171171
// Filter
172172
if (internalCaptureGroups) {
@@ -193,10 +193,10 @@ export default class Filter {
193193
return str;
194194
}
195195

196-
replaceTextResult(str: string, wordlistId: (number | false) = false, stats: boolean = true): ReplaceTextResult {
196+
replaceTextResult(str: string, wordlistId: (number | false) = false, statsType: string | null = Constants.STATS_TYPE_TEXT): ReplaceTextResult {
197197
const result: ReplaceTextResult = {
198198
original: str,
199-
filtered: this.replaceText(str, wordlistId, stats),
199+
filtered: this.replaceText(str, wordlistId, statsType),
200200
modified: false
201201
};
202202
result.modified = (result.filtered != str);

src/script/lib/globals.d.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ interface ReplaceTextResult {
112112
modified: boolean;
113113
}
114114

115+
interface Statistics {
116+
mutes: number;
117+
startedAt?: number;
118+
words: WordStatistics;
119+
}
120+
115121
interface Summary {
116122
[word: string]: {
117123
filtered: string;
@@ -146,3 +152,13 @@ interface WordOptions {
146152
separators?: boolean;
147153
sub: string;
148154
}
155+
156+
interface WordStatistic {
157+
audio: number;
158+
text: number;
159+
total?: number;
160+
}
161+
162+
interface WordStatistics {
163+
[word: string]: WordStatistic;
164+
}

src/script/lib/helper.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ export function makeRequest(method: string, url: string) {
113113
});
114114
}
115115

116+
export function numberWithCommas(number: number | string): string {
117+
return number.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ',');
118+
}
119+
116120
export function readFile(file) {
117121
return new Promise((resolve, reject) => {
118122
const fr = new FileReader();

src/script/lib/wordlist.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Constants from './constants';
12
import Word from './word';
23
import Config from './config';
34
import Logger from './logger';
@@ -20,8 +21,7 @@ export default class Wordlist {
2021

2122
// Process list of words
2223
sorted.forEach((wordStr) => {
23-
// wordlistId = 0 includes all words
24-
if (wordlistId === 0 || !Array.isArray(cfg.words[wordStr].lists) || cfg.words[wordStr].lists.includes(wordlistId)) {
24+
if (wordlistId === Constants.ALL_WORDS_WORDLIST_ID || !Array.isArray(cfg.words[wordStr].lists) || cfg.words[wordStr].lists.includes(wordlistId)) {
2525
try {
2626
const word = new Word(wordStr, cfg.words[wordStr], cfg);
2727
this.list.push(wordStr);

0 commit comments

Comments
 (0)