├── .gitignore ├── DarkReader.LICENSE ├── LICENSE ├── Makefile ├── OrionDark.LICENSE ├── README.MD ├── Tweak.h ├── Tweak.x ├── WebShade.plist ├── advanced-engine.js ├── basic-engine.js ├── control └── webshadeprefs ├── Makefile ├── Resources ├── Info.plist ├── Root.plist └── Site.plist ├── WSPCustomSiteListController.h ├── WSPCustomSiteListController.m ├── WSPRootListController.h ├── WSPRootListController.m ├── WSPSiteListController.h ├── WSPSiteListController.m └── layout └── Library └── PreferenceLoader └── Preferences └── WebShadePrefs.plist /.gitignore: -------------------------------------------------------------------------------- 1 | .theos 2 | packages 3 | .DS_Store -------------------------------------------------------------------------------- /DarkReader.LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Alexander Shutau 4 | 5 | All rights reserved. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 WilsontheWolf 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET := iphone:clang:latest:11.0 2 | INSTALL_TARGET_PROCESSES = SpringBoard 3 | export ARCHS = arm64 arm64e 4 | 5 | include $(THEOS)/makefiles/common.mk 6 | 7 | TWEAK_NAME = WebShade 8 | 9 | WebShade_FILES = Tweak.x 10 | WebShade_CFLAGS = -fobjc-arc 11 | 12 | include $(THEOS_MAKE_PATH)/tweak.mk 13 | 14 | SUBPROJECTS += webshadeprefs 15 | include $(THEOS_MAKE_PATH)/aggregate.mk 16 | -------------------------------------------------------------------------------- /OrionDark.LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Orion 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # WebShade 2 | WebShade is a simple tweak to make your websites darker. 3 | 4 | ## How it works 5 | WebShade injects a copy of [DarkReader](https://github.com/darkreader/darkreader) into the page and 6 | runs it. It's super simple with no configuration. I'll probably not support it much. Since I'm 7 | distributing DarkReader's code, I've included the license in [DarkReader.LICENSE](DarkReader.LICENSE). 8 | -------------------------------------------------------------------------------- /Tweak.h: -------------------------------------------------------------------------------- 1 | // This runs dark reader with our prefs. To see the darkreader core look below. 2 | // Also see advanced-engine.js. 3 | #define kDarkReaderRun @"if(wsToken&&window.webkit&&window.webkit.messageHandlers&&window.webkit.messageHandlers.WebShadeCorsFetch){const e=window.webkit.messageHandlers.WebShadeCorsFetch.postMessage.bind(window.webkit.messageHandlers.WebShadeCorsFetch);if(/\\{\\s+\\[native code\\]/.test(Function.prototype.toString.call(e))&&!window.webkit.WebShadeCorsFetchResponse){const t={},o=o=>{const s=Math.random().toString(36).slice(2),a=new Promise((e,o)=>{t[s]={resolve:e,reject:o}});return t[s].timeout=setTimeout(()=>{t[s].reject(new Error(\"No response\")),delete t[s]},1e5+1e3*Object.keys(t).length),e({url:encodeURI(o),id:s,token:wsToken}),a};window.webkit.WebShadeCorsFetchResponse=(({id:e,type:o,message:s})=>{if(e&&o&&t[e]){if(clearTimeout(t[e].timeout),\"data\"===o){const o={text:()=>Promise.resolve(atob(s)),blob:()=>Promise.resolve(new Blob([atob(s)]))};t[e].resolve(o)}else t[e].reject(new Error(s));delete t[e]}}),Object.freeze(window.webkit),DarkReader.setFetchMethod(o)}}const data={brightness:options.brightness,contrast:options.contrast,grayscale:options.grayscale,sepia:options.sepia,darkSchemeBackgroundColor:options.OLED?\"#000\":\"#181a1b\"};options.dynamic?DarkReader.auto(data):DarkReader.enable(data);" 4 | 5 | // This runs the simpler engine. 6 | // Also see basic-engine.js. 7 | // Also see OrionDark.LICENSE 8 | #define kBasicEngineRun @"const css=`\\n${options.dynamic?\"@media (prefers-color-scheme: dark) {\":\"\"}\\n:root {\\n filter: invert(${options.OLED?100:90}%) hue-rotate(180deg) brightness(${options.brightness}%) contrast(${options.contrast}%) grayscale(${options.grayscale}%) sepia(${options.sepia}%);\\n background: #fff;\\n} \\niframe, img, image, video, [style*=\"background-image\"] { \\n filter: invert() hue-rotate(180deg) brightness(${options.brightness+5}%) contrast(${options.contrast+5}%) !important;\\n}\\n${options.dynamic?\"}\":\"\"}\\n`,id=\"webshade-browser-dark-theme\",ee=document.getElementById(id);null!=ee&&ee.parentNode.removeChild(ee),style=document.createElement(\"style\"),style.type=\"text/css\",style.id=id,style.styleSheet?style.styleSheet.cssText=css:style.appendChild(document.createTextNode(css)),document.head.appendChild(style);" 9 | 10 | // This massive string is the entirty of dark reader. 11 | // This is taken from https://cdn.jsdelivr.net/npm/darkreader/darkreader.min.js 12 | // Last updated Thu, 10 Mar 2022 04:20:07 GMT. 13 | // Also see DarkReader.LICENSE 14 | #define kDarkReaderScript @"/**\n * Minified by jsDelivr using Terser v5.10.0.\n * Original file: /npm/darkreader@4.9.44/darkreader.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n!function(e,t){\"object\"==typeof exports&&\"undefined\"!=typeof module?t(exports):\"function\"==typeof define&&define.amd?define([\"exports\"],t):t((e=\"undefined\"!=typeof globalThis?globalThis:e||self).DarkReader={})}(this,(function(e){\"use strict\";\n/*! *****************************************************************************\n Copyright (c) Microsoft Corporation.\n\n Permission to use, copy, modify, and/or distribute this software for any\n purpose with or without fee is hereby granted.\n\n THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\n REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\n AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\n INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\n LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\n OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n PERFORMANCE OF THIS SOFTWARE.\n ***************************************************************************** */var t=function(){return t=Object.assign||function(e){for(var t,r=1,n=arguments.length;r0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?\"Object is not iterable.\":\"Symbol.iterator is not defined.\")}function a(e,t){var r=\"function\"==typeof Symbol&&e[Symbol.iterator];if(!r)return e;var n,o,a=r.call(e),i=[];try{for(;(void 0===t||t-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(e){o={error:e}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i}function i(e,t,r){if(r||2===arguments.length)for(var n,o=0,a=t.length;o Promise))`.\",\"See if using `DarkReader.setFetchMethod(window.fetch)`\",\"before `DarkReader.enable()` works.\"].join(\" \")))]}))}))},C=x;function V(e){return r(this,void 0,void 0,(function(){return n(this,(function(t){switch(t.label){case 0:return[4,C(e)];case 1:return[2,t.sent()]}}))}))}window.chrome||(window.chrome={}),chrome.runtime||(chrome.runtime={});var R=new Set;function T(){for(var e=[],t=0;t=10){if(f-u1e3)return!0;for(var t=0,r=0;r1e3)return!0;return!1}(t))!a||H()?n.forEach((function(t){return(0,t.onHugeMutations)(e)})):i||(Q(o=function(){return n.forEach((function(t){return(0,t.onHugeMutations)(e)}))}),i=!0),a=!0;else{var r=function(e){var t=new Set,r=new Set,n=new Set;e.forEach((function(e){F(e.addedNodes,(function(e){e instanceof Element&&e.isConnected&&t.add(e)})),F(e.removedNodes,(function(e){e instanceof Element&&(e.isConnected?(n.add(e),t.delete(e)):r.add(e))}))}));var o=[],a=[];return t.forEach((function(e){t.has(e.parentElement)&&o.push(e)})),r.forEach((function(e){r.has(e.parentElement)&&a.push(e)})),o.forEach((function(e){return t.delete(e)})),a.forEach((function(e){return r.delete(e)})),{additions:t,moves:n,deletions:r}}(t);n.forEach((function(e){return(0,e.onMinorMutations)(r)}))}})),r.observe(e,{childList:!0,subtree:!0}),te.set(e,r),n=new Set,re.set(r,n)}return n.add(t),{disconnect:function(){n.delete(t),o&&K(o),0===n.size&&(r.disconnect(),re.delete(r),te.delete(e))}}}var oe=new Map;function ae(e){return ee||(ee=document.createElement(\"a\")),ee.href=e,ee.href}function ie(e,t){void 0===t&&(t=null);var r=\"\".concat(e).concat(t?\";\".concat(t):\"\");if(oe.has(r))return oe.get(r);if(t){var n=new URL(e,ae(t));return oe.set(r,n),n}var o=new URL(ae(e));return oe.set(e,o),o}function ce(e,t){if(t.match(/^data\\\\?\\:/))return t;if(/^\\/\\//.test(t))return\"\".concat(location.protocol).concat(t);var r=ie(e);return ie(t,r.href).href}function ue(e,t,r){F(e,(function(e){if(e.selectorText)t(e);else if(e.href)try{ue(e.styleSheet.cssRules,t,r)}catch(e){q(\"Found a non-loaded link.\"),r&&r()}else if(e.media){var n=Array.from(e.media),o=n.some((function(e){return e.startsWith(\"screen\")||e.startsWith(\"all\")||e.startsWith(\"(\")})),a=n.some((function(e){return e.startsWith(\"print\")||e.startsWith(\"speech\")}));!o&&a||ue(e.cssRules,t,r)}else e.conditionText?CSS.supports(e.conditionText)&&ue(e.cssRules,t,r):B(\"CSSRule type not supported\",e)}))}var se=[\"background\",\"border\",\"border-color\",\"border-bottom\",\"border-left\",\"border-right\",\"border-top\",\"outline\",\"outline-color\"],le=p?se.map((function(e){return[e,new RegExp(\"\".concat(e,\":\\\\s*(.*?)\\\\s*;\"))]})):null;function de(e,t){F(e,(function(r){var n=e.getPropertyValue(r).trim();n&&t(r,n)}));var r=e.cssText;r.includes(\"var(\")&&(p?le.forEach((function(e){var n=a(e,2),o=n[0],i=n[1],c=r.match(i);if(c&&c[1]){var u=c[1].trim();t(o,u)}})):se.forEach((function(r){var n=e.getPropertyValue(r);n&&n.includes(\"var(\")&&t(r,n)})))}var fe=/url\\((('.+?')|(\".+?\")|([^\\)]*?))\\)/g,he=/@import\\s*(url\\()?(('.+?')|(\".+?\")|([^\\)]*?))\\)? ?(screen)?;?/g;function pe(e){return e.replace(/^url\\((.*)\\)$/,\"$1\").trim().replace(/^\"(.*)\"$/,\"$1\").replace(/^'(.*)'$/,\"$1\")}function ve(e){var t=ie(e);return\"\".concat(t.origin).concat(t.pathname.replace(/\\?.*$/,\"\").replace(/(\\/)([^\\/]+)$/i,\"$1\"))}var me=/\\/\\*[\\s\\S]*?\\*\\//g;var ge=/@font-face\\s*{[^}]*}/g;function be(e){var t=e.h,r=e.s,n=e.l,o=e.a,i=void 0===o?1:o;if(0===r){var c=a([n,n,n].map((function(e){return Math.round(255*e)})),3),u=c[0],s=c[1];return{r:u,g:c[2],b:s,a:i}}var l=(1-Math.abs(2*n-1))*r,d=l*(1-Math.abs(t/60%2-1)),f=n-l/2,h=a((t<60?[l,d,0]:t<120?[d,l,0]:t<180?[0,l,d]:t<240?[0,d,l]:t<300?[d,0,l]:[l,0,d]).map((function(e){return Math.round(255*(e+f))})),3);return{r:h[0],g:h[1],b:h[2],a:i}}function ye(e){var t=e.r,r=e.g,n=e.b,o=e.a,a=void 0===o?1:o,i=t/255,c=r/255,u=n/255,s=Math.max(i,c,u),l=Math.min(i,c,u),d=s-l,f=(s+l)/2;if(0===d)return{h:0,s:0,l:f,a:a};var h=60*(s===i?(c-u)/d%6:s===c?(u-i)/d+2:(i-c)/d+4);return h<0&&(h+=360),{h:h,s:d/(1-Math.abs(2*f-1)),l:f,a:a}}function ke(e,t){void 0===t&&(t=0);var r=e.toFixed(t);if(0===t)return r;var n=r.indexOf(\".\");if(n>=0){var o=r.match(/0+$/);if(o)return o.index===n+1?r.substring(0,n):r.substring(0,o.index)}return r}function Se(e){var t=e.h,r=e.s,n=e.l,o=e.a;return null!=o&&o<1?\"hsla(\".concat(ke(t),\", \").concat(ke(100*r),\"%, \").concat(ke(100*n),\"%, \").concat(ke(o,2),\")\"):\"hsl(\".concat(ke(t),\", \").concat(ke(100*r),\"%, \").concat(ke(100*n),\"%)\")}var we=/^rgba?\\([^\\(\\)]+\\)$/,_e=/^hsla?\\([^\\(\\)]+\\)$/,Ee=/^#[0-9a-f]+$/i;function xe(e){var t,r,n,o,i,c=e.trim().toLowerCase();if(c.match(we))return t=a(Ce(c,Ve,Re),4),r=t[0],n=t[1],o=t[2],i=t[3],{r:r,g:n,b:o,a:void 0===i?1:i};if(c.match(_e))return function(e){var t=a(Ce(e,Te,Me),4),r=t[0],n=t[1],o=t[2],i=t[3];return be({h:r,s:n,l:o,a:void 0===i?1:i})}(c);if(c.match(Ee))return function(e){var t=e.substring(1);switch(t.length){case 3:case 4:var r=a([0,1,2].map((function(e){return parseInt(\"\".concat(t[e]).concat(t[e]),16)})),3);return{r:r[0],g:r[1],b:r[2],a:3===t.length?1:parseInt(\"\".concat(t[3]).concat(t[3]),16)/255};case 6:case 8:var n=a([0,2,4].map((function(e){return parseInt(t.substring(e,e+2),16)})),3);return{r:n[0],g:n[1],b:n[2],a:6===t.length?1:parseInt(t.substring(6,8),16)/255}}throw new Error(\"Unable to parse \".concat(e))}(c);if(Pe.has(c))return function(e){var t=Pe.get(e);return{r:t>>16&255,g:t>>8&255,b:t>>0&255,a:1}}(c);if(Oe.has(c))return function(e){var t=Oe.get(e);return{r:t>>16&255,g:t>>8&255,b:t>>0&255,a:1}}(c);if(\"transparent\"===e)return{r:0,g:0,b:0,a:0};throw new Error(\"Unable to parse \".concat(e))}function Ce(e,t,r){var n=function(e){var t=[],r=0,n=!1,o=e.indexOf(\"(\");e=e.substring(o+1,e.length-1);for(var a=0;a=\"0\"&&i<=\"9\"||\".\"===i||\"+\"===i||\"-\"===i?n=!0:!n||\" \"!==i&&\",\"!==i?n||(r=a+1):(t.push(e.substring(r,a)),n=!1,r=a+1)}return n&&t.push(e.substring(r,e.length)),t}(e),o=Object.entries(r);return n.map((function(e){return e.trim()})).map((function(e,r){var n,i=o.find((function(t){var r=a(t,1)[0];return e.endsWith(r)}));return n=i?parseFloat(e.substring(0,e.length-i[0].length))/i[1]*t[r]:parseFloat(e),t[r]>1?Math.round(n):n}))}var Ve=[255,255,255,1],Re={\"%\":100};var Te=[360,1,1,1],Me={\"%\":100,deg:360,rad:2*Math.PI,turn:1};var Ae=function(e){return e>=\"0\"&&e<=\"9\"};function Le(e){for(var t=0,r=function(t,r,n){e=e.substring(0,t)+n+e.substring(r)},n=function(){for(var r=0,n=1;n<4;n++){var o=e[t+n];if(\" \"===o)break;if(!Ae(o))break;r*=10,r+=Number(o)}var a,i=(a=r,Math.floor(Math.log10(a))+1);if(\"%\"===e[(t+=i)+1])return t++,r};0!==(t=e.indexOf(\"calc(\"));){var o=t;t+=4;var a=n();if(!a)break;if(\" \"!==e[t+1])break;t++;var i=e[t+1];if(\"+\"!==i&&\"-\"!==i)break;if(t++,\" \"!==e[t+1])break;t++;var c=n();if(!c)break;var u=void 0;u=\"\".concat(\"+\"===i?a+c:a-c,\"%\"),r(o,t+2,u)}return e}var Pe=new Map(Object.entries({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgrey:11119017,darkgreen:25600,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,grey:8421504,green:32768,greenyellow:11403055,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgrey:13882323,lightgreen:9498256,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074})),Oe=new Map(Object.entries({ActiveBorder:3906044,ActiveCaption:0,AppWorkspace:11184810,Background:6513614,ButtonFace:16777215,ButtonHighlight:15329769,ButtonShadow:10461343,ButtonText:0,CaptionText:0,GrayText:8355711,Highlight:11720703,HighlightText:0,InactiveBorder:16777215,InactiveCaption:16777215,InactiveCaptionText:0,InfoBackground:16514245,InfoText:0,Menu:16185078,MenuText:16777215,Scrollbar:11184810,ThreeDDarkShadow:0,ThreeDFace:12632256,ThreeDHighlight:16777215,ThreeDLightShadow:16777215,ThreeDShadow:0,Window:15527148,WindowFrame:11184810,WindowText:0,\"-webkit-focus-ring-color\":15046400}).map((function(e){var t=a(e,2),r=t[0],n=t[1];return[r.toLowerCase(),n]})));function je(e,t,r,n,o){return(e-t)*(o-n)/(r-t)+n}function De(e,t,r){return Math.min(r,Math.max(t,e))}function Fe(e,t){for(var r=[],n=0,o=e.length;n.8&&(o>200&&o<280);var s=o,l=i;return n&&(u?(s=t.h,l=t.s):(s=r.h,l=r.s)),{h:s,s:l,l:je(i,0,1,t.l,r.l),a:c}}function Ze(e,t){var r=e.h,n=e.s,o=e.l,a=e.a,i=n<.12||o>.8&&(r>200&&r<280);if(o<.5){var c=je(o,0,.5,0,.4);return i?{h:t.h,s:t.s,l:c,a:a}:{h:r,s:n,l:c,a:a}}var u=je(o,.5,1,.4,t.l);if(i)return{h:t.h,s:t.s,l:u,a:a};var s=r;r>60&&r<180&&(s=r>120?je(r,120,180,135,180):je(r,60,120,60,105));return{h:s,s:n,l:u,a:a}}function et(e,r){if(0===r.mode)return Xe(e,r);var n=We(r);return Ke(e,t(t({},r),{mode:0}),Ze,n)}var tt,rt=.55;function nt(e){return je(e,205,245,205,220)}function ot(e,t){var r=e.h,n=e.s,o=e.l,a=e.a,i=o<.2||n<.24,c=!i&&r>205&&r<245;if(o>.5){var u=je(o,.5,1,rt,t.l);if(i)return{h:t.h,s:t.s,l:u,a:a};var s=r;return c&&(s=nt(r)),{h:s,s:n,l:u,a:a}}if(i)return{h:t.h,s:t.s,l:je(o,0,.5,t.l,rt),a:a};var l,d=r;return c?(d=nt(r),l=je(o,0,.5,t.l,Math.min(1,.6000000000000001))):l=je(o,0,.5,t.l,rt),{h:d,s:n,l:l,a:a}}function at(e,r){if(0===r.mode)return Xe(e,r);var n=Ue(r);return Ke(e,t(t({},r),{mode:0}),ot,n)}function it(e,t,r){var n=e.h,o=e.s,a=e.l,i=e.a,c=n,u=o;return(a<.2||o<.24)&&(a<.5?(c=t.h,u=t.s):(c=r.h,u=r.s)),{h:c,s:u,l:je(a,0,1,.5,.2),a:i}}function ct(e,r){if(0===r.mode)return Xe(e,r);var n=Ue(r),o=We(r);return Ke(e,t(t({},r),{mode:0}),it,n,o)}function ut(e,t){return et(e,t)}function st(e){var t=[];return e.mode===tt.dark&&t.push(\"invert(100%) hue-rotate(180deg)\"),100!==e.brightness&&t.push(\"brightness(\".concat(e.brightness,\"%)\")),100!==e.contrast&&t.push(\"contrast(\".concat(e.contrast,\"%)\")),0!==e.grayscale&&t.push(\"grayscale(\".concat(e.grayscale,\"%)\")),0!==e.sepia&&t.push(\"sepia(\".concat(e.sepia,\"%)\")),0===t.length?null:t.join(\" \")}!function(e){e[e.light=0]=\"light\",e[e.dark=1]=\"dark\"}(tt||(tt={}));var lt=0,dt=new Map,ft=new Map;function ht(e){return r(this,void 0,void 0,(function(){return n(this,(function(t){return[2,new Promise((function(t,r){var n=++lt;dt.set(n,t),ft.set(n,r),chrome.runtime.sendMessage({type:u,data:e,id:n})}))]}))}))}chrome.runtime.onMessage.addListener((function(e){var t=e.type,r=e.data,n=e.error,o=e.id;if(t===c){var a=dt.get(o),i=ft.get(o);dt.delete(o),ft.delete(o),n?i&&i(n):a&&a(r)}}));var pt=new(function(){function e(){this.queue=[],this.timerId=null,this.frameDuration=1e3/60}return e.prototype.addToQueue=function(e){this.queue.push(e),this.startQueue()},e.prototype.stopQueue=function(){null!==this.timerId&&(cancelAnimationFrame(this.timerId),this.timerId=null),this.queue=[]},e.prototype.startQueue=function(){var e=this;this.timerId||(this.timerId=requestAnimationFrame((function(){e.timerId=null;for(var t,r=Date.now();t=e.queue.shift();)if(t(),Date.now()-r>=e.frameDuration){e.startQueue();break}})))},e}());function vt(e){return r(this,void 0,void 0,(function(){var o=this;return n(this,(function(a){return[2,new Promise((function(a,i){return r(o,void 0,void 0,(function(){var r,o,c,u;return n(this,(function(n){switch(n.label){case 0:return e.startsWith(\"data:\")?(r=e,[3,4]):[3,1];case 1:return n.trys.push([1,3,,4]),[4,mt(e)];case 2:return r=n.sent(),[3,4];case 3:return o=n.sent(),i(o),[2];case 4:return n.trys.push([4,6,,7]),[4,gt(r)];case 5:return c=n.sent(),pt.addToQueue((function(){a(t({src:e,dataURL:r,width:c.naturalWidth,height:c.naturalHeight},function(e){bt||(t=kt,r=kt,(bt=document.createElement(\"canvas\")).width=t,bt.height=r,(yt=bt.getContext(\"2d\")).imageSmoothingEnabled=!1);var t,r;var n=e.naturalWidth,o=e.naturalHeight;if(0===o||0===n)return B(\"logWarn(Image is empty \".concat(e.currentSrc,\")\")),null;if(n*o*4>St)return q(\"Skipped large image analyzing(Larger than 5mb in memory)\"),{isDark:!1,isLight:!1,isTransparent:!1,isLarge:!1,isTooLarge:!0};var a=n*o,i=Math.min(1,Math.sqrt(kt/a)),c=Math.ceil(n*i),u=Math.ceil(o*i);yt.clearRect(0,0,c,u),yt.drawImage(e,0,0,n,o,0,0,c,u);var s,l,d,f,h,p,v,m=yt.getImageData(0,0,c,u).data,g=.05,b=.4,y=.7,k=0,S=0,w=0;for(d=0;dy&&w++);var _=c*u,E=_-k;return{isDark:S/E>=.7,isLight:w/E>=.7,isTransparent:k/_>=.1,isLarge:a>=48e4,isTooLarge:!1}}(c)))})),[3,7];case 6:return u=n.sent(),i(u),[3,7];case 7:return[2]}}))}))}))]}))}))}function mt(e){return r(this,void 0,void 0,(function(){return n(this,(function(t){switch(t.label){case 0:return new URL(e).origin!==location.origin?[3,2]:[4,_(e)];case 1:case 3:return[2,t.sent()];case 2:return[4,ht({url:e,responseType:\"data-url\"})]}}))}))}function gt(e){return r(this,void 0,void 0,(function(){return n(this,(function(t){return[2,new Promise((function(t,r){var n=new Image;n.onload=function(){return t(n)},n.onerror=function(){return r(\"Unable to load image \".concat(e))},n.src=e}))]}))}))}var bt,yt,kt=1024;var St=5242880;function wt(e,t){var r=e.dataURL,n=e.width,o=e.height,a=Be(t).slice(0,4).map((function(e){return e.map((function(e){return e.toFixed(3)})).join(\" \")})).join(\" \"),i=[''),\"\",'',''),\"\",\"\",''),\"\"].join(\"\");return\"data:image/svg+xml;base64,\".concat(btoa(i))}function _t(){pt&&pt.stopQueue(),bt=null,yt=null}var Et=\"gradient\".length,xt=\"conic-\",Ct=xt.length,Vt=\"radial-\",Rt=\"linear-\";function Tt(e,t){return Boolean(e&&e.getPropertyPriority(t))}function Mt(e,t,r,n,o,a){if(e.startsWith(\"--\")){var i=function(e,t,r,n,o,a){return e.getModifierForVariable({varName:t,sourceValue:r,rule:n,ignoredImgSelectors:o,isCancelled:a})}(n,e,t,r,o,a);if(i)return{property:e,value:i,important:Tt(r.style,e),sourceValue:t}}else if(t.includes(\"var(\")){i=function(e,t,r){return e.getModifierForVarDependant(t,r)}(n,e,t);if(i)return{property:e,value:i,important:Tt(r.style,e),sourceValue:t}}else if(e.includes(\"color\")&&\"-webkit-print-color-adjust\"!==e||\"fill\"===e||\"stroke\"===e||\"stop-color\"===e){i=function(e,t){if(jt.has(t.toLowerCase()))return t;try{var r=Ft(t);return e.includes(\"background\")?function(e){return et(r,e)}:e.includes(\"border\")||e.includes(\"outline\")?function(e){return ct(r,e)}:function(e){return at(r,e)}}catch(e){return B(\"Color parse error\",e),null}}(e,t);if(i)return{property:e,value:i,important:Tt(r.style,e),sourceValue:t}}else if(\"background-image\"===e||\"list-style-image\"===e){if(i=It(t,r,o,a))return{property:e,value:i,important:Tt(r.style,e),sourceValue:t}}else if(e.includes(\"shadow\")){i=function(e){var t=Wt(e);if(!t)return null;return function(e){return t(e).result}}(t);if(i)return{property:e,value:i,important:Tt(r.style,e),sourceValue:t}}return null}function At(){for(var e=[],t=0;t.5,d=function(e){return t(t({},s),{l:De(s.l+e,0,1)})},f=function(e){return t(t({},s),{l:De(s.l-e,0,1)})};r=Se(f(.4)),n=Se(l?f(.4):d(.4)),o=Se(s),a=Se(d(.1)),i=Se(d(.2))}u.push(\"::-webkit-scrollbar {\"),u.push(\" background-color: \".concat(r,\";\")),u.push(\" color: \".concat(n,\";\")),u.push(\"}\"),u.push(\"::-webkit-scrollbar-thumb {\"),u.push(\" background-color: \".concat(o,\";\")),u.push(\"}\"),u.push(\"::-webkit-scrollbar-thumb:hover {\"),u.push(\" background-color: \".concat(a,\";\")),u.push(\"}\"),u.push(\"::-webkit-scrollbar-thumb:active {\"),u.push(\" background-color: \".concat(i,\";\")),u.push(\"}\"),u.push(\"::-webkit-scrollbar-corner {\"),u.push(\" background-color: \".concat(c,\";\")),u.push(\"}\"),h&&(u.push(\"* {\"),u.push(\" scrollbar-color: \".concat(o,\" \").concat(r,\";\")),u.push(\"}\"));return u.join(\"\\n\")}(e)),e.selectionColor&&o.push(function(e){var t=[],r=Pt(e),n=r.backgroundColorSelection,o=r.foregroundColorSelection;return[\"::selection\",\"::-moz-selection\"].forEach((function(e){t.push(\"\".concat(e,\" {\")),t.push(\" background-color: \".concat(n,\" !important;\")),t.push(\" color: \".concat(o,\" !important;\")),t.push(\"}\")})),t.join(\"\\n\")}(e)),o.join(\"\\n\")}function Pt(e){var r,n;if(\"auto\"===e.selectionColor)r=et({r:0,g:96,b:212},t(t({},e),{grayscale:0})),n=at({r:255,g:255,b:255},t(t({},e),{grayscale:0}));else{var o=ye(xe(e.selectionColor));r=e.selectionColor,n=o.l<.5?\"#FFF\":\"#000\"}return{backgroundColorSelection:r,foregroundColorSelection:n}}function Ot(e,t){var r=t.strict,n=[],o=location.hostname.endsWith(\"microsoft.com\");return n.push(\"html, body, \".concat(r?\"body :not(iframe)\".concat(o?':not(div[style^=\"position:absolute;top:0;left:-\"]':\"\"):\"body > :not(iframe)\",\" {\")),n.push(\" background-color: \".concat(et({r:255,g:255,b:255},e),\" !important;\")),n.push(\" border-color: \".concat(ct({r:64,g:64,b:64},e),\" !important;\")),n.push(\" color: \".concat(at({r:0,g:0,b:0},e),\" !important;\")),n.push(\"}\"),n.join(\"\\n\")}var jt=new Set([\"inherit\",\"transparent\",\"initial\",\"currentcolor\",\"none\",\"unset\"]),Dt=new Map;function Ft(e){if(e=e.trim(),Dt.has(e))return Dt.get(e);e.includes(\"calc(\")&&(e=Le(e));var t=xe(e);return Dt.set(e,t),t}function Nt(e){try{return Ft(e)}catch(e){return null}}var qt=new Map,Bt=new Map;function It(e,o,a,i){var c,u,s=this;try{var l=function(e){for(var t=[],r=0,n=xt.length,o=function(){var o;if([Rt,Vt,xt].find((function(t){if(r-t.length>=0&&e.substring(r-t.length,r)===t)return r-t.length-1>=9&&\"-\"===e[r-t.length-1]?(o=\"repeating-\".concat(t,\"gradient\"),!0):(o=\"\".concat(t,\"gradient\"),!0)})),!o)return\"break\";var a=qe(e,r+Et),i=a.start,c=a.end,u=e.substring(i+1,c-1);n=c+1+Ct,t.push({type:o,content:u,hasComma:!0})};-1!==(r=e.indexOf(\"gradient\",n))&&\"break\"!==o(););return t.length&&(t[t.length-1].hasComma=!1),t}(e),d=Ne(fe,e);if(0===d.length&&0===l.length)return e;var f=(c=d,u=0,c.map((function(t){var r=e.indexOf(t,u);return u=r+t.length,{match:t,index:r}}))).map((function(e){return{type:\"url\",urlInfo:e}})).concat(l.map((function(e){return{type:\"gradient\",gradientInfo:e}}))),h=function(e,r){var n,o=e.isDark,a=e.isLight,i=e.isTransparent,c=e.isLarge,u=e.isTooLarge,s=e.width;if(u)n='url(\"'.concat(e.src,'\")');else if(o&&i&&1===r.mode&&!c&&s>2){q(\"Inverting dark image \".concat(e.src));var l=wt(e,t(t({},r),{sepia:De(r.sepia+10,0,100)}));n='url(\"'.concat(l,'\")')}else if(a&&!i&&1===r.mode)if(c)n=\"none\";else{q(\"Dimming light image \".concat(e.src));var d=wt(e,r);n='url(\"'.concat(d,'\")')}else if(0===r.mode&&a&&!c){q(\"Applying filter to image \".concat(e.src));var f=wt(e,t(t({},r),{brightness:De(r.brightness-10,5,200),sepia:De(r.sepia+10,0,100)}));n='url(\"'.concat(f,'\")')}else n=null;return n},p=[],v=0;return f.forEach((function(t,c){var u=t.type,l=t.urlInfo,d=t.gradientInfo;if(\"url\"===u){var m=l.match,g=l.index,b=v,y=g+m.length;v=y,p.push((function(){return e.substring(b,g)})),p.push(function(e){var t;if(function(e,t){if(!e||0===t.length)return!1;if(t.some((function(e){return\"*\"===e})))return!0;for(var r=e.split(/,\\s*/g),n=function(e){var n=t[e];if(r.some((function(e){return e===n})))return{value:!0}},o=0;o0},e.prototype.addRulesForMatching=function(e){this.rulesQueue.push(e)},e.prototype.matchVariablesAndDependants=function(){var e=this;this.changedTypeVars.clear(),this.initialVarTypes=new Map(this.varTypes),this.collectRootVariables(),this.collectVariablesAndVarDep(this.rulesQueue),this.rulesQueue.splice(0),this.collectRootVarDependants(),this.varRefs.forEach((function(t,r){t.forEach((function(t){e.varTypes.has(r)&&e.resolveVariableType(t,e.varTypes.get(r))}))})),this.unknownColorVars.forEach((function(t){e.unknownBgVars.has(t)?(e.unknownColorVars.delete(t),e.unknownBgVars.delete(t),e.resolveVariableType(t,1)):e.isVarType(t,7)?e.unknownColorVars.delete(t):e.undefinedVars.add(t)})),this.unknownBgVars.forEach((function(t){null!=e.findVarRef(t,(function(t){return e.unknownColorVars.has(t)||e.isVarType(t,6)}))?e.itarateVarRefs(t,(function(t){e.resolveVariableType(t,1)})):e.isVarType(t,9)?e.unknownBgVars.delete(t):e.undefinedVars.add(t)})),this.changedTypeVars.forEach((function(t){e.typeChangeSubscriptions.has(t)&&e.typeChangeSubscriptions.get(t).forEach((function(e){e()}))})),this.changedTypeVars.clear()},e.prototype.getModifierForVariable=function(e){var t=this;return function(r){var n=e.varName,o=e.sourceValue,a=e.rule,i=e.ignoredImgSelectors,c=e.isCancelled,u=function(){var e=[],u=function(a,i,c){if(t.isVarType(n,a)){var u,s=i(n);if(er(o))if(tr(o)){var l=cr(o,t.unstableVarValues);l||(l=1===a?\"#ffffff\":\"#000000\"),u=c(l,r)}else u=Qt(o,(function(e){return i(e)}),(function(e){return c(e,r)}));else u=c(o,r);e.push({property:s,value:u})}};if(u(1,Kt,or),u(2,Jt,ar),u(4,Xt,ir),t.isVarType(n,8)){var s=Yt(n),l=o;er(o)&&(l=Qt(o,(function(e){return Kt(e)}),(function(e){return or(e,r)})));var d=It(l,a,i,c);l=\"function\"==typeof d?d(r):d,e.push({property:s,value:l})}return e},s=new Set;return{declarations:u(),onTypeChange:{addListener:function(e){var r=function(){var t=u();e(t)};s.add(r),t.subscribeForVarTypeChange(n,r)},removeListeners:function(){s.forEach((function(e){t.unsubscribeFromVariableTypeChanges(n,e)}))}}}}},e.prototype.getModifierForVarDependant=function(e,t){var r=this;if(t.match(/^\\s*(rgb|hsl)a?\\(/)){var n=e.startsWith(\"background\"),o=\"color\"===e||\"caret-color\"===e;return function(e){var a=cr(t,r.unstableVarValues);return a||(a=n?\"#ffffff\":\"#000000\"),(n?or:o?ar:ir)(a,e)}}return\"background-color\"===e?function(e){return Qt(t,(function(e){return Kt(e)}),(function(t){return or(t,e)}))}:\"color\"===e||\"caret-color\"===e?function(e){return Qt(t,(function(e){return Jt(e)}),(function(t){return ar(t,e)}))}:\"background\"===e||\"background-image\"===e||\"box-shadow\"===e?function(n){var o=new Set,a=function(){var a=Qt(t,(function(e){return r.isVarType(e,1)?Kt(e):r.isVarType(e,8)?Yt(e):(o.add(e),e)}),(function(e){return or(e,n)}));if(\"box-shadow\"===e){var i=Wt(a)(n);if(i.unparseableMatchesLength!==i.matchesLength)return i.result}return a},i=a();return o.size>0?new Promise((function(e){var t=o.values().next().value,n=function(){r.unsubscribeFromVariableTypeChanges(t,n);var o=a();e(o)};r.subscribeForVarTypeChange(t,n)})):i}:e.startsWith(\"border\")||e.startsWith(\"outline\")?function(e){return Qt(t,(function(e){return Xt(e)}),(function(t){return ir(t,e)}))}:null},e.prototype.subscribeForVarTypeChange=function(e,t){this.typeChangeSubscriptions.has(e)||this.typeChangeSubscriptions.set(e,new Set);var r=this.typeChangeSubscriptions.get(e);r.has(t)||r.add(t)},e.prototype.unsubscribeFromVariableTypeChanges=function(e,t){this.typeChangeSubscriptions.has(e)&&this.typeChangeSubscriptions.get(e).delete(t)},e.prototype.collectVariablesAndVarDep=function(e){var t=this;e.forEach((function(e){ue(e,(function(e){e.style&&de(e.style,(function(e,r){Zt(e)&&t.inspectVariable(e,r),er(r)&&t.inspectVarDependant(e,r)}))}))}))},e.prototype.collectRootVariables=function(){var e=this;de(document.documentElement.style,(function(t,r){Zt(t)&&e.inspectVariable(t,r)}))},e.prototype.inspectVariable=function(e,t){(this.unstableVarValues.set(e,t),er(t)&&tr(t)&&(this.unknownColorVars.add(e),this.definedVars.add(e)),this.definedVars.has(e))||(this.definedVars.add(e),Nt(t)?this.unknownColorVars.add(e):(t.includes(\"url(\")||t.includes(\"linear-gradient(\")||t.includes(\"radial-gradient(\"))&&this.resolveVariableType(e,8))},e.prototype.resolveVariableType=function(e,t){var r=this.initialVarTypes.get(e)||0,n=(this.varTypes.get(e)||0)|t;this.varTypes.set(e,n),(n!==r||this.undefinedVars.has(e))&&(this.changedTypeVars.add(e),this.undefinedVars.delete(e)),this.unknownColorVars.delete(e),this.unknownBgVars.delete(e)},e.prototype.collectRootVarDependants=function(){var e=this;de(document.documentElement.style,(function(t,r){er(r)&&e.inspectVarDependant(t,r)}))},e.prototype.inspectVarDependant=function(e,t){var r=this;Zt(e)?this.iterateVarDeps(t,(function(t){r.varRefs.has(e)||r.varRefs.set(e,new Set),r.varRefs.get(e).add(t)})):\"background-color\"===e||\"box-shadow\"===e?this.iterateVarDeps(t,(function(e){return r.resolveVariableType(e,1)})):\"color\"===e||\"caret-color\"===e?this.iterateVarDeps(t,(function(e){return r.resolveVariableType(e,2)})):e.startsWith(\"border\")||e.startsWith(\"outline\")?this.iterateVarDeps(t,(function(e){return r.resolveVariableType(e,4)})):\"background\"!==e&&\"background-image\"!==e||this.iterateVarDeps(t,(function(e){if(!r.isVarType(e,9)){var t=null!=r.findVarRef(e,(function(e){return r.unknownColorVars.has(e)||r.isVarType(e,6)}));r.itarateVarRefs(e,(function(e){t?r.resolveVariableType(e,1):r.unknownBgVars.add(e)}))}}))},e.prototype.iterateVarDeps=function(e,t){var r=new Set;!function(e,t){Qt(e,(function(e){return t(e),e}))}(e,(function(e){return r.add(e)})),r.forEach((function(e){return t(e)}))},e.prototype.findVarRef=function(e,t,r){var n,a;if(void 0===r&&(r=new Set),r.has(e))return null;if(r.add(e),t(e))return e;var i=this.varRefs.get(e);if(!i||0===i.size)return null;try{for(var c=o(i),u=c.next();!u.done;u=c.next()){var s=u.value,l=this.findVarRef(s,t,r);if(l)return l}}catch(e){n={error:e}}finally{try{u&&!u.done&&(a=c.return)&&a.call(c)}finally{if(n)throw n.error}}return null},e.prototype.itarateVarRefs=function(e,t){this.findVarRef(e,(function(e){return t(e),!1}))},e.prototype.setOnRootVariableChange=function(e){this.onRootVariableDefined=e},e.prototype.putRootVars=function(e,t){var r,n,i=this,c=e.sheet;c.cssRules.length>0&&c.deleteRule(0);var u=new Map;de(document.documentElement.style,(function(e,r){Zt(e)&&(i.isVarType(e,1)&&u.set(Kt(e),or(r,t)),i.isVarType(e,2)&&u.set(Jt(e),ar(r,t)),i.isVarType(e,4)&&u.set(Xt(e),ir(r,t)),i.subscribeForVarTypeChange(e,i.onRootVariableDefined))}));var s=[];s.push(\":root {\");try{for(var l=o(u),d=l.next();!d.done;d=l.next()){var f=a(d.value,2),h=f[0],p=f[1];s.push(\" \".concat(h,\": \").concat(p,\";\"))}}catch(e){r={error:e}}finally{try{d&&!d.done&&(n=l.return)&&n.call(l)}finally{if(r)throw r.error}}s.push(\"}\");var v=s.join(\"\\n\");c.insertRule(v)},e}());function zt(e,t){void 0===t&&(t=0);var r=e.indexOf(\"var(\",t);if(r>=0){var n=qe(e,r+3);return n?{start:r,end:n.end}:null}}function Ht(e,t){var r=function(e){for(var t,r=[],n=0;t=zt(e,n);){var o=t.start,a=t.end;r.push({start:o,end:a,value:e.substring(o,a)}),n=t.end+1}return r}(e),n=r.length;if(0===n)return e;var o=e.length,a=r.map((function(e){return t(e.value)})),i=[];i.push(e.substring(0,r[0].start));for(var c=0;c=0?(t=e.substring(4,n).trim(),r=e.substring(n+1,e.length-1).trim()):(t=e.substring(4,e.length-1).trim(),r=\"\"),{name:t,fallback:r}}function Qt(e,t,r){return Ht(e,(function(e){var n,o=Gt(e),a=o.name,i=o.fallback,c=t(a);return i?(n=er(i)?Qt(i,t,r):r?r(i):i,\"var(\".concat(c,\", \").concat(n,\")\")):\"var(\".concat(c,\")\")}))}function Kt(e){return\"--darkreader-bg\".concat(e)}function Jt(e){return\"--darkreader-text\".concat(e)}function Xt(e){return\"--darkreader-border\".concat(e)}function Yt(e){return\"--darkreader-bgimg\".concat(e)}function Zt(e){return e.startsWith(\"--\")}function er(e){return e.includes(\"var(\")}function tr(e){return e.match(/^\\s*(rgb|hsl)a?\\(/)}var rr=/^\\d{1,3}, ?\\d{1,3}, ?\\d{1,3}$/;function nr(e,t,r){var n=function(e){if(rr.test(e)){var t=e.split(\",\"),r=\"rgb(\";return t.forEach((function(e){r+=\"\".concat(e.trim(),\", \")})),r=r.substr(0,r.length-2),{isRaw:!0,color:r+=\")\"}}return{isRaw:!1,color:e}}(e),o=n.isRaw,a=n.color,i=Nt(a);if(i){var c=r(i,t);if(o){var u=Nt(c);return u?\"\".concat(u.r,\", \").concat(u.g,\", \").concat(u.b):c}return c}return a}function or(e,t){return nr(e,t,et)}function ar(e,t){return nr(e,t,at)}function ir(e,t){return nr(e,t,ct)}function cr(e,t,r){void 0===r&&(r=new Set);var n=!1,o=Ht(e,(function(e){var o=Gt(e),a=o.name,i=o.fallback;if(r.has(a))return n=!0,null;r.add(a);var c=t.get(a)||i,u=null;return c&&(u=er(c)?cr(c,t,r):c),u||(n=!0,null)}));return n?null:o}var ur={\"background-color\":{customProp:\"--darkreader-inline-bgcolor\",cssProp:\"background-color\",dataAttr:\"data-darkreader-inline-bgcolor\"},\"background-image\":{customProp:\"--darkreader-inline-bgimage\",cssProp:\"background-image\",dataAttr:\"data-darkreader-inline-bgimage\"},\"border-color\":{customProp:\"--darkreader-inline-border\",cssProp:\"border-color\",dataAttr:\"data-darkreader-inline-border\"},\"border-bottom-color\":{customProp:\"--darkreader-inline-border-bottom\",cssProp:\"border-bottom-color\",dataAttr:\"data-darkreader-inline-border-bottom\"},\"border-left-color\":{customProp:\"--darkreader-inline-border-left\",cssProp:\"border-left-color\",dataAttr:\"data-darkreader-inline-border-left\"},\"border-right-color\":{customProp:\"--darkreader-inline-border-right\",cssProp:\"border-right-color\",dataAttr:\"data-darkreader-inline-border-right\"},\"border-top-color\":{customProp:\"--darkreader-inline-border-top\",cssProp:\"border-top-color\",dataAttr:\"data-darkreader-inline-border-top\"},\"box-shadow\":{customProp:\"--darkreader-inline-boxshadow\",cssProp:\"box-shadow\",dataAttr:\"data-darkreader-inline-boxshadow\"},color:{customProp:\"--darkreader-inline-color\",cssProp:\"color\",dataAttr:\"data-darkreader-inline-color\"},fill:{customProp:\"--darkreader-inline-fill\",cssProp:\"fill\",dataAttr:\"data-darkreader-inline-fill\"},stroke:{customProp:\"--darkreader-inline-stroke\",cssProp:\"stroke\",dataAttr:\"data-darkreader-inline-stroke\"},\"outline-color\":{customProp:\"--darkreader-inline-outline\",cssProp:\"outline-color\",dataAttr:\"data-darkreader-inline-outline\"},\"stop-color\":{customProp:\"--darkreader-inline-stopcolor\",cssProp:\"stop-color\",dataAttr:\"data-darkreader-inline-stopcolor\"}},sr=Object.values(ur),lr={};sr.forEach((function(e){var t=e.cssProp,r=e.customProp;return lr[r]=t}));var dr=[\"style\",\"fill\",\"stop-color\",\"stroke\",\"bgcolor\",\"color\"],fr=dr.map((function(e){return\"[\".concat(e,\"]\")})).join(\", \");function hr(){return sr.map((function(e){var t=e.dataAttr,r=e.customProp,n=e.cssProp;return[\"[\".concat(t,\"] {\"),\" \".concat(n,\": var(\").concat(r,\") !important;\"),\"}\"].join(\"\\n\")})).join(\"\\n\")}var pr=new Map,vr=new Map;function mr(e,t,r){pr.has(e)&&(pr.get(e).disconnect(),vr.get(e).disconnect());var n=new WeakSet;function o(e){(function(e){var t=[];return e instanceof Element&&e.matches(fr)&&t.push(e),(e instanceof Element||b&&e instanceof ShadowRoot||e instanceof Document)&&N(t,e.querySelectorAll(fr)),t})(e).forEach((function(e){n.has(e)||(n.add(e),t(e))})),z(e,(function(o){n.has(e)||(n.add(e),r(o.shadowRoot),mr(o.shadowRoot,t,r))}))}var c=ne(e,{onMinorMutations:function(e){e.additions.forEach((function(e){return o(e)}))},onHugeMutations:function(){o(e)}});pr.set(e,c);var u=0,s=null,l=W({seconds:10}),d=W({seconds:2}),f=[],h=null,p=I((function(e){e.forEach((function(e){dr.includes(e.attributeName)&&t(e.target)}))})),v=new MutationObserver((function(e){if(h)f.push.apply(f,i([],a(e),!1));else{u++;var t=Date.now();if(null==s)s=t;else if(u>=50){if(t-s0&&function(e,t){for(var r=0,n=t.length;r32||n>32?\"background-color\":\"color\",a)};J()?i():Y(i)}}e.hasAttribute(\"stop-color\")&&u(\"stop-color\",\"background-color\",e.getAttribute(\"stop-color\"))}if(e.hasAttribute(\"stroke\")){var c=e.getAttribute(\"stroke\");u(\"stroke\",e instanceof SVGLineElement||e instanceof SVGTextElement?\"border-color\":\"color\",c)}e.style&&de(e.style,(function(t,r){if(\"background-image\"!==t||!r.includes(\"url\"))if(ur.hasOwnProperty(t)||t.startsWith(\"--\")&&!lr[t])u(t,t,r);else{var n=lr[t];if(n&&!e.style.getPropertyValue(n)&&!e.hasAttribute(n)){if(\"background-color\"===n&&e.hasAttribute(\"bgcolor\"))return;e.style.setProperty(t,\"\")}}})),e.style&&e instanceof SVGTextElement&&e.style.fill&&u(\"fill\",\"color\",e.style.getPropertyValue(\"fill\")),F(o,(function(t){e.removeAttribute(ur[t].dataAttr)})),gr.set(e,yr(e,t))}}function u(r,a,i){var c=r.startsWith(\"--\"),u=c?{}:ur[r],s=u.customProp,l=u.dataAttr,d=Mt(a,i,{},$t,n,null);if(d){var f=d.value;if(\"function\"==typeof f&&(f=f(t)),c&&\"object\"==typeof f)f.declarations.forEach((function(t){var r=t.property,n=t.value;!(n instanceof Promise)&&e.style.setProperty(r,n)}));else e.style.setProperty(s,f),e.hasAttribute(l)||e.setAttribute(l,\"\"),o.delete(r)}}}var Sr=\"theme-color\",wr='meta[name=\"'.concat(Sr,'\"]'),_r=null,Er=null;function xr(e,t){_r=_r||e.content;try{var r=xe(_r);e.content=et(r,t)}catch(e){B(e)}}var Cr=[\"mode\",\"brightness\",\"contrast\",\"grayscale\",\"sepia\",\"darkSchemeBackgroundColor\",\"darkSchemeTextColor\",\"lightSchemeBackgroundColor\",\"lightSchemeTextColor\"];var Vr=function(){var e=[],t=null;function r(){for(var r;r=e.shift();)r();t=null}return{add:function(n){e.push(n),t||(t=requestAnimationFrame(r))},cancel:function(){e.splice(0),cancelAnimationFrame(t),t=null}}}();function Rr(){var e=0,t=new Set,r=new Map,n=new Set,o=null,c=!1,u=!1;return{modifySheet:function(s){var l=s.sourceCSSRules,d=s.theme,f=s.ignoreImageAnalysis,h=s.force,p=s.prepareSheet,v=s.isAsyncCancelled,m=0===r.size,g=new Set(r.keys()),b=function(e){var t=\"\";return Cr.forEach((function(r){t+=\"\".concat(r,\":\").concat(e[r],\";\")})),t}(d),y=b!==o;c&&(u=!0);var k=[];if(ue(l,(function(e){var n=e.cssText,o=!1;if(g.delete(n),e.parentRule instanceof CSSMediaRule&&(n+=\";\".concat(e.parentRule.media.mediaText)),t.has(n)||(t.add(n),o=!0),o){m=!0;var a=[];e.style&&de(e.style,(function(t,r){var n=Mt(t,r,e,$t,f,v);n&&a.push(n)}));var i=null;if(a.length>0){var c=e.parentRule;i={selector:e.selectorText,declarations:a,parentRule:c},k.push(i)}r.set(n,i)}else k.push(r.get(n))}),(function(){c=!0})),g.forEach((function(e){t.delete(e),r.delete(e)})),o=b,h||m||y){e++;var S=new Map,w=new Map,_=0,E=0,x={rule:null,rules:[],isGroup:!0},C=new WeakMap;n.forEach((function(e){return e()})),n.clear(),k.filter((function(e){return e})).forEach((function(t){var r=t.selector,o=t.declarations,c=T(t.parentRule),u={selector:r,declarations:[],isGroup:!1},s=u.declarations;function l(t,r,n,o){var a=++_,i={property:t,value:null,important:n,asyncKey:a,sourceValue:o};s.push(i);var c=e;r.then((function(t){t&&!v()&&c===e&&(i.value=t,Vr.add((function(){v()||c!==e||function(e){var t=S.get(e),r=t.rule,n=t.target,o=t.index;n.deleteRule(o),R(n,o,r),S.delete(e)}(a)})))}))}function f(t,r,o,c){var u=r,d=u.declarations,f=u.onTypeChange,h=++E,p=e,m=s.length,g=[];if(0===d.length){var b={property:t,value:c,important:o,sourceValue:c,varKey:h};s.push(b),g=[b]}d.forEach((function(e){if(e.value instanceof Promise)l(e.property,e.value,o,c);else{var t={property:e.property,value:e.value,important:o,sourceValue:c,varKey:h};s.push(t),g.push(t)}})),f.addListener((function(t){if(!v()&&p===e){var r=t.map((function(e){return{property:e.property,value:e.value,important:o,sourceValue:c,varKey:h}})),n=s.indexOf(g[0],m);s.splice.apply(s,i([n,g.length],a(r),!1)),g=r,function(e){var t=w.get(e),r=t.rule,n=t.target,o=t.index;n.deleteRule(o),R(n,o,r)}(h)}})),n.add((function(){return f.removeListeners()}))}c.rules.push(u),o.forEach((function(e){var t=e.property,r=e.value,n=e.important,o=e.sourceValue;if(\"function\"==typeof r){var a=r(d);a instanceof Promise?l(t,a,n,o):t.startsWith(\"--\")?f(t,a,n,o):s.push({property:t,value:a,important:n,sourceValue:o})}else s.push({property:t,value:r,important:n,sourceValue:o})}))}));var V=p();!function e(t,r,n){t.rules.forEach((function(t){if(t.isGroup){var o=function(e,t){var r=e.rule;if(r instanceof CSSMediaRule){var n=r.media,o=t.cssRules.length;return t.insertRule(\"@media \".concat(n.mediaText,\" {}\"),o),t.cssRules[o]}return t}(t,r);e(t,o,n)}else n(t,r)}))}(x,V,(function(e,t){var r=t.cssRules.length;e.declarations.forEach((function(n){var o=n.asyncKey,a=n.varKey;null!=o&&S.set(o,{rule:e,target:t,index:r}),null!=a&&w.set(a,{rule:e,target:t,index:r})})),R(t,r,e)}))}function R(e,t,r){var n=r.selector,o=r.declarations,a=\"\";o.forEach((function(e){var t,r,n,o,i;a+=\"\".concat((r=(t=e).property,n=t.value,o=t.important,i=t.sourceValue,\"\".concat(r,\": \").concat(null==n?i:n).concat(o?\" !important\":\"\",\";\")),\" \")}));var i=\"\".concat(n,\" { \").concat(a,\" }\");e.insertRule(i,t)}function T(e){if(null==e)return x;if(C.has(e))return C.get(e);var t={rule:e,rules:[],isGroup:!0};return C.set(e,t),T(e.parentRule).rules.push(t),t}},shouldRebuildStyle:function(){return c&&!u}}}function Tr(e){return(e instanceof HTMLStyleElement||e instanceof SVGStyleElement||e instanceof HTMLLinkElement&&e.rel&&e.rel.toLowerCase().includes(\"stylesheet\")&&!e.disabled&&(!h||!e.href.startsWith(\"moz-extension://\")))&&!e.classList.contains(\"darkreader\")&&\"print\"!==e.media.toLowerCase()&&!e.classList.contains(\"stylus\")}function Mr(e,t,r){return void 0===t&&(t=[]),void 0===r&&(r=!0),Tr(e)?t.push(e):(e instanceof Element||b&&e instanceof ShadowRoot||e===document)&&(F(e.querySelectorAll('style, link[rel*=\"stylesheet\" i]:not([disabled])'),(function(e){return Mr(e,t,!1)})),r&&z(e,(function(e){return Mr(e.shadowRoot,t,!1)}))),t}var Ar=new WeakSet,Lr=new WeakSet,Pr=!1;document.addEventListener(\"__darkreader__inlineScriptsAllowed\",(function(){Pr=!0}));var Or=0,jr=new Map;function Dr(e,t){for(var o=t.update,i=t.loadingStart,c=t.loadingEnd,u=[],s=e;(s=s.nextElementSibling)&&s.matches(\".darkreader\");)u.push(s);var l=u.find((function(e){return e.matches(\".darkreader--cors\")&&!Lr.has(e)}))||null,d=u.find((function(e){return e.matches(\".darkreader--sync\")&&!Ar.has(e)}))||null,h=null,v=null,m=!1,g=!0,b=Rr(),y=new MutationObserver((function(){o()})),k={attributes:!0,childList:!0,subtree:!0,characterData:!0};function S(){return e instanceof HTMLStyleElement&&e.textContent.trim().match(he)}function w(e,t){var r=!1;if(e){var n=void 0;e:for(var o=0,a=e.length;o=0;t--)e.deleteRule(t)}(d.sheet),v?v.run():v=$(d,\"prev-sibling\",(function(){T=!0,i()})),d.sheet}function i(){var e=T;T=!1,b.modifySheet({prepareSheet:a,sourceCSSRules:n,theme:t,ignoreImageAnalysis:r,force:e,isAsyncCancelled:function(){return m}}),g=0===d.sheet.cssRules.length,b.shouldRebuildStyle()&&Y((function(){return o()}))}n&&(m=!1,i())},pause:W,destroy:function(){if(W(),U(l),U(d),c(),jr.has(V)){var e=jr.get(V);jr.delete(V),e&&e()}},watch:function(){y.observe(e,k),e instanceof HTMLStyleElement&&L()},restore:function(){d&&(++z>10?B(\"Style sheet was moved multiple times\",e):(B(\"Restore style\",d,e),E(),h&&h.skip(),v&&v.skip(),g||(T=!0,o())))}}}function Fr(e,t){return r(this,void 0,void 0,(function(){return n(this,(function(r){return[2,new Promise((function(r,n){var o=function(){e.removeEventListener(\"load\",a),e.removeEventListener(\"error\",i),jr.delete(t)},a=function(){o(),q(\"Linkelement \".concat(t,\" has been loaded\")),r()},i=function(){o(),n(\"Linkelement \".concat(t,\" couldn't be loaded. \").concat(e.href))};jr.set(t,(function(){o(),n()})),e.addEventListener(\"load\",a),e.addEventListener(\"error\",i),e.href||i()}))]}))}))}function Nr(e){return r(this,void 0,void 0,(function(){return n(this,(function(t){switch(t.label){case 0:return e.startsWith(\"data:\")?[4,fetch(e)]:[3,3];case 1:return[4,t.sent().text()];case 2:case 4:return[2,t.sent()];case 3:return[4,ht({url:e,responseType:\"text\",mimeType:\"text/css\",origin:window.location.origin})]}}))}))}function qr(e,t,a){return void 0===a&&(a=new Map),r(this,void 0,void 0,(function(){var r,i,c,u,s,l,d,f,h,p;return n(this,(function(n){switch(n.label){case 0:e=function(e,t){return e.replace(fe,(function(e){var r=pe(e);try{return'url(\"'.concat(ce(t,r),'\")')}catch(t){return B(\"Not able to replace relative URL with Absolute URL, skipping\"),e}}))}(e=function(e){return e.replace(ge,\"\")}(e=e.replace(me,\"\")),t),r=Ne(he,e),n.label=1;case 1:n.trys.push([1,10,11,12]),i=o(r),c=i.next(),n.label=2;case 2:return c.done?[3,9]:(u=c.value,s=pe(u.substring(7).trim().replace(/;$/,\"\").replace(/screen$/,\"\")),l=ce(t,s),d=void 0,a.has(l)?(d=a.get(l),[3,7]):[3,3]);case 3:return n.trys.push([3,6,,7]),[4,Nr(l)];case 4:return d=n.sent(),a.set(l,d),[4,qr(d,ve(l),a)];case 5:return d=n.sent(),[3,7];case 6:return B(n.sent()),d=\"\",[3,7];case 7:e=e.split(u).join(d),n.label=8;case 8:return c=i.next(),[3,2];case 9:return[3,12];case 10:return f=n.sent(),h={error:f},[3,12];case 11:try{c&&!c.done&&(p=i.return)&&p.call(i)}finally{if(h)throw h.error}return[7];case 12:return[2,e=e.trim()]}}))}))}var Br,Ir,Wr=[],Ur=new Map;function $r(e){k&&F(e.querySelectorAll(\":not(:defined)\"),(function(e){var t=e.tagName.toLowerCase();if(!t.includes(\"-\")){var o=e.getAttribute(\"is\");if(!o)return;t=o}Ur.has(t)||(Ur.set(t,new Set),function(e){return r(this,void 0,void 0,(function(){return n(this,(function(t){return[2,new Promise((function(t){if(window.customElements&&\"function\"==typeof customElements.whenDefined)customElements.whenDefined(e).then((function(){return t()}));else if(zr)Hr.set(e,t),document.dispatchEvent(new CustomEvent(\"__darkreader__addUndefinedResolver\",{detail:{tag:e}}));else{var r=function(){var n=Ur.get(e);n&&n.size>0&&(n.values().next().value.matches(\":defined\")?t():requestAnimationFrame(r))};requestAnimationFrame(r)}}))]}))}))}(t).then((function(){if(Ir){var e=Ur.get(t);Ur.delete(t),Ir(Array.from(e))}}))),Ur.get(t).add(e)}))}var zr=!1;document.addEventListener(\"__darkreader__inlineScriptsAllowed\",(function(){zr=!0}));var Hr=new Map;function Gr(e){(zr=!0,Hr.has(e.detail.tag))&&Hr.get(e.detail.tag)()}function Qr(e,t,r){Kr();var n=new Set(e),o=new WeakMap,a=new WeakMap;function i(e){o.set(e,e.previousElementSibling),a.set(e,e.nextElementSibling)}function c(e){var r=e.createdStyles,c=e.removedStyles,u=e.movedStyles;r.forEach((function(e){return i(e)})),u.forEach((function(e){return i(e)})),c.forEach((function(e){return t=e,o.delete(t),void a.delete(t);var t})),r.forEach((function(e){return n.add(e)})),c.forEach((function(e){return n.delete(e)})),r.size+c.size+u.size>0&&t({created:Array.from(r),removed:Array.from(c),moved:Array.from(u),updated:[]})}function u(e){var t=e.additions,r=e.moves,n=e.deletions,o=new Set,a=new Set,i=new Set;t.forEach((function(e){return Mr(e).forEach((function(e){return o.add(e)}))})),n.forEach((function(e){return Mr(e).forEach((function(e){return a.add(e)}))})),r.forEach((function(e){return Mr(e).forEach((function(e){return i.add(e)}))})),c({createdStyles:o,removedStyles:a,movedStyles:i}),t.forEach((function(e){z(e,f),$r(e)}))}function s(e){var t=new Set(Mr(e)),r=new Set,i=new Set,u=new Set;t.forEach((function(e){n.has(e)||r.add(e)})),n.forEach((function(e){t.has(e)||i.add(e)})),t.forEach((function(e){var t;r.has(e)||i.has(e)||(t=e).previousElementSibling===o.get(t)&&t.nextElementSibling===a.get(t)||u.add(e)})),c({createdStyles:r,removedStyles:i,movedStyles:u}),z(e,f),$r(e)}function l(e){var r=new Set,n=new Set;e.forEach((function(e){var t=e.target;t.isConnected&&(Tr(t)?r.add(t):t instanceof HTMLLinkElement&&t.disabled&&n.add(t))})),r.size+n.size>0&&t({updated:Array.from(r),created:[],removed:Array.from(n),moved:[]})}function d(e){var t=ne(e,{onMinorMutations:u,onHugeMutations:s}),r=new MutationObserver(l);r.observe(e,{attributes:!0,attributeFilter:[\"rel\",\"disabled\",\"media\"],subtree:!0}),Wr.push(t,r),Br.add(e)}function f(e){var t=e.shadowRoot;null==t||Br.has(t)||(d(t),r(t))}e.forEach(i),d(document),z(document.documentElement,f),Ir=function(e){var r=[];e.forEach((function(e){return N(r,Mr(e.shadowRoot))})),t({created:r,updated:[],removed:[],moved:[]}),e.forEach((function(e){var t=e.shadowRoot;null!=t&&(f(e),z(t,f),$r(t))}))},document.addEventListener(\"__darkreader__isDefined\",Gr),$r(document)}function Kr(){Wr.forEach((function(e){return e.disconnect()})),Wr.splice(0,Wr.length),Br=new WeakSet,Ir=null,Ur.clear(),document.removeEventListener(\"__darkreader__isDefined\",Gr)}var Jr=new WeakMap,Xr=new WeakSet;function Yr(e){var t=!1;return{render:function(r,n){e.adoptedStyleSheets.forEach((function(o){if(!Xr.has(o)){var c=o.rules,u=new CSSStyleSheet;Rr().modifySheet({prepareSheet:function(){for(var t=u.cssRules.length-1;t>=0;t--)u.deleteRule(t);return function(t,r){var n=i([],a(e.adoptedStyleSheets),!1),o=n.indexOf(t),c=n.indexOf(r);o!==c-1&&(c>=0&&n.splice(c,1),n.splice(o+1,0,r),e.adoptedStyleSheets=n)}(o,u),Jr.set(o,u),Xr.add(u),u},sourceCSSRules:c,theme:r,ignoreImageAnalysis:n,force:!1,isAsyncCancelled:function(){return t}})}}))},destroy:function(){t=!0;var r=i([],a(e.adoptedStyleSheets),!1);e.adoptedStyleSheets.forEach((function(e){if(Xr.has(e)){var t=r.indexOf(e);t>=0&&r.splice(t,1),Jr.delete(e),Xr.delete(e)}})),e.adoptedStyleSheets=r}}}function Zr(e){document.dispatchEvent(new CustomEvent(\"__darkreader__inlineScriptsAllowed\"));var t=Object.getOwnPropertyDescriptor(CSSStyleSheet.prototype,\"addRule\"),r=Object.getOwnPropertyDescriptor(CSSStyleSheet.prototype,\"insertRule\"),n=Object.getOwnPropertyDescriptor(CSSStyleSheet.prototype,\"deleteRule\"),o=Object.getOwnPropertyDescriptor(CSSStyleSheet.prototype,\"removeRule\"),c=e?Object.getOwnPropertyDescriptor(Document.prototype,\"styleSheets\"):null,u=location.hostname.endsWith(\"baidu.com\"),s=u?Object.getOwnPropertyDescriptor(Element.prototype,\"getElementsByTagName\"):null,l=function(){Object.defineProperty(CSSStyleSheet.prototype,\"addRule\",t),Object.defineProperty(CSSStyleSheet.prototype,\"insertRule\",r),Object.defineProperty(CSSStyleSheet.prototype,\"deleteRule\",n),Object.defineProperty(CSSStyleSheet.prototype,\"removeRule\",o),document.removeEventListener(\"__darkreader__cleanUp\",l),document.removeEventListener(\"__darkreader__addUndefinedResolver\",d),e&&Object.defineProperty(Document.prototype,\"styleSheets\",c),u&&Object.defineProperty(Element.prototype,\"getElementsByTagName\",s)},d=function(e){customElements.whenDefined(e.detail.tag).then((function(){document.dispatchEvent(new CustomEvent(\"__darkreader__isDefined\",{detail:{tag:e.detail.tag}}))}))};document.addEventListener(\"__darkreader__cleanUp\",l),document.addEventListener(\"__darkreader__addUndefinedResolver\",d);var f=new Event(\"__darkreader__updateSheet\");Object.defineProperty(CSSStyleSheet.prototype,\"addRule\",Object.assign({},t,{value:function(e,r,n){return t.value.call(this,e,r,n),this.ownerNode&&!this.ownerNode.classList.contains(\"darkreader\")&&this.ownerNode.dispatchEvent(f),-1}})),Object.defineProperty(CSSStyleSheet.prototype,\"insertRule\",Object.assign({},r,{value:function(e,t){var n=r.value.call(this,e,t);return this.ownerNode&&!this.ownerNode.classList.contains(\"darkreader\")&&this.ownerNode.dispatchEvent(f),n}})),Object.defineProperty(CSSStyleSheet.prototype,\"deleteRule\",Object.assign({},n,{value:function(e){n.value.call(this,e),this.ownerNode&&!this.ownerNode.classList.contains(\"darkreader\")&&this.ownerNode.dispatchEvent(f)}})),Object.defineProperty(CSSStyleSheet.prototype,\"removeRule\",Object.assign({},o,{value:function(e){o.value.call(this,e),this.ownerNode&&!this.ownerNode.classList.contains(\"darkreader\")&&this.ownerNode.dispatchEvent(f)}})),e&&Object.defineProperty(Document.prototype,\"styleSheets\",Object.assign({},c,{get:function(){var e=this,t=function(){var t=c.get.call(e);return Object.setPrototypeOf(i([],a(t),!1).filter((function(e){return!e.ownerNode.classList.contains(\"darkreader\")})),StyleSheetList.prototype)},r=t();return new Proxy(r,{get:function(e,r){return t()[r]}})}})),u&&Object.defineProperty(Element.prototype,\"getElementsByTagName\",Object.assign({},s,{value:function(e){var t=this;if(\"style\"!==e)return s.value.call(this,e);var r=function(){var r=s.value.call(t,e);return Object.setPrototypeOf(i([],a(r),!1).filter((function(e){return!e.classList.contains(\"darkreader\")})),NodeList.prototype)},n=r();return new Proxy(n,{get:function(e,t){return r()[Number(t)]}})}}))}var en=function(){if(\"randomUUID\"in crypto){var e=crypto.randomUUID();return e.substring(0,8)+e.substring(9,13)+e.substring(14,18)+e.substring(19,23)+e.substring(24)}return Array.from(crypto.getRandomValues(new Uint8Array(16))).map((function(e){return((t=e)<16?\"0\":\"\")+t.toString(16);var t})).join(\"\")}(),tn=new Map,rn=[],nn=null,on=null,an=null,cn=null,un=null;function sn(e,t){void 0===t&&(t=document.head||document);var r=t.querySelector(\".\".concat(e));return r||((r=document.createElement(\"style\")).classList.add(\"darkreader\"),r.classList.add(e),r.media=\"screen\",r.textContent=\"\"),r}var ln=new Map;function dn(e,t){ln.has(t)&&ln.get(t).stop(),ln.set(t,$(e,\"parent\"))}function fn(){var e=sn(\"darkreader--fallback\",document);e.textContent=Ot(nn,{strict:!0}),document.head.insertBefore(e,document.head.firstChild),dn(e,\"fallback\");var r=sn(\"darkreader--user-agent\");r.textContent=Lt(nn,an,nn.styleSystemControls),document.head.insertBefore(r,e.nextSibling),dn(r,\"user-agent\");var n,o,a=sn(\"darkreader--text\");nn.useFont||nn.textStroke>0?a.textContent=(n=nn,(o=[]).push('*:not(pre, pre *, code, .far, .fa, .glyphicon, [class*=\"vjs-\"], .fab, .fa-github, .fas, .material-icons, .icofont, .typcn, mu, [class*=\"mu-\"], .glyphicon, .icon) {'),n.useFont&&n.fontFamily&&o.push(\" font-family: \".concat(n.fontFamily,\" !important;\")),n.textStroke>0&&(o.push(\" -webkit-text-stroke: \".concat(n.textStroke,\"px !important;\")),o.push(\" text-stroke: \".concat(n.textStroke,\"px !important;\"))),o.push(\"}\"),o.join(\"\\n\")):a.textContent=\"\",document.head.insertBefore(a,e.nextSibling),dn(a,\"text\");var i=sn(\"darkreader--invert\"),c=\"\";on&&Array.isArray(on.invert)&&on.invert.length>0&&(c+=[\"\".concat(on.invert.join(\", \"),\" {\"),\" filter: \".concat(st(t(t({},nn),{contrast:0===nn.mode?nn.contrast:De(nn.contrast-10,0,100)})),\" !important;\"),\"}\",\"\"].join(\"\\n\"));var u=st(t(t({},nn),{mode:tt.light}));u&&(c+=\"img { filter: \".concat(u,\" !important;\\n\")),i.textContent=c,document.head.insertBefore(i,a.nextSibling),dn(i,\"invert\");var s=sn(\"darkreader--inline\");s.textContent=hr(),document.head.insertBefore(s,i.nextSibling),dn(s,\"inline\");var l=sn(\"darkreader--override\");l.textContent=on&&on.css?vn(on.css):\"\",document.head.appendChild(l),dn(l,\"override\");var d=sn(\"darkreader--variables\"),f=Pt(nn),h=nn.darkSchemeBackgroundColor,p=nn.darkSchemeTextColor,v=nn.lightSchemeBackgroundColor,m=nn.lightSchemeTextColor,g=nn.mode,b=0===g?v:h,y=0===g?m:p;b=et(xe(b),nn),y=at(xe(y),nn),d.textContent=[\":root {\",\" --darkreader-neutral-background: \".concat(b,\";\"),\" --darkreader-neutral-text: \".concat(y,\";\"),\" --darkreader-selection-background: \".concat(f.backgroundColorSelection,\";\"),\" --darkreader-selection-text: \".concat(f.foregroundColorSelection,\";\"),\"}\"].join(\"\\n\"),document.head.insertBefore(d,s.nextSibling),dn(d,\"variables\");var k=sn(\"darkreader--root-vars\");document.head.insertBefore(k,d.nextSibling);var S=function(e,t){void 0===t&&(t=document.head||document);var r=t.querySelector(\".\".concat(e));return r||((r=document.createElement(\"script\")).classList.add(\"darkreader\"),r.classList.add(e)),r}(\"darkreader--proxy\");S.append(\"(\".concat(Zr,\")(!\").concat(on&&on.disableStyleSheetsProxy,\")\")),document.head.insertBefore(S,k.nextSibling),S.remove()}var hn=new Set;function pn(e){var r=sn(\"darkreader--inline\",e);r.textContent=hr(),e.insertBefore(r,e.firstChild);var n=sn(\"darkreader--override\",e);n.textContent=on&&on.css?vn(on.css):\"\",e.insertBefore(n,r.nextSibling);var o=sn(\"darkreader--invert\",e);on&&Array.isArray(on.invert)&&on.invert.length>0?o.textContent=[\"\".concat(on.invert.join(\", \"),\" {\"),\" filter: \".concat(st(t(t({},nn),{contrast:0===nn.mode?nn.contrast:De(nn.contrast-10,0,100)})),\" !important;\"),\"}\"].join(\"\\n\"):o.textContent=\"\",e.insertBefore(o,n.nextSibling),hn.add(e)}function vn(e){return e.replace(/\\${(.+?)}/g,(function(e,t){var r=Nt(t);return r?Ke(r,nn,Je):(B(\"Couldn't parse CSSTemplate's color.\"),t)}))}function mn(){var e=document.querySelector(\".darkreader--fallback\");e&&(e.textContent=\"\")}var gn=0,bn=new Set;function yn(e){var t=++gn;q(\"New manager for element, with loadingStyleID \".concat(t),e);var r=Dr(e,{update:function(){var e=r.details({secondRound:!0});e&&($t.addRulesForMatching(e.rules),$t.matchVariablesAndDependants(),r.render(nn,cn))},loadingStart:function(){if(!H()||!xn){bn.add(t),q(\"Current amount of styles loading: \".concat(bn.size));var e=document.querySelector(\".darkreader--fallback\");e.textContent||(e.textContent=Ot(nn,{strict:!1}))}},loadingEnd:function(){bn.delete(t),q(\"Removed loadingStyle \".concat(t,\", now awaiting: \").concat(bn.size)),q(\"To-do to be loaded\",bn),0===bn.size&&H()&&mn()}});return tn.set(e,r),r}function kn(e){var t=tn.get(e);t&&(t.destroy(),tn.delete(e))}var Sn=I((function(e){tn.forEach((function(e){return e.render(nn,cn)})),rn.forEach((function(e){return e.render(nn,cn)})),e&&e()})),wn=function(){Sn.cancel()};function _n(){0!==bn.size?B(\"DOM is ready, but still have styles being loaded.\",bn):mn()}var En=null,xn=!document.hidden;function Cn(){document.removeEventListener(\"visibilitychange\",En),En=null}function Vn(){function e(){var e,t;!function(){wn();var e=Mr(document).filter((function(e){return!tn.has(e)})).map((function(e){return yn(e)}));e.map((function(e){return e.details({secondRound:!1})})).filter((function(e){return e&&e.rules.length>0})).forEach((function(e){$t.addRulesForMatching(e.rules)})),$t.matchVariablesAndDependants(),$t.setOnRootVariableChange((function(){$t.putRootVars(document.head.querySelector(\".darkreader--root-vars\"),nn)})),$t.putRootVars(document.head.querySelector(\".darkreader--root-vars\"),nn),tn.forEach((function(e){return e.render(nn,cn)})),0===bn.size&&mn(),e.forEach((function(e){return e.watch()}));var t=function(e){for(var t=[],r=0,n=e.length;r0&&N(t,r)})),t.forEach((function(e){return kr(e,nn,un,cn)})),Rn(document)}(),Qr(Array.from(tn.keys()),(function(e){var t=e.created,r=e.updated,n=e.removed,o=e.moved,a=n,i=t.concat(r).concat(o).filter((function(e){return!tn.has(e)})),c=o.filter((function(e){return tn.has(e)}));q(\"Styles to be removed:\",a),a.forEach((function(e){return kn(e)}));var u=i.map((function(e){return yn(e)}));u.map((function(e){return e.details({secondRound:!1})})).filter((function(e){return e&&e.rules.length>0})).forEach((function(e){$t.addRulesForMatching(e.rules)})),$t.matchVariablesAndDependants(),u.forEach((function(e){return e.render(nn,cn)})),u.forEach((function(e){return e.watch()})),c.forEach((function(e){return tn.get(e).restore()}))}),(function(e){pn(e),Rn(e)})),e=function(e){kr(e,nn,un,cn),e===document.documentElement&&(e.getAttribute(\"style\")||\"\").includes(\"--\")&&($t.matchVariablesAndDependants(),$t.putRootVars(document.head.querySelector(\".darkreader--root-vars\"),nn))},t=function(e){pn(e);var t=e.querySelectorAll(fr);t.length>0&&F(t,(function(e){return kr(e,nn,un,cn)}))},mr(document,e,t),z(document.documentElement,(function(r){mr(r.shadowRoot,e,t)})),Q(_n)}var t,r,n,o;fn(),document.hidden?(t=e,r=Boolean(En),En=function(){document.hidden||(Cn(),t(),xn=!0)},r||document.addEventListener(\"visibilitychange\",En)):e(),n=nn,(o=document.querySelector(wr))?xr(o,n):(Er&&Er.disconnect(),(Er=new MutationObserver((function(e){e:for(var t=0;t0){var t=Yr(e);rn.push(t),t.render(nn,cn)}}function Tn(){tn.forEach((function(e){return e.pause()})),F(ln.values(),(function(e){return e.stop()})),ln.clear(),Kr(),pr.forEach((function(e){return e.disconnect()})),vr.forEach((function(e){return e.disconnect()})),pr.clear(),vr.clear(),K(_n),X.clear()}function Mn(){var e,t=document.querySelector('meta[name=\"darkreader\"]');return t?t.content!==en:((e=document.createElement(\"meta\")).name=\"darkreader\",e.content=en,document.head.appendChild(e),!1)}function An(e,t,r){if(nn=e,(on=t)?(cn=Array.isArray(on.ignoreImageAnalysis)?on.ignoreImageAnalysis:[],un=Array.isArray(on.ignoreInlineStyle)?on.ignoreInlineStyle:[]):(cn=[],un=[]),an=r,document.head){if(Mn())return;document.documentElement.setAttribute(\"data-darkreader-mode\",\"dynamic\"),document.documentElement.setAttribute(\"data-darkreader-scheme\",nn.mode?\"dark\":\"dimmed\"),Vn()}else{if(!h){var n=sn(\"darkreader--fallback\");document.documentElement.appendChild(n),n.textContent=Ot(nn,{strict:!0})}var o=new MutationObserver((function(){if(document.head){if(o.disconnect(),Mn())return void Ln();Vn()}}));o.observe(document,{childList:!0,subtree:!0})}}function Ln(){document.documentElement.removeAttribute(\"data-darkreader-mode\"),document.documentElement.removeAttribute(\"data-darkreader-scheme\"),$t.clear(),oe.clear(),Cn(),wn(),Tn(),Ut(),U(document.querySelector(\".darkreader--fallback\")),document.head&&(!function(){Er&&(Er.disconnect(),Er=null);var e=document.querySelector(wr);e&&_r&&(e.content=_r)}(),U(document.head.querySelector(\".darkreader--user-agent\")),U(document.head.querySelector(\".darkreader--text\")),U(document.head.querySelector(\".darkreader--invert\")),U(document.head.querySelector(\".darkreader--inline\")),U(document.head.querySelector(\".darkreader--override\")),U(document.head.querySelector(\".darkreader--variables\")),U(document.head.querySelector(\".darkreader--root-vars\")),U(document.head.querySelector('meta[name=\"darkreader\"]')),document.dispatchEvent(new CustomEvent(\"__darkreader__cleanUp\")),U(document.head.querySelector(\".darkreader--proxy\"))),hn.forEach((function(e){U(e.querySelector(\".darkreader--inline\")),U(e.querySelector(\".darkreader--override\"))})),hn.clear(),F(tn.keys(),(function(e){return kn(e)})),bn.clear(),jr.clear(),F(document.querySelectorAll(\".darkreader\"),U),rn.forEach((function(e){e.destroy()})),rn.splice(0)}var Pn=/url\\(\\\"(blob\\:.*?)\\\"\\)/g;function On(e){return r(this,void 0,void 0,(function(){var t,r;return n(this,(function(n){switch(n.label){case 0:return t=[],Ne(Pn,e,1).forEach((function(e){var r=_(e);t.push(r)})),[4,Promise.all(t)];case 1:return r=n.sent(),[2,e.replace(Pn,(function(){return'url(\"'.concat(r.shift(),'\")')}))]}}))}))}function jn(){return r(this,void 0,void 0,(function(){function e(e,r){var n=document.querySelector(e);n&&n.textContent&&(t.push(\"/* \".concat(r,\" */\")),t.push(n.textContent),t.push(\"\"))}var t,r,o,a,i;return n(this,(function(n){switch(n.label){case 0:return t=['/*\\n _______\\n / \\\\\\n .==. .==.\\n (( ))==(( ))\\n / \"==\" \"==\"\\\\\\n /____|| || ||___\\\\\\n ________ ____ ________ ___ ___\\n | ___ \\\\ / \\\\ | ___ \\\\ | | / /\\n | | \\\\ \\\\ / /\\\\ \\\\ | | \\\\ \\\\| |_/ /\\n | | ) / /__\\\\ \\\\ | |__/ /| ___ \\\\\\n | |__/ / ______ \\\\| ____ \\\\| | \\\\ \\\\\\n_______|_______/__/ ____ \\\\__\\\\__|___\\\\__\\\\__|___\\\\__\\\\____\\n| ___ \\\\ | ____/ / \\\\ | ___ \\\\ | ____| ___ \\\\\\n| | \\\\ \\\\| |___ / /\\\\ \\\\ | | \\\\ \\\\| |___| | \\\\ \\\\\\n| |__/ /| ____/ /__\\\\ \\\\ | | ) | ____| |__/ /\\n| ____ \\\\| |__/ ______ \\\\| |__/ /| |___| ____ \\\\\\n|__| \\\\__\\\\____/__/ \\\\__\\\\_______/ |______|__| \\\\__\\\\\\n https://darkreader.org\\n*/\\n\\n/*! Dark reader generated CSS | Licensed under MIT https://github.com/darkreader/darkreader/blob/master/LICENSE */\\n'],e(\".darkreader--fallback\",\"Fallback Style\"),e(\".darkreader--user-agent\",\"User-Agent Style\"),e(\".darkreader--text\",\"Text Style\"),e(\".darkreader--invert\",\"Invert Style\"),e(\".darkreader--variables\",\"Variables Style\"),r=[],document.querySelectorAll(\".darkreader--sync\").forEach((function(e){F(e.sheet.cssRules,(function(e){e&&e.cssText&&r.push(e.cssText)}))})),r.length?(o=function(e){function t(e){return e.replace(/^\\s+/,\"\")}function r(e){return 0===e?\"\":\" \".repeat(4*e)}if(e.length<5e4)for(var n=/[^{}]+{\\s*}/;n.test(e);)e=e.replace(n,\"\");for(var o=e.replace(/\\s{2,}/g,\" \").replace(/\\{/g,\"{\\n\").replace(/\\}/g,\"\\n}\\n\").replace(/\\;(?![^\\(|\\\"]*(\\)|\\\"))/g,\";\\n\").replace(/\\,(?![^\\(|\\\"]*(\\)|\\\"))/g,\",\\n\").replace(/\\n\\s*\\n/g,\"\\n\").split(\"\\n\"),a=0,i=[],c=0,u=o.length;c 2 | #import 3 | 4 | %group Inject 5 | #import "Tweak.h" 6 | 7 | @interface WSHelperObject:NSObject { 8 | NSString *key; 9 | NSOperationQueue *queue; 10 | } 11 | @end 12 | 13 | @implementation WSHelperObject 14 | 15 | -(id)init { 16 | self = [super init]; 17 | key = [[NSProcessInfo processInfo] globallyUniqueString]; 18 | queue = [[NSOperationQueue alloc] init]; 19 | queue.maxConcurrentOperationCount = 100; 20 | return self; 21 | } 22 | 23 | -(void) injectIntoController:(WKUserContentController *)controller { 24 | NSLog(@"[webshade-fetch] Injecting into controller"); 25 | [controller addScriptMessageHandler:self name:@"WebShadeCorsFetch"]; 26 | } 27 | 28 | -(void) informChild:(NSString *)id fromView:(WKWebView *)webView withResponse:(NSString *)message ofType:(NSString *)type { 29 | NSString *js = [NSString stringWithFormat:@"window.webkit.WebShadeCorsFetchResponse({id: '%@', message: '%@', type: '%@'});", id, message, type]; 30 | [webView evaluateJavaScript:js completionHandler:nil]; 31 | } 32 | 33 | -(NSString*) getKey { 34 | return key; 35 | } 36 | 37 | -(void) resetKey { 38 | key = [[NSProcessInfo processInfo] globallyUniqueString]; 39 | } 40 | 41 | // This function is used to bypass cors and other stuff 42 | // for the advanced/dark reader engine. Now, obviously 43 | // this is delicate stuff and could have security 44 | // issues. As such I've taken the time to implement 45 | // as many precautions as possible, as well as 46 | // explain them here. If you have any issues with 47 | // how I did this or found an exploit *please* contact 48 | // me either through github issues or on discord at 49 | // WilsontheWolf#0074, 50 | // 51 | // Firstly we'll talk about the obj-c side. The 52 | // following are in place. 53 | // - A randomly generated key is required to make 54 | // requests. This prevents any sites from making 55 | // requests at will. This key is per-process and 56 | // reset on process load making it very hard to guess 57 | // - The ability to turn it off is available. This 58 | // disables anyone from using this method, in the 59 | // case the user is not conformable with this. 60 | // Next we'll talk about the JS side. 61 | // - The token, all injected scripts and functions 62 | // are injected into their own scope, preventing 63 | // malicious sites from using fetch or reading 64 | // the token, 65 | // - The script generates a random id when making 66 | // requests to prevent malicious sites from imitating 67 | // WebShade. 68 | // - The script attempts to check if the function has 69 | // been replaced, and if it has it falls back to fetch. 70 | // This prevents malicious sites from stealing the token. 71 | // If you would like to see the js side of this checkout 72 | // the file advanced-engine.js. 73 | - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{ 74 | NSDictionary *messageBody = message.body; 75 | NSString *id = messageBody[@"id"]; 76 | if(!id) { 77 | return; 78 | } 79 | NSDictionary *settings = [NSDictionary 80 | dictionaryWithContentsOfFile:@"/User/Library/Preferences/com.wilsonthewolf.webshadeprefs.plist"]; 81 | BOOL enabled = [[settings valueForKey:@"enabled"] == nil ? @"1" : [settings valueForKey:@"enabled"] boolValue]; 82 | if(!enabled) { 83 | NSLog(@"[webshade-fetch] WebShade is disabled but a request was made!"); 84 | [self informChild:id fromView:message.webView withResponse:@"disabled" ofType:@"error"]; 85 | return; 86 | } 87 | BOOL canUseFetch = [[settings valueForKey:@"allowFetch"] == nil ? @"1" : [settings valueForKey:@"allowFetch"] boolValue]; 88 | if(!canUseFetch) { 89 | NSLog(@"[webshade-fetch] Fetching is disabled but a request was made!"); 90 | [self informChild:id fromView:message.webView withResponse:@"access denied" ofType:@"error"]; 91 | return; 92 | } 93 | NSString *token = messageBody[@"token"]; 94 | if([token isEqualToString:key]) { 95 | NSString *url = messageBody[@"url"]; 96 | NSURLSessionConfiguration *defaultSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; 97 | NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultSessionConfiguration]; 98 | 99 | [queue addOperationWithBlock: ^{ 100 | NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]]; 101 | 102 | [urlRequest setHTTPMethod:@"GET"]; 103 | 104 | __block BOOL done = NO; 105 | NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 106 | if(error) { 107 | NSLog(@"[webshade-fetch] error %@", error); 108 | NSLog(@"[webshade-fetch] error %@", url); 109 | dispatch_async(dispatch_get_main_queue(), ^{ 110 | [self informChild:id fromView: [message webView] withResponse:[error localizedDescription] ofType:@"error"]; 111 | }); 112 | 113 | } else { 114 | dispatch_async(dispatch_get_main_queue(), ^{ 115 | [self informChild:id fromView: [message webView] withResponse:[data base64EncodedStringWithOptions:0] ofType:@"data"]; 116 | }); 117 | } 118 | done = YES; 119 | }]; 120 | [dataTask resume]; 121 | 122 | while (!done) { 123 | NSDate *date = [[NSDate alloc] initWithTimeIntervalSinceNow:0.1]; 124 | [[NSRunLoop currentRunLoop] runUntilDate:date]; 125 | } 126 | }]; 127 | } else { 128 | NSLog(@"[webshade-fetch] invalid token: %@", token); 129 | [self informChild:id fromView: [message webView] withResponse:@"access denied" ofType:@"error"]; 130 | } 131 | } 132 | 133 | - (id)getValueForKey:(NSString *)keyValue fromSettings:(NSDictionary *)settings fromDetails:(NSDictionary *)details usingGlobal:(BOOL)global useGlobalAsDefault:(BOOL)useGlobalAsDefault { 134 | id value = [details valueForKey:keyValue]; 135 | if(value == nil && !global && useGlobalAsDefault) { 136 | value = [settings valueForKey:keyValue]; 137 | } 138 | if(value == nil) { 139 | // Handle defaults 140 | if([keyValue isEqualToString:@"engine"]) { 141 | return @0; 142 | } 143 | if([keyValue isEqualToString:@"followSystemTheme"]) { 144 | return @"1"; 145 | } 146 | if([keyValue isEqualToString:@"oled"]) { 147 | return @"0"; 148 | } 149 | if([keyValue isEqualToString:@"sliders"]) { 150 | return @"0"; 151 | } 152 | if([keyValue isEqualToString:@"brightness"]) { 153 | return @"100"; 154 | } 155 | if([keyValue isEqualToString:@"contrast"]) { 156 | return @"100"; 157 | } 158 | if([keyValue isEqualToString:@"grayscale"]) { 159 | return @"0"; 160 | } 161 | if([keyValue isEqualToString:@"sepia"]) { 162 | return @"0"; 163 | } 164 | } 165 | return value; 166 | } 167 | @end 168 | 169 | static WSHelperObject *helper = nil; 170 | 171 | %hook WKWebView 172 | 173 | %property (nonatomic, strong) WSHelperObject *WSHelperObject; 174 | 175 | - (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration { 176 | if(!configuration) { 177 | configuration = [[WKWebViewConfiguration alloc] init]; 178 | } 179 | if(!configuration.userContentController) { 180 | configuration.userContentController = [[WKUserContentController alloc] init]; 181 | } 182 | if(!helper) { 183 | helper = [WSHelperObject new]; 184 | [helper injectIntoController:configuration.userContentController]; 185 | } 186 | return %orig; 187 | }; 188 | 189 | - (bool)_didCommitLoadForMainFrame { 190 | NSLog(@"[webshade-core] Running on %@", self.URL.absoluteString); 191 | if (![self.URL.scheme isEqualToString:@"http"] && ![self.URL.scheme isEqualToString:@"https"]) { 192 | NSLog(@"[webshade-core] Not a web page, skipping"); 193 | return %orig; 194 | } 195 | NSDictionary *settings = [NSDictionary 196 | dictionaryWithContentsOfFile:@"/User/Library/Preferences/com.wilsonthewolf.webshadeprefs.plist"]; 197 | BOOL enabled = [[settings valueForKey:@"enabled"] == nil ? @"1" : [settings valueForKey:@"enabled"] boolValue]; 198 | if(enabled) { 199 | NSDictionary *sites = [NSDictionary 200 | dictionaryWithContentsOfFile:@"/User/Library/Preferences/com.wilsonthewolf.webshadesites.plist"]; 201 | NSDictionary *details = settings; 202 | BOOL usingGlobal = YES; 203 | BOOL useGlobalAsDefault = [[settings valueForKey:@"useGlobalAsDefault"] == nil ? @"1" : [settings valueForKey:@"useGlobalAsDefault"] boolValue]; 204 | for(NSString *site in sites) { 205 | NSDictionary *value = sites[site]; 206 | NSString *matchString = value[@"websiteMatch"]; 207 | if(matchString == nil) { 208 | continue; 209 | } 210 | NSArray *matchArray = [matchString componentsSeparatedByString:@"|"]; 211 | NSString *finalMatch = nil; 212 | for(NSString *matchInfo in matchArray) { 213 | NSString *match = [matchInfo stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 214 | if([match isEqualToString:@""]) { 215 | continue; 216 | } 217 | match = [[match stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]] lowercaseString]; 218 | if([[self.URL.absoluteString lowercaseString] containsString:match]) { 219 | finalMatch = match; 220 | break; 221 | } 222 | } 223 | if(finalMatch == nil) { 224 | continue; 225 | } 226 | details = value; 227 | usingGlobal = NO; 228 | NSLog(@"[webshade-core] Using ruleset from %@. Matched %@", site, finalMatch); 229 | break; 230 | } 231 | BOOL canUseFetch = [[settings valueForKey:@"allowFetch"] == nil ? @"1" : [settings valueForKey:@"allowFetch"] boolValue]; 232 | NSNumber *engine = [helper getValueForKey:@"engine" fromSettings:settings fromDetails:details usingGlobal:usingGlobal useGlobalAsDefault:useGlobalAsDefault]; 233 | if (![engine isEqual: @2]) { // Not Off 234 | NSLog(@"[webshade-core] Engine: %@", engine); 235 | NSString *brightness = @"100"; 236 | NSString *contrast = @"100"; 237 | NSString *grayscale = @"0"; 238 | NSString *sepia = @"0"; 239 | NSString *script = @""; 240 | BOOL followSystemTheme = [[helper getValueForKey:@"followSystemTheme" fromSettings:settings fromDetails:details usingGlobal:usingGlobal useGlobalAsDefault:useGlobalAsDefault] boolValue]; 241 | BOOL oled = [[helper getValueForKey:@"oled" fromSettings:settings fromDetails:details usingGlobal:usingGlobal useGlobalAsDefault:useGlobalAsDefault] boolValue]; 242 | if([UIDevice currentDevice].systemVersion.floatValue < 13) { 243 | followSystemTheme = false; 244 | } 245 | if ([engine isEqual: @0]) { // Advanced (Dark reader) 246 | script = [NSString stringWithFormat: @"%@\n%@", 247 | kDarkReaderScript, 248 | kDarkReaderRun]; 249 | } else if ([engine isEqual: @1]) { // Basic 250 | script = kBasicEngineRun; 251 | } 252 | if([[helper getValueForKey:@"sliders" fromSettings:settings fromDetails:details usingGlobal:usingGlobal useGlobalAsDefault:useGlobalAsDefault] boolValue]) { 253 | brightness = [helper getValueForKey:@"brightness" fromSettings:settings fromDetails:details usingGlobal:usingGlobal useGlobalAsDefault:useGlobalAsDefault]; 254 | contrast = [helper getValueForKey:@"contrast" fromSettings:settings fromDetails:details usingGlobal:usingGlobal useGlobalAsDefault:useGlobalAsDefault]; 255 | grayscale = [helper getValueForKey:@"grayscale" fromSettings:settings fromDetails:details usingGlobal:usingGlobal useGlobalAsDefault:useGlobalAsDefault]; 256 | sepia = [helper getValueForKey:@"sepia" fromSettings:settings fromDetails:details usingGlobal:usingGlobal useGlobalAsDefault:useGlobalAsDefault]; 257 | } 258 | NSString *jsOptions = [NSString stringWithFormat:@"{dynamic: %@, brightness: %@, contrast: %@, grayscale: %@, sepia: %@, OLED: %@}", 259 | followSystemTheme ? @"true" : @"false", 260 | brightness, contrast, grayscale, sepia, oled ? @"true" : @"false"]; 261 | NSLog(@"[webshade-core] Options: %@", jsOptions); 262 | NSLog(@"[webshade-core] Can use webshade-fetch: %d", (int)canUseFetch); 263 | [self evaluateJavaScript: [NSString stringWithFormat:@"{\nconst options = %@;\nconst wsToken = '%@';\n%@\n}", jsOptions, canUseFetch ? [helper getKey] : @"", script] 264 | completionHandler: nil]; 265 | NSLog(@"[webshade-core] Injected"); 266 | } else { 267 | NSLog(@"[webshade-core] Engine off"); 268 | } 269 | } else { 270 | NSLog(@"[webshade-core] Disabled"); 271 | } 272 | return %orig; 273 | } 274 | %end 275 | %end 276 | 277 | 278 | // methods of getting executablePath and bundleIdentifier with the least side effects possible 279 | // for more information, check out https://github.com/checkra1n/BugTracker/issues/343 280 | // Thanks to @opa334dev for this https://github.com/opa334/Choicy/blob/master/Tweak.x#L37-L58 281 | extern char*** _NSGetArgv(); 282 | NSString* safe_getExecutablePath() 283 | { 284 | char* executablePathC = **_NSGetArgv(); 285 | return [NSString stringWithUTF8String:executablePathC]; 286 | } 287 | 288 | %ctor { 289 | // This prevents us from injecting into springboard and making Xen HTML widgets dark mode. 290 | // Thanks to Galactic-Dev who I stole this from. 291 | NSString *executablePath = safe_getExecutablePath(); 292 | if(executablePath) { 293 | BOOL isApplication = [executablePath rangeOfString:@"/Application"].location != NSNotFound 294 | && [executablePath rangeOfString:@"Spotlight"].location == NSNotFound // Fix Spotlight dictionary glitches 295 | && [executablePath rangeOfString:@"Cydia"].location == NSNotFound; // Cydia crashes for some people and it doesn't even affect it at all. 296 | if(isApplication) { 297 | %init(Inject); 298 | } else { 299 | NSLog(@"[webshade] Not injecting"); 300 | } 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /WebShade.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.apple.WebKit" ); }; } 2 | -------------------------------------------------------------------------------- /advanced-engine.js: -------------------------------------------------------------------------------- 1 | // I'm just including this https://cdn.jsdelivr.net/npm/darkreader/darkreader.min.js above 2 | // then adding it into the main tweak with this below. Nice and simple 3 | 4 | // const options = { dynamic: true, brightness: 100, contrast: 100, grayscale: 0, sepia: 0, OLED: false }; 5 | 6 | // This implements webshade-fetch, which allows darkreader to avoid cors. If its not enabled, it will use the default fetch. 7 | if (wsToken) { 8 | if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.WebShadeCorsFetch) { 9 | const postMessage = window.webkit.messageHandlers.WebShadeCorsFetch.postMessage.bind(window.webkit.messageHandlers.WebShadeCorsFetch); 10 | // This checks if the handler is native code. and if theres already 11 | // a response. If the handler isn't native code, this 12 | // means its most likely being impersonated by a script. 13 | // If the response is already set, then we can assume that 14 | // someone is messing with something, or we're already injected (?) 15 | // If this is the case, we use the default fetch to prevent token leakage. 16 | if (/\{\s+\[native code\]/.test(Function.prototype.toString.call(postMessage)) && !window.webkit.WebShadeCorsFetchResponse) { 17 | const promises = {}; 18 | const fakeFetch = (url) => { 19 | const id = Math.random().toString(36).slice(2); 20 | const promise = new Promise((resolve, reject) => { 21 | promises[id] = { resolve, reject }; 22 | }); 23 | promises[id].timeout = setTimeout(() => { 24 | promises[id].reject(new Error('No response')); 25 | delete promises[id]; 26 | }, 100000 + 1000 * Object.keys(promises).length); // 100 + how many fetches in the queue secs 27 | 28 | postMessage({ url: encodeURI(url), id, token: wsToken }); 29 | return promise; 30 | }; 31 | window.webkit.WebShadeCorsFetchResponse = ({ id, type, message }) => { 32 | if (!id || !type) return; 33 | if (!promises[id]) return; 34 | clearTimeout(promises[id].timeout); 35 | if (type === 'data') { 36 | const fakeFetch = { 37 | text: () => Promise.resolve(atob(message)), 38 | blob: () => Promise.resolve(new Blob([atob(message)])), 39 | }; 40 | promises[id].resolve(fakeFetch); 41 | } else { 42 | promises[id].reject(new Error(message)); 43 | } 44 | delete promises[id]; 45 | }; 46 | // Attempt to prevent someone from messing with the response handler. 47 | // It's probably able to be worked around, but it should help. 48 | Object.freeze(window.webkit); 49 | DarkReader.setFetchMethod(fakeFetch); 50 | } 51 | } 52 | } 53 | 54 | const data = { 55 | brightness: options.brightness, 56 | contrast: options.contrast, 57 | grayscale: options.grayscale, 58 | sepia: options.sepia, 59 | darkSchemeBackgroundColor: options.OLED ? '#000' : '#181a1b', 60 | } 61 | if (options.dynamic) { 62 | DarkReader.auto(data); 63 | } else { 64 | DarkReader.enable(data); 65 | } -------------------------------------------------------------------------------- /basic-engine.js: -------------------------------------------------------------------------------- 1 | // Modified from https://github.com/OrionBrowser/DarkMode/blob/main/oriondark.js 2 | // const options = { dynamic: true, brightness: 100, contrast: 100, grayscale: 0, sepia: 0, OLED: false }; 3 | const css = ` 4 | ${options.dynamic ? '@media (prefers-color-scheme: dark) {' : ''} 5 | :root { 6 | filter: invert(${options.OLED ? 100 : 90}%) hue-rotate(180deg) brightness(${options.brightness}%) contrast(${options.contrast}%) grayscale(${options.grayscale}%) sepia(${options.sepia}%); 7 | background: #fff; 8 | } 9 | iframe, img, image, video, [style*="background-image"] { 10 | filter: invert() hue-rotate(180deg) brightness(${options.brightness + 5}%) contrast(${options.contrast + 5}%) !important; 11 | } 12 | ${options.dynamic ? '}' : ''} 13 | `; 14 | const id = "webshade-browser-dark-theme"; 15 | const ee = document.getElementById(id); 16 | if (null != ee) ee.parentNode.removeChild(ee); 17 | style = document.createElement('style'); 18 | style.type = "text/css"; 19 | style.id = id; 20 | if (style.styleSheet) style.styleSheet.cssText = css; 21 | else style.appendChild(document.createTextNode(css)); 22 | document.head.appendChild(style); -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: com.wilsonthewolf.webshade 2 | Name: WebShade 3 | Version: 0.0.6 4 | Architecture: iphoneos-arm 5 | Description: Make your websites dark! 6 | Maintainer: WilsontheWolf 7 | Author: WilsontheWolf 8 | Section: Tweaks 9 | Depends: mobilesubstrate (>= 0.9.5000), preferenceloader 10 | Depiction: https://wilson.antti.codes/repo/depictions/web/com.wilsonthewolf.webshade 11 | SileoDepiction: https://wilson.antti.codes/repo/depictions/sileo/com.wilsonthewolf.webshade 12 | -------------------------------------------------------------------------------- /webshadeprefs/Makefile: -------------------------------------------------------------------------------- 1 | TARGET := iphone:clang:latest:11.0 2 | 3 | include $(THEOS)/makefiles/common.mk 4 | 5 | BUNDLE_NAME = WebShadePrefs 6 | 7 | WebShadePrefs_FILES = WSPRootListController.m WSPSiteListController.m WSPCustomSiteListController.m 8 | WebShadePrefs_FRAMEWORKS = UIKit 9 | WebShadePrefs_PRIVATE_FRAMEWORKS = Preferences 10 | WebShadePrefs_INSTALL_PATH = /Library/PreferenceBundles 11 | WebShadePrefs_CFLAGS = -fobjc-arc 12 | 13 | include $(THEOS_MAKE_PATH)/bundle.mk 14 | -------------------------------------------------------------------------------- /webshadeprefs/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | WebShadePrefs 9 | CFBundleIdentifier 10 | com.wilsonthewolf.webshadeprefs 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1.0 21 | NSPrincipalClass 22 | WSPRootListController 23 | 24 | 25 | -------------------------------------------------------------------------------- /webshadeprefs/Resources/Root.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | items 6 | 7 | 8 | cell 9 | PSGroupCell 10 | footerText 11 | Please note that you might have to reload the page for some settings to take affect. 12 | 13 | 14 | cell 15 | PSGroupCell 16 | label 17 | Tweak Settings 18 | footerText 19 | Use this to enable/disable the tweak. 20 | 21 | 22 | cell 23 | PSSwitchCell 24 | default 25 | 26 | defaults 27 | com.wilsonthewolf.webshadeprefs 28 | key 29 | enabled 30 | label 31 | Enabled 32 | 33 | 34 | cell 35 | PSGroupCell 36 | footerText 37 | This allows you to control which sites WebShade will work on. 38 | 39 | 40 | cell 41 | PSLinkCell 42 | detail 43 | WSPSiteListController 44 | isController 45 | 46 | label 47 | Site Control 48 | 49 | 50 | cell 51 | PSGroupCell 52 | footerText 53 | When this is enabled, webshade will use the global setting for unknown values in site control. When disabled webshade will use its built in defaults. 54 | 55 | 56 | cell 57 | PSSwitchCell 58 | default 59 | 60 | defaults 61 | com.wilsonthewolf.webshadeprefs 62 | key 63 | useGlobalAsDefault 64 | label 65 | Use Global Settings as Default 66 | 67 | 68 | cell 69 | PSGroupCell 70 | footerText 71 | This allows the advanced engine to more reliably work on websites. It utilizes internal functions to request assets for the engine. If you don't feel confortable with WebShade making requests to sites, you may turn this off. 72 | 73 | 74 | cell 75 | PSSwitchCell 76 | default 77 | 78 | defaults 79 | com.wilsonthewolf.webshadeprefs 80 | key 81 | allowFetch 82 | label 83 | Use WebShade Fetch 84 | 85 | 86 | cell 87 | PSGroupCell 88 | label 89 | Global Settings 90 | footerText 91 | Disabling this causes the tweak to always be dark mode instead of following your system's dark mode. 92 | If you are on iOS 12 or lower this will have no effect. 93 | 94 | 95 | cell 96 | PSSwitchCell 97 | default 98 | 99 | defaults 100 | com.wilsonthewolf.webshadeprefs 101 | key 102 | followSystemTheme 103 | label 104 | Follow System Theme 105 | 106 | 107 | cell 108 | PSGroupCell 109 | footerText 110 | This causes websites to have a pure black backround. 111 | 112 | 113 | cell 114 | PSSwitchCell 115 | default 116 | 117 | defaults 118 | com.wilsonthewolf.webshadeprefs 119 | key 120 | oled 121 | label 122 | Enable OLED Mode 123 | 124 | 125 | cell 126 | PSGroupCell 127 | label 128 | Engine 129 | footerText 130 | The engine is responsible for changing the theme. Different engines have their quirks. 131 | 132 | The advanced engine is the default engine. It is smarter with how to color stuff and *usually* looks better. It is, however, more resource intensive so slower devices might have noticeable slowdown with this engine. It also has some incompatibility with sites, which might cause some weird issues, including not staying light theme, and receiving compatibility errors on sites. 133 | 134 | The basic engine is a much simpler engine. It uses less resources and is more suitable on lower end devices. It also works better with some sites. It does have the issue where if a site is already dark, it will make it light instead. 135 | 136 | 137 | cell 138 | PSSegmentCell 139 | default 140 | 0 141 | defaults 142 | com.wilsonthewolf.webshadeprefs 143 | key 144 | engine 145 | validValues 146 | 147 | 0 148 | 1 149 | 2 150 | 151 | validTitles 152 | 153 | Advanced 154 | Basic 155 | Off 156 | 157 | 158 | 159 | cell 160 | PSGroupCell 161 | label 162 | Display Settings 163 | footerText 164 | These adjust how the background looks. 165 | It's recommended to use the "Default Sliders" option but if you want to you can enable "Custom Sliders" and then it will use your values. 166 | 167 | 168 | cell 169 | PSSegmentCell 170 | default 171 | 0 172 | defaults 173 | com.wilsonthewolf.webshadeprefs 174 | key 175 | sliders 176 | validValues 177 | 178 | 0 179 | 1 180 | 181 | validTitles 182 | 183 | Default Sliders 184 | Custom Sliders 185 | 186 | 187 | 188 | cell 189 | PSGroupCell 190 | label 191 | Brightness 192 | footerText 193 | The brightness controls how bright everything is. 194 | Setting it to 100 is recommended. 195 | Lower values makes everything darker and higher values makes everything lighter. 196 | 197 | 198 | cell 199 | PSSliderCell 200 | min 201 | 0 202 | max 203 | 200 204 | default 205 | 100 206 | defaults 207 | com.wilsonthewolf.webshadeprefs 208 | showValue 209 | 210 | key 211 | brightness 212 | 213 | 214 | cell 215 | PSGroupCell 216 | label 217 | Contrast 218 | footerText 219 | The contrast controls how much difference the background and foreground are. 220 | Setting it to 100 or higher is recommended. 221 | Lower values makes everything greyer and higher values makes everything blacker. 222 | 223 | 224 | cell 225 | PSSliderCell 226 | min 227 | -200 228 | max 229 | 200 230 | default 231 | 100 232 | defaults 233 | com.wilsonthewolf.webshadeprefs 234 | showValue 235 | 236 | key 237 | contrast 238 | 239 | 240 | cell 241 | PSGroupCell 242 | label 243 | Grayscale 244 | footerText 245 | The grayscale controls how much colour there is. 246 | Setting it to 0 is recommended. 247 | Increasing this value causes the page to become more gray. 248 | It does not affect images on the advanced engine. 249 | 250 | 251 | cell 252 | PSSliderCell 253 | min 254 | 0 255 | max 256 | 100 257 | default 258 | 0 259 | defaults 260 | com.wilsonthewolf.webshadeprefs 261 | showValue 262 | 263 | key 264 | grayscale 265 | 266 | 267 | cell 268 | PSGroupCell 269 | label 270 | Sepia 271 | footerText 272 | The sepia controls how warm the page is. 273 | Setting it to 0 is recommended. 274 | Negative values makes everything bluer and positive values makes everything yellowier. 275 | The basic engine needs a positive sepia value. Super high sepia values might cause inconsistant results. 276 | 277 | 278 | cell 279 | PSSliderCell 280 | min 281 | -200 282 | max 283 | 200 284 | default 285 | 0 286 | defaults 287 | com.wilsonthewolf.webshadeprefs 288 | showValue 289 | 290 | key 291 | sepia 292 | 293 | 294 | cell 295 | PSGroupCell 296 | label 297 | Links 298 | 299 | 300 | cell 301 | PSButtonCell 302 | label 303 | GitHub 304 | action 305 | openGithub 306 | 307 | 308 | 309 | title 310 | WebShade 311 | 312 | 313 | -------------------------------------------------------------------------------- /webshadeprefs/Resources/Site.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | items 6 | 7 | 8 | cell 9 | PSGroupCell 10 | label 11 | Website Match 12 | footerText 13 | Any text you put in here. It will match any websites with that text in their URL. 14 | 15 | For example "example.com" would match "example.com", "test.example.com" and "example.com/page". 16 | "cool" would match "cool.com", "example.com/cool" and "apple.com/coolstuff" 17 | 18 | You can add multiple matches by seperating them by a pipe (|) character. For example "example.com|google.com" would match "example.com" and "google.com". 19 | 20 | Leaving this blank will disable this rule. 21 | 22 | 23 | cell 24 | PSEditTextCell 25 | default 26 | 27 | key 28 | websiteMatch 29 | placeholder 30 | example.com 31 | noAutoCorrect 32 | 33 | defaults 34 | com.wilsonthewolf.webshadesites 35 | 36 | 37 | cell 38 | PSGroupCell 39 | footerText 40 | Disabling this causes the tweak to always be dark mode instead of following your system's dark mode. 41 | If you are on iOS 12 or lower this will have no effect. 42 | 43 | 44 | cell 45 | PSSwitchCell 46 | default 47 | 48 | key 49 | followSystemTheme 50 | label 51 | Follow System Theme 52 | defaults 53 | com.wilsonthewolf.webshadesites 54 | 55 | 56 | cell 57 | PSGroupCell 58 | footerText 59 | This causes websites to have a pure black backround. 60 | 61 | 62 | cell 63 | PSSwitchCell 64 | default 65 | 66 | defaults 67 | com.wilsonthewolf.webshadesites 68 | key 69 | oled 70 | label 71 | Enable OLED Mode 72 | 73 | 74 | cell 75 | PSGroupCell 76 | label 77 | Engine 78 | footerText 79 | The engine is responsible for changing the theme. Different engines have their quirks. 80 | 81 | The advanced engine is the default engine. It is smarter with how to color stuff and *usually* looks better. It is, however, more resource intensive so slower devices might have noticeable slowdown with this engine. It also has some incompatibility with sites, which might cause some weird issues, including not staying light theme, and receiving compatibility errors on sites. 82 | 83 | The basic engine is a much simpler engine. It uses less resources and is more suitable on lower end devices. It also works better with some sites. It does have the issue where if a site is already dark, it will make it light instead. 84 | 85 | 86 | cell 87 | PSSegmentCell 88 | default 89 | 0 90 | key 91 | engine 92 | validValues 93 | 94 | 0 95 | 1 96 | 2 97 | 98 | validTitles 99 | 100 | Advanced 101 | Basic 102 | Off 103 | 104 | defaults 105 | com.wilsonthewolf.webshadesites 106 | 107 | 108 | cell 109 | PSGroupCell 110 | label 111 | Display Settings 112 | footerText 113 | These adjust how the background looks. 114 | It's recommended to use the "Default Sliders" option but if you want to you can enable "Custom Sliders" and then it will use your values. 115 | 116 | 117 | cell 118 | PSSegmentCell 119 | default 120 | 0 121 | key 122 | sliders 123 | validValues 124 | 125 | 0 126 | 1 127 | 128 | validTitles 129 | 130 | Default Sliders 131 | Custom Sliders 132 | 133 | defaults 134 | com.wilsonthewolf.webshadesites 135 | 136 | 137 | cell 138 | PSGroupCell 139 | label 140 | Brightness 141 | footerText 142 | The brightness controls how bright everything is. 143 | Setting it to 100 is recommended. 144 | Lower values makes everything darker and higher values makes everything lighter. 145 | 146 | 147 | cell 148 | PSSliderCell 149 | min 150 | 0 151 | max 152 | 200 153 | default 154 | 100 155 | showValue 156 | 157 | key 158 | brightness 159 | defaults 160 | com.wilsonthewolf.webshadesites 161 | 162 | 163 | cell 164 | PSGroupCell 165 | label 166 | Contrast 167 | footerText 168 | The contrast controls how much difference the background and foreground are. 169 | Setting it to 100 or higher is recommended. 170 | Lower values makes everything greyer and higher values makes everything blacker. 171 | 172 | 173 | cell 174 | PSSliderCell 175 | min 176 | -200 177 | max 178 | 200 179 | default 180 | 100 181 | showValue 182 | 183 | key 184 | contrast 185 | defaults 186 | com.wilsonthewolf.webshadesites 187 | 188 | 189 | cell 190 | PSGroupCell 191 | label 192 | Grayscale 193 | footerText 194 | The grayscale controls how much colour there is. 195 | Setting it to 0 is recommended. 196 | Increasing this value causes the page to become more gray. 197 | It does not affect images on the advanced engine. 198 | 199 | 200 | cell 201 | PSSliderCell 202 | min 203 | 0 204 | max 205 | 100 206 | default 207 | 0 208 | showValue 209 | 210 | key 211 | grayscale 212 | defaults 213 | com.wilsonthewolf.webshadesites 214 | 215 | 216 | cell 217 | PSGroupCell 218 | label 219 | Sepia 220 | footerText 221 | The sepia controls how warm the page is. 222 | Setting it to 0 is recommended. 223 | Negative values makes everything bluer and positive values makes everything yellowier. 224 | The basic engine needs a positive sepia value. Super high sepia values might cause inconsistant results. 225 | 226 | 227 | cell 228 | PSSliderCell 229 | min 230 | -200 231 | max 232 | 200 233 | default 234 | 0 235 | showValue 236 | 237 | key 238 | sepia 239 | defaults 240 | com.wilsonthewolf.webshadesites 241 | 242 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /webshadeprefs/WSPCustomSiteListController.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface WSPCustomSiteListController : PSListController 5 | @property (strong, nonatomic) NSMutableDictionary *site; 6 | @property (strong, nonatomic) NSDictionary *global; 7 | @property (strong, nonatomic) NSString *selectedSite; 8 | @end 9 | -------------------------------------------------------------------------------- /webshadeprefs/WSPCustomSiteListController.m: -------------------------------------------------------------------------------- 1 | #include "WSPCustomSiteListController.h" 2 | 3 | @implementation WSPCustomSiteListController 4 | 5 | - (NSArray *)specifiers { 6 | if (!_specifiers) { 7 | self.selectedSite = self.title; 8 | _specifiers = [self loadSpecifiersFromPlistName:@"Site" target:self]; 9 | // Loading the plist makes the title blank. 10 | self.title = self.selectedSite; 11 | } 12 | return _specifiers; 13 | } 14 | 15 | - (void)setPreferenceValue:(id)value specifier:(PSSpecifier*)specifier { 16 | NSString *path = [NSString stringWithFormat:@"/User/Library/Preferences/%@.plist", specifier.properties[@"defaults"]]; 17 | NSMutableDictionary *sites = [NSMutableDictionary dictionaryWithContentsOfFile:path] == nil ? [NSMutableDictionary dictionary] : [NSMutableDictionary dictionaryWithContentsOfFile:path]; 18 | NSMutableDictionary *site = sites[self.selectedSite] == nil ? [NSMutableDictionary dictionary] : [NSMutableDictionary dictionaryWithDictionary:sites[self.selectedSite]]; 19 | [site setObject:value forKey:specifier.properties[@"key"]]; 20 | [sites setObject:site forKey:self.selectedSite]; 21 | [sites writeToFile:path atomically:YES]; 22 | } 23 | 24 | -(id)readPreferenceValue:(PSSpecifier *)specifier { 25 | return self.site[specifier.properties[@"key"]] ?: 26 | self.global[@"useGlobalAsDefault"] == nil || [self.global[@"useGlobalAsDefault"] boolValue] ? 27 | self.global[specifier.properties[@"key"]] : 28 | specifier.properties[@"default"]; 29 | } 30 | 31 | -(void)viewDidLoad { 32 | [super viewDidLoad]; 33 | 34 | NSString *path = @"/User/Library/Preferences/com.wilsonthewolf.webshadesites.plist"; 35 | NSDictionary *sitePrefs = [NSDictionary dictionaryWithContentsOfFile:path] == nil ? [NSDictionary dictionary] : [NSDictionary dictionaryWithContentsOfFile:path]; 36 | NSString *globalPath = @"/User/Library/Preferences/com.wilsonthewolf.webshadeprefs.plist"; 37 | self.global = [NSDictionary dictionaryWithContentsOfFile:globalPath] == nil ? [NSDictionary dictionary] : [NSDictionary dictionaryWithContentsOfFile:globalPath]; 38 | self.site = sitePrefs[self.selectedSite] == nil ? [NSMutableDictionary dictionary] : [sitePrefs[self.selectedSite] mutableCopy]; 39 | NSLog(@"[webshade-prefs] Site loaded: %@", self.selectedSite); 40 | } 41 | 42 | -(void)_returnKeyPressed:(id)arg1 { 43 | [self.view endEditing:YES]; 44 | } 45 | 46 | @end -------------------------------------------------------------------------------- /webshadeprefs/WSPRootListController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface WSPRootListController : PSListController 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /webshadeprefs/WSPRootListController.m: -------------------------------------------------------------------------------- 1 | #include "WSPRootListController.h" 2 | 3 | @implementation WSPRootListController 4 | 5 | - (NSArray *)specifiers { 6 | if (!_specifiers) { 7 | _specifiers = [self loadSpecifiersFromPlistName:@"Root" target:self]; 8 | } 9 | 10 | return _specifiers; 11 | } 12 | 13 | -(void)openGithub { 14 | [[UIApplication sharedApplication] 15 | openURL:[NSURL URLWithString:@"https://github.com/WilsontheWolf/WebShade"] 16 | options:@{} 17 | completionHandler:nil]; 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /webshadeprefs/WSPSiteListController.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | @interface WSPSiteListController : PSListController 6 | @property (nonatomic, retain) NSMutableDictionary *sites; 7 | - (void)loadSites; 8 | - (void)loadData; 9 | @end 10 | -------------------------------------------------------------------------------- /webshadeprefs/WSPSiteListController.m: -------------------------------------------------------------------------------- 1 | #include 2 | #include "WSPSiteListController.h" 3 | // Special thanks to @LacertosusRepo @denialpan @AzzouDuGhetto @Galactic-Dev for this 4 | // No way I could do this myself. 5 | // If your looking to do something similar yourself, trust me 6 | // Turn away while you still can. 7 | 8 | @implementation WSPSiteListController 9 | -(id)init { 10 | self = [super init]; 11 | 12 | if(self) { 13 | [self loadData]; 14 | } 15 | 16 | return self; 17 | } 18 | 19 | -(NSArray *)specifiers { 20 | if (!_specifiers) { 21 | [self loadSites]; 22 | } 23 | 24 | return _specifiers; 25 | } 26 | 27 | -(void)loadSites { 28 | NSMutableArray *siteSpecifiers = [[NSMutableArray alloc] init]; 29 | PSSpecifier *groupSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Custom Site Rules" target:self set:nil get:nil detail:nil cell:PSGroupCell edit:nil]; 30 | [groupSpecifier setProperty:@"Swipe to delete or rename sites." forKey:@"footerText"]; 31 | [siteSpecifiers addObject:groupSpecifier]; 32 | 33 | for(NSString *site in self.sites) { 34 | PSSpecifier *specifier = [PSSpecifier preferenceSpecifierNamed:site target:self set:nil get:nil detail:objc_getClass("WSPCustomSiteListController") cell:PSLinkCell edit:nil]; 35 | [specifier setProperty:@YES forKey:@"enabled"]; 36 | [self insertSpecifier:specifier atIndex:1 animated:YES]; 37 | [siteSpecifiers addObject:specifier]; 38 | } 39 | 40 | _specifiers = [siteSpecifiers copy]; 41 | } 42 | 43 | -(void)loadData { 44 | NSString *path = @"/User/Library/Preferences/com.wilsonthewolf.webshadesites.plist"; 45 | self.sites = [NSMutableDictionary dictionaryWithContentsOfFile:path] == nil ? [NSMutableDictionary dictionary] : [NSMutableDictionary dictionaryWithContentsOfFile:path]; 46 | } 47 | 48 | -(void)addSite { 49 | UIAlertController * alertController = [UIAlertController alertControllerWithTitle: @"New Site Rule" 50 | message: @"Please input what you want this to show as.\nNote: this is not the necessarily the name or the url of the site." 51 | preferredStyle:UIAlertControllerStyleAlert]; 52 | [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { 53 | textField.placeholder = @"Name"; 54 | textField.clearButtonMode = UITextFieldViewModeWhileEditing; 55 | }]; 56 | [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { 57 | }]]; 58 | 59 | UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { 60 | NSArray *textfields = alertController.textFields; 61 | UITextField *namefield = textfields[0]; 62 | NSString *text = [namefield.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 63 | NSString *error = nil; 64 | if(text.length == 0) { 65 | error = @"Please enter a name."; 66 | } else if([self.sites objectForKey:text]) { 67 | error = @"A site with that name already exists."; 68 | } 69 | if(error != nil) { 70 | UIAlertController * alertController = [UIAlertController alertControllerWithTitle: @"Error" 71 | message: error 72 | preferredStyle:UIAlertControllerStyleAlert]; 73 | [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { 74 | }]]; 75 | [self presentViewController:alertController animated:YES completion:nil]; 76 | } else { 77 | NSLog(@"[webshade-prefs] Site added: %@",text); 78 | PSSpecifier *specifier = [PSSpecifier preferenceSpecifierNamed:text target:self set:nil get:nil detail:objc_getClass("WSPCustomSiteListController") cell:PSLinkCell edit:nil]; 79 | [specifier setProperty:@YES forKey:@"enabled"]; 80 | [self insertSpecifier:specifier atIndex:1 animated:YES]; 81 | 82 | [self saveSites]; 83 | } 84 | }]; 85 | [alertController addAction:okAction]; 86 | alertController.preferredAction = okAction; 87 | [self presentViewController:alertController animated:YES completion:nil]; 88 | } 89 | 90 | - (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath { 91 | UIContextualAction *deleteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"Delete" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) { 92 | PSSpecifier *specifierToBeRemoved = [self specifierAtIndexPath:indexPath]; 93 | [self removeSpecifier:specifierToBeRemoved animated:YES]; 94 | [self.sites removeObjectForKey:[specifierToBeRemoved name]]; 95 | NSLog(@"[webshade-prefs] Site deleted: %@", [specifierToBeRemoved name]); 96 | NSLog(@"[webshade-prefs] self.sites: %@", self.sites); 97 | [self saveSites]; 98 | completionHandler(YES); 99 | }]; 100 | UIContextualAction *updateAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:@"Rename" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) { 101 | PSSpecifier *specifier = [self specifierAtIndexPath:indexPath]; 102 | UIAlertController * alertController = [UIAlertController alertControllerWithTitle: @"Rename Site Rule" 103 | message: @"Please input the new name." 104 | preferredStyle:UIAlertControllerStyleAlert]; 105 | [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { 106 | textField.placeholder = [specifier name]; 107 | textField.clearButtonMode = UITextFieldViewModeWhileEditing; 108 | }]; 109 | [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { 110 | }]]; 111 | 112 | UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { 113 | NSArray *textfields = alertController.textFields; 114 | UITextField *namefield = textfields[0]; 115 | NSString *text = [namefield.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 116 | NSString *error = nil; 117 | if(text.length == 0) { 118 | error = @"Please enter a name."; 119 | } else if([self.sites objectForKey:text]) { 120 | error = @"A site with that name already exists."; 121 | } 122 | if(error != nil) { 123 | UIAlertController * alertController = [UIAlertController alertControllerWithTitle: @"Error" 124 | message: error 125 | preferredStyle:UIAlertControllerStyleAlert]; 126 | [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { 127 | }]]; 128 | [self presentViewController:alertController animated:YES completion:nil]; 129 | } else { 130 | NSLog(@"[webshade-prefs] Site updated: %@",text); 131 | NSDictionary *site = [self.sites objectForKey:[specifier name]] ?: @{}; 132 | [self.sites setObject:site forKey:text]; 133 | [specifier setName:text]; 134 | [self reloadSpecifier:specifier]; 135 | [self saveSites]; 136 | } 137 | }]; 138 | [alertController addAction:okAction]; 139 | alertController.preferredAction = okAction; 140 | [self presentViewController:alertController animated:YES completion:nil]; 141 | completionHandler(YES); 142 | }]; 143 | updateAction.backgroundColor = [UIColor systemYellowColor]; 144 | 145 | UISwipeActionsConfiguration *config = [UISwipeActionsConfiguration configurationWithActions:@[deleteAction, updateAction]]; 146 | return config; 147 | }; 148 | 149 | -(void)saveSites { 150 | NSString *path = @"/User/Library/Preferences/com.wilsonthewolf.webshadesites.plist"; 151 | NSMutableDictionary *data =[NSMutableDictionary dictionary]; 152 | 153 | for(PSSpecifier *specifier in _specifiers) { 154 | // Prevents the header explaining the value to be written. 155 | if([specifier cellType] != PSLinkCell) { 156 | continue; 157 | } 158 | NSString *name = [specifier name]; 159 | NSLog(@"[webshade-prefs] Saving site: %@", name); 160 | if(!self.sites[name]) { 161 | [data setObject:@{} forKey:name]; 162 | } else { 163 | [data setObject:self.sites[name] forKey:name]; 164 | } 165 | } 166 | 167 | NSLog(@"[webshade-prefs] Saving sites: %@", data); 168 | [data writeToFile:path atomically:YES]; 169 | } 170 | 171 | -(void)viewDidLoad { 172 | [super viewDidLoad]; 173 | 174 | [self.navigationItem setRightBarButtonItem:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addSite)] animated:YES]; 175 | } 176 | 177 | -(void)viewDidAppear:(BOOL)animated { 178 | [super viewDidAppear:animated]; 179 | 180 | if(_specifiers) { 181 | [self loadData]; 182 | } 183 | } 184 | @end -------------------------------------------------------------------------------- /webshadeprefs/layout/Library/PreferenceLoader/Preferences/WebShadePrefs.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | entry 6 | 7 | bundle 8 | WebShadePrefs 9 | cell 10 | PSLinkCell 11 | detail 12 | WSPRootListController 13 | icon 14 | icon.png 15 | isController 16 | 17 | label 18 | WebShade 19 | 20 | 21 | 22 | --------------------------------------------------------------------------------