mirror of
https://github.com/gorhill/uBlock.git
synced 2024-09-04 18:19:38 +02:00
[mv3] Add support for highly generic cosmetic filters
Related issue: - https://github.com/uBlockOrigin/uBOL-issues/issues/54
This commit is contained in:
parent
1809a9b32c
commit
872eafa378
@ -79,7 +79,12 @@ const arrayEq = (a = [], b = [], sort = true) => {
|
|||||||
|
|
||||||
const normalizeRegisteredContentScripts = registered => {
|
const normalizeRegisteredContentScripts = registered => {
|
||||||
for ( const entry of registered ) {
|
for ( const entry of registered ) {
|
||||||
const { js } = entry;
|
const { css = [], js = [] } = entry;
|
||||||
|
for ( let i = 0; i < css.length; i++ ) {
|
||||||
|
const path = css[i];
|
||||||
|
if ( path.startsWith('/') ) { continue; }
|
||||||
|
css[i] = `/${path}`;
|
||||||
|
}
|
||||||
for ( let i = 0; i < js.length; i++ ) {
|
for ( let i = 0; i < js.length; i++ ) {
|
||||||
const path = js[i];
|
const path = js[i];
|
||||||
if ( path.startsWith('/') ) { continue; }
|
if ( path.startsWith('/') ) { continue; }
|
||||||
@ -91,6 +96,78 @@ const normalizeRegisteredContentScripts = registered => {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
function registerHighGeneric(context, genericDetails) {
|
||||||
|
const { before, filteringModeDetails, rulesetsDetails } = context;
|
||||||
|
|
||||||
|
const excludeHostnames = [];
|
||||||
|
const css = [];
|
||||||
|
for ( const details of rulesetsDetails ) {
|
||||||
|
const hostnames = genericDetails.get(details.id);
|
||||||
|
if ( hostnames !== undefined ) {
|
||||||
|
excludeHostnames.push(...hostnames);
|
||||||
|
}
|
||||||
|
const count = details.css?.generichigh || 0;
|
||||||
|
if ( count === 0 ) { continue; }
|
||||||
|
css.push(`/rulesets/scripting/generichigh/${details.id}.css`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( css.length === 0 ) { return; }
|
||||||
|
|
||||||
|
const { none, basic, optimal, complete } = filteringModeDetails;
|
||||||
|
const matches = [];
|
||||||
|
const excludeMatches = [];
|
||||||
|
if ( complete.has('all-urls') ) {
|
||||||
|
excludeMatches.push(...ut.matchesFromHostnames(none));
|
||||||
|
excludeMatches.push(...ut.matchesFromHostnames(basic));
|
||||||
|
excludeMatches.push(...ut.matchesFromHostnames(optimal));
|
||||||
|
excludeMatches.push(...ut.matchesFromHostnames(excludeHostnames));
|
||||||
|
matches.push('<all_urls>');
|
||||||
|
} else {
|
||||||
|
matches.push(
|
||||||
|
...ut.matchesFromHostnames(
|
||||||
|
ut.subtractHostnameIters(
|
||||||
|
Array.from(complete),
|
||||||
|
excludeHostnames
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( matches.length === 0 ) { return; }
|
||||||
|
|
||||||
|
const registered = before.get('css-generichigh');
|
||||||
|
before.delete('css-generichigh'); // Important!
|
||||||
|
|
||||||
|
// https://github.com/w3c/webextensions/issues/414#issuecomment-1623992885
|
||||||
|
// Once supported, add:
|
||||||
|
// cssOrigin: 'USER',
|
||||||
|
const directive = {
|
||||||
|
id: 'css-generichigh',
|
||||||
|
css,
|
||||||
|
matches,
|
||||||
|
excludeMatches,
|
||||||
|
runAt: 'document_end',
|
||||||
|
};
|
||||||
|
|
||||||
|
// register
|
||||||
|
if ( registered === undefined ) {
|
||||||
|
context.toAdd.push(directive);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update
|
||||||
|
if (
|
||||||
|
arrayEq(registered.css, css, false) === false ||
|
||||||
|
arrayEq(registered.matches, matches) === false ||
|
||||||
|
arrayEq(registered.excludeMatches, excludeMatches) === false
|
||||||
|
) {
|
||||||
|
context.toRemove.push('css-generichigh');
|
||||||
|
context.toAdd.push(directive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
function registerGeneric(context, genericDetails) {
|
function registerGeneric(context, genericDetails) {
|
||||||
const { before, filteringModeDetails, rulesetsDetails } = context;
|
const { before, filteringModeDetails, rulesetsDetails } = context;
|
||||||
|
|
||||||
@ -459,6 +536,7 @@ async function registerInjectables(origins) {
|
|||||||
registerScriptlet(context, scriptletDetails);
|
registerScriptlet(context, scriptletDetails);
|
||||||
registerSpecific(context);
|
registerSpecific(context);
|
||||||
registerGeneric(context, genericDetails);
|
registerGeneric(context, genericDetails);
|
||||||
|
registerHighGeneric(context, genericDetails);
|
||||||
|
|
||||||
toRemove.push(...Array.from(before.keys()));
|
toRemove.push(...Array.from(before.keys()));
|
||||||
|
|
||||||
|
@ -382,7 +382,8 @@ function loadAllSourceScriptlets() {
|
|||||||
const originalScriptletMap = new Map();
|
const originalScriptletMap = new Map();
|
||||||
for ( const details of results ) {
|
for ( const details of results ) {
|
||||||
originalScriptletMap.set(
|
originalScriptletMap.set(
|
||||||
details.file.replace('.template.js', ''),
|
details.file.replace('.template.js', '')
|
||||||
|
.replace('.template.css', ''),
|
||||||
details.text
|
details.text
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -395,7 +396,7 @@ function loadAllSourceScriptlets() {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
async function processGenericCosmeticFilters(assetDetails, bucketsMap, exclusions) {
|
async function processGenericCosmeticFilters(assetDetails, bucketsMap) {
|
||||||
if ( bucketsMap === undefined ) { return 0; }
|
if ( bucketsMap === undefined ) { return 0; }
|
||||||
if ( bucketsMap.size === 0 ) { return 0; }
|
if ( bucketsMap.size === 0 ) { return 0; }
|
||||||
const bucketsList = Array.from(bucketsMap);
|
const bucketsList = Array.from(bucketsMap);
|
||||||
@ -419,8 +420,6 @@ async function processGenericCosmeticFilters(assetDetails, bucketsMap, exclusion
|
|||||||
patchedScriptlet
|
patchedScriptlet
|
||||||
);
|
);
|
||||||
|
|
||||||
genericDetails.set(assetDetails.id, exclusions.sort());
|
|
||||||
|
|
||||||
log(`CSS-generic: ${count} plain CSS selectors`);
|
log(`CSS-generic: ${count} plain CSS selectors`);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
@ -428,6 +427,33 @@ async function processGenericCosmeticFilters(assetDetails, bucketsMap, exclusion
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
async function processGenericHighCosmeticFilters(assetDetails, selectorSet) {
|
||||||
|
if ( selectorSet === undefined ) { return 0; }
|
||||||
|
if ( selectorSet.size === 0 ) { return 0; }
|
||||||
|
const selectorLists = Array.from(selectorSet).sort().join(',\n');
|
||||||
|
const originalScriptletMap = await loadAllSourceScriptlets();
|
||||||
|
|
||||||
|
let patchedScriptlet = originalScriptletMap.get('css-generichigh').replace(
|
||||||
|
'$rulesetId$',
|
||||||
|
assetDetails.id
|
||||||
|
);
|
||||||
|
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||||
|
/\$selectorList\$/,
|
||||||
|
selectorLists
|
||||||
|
);
|
||||||
|
|
||||||
|
writeFile(
|
||||||
|
`${scriptletDir}/generichigh/${assetDetails.id}.css`,
|
||||||
|
patchedScriptlet
|
||||||
|
);
|
||||||
|
|
||||||
|
log(`CSS-generic-high: ${selectorSet.size} plain CSS selectors`);
|
||||||
|
|
||||||
|
return selectorSet.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
// This merges selectors which are used by the same hostnames
|
// This merges selectors which are used by the same hostnames
|
||||||
|
|
||||||
function groupSelectorsByHostnames(mapin) {
|
function groupSelectorsByHostnames(mapin) {
|
||||||
@ -887,10 +913,23 @@ async function rulesetFromURLs(assetDetails) {
|
|||||||
log(rejectedCosmetic.map(line => `\t${line}`).join('\n'), true);
|
log(rejectedCosmetic.map(line => `\t${line}`).join('\n'), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
Array.isArray(results.network.generichideExclusions) &&
|
||||||
|
results.network.generichideExclusions.length !== 0
|
||||||
|
) {
|
||||||
|
genericDetails.set(
|
||||||
|
assetDetails.id,
|
||||||
|
results.network.generichideExclusions.filter(hn => hn.endsWith('.*') === false).sort()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const genericCosmeticStats = await processGenericCosmeticFilters(
|
const genericCosmeticStats = await processGenericCosmeticFilters(
|
||||||
assetDetails,
|
assetDetails,
|
||||||
results.genericCosmetic,
|
results.genericCosmetic
|
||||||
results.network.generichideExclusions.filter(hn => hn.endsWith('.*') === false)
|
);
|
||||||
|
const genericHighCosmeticStats = await processGenericHighCosmeticFilters(
|
||||||
|
assetDetails,
|
||||||
|
results.genericHighCosmetic
|
||||||
);
|
);
|
||||||
const specificCosmeticStats = await processCosmeticFilters(
|
const specificCosmeticStats = await processCosmeticFilters(
|
||||||
assetDetails,
|
assetDetails,
|
||||||
@ -933,6 +972,7 @@ async function rulesetFromURLs(assetDetails) {
|
|||||||
},
|
},
|
||||||
css: {
|
css: {
|
||||||
generic: genericCosmeticStats,
|
generic: genericCosmeticStats,
|
||||||
|
generichigh: genericHighCosmeticStats,
|
||||||
specific: specificCosmeticStats,
|
specific: specificCosmeticStats,
|
||||||
declarative: declarativeStats,
|
declarative: declarativeStats,
|
||||||
procedural: proceduralStats,
|
procedural: proceduralStats,
|
||||||
|
@ -147,17 +147,23 @@ function addExtendedToDNR(context, parser) {
|
|||||||
|
|
||||||
// Generic cosmetic filtering
|
// Generic cosmetic filtering
|
||||||
if ( parser.hasOptions() === false ) {
|
if ( parser.hasOptions() === false ) {
|
||||||
if ( context.genericCosmeticFilters === undefined ) {
|
|
||||||
context.genericCosmeticFilters = new Map();
|
|
||||||
}
|
|
||||||
const { compiled } = parser.result;
|
const { compiled } = parser.result;
|
||||||
if ( compiled === undefined ) { return; }
|
if ( compiled === undefined ) { return; }
|
||||||
if ( compiled.length <= 1 ) { return; }
|
if ( compiled.length <= 1 ) { return; }
|
||||||
if ( compiled.charCodeAt(0) === 0x7B /* '{' */ ) { return; }
|
if ( compiled.charCodeAt(0) === 0x7B /* '{' */ ) { return; }
|
||||||
const key = keyFromSelector(compiled);
|
const key = keyFromSelector(compiled);
|
||||||
if ( key === undefined ) { return; }
|
if ( key === undefined ) {
|
||||||
|
if ( context.genericHighCosmeticFilters === undefined ) {
|
||||||
|
context.genericHighCosmeticFilters = new Set();
|
||||||
|
}
|
||||||
|
context.genericHighCosmeticFilters.add(compiled);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const type = key.charCodeAt(0);
|
const type = key.charCodeAt(0);
|
||||||
const hash = hashFromStr(type, key.slice(1));
|
const hash = hashFromStr(type, key.slice(1));
|
||||||
|
if ( context.genericCosmeticFilters === undefined ) {
|
||||||
|
context.genericCosmeticFilters = new Map();
|
||||||
|
}
|
||||||
let bucket = context.genericCosmeticFilters.get(hash);
|
let bucket = context.genericCosmeticFilters.get(hash);
|
||||||
if ( bucket === undefined ) {
|
if ( bucket === undefined ) {
|
||||||
context.genericCosmeticFilters.set(hash, bucket = []);
|
context.genericCosmeticFilters.set(hash, bucket = []);
|
||||||
@ -291,6 +297,7 @@ async function dnrRulesetFromRawLists(lists, options = {}) {
|
|||||||
return {
|
return {
|
||||||
network: staticNetFilteringEngine.dnrFromCompiled('end', context),
|
network: staticNetFilteringEngine.dnrFromCompiled('end', context),
|
||||||
genericCosmetic: context.genericCosmeticFilters,
|
genericCosmetic: context.genericCosmeticFilters,
|
||||||
|
genericHighCosmetic: context.genericHighCosmeticFilters,
|
||||||
specificCosmetic: context.specificCosmeticFilters,
|
specificCosmetic: context.specificCosmeticFilters,
|
||||||
scriptlet: context.scriptletFilters,
|
scriptlet: context.scriptletFilters,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user