darkreader 4.9.82 → 4.9.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/darkreader.js +116 -35
- package/index.d.ts +1 -1
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ Please note that if you encounter error `Too many open files (os error 24)`, the
|
|
|
43
43
|
|
|
44
44
|
### Bundling with official Firefox store signatures (experimental)
|
|
45
45
|
|
|
46
|
-
Prior to publication, extension stores provide digital signatures for extensions. These digital signatures certify the integrity of the archive (that extension bundle did not get corrupted or bit-rotted) and that extension store
|
|
46
|
+
Prior to publication, extension stores provide digital signatures for extensions. These digital signatures certify the integrity of the archive (that extension bundle did not get corrupted or bit-rotted) and that extension store performed very basic extension validation.
|
|
47
47
|
|
|
48
48
|
Dark Reader repository contains these digital signatures and you can add them to the extension bundle. The following will build Dark Reader for Firefox version 4.9.63:
|
|
49
49
|
```
|
|
@@ -147,7 +147,7 @@ Step 1: change Dark Reader's settings.
|
|
|
147
147
|
- Click on the Dark Reader icon.
|
|
148
148
|
- Click on the `Dev tools` button (in the bottom-right corner).
|
|
149
149
|
- Click on the `Preview new design button`.
|
|
150
|
-
- Enable the `Enable on restricted pages` setting under `Settings` -> `
|
|
150
|
+
- Enable the `Enable on restricted pages` setting under `Settings` -> `Advanced`.
|
|
151
151
|
|
|
152
152
|
Step 2: change Firefox's settings.
|
|
153
153
|
|
package/darkreader.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Dark Reader v4.9.
|
|
2
|
+
* Dark Reader v4.9.84
|
|
3
3
|
* https://darkreader.org/
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -127,6 +127,7 @@
|
|
|
127
127
|
const isMatchMediaChangeEventListenerSupported =
|
|
128
128
|
typeof MediaQueryList === "function" &&
|
|
129
129
|
typeof MediaQueryList.prototype.addEventListener === "function";
|
|
130
|
+
const isLayerRuleSupported = typeof CSSLayerBlockRule === "function";
|
|
130
131
|
(() => {
|
|
131
132
|
const m = userAgent.match(/chrom(?:e|ium)(?:\/| )([^ ]+)/);
|
|
132
133
|
if (m && m[1]) {
|
|
@@ -212,6 +213,10 @@
|
|
|
212
213
|
});
|
|
213
214
|
return dataURL;
|
|
214
215
|
}
|
|
216
|
+
async function loadAsText(url, mimeType, origin) {
|
|
217
|
+
const response = await getOKResponse(url, mimeType, origin);
|
|
218
|
+
return await response.text();
|
|
219
|
+
}
|
|
215
220
|
|
|
216
221
|
const throwCORSError = async (url) => {
|
|
217
222
|
return Promise.reject(
|
|
@@ -785,6 +790,15 @@
|
|
|
785
790
|
}
|
|
786
791
|
return matches;
|
|
787
792
|
}
|
|
793
|
+
function getHashCode(text) {
|
|
794
|
+
const len = text.length;
|
|
795
|
+
let hash = 0;
|
|
796
|
+
for (let i = 0; i < len; i++) {
|
|
797
|
+
const c = text.charCodeAt(i);
|
|
798
|
+
hash = ((hash << 5) - hash + c) & 4294967295;
|
|
799
|
+
}
|
|
800
|
+
return hash;
|
|
801
|
+
}
|
|
788
802
|
function escapeRegExpSpecialChars(input) {
|
|
789
803
|
return input.replaceAll(/[\^$.*+?\(\)\[\]{}|\-\\]/g, "\\$&");
|
|
790
804
|
}
|
|
@@ -1143,7 +1157,7 @@
|
|
|
1143
1157
|
if (layerRules.has(rule)) {
|
|
1144
1158
|
return true;
|
|
1145
1159
|
}
|
|
1146
|
-
if (rule instanceof CSSLayerBlockRule) {
|
|
1160
|
+
if (isLayerRuleSupported && rule instanceof CSSLayerBlockRule) {
|
|
1147
1161
|
layerRules.add(rule);
|
|
1148
1162
|
return true;
|
|
1149
1163
|
}
|
|
@@ -2255,8 +2269,7 @@
|
|
|
2255
2269
|
const analysis = analyzeImage(image);
|
|
2256
2270
|
resolve({
|
|
2257
2271
|
src: url,
|
|
2258
|
-
|
|
2259
|
-
dataURL,
|
|
2272
|
+
dataURL: analysis.isLarge ? "" : dataURL,
|
|
2260
2273
|
width: image.width,
|
|
2261
2274
|
height: image.height,
|
|
2262
2275
|
...analysis
|
|
@@ -2336,18 +2349,10 @@
|
|
|
2336
2349
|
isDark: false,
|
|
2337
2350
|
isLight: false,
|
|
2338
2351
|
isTransparent: false,
|
|
2339
|
-
isLarge: false
|
|
2340
|
-
isTooLarge: false
|
|
2341
|
-
};
|
|
2342
|
-
}
|
|
2343
|
-
if (sw * sh > LARGE_IMAGE_PIXELS_COUNT) {
|
|
2344
|
-
return {
|
|
2345
|
-
isDark: false,
|
|
2346
|
-
isLight: false,
|
|
2347
|
-
isTransparent: false,
|
|
2348
|
-
isLarge: true
|
|
2352
|
+
isLarge: false
|
|
2349
2353
|
};
|
|
2350
2354
|
}
|
|
2355
|
+
const isLarge = sw * sh > LARGE_IMAGE_PIXELS_COUNT;
|
|
2351
2356
|
const sourcePixelsCount = sw * sh;
|
|
2352
2357
|
const k = Math.min(
|
|
2353
2358
|
1,
|
|
@@ -2400,7 +2405,7 @@
|
|
|
2400
2405
|
isTransparent:
|
|
2401
2406
|
transparentPixelsCount / totalPixelsCount >=
|
|
2402
2407
|
TRANSPARENT_IMAGE_THRESHOLD,
|
|
2403
|
-
isLarge
|
|
2408
|
+
isLarge
|
|
2404
2409
|
};
|
|
2405
2410
|
}
|
|
2406
2411
|
let isBlobURLSupported = null;
|
|
@@ -2509,7 +2514,8 @@
|
|
|
2509
2514
|
if (!isBlobURLSupported) {
|
|
2510
2515
|
return null;
|
|
2511
2516
|
}
|
|
2512
|
-
|
|
2517
|
+
const hash = getHashCode(dataURL);
|
|
2518
|
+
let blobURL = dataURLBlobURLs.get(hash);
|
|
2513
2519
|
if (blobURL) {
|
|
2514
2520
|
return blobURL;
|
|
2515
2521
|
}
|
|
@@ -2519,7 +2525,7 @@
|
|
|
2519
2525
|
blob = await response.blob();
|
|
2520
2526
|
}
|
|
2521
2527
|
blobURL = URL.createObjectURL(blob);
|
|
2522
|
-
dataURLBlobURLs.set(
|
|
2528
|
+
dataURLBlobURLs.set(hash, blobURL);
|
|
2523
2529
|
return blobURL;
|
|
2524
2530
|
}
|
|
2525
2531
|
function cleanImageProcessingCache() {
|
|
@@ -2693,7 +2699,7 @@
|
|
|
2693
2699
|
);
|
|
2694
2700
|
lines.push("}");
|
|
2695
2701
|
}
|
|
2696
|
-
if (isCSSColorSchemePropSupported &&
|
|
2702
|
+
if (isCSSColorSchemePropSupported && theme.mode === 1) {
|
|
2697
2703
|
lines.push("html {");
|
|
2698
2704
|
lines.push(` color-scheme: dark !important;`);
|
|
2699
2705
|
lines.push("}");
|
|
@@ -2732,6 +2738,11 @@
|
|
|
2732
2738
|
` border-color: ${modifyBorderColor({r: 128, g: 128, b: 128}, theme)};`
|
|
2733
2739
|
);
|
|
2734
2740
|
lines.push("}");
|
|
2741
|
+
lines.push("mark {");
|
|
2742
|
+
lines.push(
|
|
2743
|
+
` color: ${modifyForegroundColor({r: 0, g: 0, b: 0}, theme)};`
|
|
2744
|
+
);
|
|
2745
|
+
lines.push("}");
|
|
2735
2746
|
lines.push("::placeholder {");
|
|
2736
2747
|
lines.push(
|
|
2737
2748
|
` color: ${modifyForegroundColor({r: 169, g: 169, b: 169}, theme)};`
|
|
@@ -2753,6 +2764,10 @@
|
|
|
2753
2764
|
if (theme.selectionColor) {
|
|
2754
2765
|
lines.push(getModifiedSelectionStyle(theme));
|
|
2755
2766
|
}
|
|
2767
|
+
if (isLayerRuleSupported) {
|
|
2768
|
+
lines.unshift("@layer {");
|
|
2769
|
+
lines.push("}");
|
|
2770
|
+
}
|
|
2756
2771
|
return lines.join("\n");
|
|
2757
2772
|
}
|
|
2758
2773
|
function getSelectionColor(theme) {
|
|
@@ -3087,9 +3102,9 @@
|
|
|
3087
3102
|
const logSrc = imageDetails.src.startsWith("data:")
|
|
3088
3103
|
? "data:"
|
|
3089
3104
|
: imageDetails.src;
|
|
3090
|
-
if (isLarge) {
|
|
3091
|
-
logInfo(`
|
|
3092
|
-
result =
|
|
3105
|
+
if (isLarge && isLight && !isTransparent && theme.mode === 1) {
|
|
3106
|
+
logInfo(`Hiding large light image ${logSrc}`);
|
|
3107
|
+
result = "none";
|
|
3093
3108
|
} else if (
|
|
3094
3109
|
isDark &&
|
|
3095
3110
|
isTransparent &&
|
|
@@ -4142,6 +4157,11 @@
|
|
|
4142
4157
|
"}"
|
|
4143
4158
|
].join("\n");
|
|
4144
4159
|
})
|
|
4160
|
+
.concat([
|
|
4161
|
+
"[data-darkreader-inline-invert] {",
|
|
4162
|
+
" filter: invert(100%) hue-rotate(180deg);",
|
|
4163
|
+
"}"
|
|
4164
|
+
])
|
|
4145
4165
|
.join("\n");
|
|
4146
4166
|
}
|
|
4147
4167
|
function getInlineStyleElements(root) {
|
|
@@ -4279,7 +4299,23 @@
|
|
|
4279
4299
|
attrObservers.clear();
|
|
4280
4300
|
}
|
|
4281
4301
|
const inlineStyleCache = new WeakMap();
|
|
4302
|
+
const svgInversionCache = new WeakSet();
|
|
4303
|
+
const svgAnalysisConditionCache = new WeakMap();
|
|
4282
4304
|
const themeProps = ["brightness", "contrast", "grayscale", "sepia", "mode"];
|
|
4305
|
+
function shouldAnalyzeSVGAsImage(svg) {
|
|
4306
|
+
if (svgAnalysisConditionCache.has(svg)) {
|
|
4307
|
+
return svgAnalysisConditionCache.get(svg);
|
|
4308
|
+
}
|
|
4309
|
+
const shouldAnalyze = Boolean(
|
|
4310
|
+
svg &&
|
|
4311
|
+
(svg.role === "img" ||
|
|
4312
|
+
svg.parentElement?.role === "img" ||
|
|
4313
|
+
svg.getAttribute("class")?.includes("logo") ||
|
|
4314
|
+
svg.parentElement?.getAttribute("class")?.includes("logo"))
|
|
4315
|
+
);
|
|
4316
|
+
svgAnalysisConditionCache.set(svg, shouldAnalyze);
|
|
4317
|
+
return shouldAnalyze;
|
|
4318
|
+
}
|
|
4283
4319
|
function getInlineStyleCacheKey(el, theme) {
|
|
4284
4320
|
return INLINE_STYLE_ATTRS.map(
|
|
4285
4321
|
(attr) => `${attr}="${el.getAttribute(attr)}"`
|
|
@@ -4388,6 +4424,46 @@
|
|
|
4388
4424
|
return;
|
|
4389
4425
|
}
|
|
4390
4426
|
}
|
|
4427
|
+
const isSVGElement = element instanceof SVGElement;
|
|
4428
|
+
const svg = isSVGElement
|
|
4429
|
+
? element.ownerSVGElement ??
|
|
4430
|
+
(element instanceof SVGSVGElement ? element : null)
|
|
4431
|
+
: null;
|
|
4432
|
+
if (isSVGElement && theme.mode === 1 && svg) {
|
|
4433
|
+
if (svgInversionCache.has(svg)) {
|
|
4434
|
+
return;
|
|
4435
|
+
}
|
|
4436
|
+
if (shouldAnalyzeSVGAsImage(svg)) {
|
|
4437
|
+
svgInversionCache.add(svg);
|
|
4438
|
+
const handleSVGRoot = () => {
|
|
4439
|
+
let svgString = svg.outerHTML;
|
|
4440
|
+
svgString = svgString.replaceAll(
|
|
4441
|
+
'<style class="darkreader darkreader--sync" media="screen"></style>',
|
|
4442
|
+
""
|
|
4443
|
+
);
|
|
4444
|
+
const dataURL = `data:image/svg+xml;base64,${btoa(svgString)}`;
|
|
4445
|
+
getImageDetails(dataURL).then((details) => {
|
|
4446
|
+
if (
|
|
4447
|
+
(details.isDark && details.isTransparent) ||
|
|
4448
|
+
(details.isLarge &&
|
|
4449
|
+
details.isLight &&
|
|
4450
|
+
!details.isTransparent)
|
|
4451
|
+
) {
|
|
4452
|
+
svg.setAttribute(
|
|
4453
|
+
"data-darkreader-inline-invert",
|
|
4454
|
+
""
|
|
4455
|
+
);
|
|
4456
|
+
}
|
|
4457
|
+
});
|
|
4458
|
+
};
|
|
4459
|
+
if (isReadyStateComplete()) {
|
|
4460
|
+
handleSVGRoot();
|
|
4461
|
+
} else {
|
|
4462
|
+
addReadyStateCompleteListener(handleSVGRoot);
|
|
4463
|
+
}
|
|
4464
|
+
return;
|
|
4465
|
+
}
|
|
4466
|
+
}
|
|
4391
4467
|
if (element.hasAttribute("bgcolor")) {
|
|
4392
4468
|
let value = element.getAttribute("bgcolor");
|
|
4393
4469
|
if (
|
|
@@ -4420,7 +4496,7 @@
|
|
|
4420
4496
|
}
|
|
4421
4497
|
setCustomProp("color", "color", value);
|
|
4422
4498
|
}
|
|
4423
|
-
if (
|
|
4499
|
+
if (isSVGElement) {
|
|
4424
4500
|
if (element.hasAttribute("fill")) {
|
|
4425
4501
|
const SMALL_SVG_LIMIT = 32;
|
|
4426
4502
|
const value = element.getAttribute("fill");
|
|
@@ -4602,6 +4678,13 @@
|
|
|
4602
4678
|
const asyncQueue = createAsyncTasksQueue();
|
|
4603
4679
|
function createStyleSheetModifier() {
|
|
4604
4680
|
let renderId = 0;
|
|
4681
|
+
function getStyleRuleHash(rule) {
|
|
4682
|
+
let cssText = rule.cssText;
|
|
4683
|
+
if (isMediaRule(rule.parentRule)) {
|
|
4684
|
+
cssText = `${rule.parentRule.media.mediaText} { ${cssText} }`;
|
|
4685
|
+
}
|
|
4686
|
+
return getHashCode(cssText);
|
|
4687
|
+
}
|
|
4605
4688
|
const rulesTextCache = new Set();
|
|
4606
4689
|
const rulesModCache = new Map();
|
|
4607
4690
|
const varTypeChangeCleaners = new Set();
|
|
@@ -4631,23 +4714,17 @@
|
|
|
4631
4714
|
iterateCSSRules(
|
|
4632
4715
|
rules,
|
|
4633
4716
|
(rule) => {
|
|
4634
|
-
|
|
4717
|
+
const hash = getStyleRuleHash(rule);
|
|
4635
4718
|
let textDiffersFromPrev = false;
|
|
4636
|
-
notFoundCacheKeys.delete(
|
|
4637
|
-
if (
|
|
4638
|
-
|
|
4639
|
-
}
|
|
4640
|
-
if (isLayerRule(rule.parentRule)) {
|
|
4641
|
-
cssText += `;${rule.parentRule.name}`;
|
|
4642
|
-
}
|
|
4643
|
-
if (!rulesTextCache.has(cssText)) {
|
|
4644
|
-
rulesTextCache.add(cssText);
|
|
4719
|
+
notFoundCacheKeys.delete(hash);
|
|
4720
|
+
if (!rulesTextCache.has(hash)) {
|
|
4721
|
+
rulesTextCache.add(hash);
|
|
4645
4722
|
textDiffersFromPrev = true;
|
|
4646
4723
|
}
|
|
4647
4724
|
if (textDiffersFromPrev) {
|
|
4648
4725
|
rulesChanged = true;
|
|
4649
4726
|
} else {
|
|
4650
|
-
modRules.push(rulesModCache.get(
|
|
4727
|
+
modRules.push(rulesModCache.get(hash));
|
|
4651
4728
|
return;
|
|
4652
4729
|
}
|
|
4653
4730
|
if (rule.style.all === "revert") {
|
|
@@ -4681,7 +4758,7 @@
|
|
|
4681
4758
|
};
|
|
4682
4759
|
modRules.push(modRule);
|
|
4683
4760
|
}
|
|
4684
|
-
rulesModCache.set(
|
|
4761
|
+
rulesModCache.set(hash, modRule);
|
|
4685
4762
|
},
|
|
4686
4763
|
() => {
|
|
4687
4764
|
hasNonLoadedLink = true;
|
|
@@ -5539,11 +5616,15 @@
|
|
|
5539
5616
|
if (url.startsWith("data:")) {
|
|
5540
5617
|
return await (await fetch(url)).text();
|
|
5541
5618
|
}
|
|
5619
|
+
const parsedURL = new URL(url);
|
|
5620
|
+
if (parsedURL.origin === location.origin) {
|
|
5621
|
+
return await loadAsText(url, "text/css", location.origin);
|
|
5622
|
+
}
|
|
5542
5623
|
return await bgFetch({
|
|
5543
5624
|
url,
|
|
5544
5625
|
responseType: "text",
|
|
5545
5626
|
mimeType: "text/css",
|
|
5546
|
-
origin:
|
|
5627
|
+
origin: location.origin
|
|
5547
5628
|
});
|
|
5548
5629
|
}
|
|
5549
5630
|
async function replaceCSSImports(cssText, basePath, cache = new Map()) {
|
package/index.d.ts
CHANGED
|
@@ -153,7 +153,7 @@ declare namespace DarkReader {
|
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
155
|
* A toggle to disable the proxying of `document.styleSheets`.
|
|
156
|
-
* This is a API-Exclusive option, as it can break
|
|
156
|
+
* This is a API-Exclusive option, as it can break legitimate websites,
|
|
157
157
|
* who are using the Dark Reader API.
|
|
158
158
|
*/
|
|
159
159
|
disableStyleSheetsProxy: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "darkreader",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.84",
|
|
4
4
|
"description": "Dark mode for every website",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"api": "node --max-old-space-size=3072 tasks/cli.js build --api",
|
|
@@ -58,16 +58,16 @@
|
|
|
58
58
|
"@rollup/plugin-node-resolve": "15.2.3",
|
|
59
59
|
"@rollup/plugin-replace": "5.0.5",
|
|
60
60
|
"@rollup/plugin-typescript": "11.1.6",
|
|
61
|
-
"@types/chrome": "0.0.
|
|
62
|
-
"@types/eslint": "8.56.
|
|
61
|
+
"@types/chrome": "0.0.266",
|
|
62
|
+
"@types/eslint": "8.56.7",
|
|
63
63
|
"@types/jasmine": "5.1.4",
|
|
64
64
|
"@types/jest": "29.5.12",
|
|
65
65
|
"@types/karma": "6.3.8",
|
|
66
66
|
"@types/karma-coverage": "2.0.3",
|
|
67
|
-
"@types/node": "20.12.
|
|
67
|
+
"@types/node": "20.12.6",
|
|
68
68
|
"@types/ws": "8.5.10",
|
|
69
|
-
"@typescript-eslint/eslint-plugin": "7.
|
|
70
|
-
"@typescript-eslint/parser": "7.
|
|
69
|
+
"@typescript-eslint/eslint-plugin": "7.6.0",
|
|
70
|
+
"@typescript-eslint/parser": "7.6.0",
|
|
71
71
|
"chokidar": "3.6.0",
|
|
72
72
|
"eslint": "8.57.0",
|
|
73
73
|
"eslint-plugin-compat": "4.2.0",
|
|
@@ -88,12 +88,12 @@
|
|
|
88
88
|
"less": "4.2.0",
|
|
89
89
|
"malevic": "0.20.1",
|
|
90
90
|
"prettier": "3.2.5",
|
|
91
|
-
"puppeteer-core": "22.6.
|
|
92
|
-
"rollup": "4.
|
|
91
|
+
"puppeteer-core": "22.6.3",
|
|
92
|
+
"rollup": "4.14.1",
|
|
93
93
|
"rollup-plugin-istanbul": "5.0.0",
|
|
94
94
|
"ts-jest": "29.1.2",
|
|
95
95
|
"tslib": "2.6.2",
|
|
96
|
-
"typescript": "5.4.
|
|
96
|
+
"typescript": "5.4.4",
|
|
97
97
|
"web-ext": "7.11.0",
|
|
98
98
|
"ws": "8.16.0",
|
|
99
99
|
"yazl": "2.5.1"
|