src/eric7/WebBrowser/AdBlock/AdBlockMatcher.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9473
3f23dbf37dbe
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
15 15
16 class AdBlockMatcher(QObject): 16 class AdBlockMatcher(QObject):
17 """ 17 """
18 Class implementing the AdBlock matcher. 18 Class implementing the AdBlock matcher.
19 """ 19 """
20
20 def __init__(self, manager): 21 def __init__(self, manager):
21 """ 22 """
22 Constructor 23 Constructor
23 24
24 @param manager reference to the AdBlock manager object 25 @param manager reference to the AdBlock manager object
25 @type AdBlockManager 26 @type AdBlockManager
26 """ 27 """
27 super().__init__(manager) 28 super().__init__(manager)
28 29
29 self.__manager = manager 30 self.__manager = manager
30 31
31 self.__createdRules = [] 32 self.__createdRules = []
32 self.__networkExceptionRules = [] 33 self.__networkExceptionRules = []
33 self.__networkBlockRules = [] 34 self.__networkBlockRules = []
34 self.__domainRestrictedCssRules = [] 35 self.__domainRestrictedCssRules = []
35 self.__documentRules = [] 36 self.__documentRules = []
36 self.__elemhideRules = [] 37 self.__elemhideRules = []
37 38
38 self.__elementHidingRules = "" 39 self.__elementHidingRules = ""
39 self.__networkBlockTree = AdBlockSearchTree() 40 self.__networkBlockTree = AdBlockSearchTree()
40 self.__networkExceptionTree = AdBlockSearchTree() 41 self.__networkExceptionTree = AdBlockSearchTree()
41 42
42 def match(self, request, urlDomain, urlString): 43 def match(self, request, urlDomain, urlString):
43 """ 44 """
44 Public method to match a request. 45 Public method to match a request.
45 46
46 @param request URL request to be matched 47 @param request URL request to be matched
47 @type QWebEngineUrlRequestInfo 48 @type QWebEngineUrlRequestInfo
48 @param urlDomain domain of the URL 49 @param urlDomain domain of the URL
49 @type str 50 @type str
50 @param urlString requested URL as a lowercase string 51 @param urlString requested URL as a lowercase string
53 @rtype AdBlockRule 54 @rtype AdBlockRule
54 """ 55 """
55 # exception rules 56 # exception rules
56 if self.__networkExceptionTree.find(request, urlDomain, urlString): 57 if self.__networkExceptionTree.find(request, urlDomain, urlString):
57 return None 58 return None
58 59
59 for rule in self.__networkExceptionRules: 60 for rule in self.__networkExceptionRules:
60 if rule.networkMatch(request, urlDomain, urlString): 61 if rule.networkMatch(request, urlDomain, urlString):
61 return None 62 return None
62 63
63 # block rules 64 # block rules
64 rule = self.__networkBlockTree.find(request, urlDomain, urlString) 65 rule = self.__networkBlockTree.find(request, urlDomain, urlString)
65 if rule: 66 if rule:
66 return rule 67 return rule
67 68
68 for rule in self.__networkBlockRules: 69 for rule in self.__networkBlockRules:
69 if rule.networkMatch(request, urlDomain, urlString): 70 if rule.networkMatch(request, urlDomain, urlString):
70 return rule 71 return rule
71 72
72 return None 73 return None
73 74
74 def adBlockDisabledForUrl(self, url): 75 def adBlockDisabledForUrl(self, url):
75 """ 76 """
76 Public method to check, if AdBlock is disabled for the given URL. 77 Public method to check, if AdBlock is disabled for the given URL.
77 78
78 @param url URL to check 79 @param url URL to check
79 @type QUrl 80 @type QUrl
80 @return flag indicating disabled state 81 @return flag indicating disabled state
81 @rtype bool 82 @rtype bool
82 """ 83 """
83 return any(rule.urlMatch(url) for rule in self.__documentRules) 84 return any(rule.urlMatch(url) for rule in self.__documentRules)
84 85
85 def elemHideDisabledForUrl(self, url): 86 def elemHideDisabledForUrl(self, url):
86 """ 87 """
87 Public method to check, if element hiding is disabled for the given 88 Public method to check, if element hiding is disabled for the given
88 URL. 89 URL.
89 90
90 @param url URL to check 91 @param url URL to check
91 @type QUrl 92 @type QUrl
92 @return flag indicating disabled state 93 @return flag indicating disabled state
93 @rtype bool 94 @rtype bool
94 """ 95 """
95 if self.adBlockDisabledForUrl(url): 96 if self.adBlockDisabledForUrl(url):
96 return True 97 return True
97 98
98 return any(rule.urlMatch(url) for rule in self.__elemhideRules) 99 return any(rule.urlMatch(url) for rule in self.__elemhideRules)
99 100
100 def elementHidingRules(self): 101 def elementHidingRules(self):
101 """ 102 """
102 Public method to get the element hiding rules. 103 Public method to get the element hiding rules.
103 104
104 @return element hiding rules 105 @return element hiding rules
105 @rtype str 106 @rtype str
106 """ 107 """
107 return self.__elementHidingRules 108 return self.__elementHidingRules
108 109
109 def elementHidingRulesForDomain(self, domain): 110 def elementHidingRulesForDomain(self, domain):
110 """ 111 """
111 Public method to get the element hiding rules for the given domain. 112 Public method to get the element hiding rules for the given domain.
112 113
113 @param domain domain name 114 @param domain domain name
114 @type str 115 @type str
115 @return element hiding rules 116 @return element hiding rules
116 @rtype str 117 @rtype str
117 """ 118 """
118 rules = "" 119 rules = ""
119 addedRulesCount = 0 120 addedRulesCount = 0
120 121
121 for rule in self.__domainRestrictedCssRules: 122 for rule in self.__domainRestrictedCssRules:
122 if not rule.matchDomain(domain): 123 if not rule.matchDomain(domain):
123 continue 124 continue
124 125
125 if addedRulesCount == 1000: 126 if addedRulesCount == 1000:
126 rules += rule.cssSelector() 127 rules += rule.cssSelector()
127 rules += "{display:none !important;}\n" 128 rules += "{display:none !important;}\n"
128 addedRulesCount = 0 129 addedRulesCount = 0
129 else: 130 else:
130 rules += rule.cssSelector() + "," 131 rules += rule.cssSelector() + ","
131 addedRulesCount += 1 132 addedRulesCount += 1
132 133
133 if addedRulesCount != 0: 134 if addedRulesCount != 0:
134 rules = rules[:-1] 135 rules = rules[:-1]
135 rules += "{display:none !important;}\n" 136 rules += "{display:none !important;}\n"
136 137
137 return rules 138 return rules
138 139
139 def update(self): 140 def update(self):
140 """ 141 """
141 Public slot to update the internal state. 142 Public slot to update the internal state.
142 """ 143 """
143 self.clear() 144 self.clear()
144 145
145 cssRulesDict = {} 146 cssRulesDict = {}
146 exceptionCssRules = [] 147 exceptionCssRules = []
147 148
148 for subscription in self.__manager.subscriptions(): 149 for subscription in self.__manager.subscriptions():
149 if subscription.isEnabled(): 150 if subscription.isEnabled():
150 for rule in subscription.allRules(): 151 for rule in subscription.allRules():
151 # Don't add internally disabled rules to the cache 152 # Don't add internally disabled rules to the cache
152 if rule.isInternalDisabled(): 153 if rule.isInternalDisabled():
153 continue 154 continue
154 155
155 if rule.isCSSRule(): 156 if rule.isCSSRule():
156 # Only enabled CSS rules are added to the cache because 157 # Only enabled CSS rules are added to the cache because
157 # there is no enabled/disabled check on match. They are 158 # there is no enabled/disabled check on match. They are
158 # directly embedded to pages. 159 # directly embedded to pages.
159 if not rule.isEnabled(): 160 if not rule.isEnabled():
160 continue 161 continue
161 162
162 if rule.isException(): 163 if rule.isException():
163 exceptionCssRules.append(rule) 164 exceptionCssRules.append(rule)
164 else: 165 else:
165 cssRulesDict[rule.cssSelector()] = rule 166 cssRulesDict[rule.cssSelector()] = rule
166 elif rule.isDocument(): 167 elif rule.isDocument():
171 if not self.__networkExceptionTree.add(rule): 172 if not self.__networkExceptionTree.add(rule):
172 self.__networkBlockRules.append(rule) 173 self.__networkBlockRules.append(rule)
173 else: 174 else:
174 if not self.__networkBlockTree.add(rule): 175 if not self.__networkBlockTree.add(rule):
175 self.__networkBlockRules.append(rule) 176 self.__networkBlockRules.append(rule)
176 177
177 for rule in exceptionCssRules: 178 for rule in exceptionCssRules:
178 try: 179 try:
179 originalRule = cssRulesDict[rule.cssSelector()] 180 originalRule = cssRulesDict[rule.cssSelector()]
180 except KeyError: 181 except KeyError:
181 # If there is no such selector, the exception does nothing. 182 # If there is no such selector, the exception does nothing.
182 continue 183 continue
183 184
184 copiedRule = AdBlockRule() 185 copiedRule = AdBlockRule()
185 copiedRule.copyFrom(originalRule) 186 copiedRule.copyFrom(originalRule)
186 copiedRule.setOption(AdBlockRuleOption.DomainRestrictedOption) 187 copiedRule.setOption(AdBlockRuleOption.DomainRestrictedOption)
187 copiedRule.addBlockedDomains(rule.allowedDomains()) 188 copiedRule.addBlockedDomains(rule.allowedDomains())
188 189
189 cssRulesDict[rule.cssSelector()] = copiedRule 190 cssRulesDict[rule.cssSelector()] = copiedRule
190 self.__createdRules.append(copiedRule) 191 self.__createdRules.append(copiedRule)
191 192
192 # Excessive amount of selectors for one CSS rule is not what the 193 # Excessive amount of selectors for one CSS rule is not what the
193 # rendering engine likes. So split them up by 1.000 selectors. 194 # rendering engine likes. So split them up by 1.000 selectors.
194 hidingRulesCount = 0 195 hidingRulesCount = 0
195 for key in cssRulesDict: 196 for key in cssRulesDict:
196 rule = cssRulesDict[key] 197 rule = cssRulesDict[key]
197 198
198 if rule.isDomainRestricted(): 199 if rule.isDomainRestricted():
199 self.__domainRestrictedCssRules.append(rule) 200 self.__domainRestrictedCssRules.append(rule)
200 elif hidingRulesCount == 1000: 201 elif hidingRulesCount == 1000:
201 self.__elementHidingRules += rule.cssSelector() 202 self.__elementHidingRules += rule.cssSelector()
202 self.__elementHidingRules += "{display:none !important;} " 203 self.__elementHidingRules += "{display:none !important;} "
203 hidingRulesCount = 0 204 hidingRulesCount = 0
204 else: 205 else:
205 self.__elementHidingRules += rule.cssSelector() + "," 206 self.__elementHidingRules += rule.cssSelector() + ","
206 hidingRulesCount += 1 207 hidingRulesCount += 1
207 208
208 if hidingRulesCount != 0: 209 if hidingRulesCount != 0:
209 self.__elementHidingRules = self.__elementHidingRules[:-1] 210 self.__elementHidingRules = self.__elementHidingRules[:-1]
210 self.__elementHidingRules += "{display:none !important;} " 211 self.__elementHidingRules += "{display:none !important;} "
211 212
212 def clear(self): 213 def clear(self):
213 """ 214 """
214 Public slot to clear the internal structures. 215 Public slot to clear the internal structures.
215 """ 216 """
216 self.__createdRules = [] 217 self.__createdRules = []
217 self.__networkExceptionRules = [] 218 self.__networkExceptionRules = []
218 self.__networkBlockRules = [] 219 self.__networkBlockRules = []
219 self.__domainRestrictedCssRules = [] 220 self.__domainRestrictedCssRules = []
220 self.__documentRules = [] 221 self.__documentRules = []
221 self.__elemhideRules = [] 222 self.__elemhideRules = []
222 223
223 self.__elementHidingRules = "" 224 self.__elementHidingRules = ""
224 self.__networkBlockTree.clear() 225 self.__networkBlockTree.clear()
225 self.__networkExceptionTree.clear() 226 self.__networkExceptionTree.clear()

eric ide

mercurial