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