Skip to content

Commit 2eebc75

Browse files
committed
[mv3] Merge content scripts related to specific and procedural cosmetic filters
There is now no benefit splitting them in two sets of content scripts.
1 parent 9e5299e commit 2eebc75

6 files changed

Lines changed: 170 additions & 279 deletions

File tree

platform/mv3/extension/js/scripting-manager.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -169,17 +169,19 @@ function registerGeneric(context, genericDetails) {
169169

170170
/******************************************************************************/
171171

172-
async function registerCosmetic(realm, context) {
172+
async function registerCosmetic(context) {
173173
const { filteringModeDetails, rulesetsDetails } = context;
174174

175175
{
176176
const keys = await localKeys();
177-
localRemove(keys.filter(a => a.startsWith(`css.${realm}.`)));
177+
localRemove(keys.filter(a => a.startsWith('css.specific.')));
178+
// TODO: remove after a few versions after 2026.516.1652
179+
localRemove(keys.filter(a => a.startsWith('css.procedural.')));
178180
}
179181

180182
const rulesetIds = [];
181183
for ( const rulesetDetails of rulesetsDetails ) {
182-
const count = rulesetDetails.css?.[realm] || 0;
184+
const count = rulesetDetails.css?.specific ?? 0;
183185
if ( count === 0 ) { continue; }
184186
rulesetIds.push(rulesetDetails.id);
185187
}
@@ -196,8 +198,8 @@ async function registerCosmetic(realm, context) {
196198
const promises = [];
197199
for ( const id of rulesetIds ) {
198200
promises.push(
199-
fetchJSON(`/rulesets/scripting/${realm}/${id}`).then(data => {
200-
return localWrite(`css.${realm}.${id}`, data);
201+
fetchJSON(`/rulesets/scripting/specific/${id}`).then(data => {
202+
return localWrite(`css.specific.${id}`, data);
201203
})
202204
);
203205
}
@@ -206,13 +208,12 @@ async function registerCosmetic(realm, context) {
206208

207209
normalizeMatches(matches);
208210

209-
const realmid = `css-${realm}`;
210-
const js = rulesetIds.map(id => `/rulesets/scripting/${realm}/${id}.js`);
211+
const js = rulesetIds.map(id => `/rulesets/scripting/specific/${id}.js`);
211212
js.unshift('/js/scripting/css-api.js', '/js/scripting/isolated-api.js');
212-
if ( realm === 'procedural' && webextFlavor === 'safari' ) {
213+
if ( webextFlavor === 'safari' ) {
213214
js.push('/js/scripting/css-procedural-api.js');
214215
}
215-
js.push(`/js/scripting/${realmid}.js`);
216+
js.push('/js/scripting/css-specific.js');
216217

217218
const excludeMatches = [];
218219
if ( none.has('all-urls') === false && basic.has('all-urls') === false ) {
@@ -226,7 +227,7 @@ async function registerCosmetic(realm, context) {
226227
}
227228

228229
const directive = {
229-
id: realmid,
230+
id: 'css-specific',
230231
js,
231232
matches,
232233
allFrames: true,
@@ -338,8 +339,7 @@ registerInjectables.register = async function register() {
338339

339340
await Promise.all([
340341
registerScriptlet(context, scriptletDetails),
341-
registerCosmetic('specific', context),
342-
registerCosmetic('procedural', context),
342+
registerCosmetic(context),
343343
registerGeneric(context, genericDetails),
344344
registerCustomFilters(context),
345345
registerCustomScriptlets(context),

platform/mv3/extension/js/scripting/css-procedural.js

Lines changed: 0 additions & 64 deletions
This file was deleted.

platform/mv3/extension/js/scripting/css-specific.js

Lines changed: 141 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,147 @@ self.specificImports = undefined;
3030

3131
/******************************************************************************/
3232

33-
const selectors = await self.cosmeticAPI.getSelectors('specific', specificImports);
34-
self.cosmeticAPI.release();
35-
if ( selectors.length === 0 ) { return; }
36-
self.cssAPI.insert(`${selectors.join(',\n')}{display:none!important;}`);
33+
const { isolatedAPI } = self;
34+
35+
const sessionRead = async function(key) {
36+
try {
37+
const bin = await chrome.storage.session.get(key);
38+
return bin?.[key] ?? undefined;
39+
} catch {
40+
}
41+
};
42+
43+
const sessionWrite = function(key, data) {
44+
try {
45+
chrome.storage.session.set({ [key]: data });
46+
} catch {
47+
}
48+
};
49+
50+
const localRead = async function(key) {
51+
try {
52+
const bin = await chrome.storage.local.get(key);
53+
return bin?.[key] ?? undefined;
54+
} catch {
55+
}
56+
};
57+
58+
const selectorsFromListIndex = (data, ilist) => {
59+
const list = JSON.parse(`[${data.selectorLists[ilist]}]`);
60+
const { result } = data;
61+
for ( const iselector of list ) {
62+
if ( iselector >= 0 ) {
63+
result.selectors.add(data.selectors[iselector]);
64+
} else {
65+
result.exceptions.add(data.selectors[~iselector]);
66+
}
67+
}
68+
};
69+
70+
const selectorsFromHostnames = (haystack, needles, data) => {
71+
let listref = -1;
72+
for ( const needle of needles ) {
73+
listref = isolatedAPI.binarySearch(haystack, needle, listref);
74+
if ( listref >= 0 ) {
75+
selectorsFromListIndex(data, data.selectorListRefs[listref]);
76+
} else {
77+
listref = ~listref;
78+
}
79+
}
80+
};
81+
82+
const selectorsFromRuleset = async (rulesetId, result) => {
83+
const data = await localRead(`css.specific.${rulesetId}`);
84+
if ( typeof data !== 'object' || data === null ) { return; }
85+
data.result = result;
86+
selectorsFromHostnames(data.hostnames, isolatedAPI.contexts.hostnames, data);
87+
if ( data.hasEntities ) {
88+
selectorsFromHostnames(data.hostnames, isolatedAPI.contexts.entities, data);
89+
}
90+
const { regexes } = data;
91+
for ( let i = 0, n = regexes.length; i < n; i += 3 ) {
92+
if ( thisHostname.includes(regexes[i+0]) === false ) { continue; }
93+
if ( typeof regexes[i+1] === 'string' ) {
94+
regexes[i+1] = new RegExp(regexes[i+1]);
95+
}
96+
if ( regexes[i+1].test(thisHostname) === false ) { continue; }
97+
selectorsFromListIndex(data, regexes[i+2]);
98+
}
99+
};
100+
101+
const fillCache = async function(rulesetIds) {
102+
const selectors = new Set();
103+
const exceptions = new Set();
104+
const result = { selectors, exceptions };
105+
const [ filteringModeDetails ] = await Promise.all([
106+
localRead('filteringModeDetails'),
107+
...rulesetIds.map(a => selectorsFromRuleset(a, result)),
108+
]);
109+
const skip = filteringModeDetails?.none.some(a => {
110+
if ( topHostname.endsWith(a) === false ) { return false; }
111+
const n = a.length;
112+
return topHostname.length === n || topHostname.at(-n-1) === '.';
113+
});
114+
for ( const selector of exceptions ) {
115+
selectors.delete(selector);
116+
}
117+
if ( skip ) {
118+
selectors.clear();
119+
}
120+
cacheEntry.s = [];
121+
cacheEntry.p = [];
122+
for ( const selector of selectors ) {
123+
if ( selector.startsWith('{') ) {
124+
cacheEntry.p.push(JSON.parse(selector));
125+
} else {
126+
cacheEntry.s.push(selector);
127+
}
128+
}
129+
return cacheEntry;
130+
};
131+
132+
const topHostname = isolatedAPI.contexts.topHostname;
133+
const thisHostname = document.location.hostname || '';
134+
const cachePath = topHostname !== thisHostname ? `${topHostname}/` : '';
135+
const cacheKey = `cache.css.${cachePath}${thisHostname}`;
136+
137+
let cacheEntry = await sessionRead(cacheKey) ?? { t: 0 };
138+
if ( cacheEntry.t === 0 ) {
139+
cacheEntry = await fillCache(specificImports);
140+
}
141+
const now = Math.round(Date.now() / 15000);
142+
const since = now - cacheEntry.t;
143+
if ( since > 1 ) {
144+
cacheEntry.t = now;
145+
sessionWrite(cacheKey, cacheEntry);
146+
}
147+
148+
const { s, p } = cacheEntry;
149+
150+
if ( s.length !== 0 ) {
151+
self.cssAPI.insert(`${s.join(',\n')}{display:none!important;}`);
152+
}
153+
154+
if ( p.length === 0 ) { return; }
155+
156+
if ( self.ProceduralFiltererAPI === undefined ) {
157+
self.ProceduralFiltererAPI = chrome.runtime.sendMessage({
158+
what: 'injectCSSProceduralAPI'
159+
}).catch(( ) => {
160+
});
161+
}
162+
163+
await self.ProceduralFiltererAPI;
164+
self.listsProceduralFiltererAPI = new self.ProceduralFiltererAPI();
165+
166+
const declaratives = p.filter(a => a.cssable);
167+
if ( declaratives.length !== 0 ) {
168+
self.listsProceduralFiltererAPI.addDeclaratives(declaratives);
169+
}
170+
const procedurals = p.filter(a => !a.cssable);
171+
if ( procedurals.length !== 0 ) {
172+
self.listsProceduralFiltererAPI.addProcedurals(procedurals);
173+
}
37174

38175
/******************************************************************************/
39176

0 commit comments

Comments
 (0)