30 Class implementing the AdBlock manager. |
31 Class implementing the AdBlock manager. |
31 |
32 |
32 @signal rulesChanged() emitted after some rule has changed |
33 @signal rulesChanged() emitted after some rule has changed |
33 @signal requiredSubscriptionLoaded(subscription) emitted to indicate |
34 @signal requiredSubscriptionLoaded(subscription) emitted to indicate |
34 loading of a required subscription is finished (AdBlockSubscription) |
35 loading of a required subscription is finished (AdBlockSubscription) |
|
36 @signal enabledChanged(enabled) emitted to indicate a change of the |
|
37 enabled state |
35 """ |
38 """ |
36 rulesChanged = pyqtSignal() |
39 rulesChanged = pyqtSignal() |
37 requiredSubscriptionLoaded = pyqtSignal(AdBlockSubscription) |
40 requiredSubscriptionLoaded = pyqtSignal(AdBlockSubscription) |
|
41 enabledChanged = pyqtSignal(bool) |
38 |
42 |
39 def __init__(self, parent=None): |
43 def __init__(self, parent=None): |
40 """ |
44 """ |
41 Constructor |
45 Constructor |
42 |
46 |
43 @param parent reference to the parent object (QObject) |
47 @param parent reference to the parent object |
|
48 @type QObject |
44 """ |
49 """ |
45 super(AdBlockManager, self).__init__(parent) |
50 super(AdBlockManager, self).__init__(parent) |
46 |
51 |
47 self.__loaded = False |
52 self.__loaded = False |
48 self.__subscriptionsLoaded = False |
53 self.__subscriptionsLoaded = False |
92 |
101 |
93 def isEnabled(self): |
102 def isEnabled(self): |
94 """ |
103 """ |
95 Public method to check, if blocking ads is enabled. |
104 Public method to check, if blocking ads is enabled. |
96 |
105 |
97 @return flag indicating the enabled state (boolean) |
106 @return flag indicating the enabled state |
|
107 @rtype bool |
98 """ |
108 """ |
99 if not self.__loaded: |
109 if not self.__loaded: |
100 self.load() |
110 self.load() |
101 |
111 |
102 return self.__enabled |
112 return self.__enabled |
103 |
113 |
104 def setEnabled(self, enabled): |
114 def setEnabled(self, enabled): |
105 """ |
115 """ |
106 Public slot to set the enabled state. |
116 Public slot to set the enabled state. |
107 |
117 |
108 @param enabled flag indicating the enabled state (boolean) |
118 @param enabled flag indicating the enabled state |
|
119 @type bool |
109 """ |
120 """ |
110 if self.isEnabled() == enabled: |
121 if self.isEnabled() == enabled: |
111 return |
122 return |
112 |
123 |
113 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
124 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
114 self.__enabled = enabled |
125 self.__enabled = enabled |
115 for mainWindow in WebBrowserWindow.mainWindows(): |
126 for mainWindow in WebBrowserWindow.mainWindows(): |
116 mainWindow.adBlockIcon().setEnabled(enabled) |
127 mainWindow.adBlockIcon().setEnabled(enabled) |
117 if enabled: |
128 if enabled: |
118 self.__loadSubscriptions() |
129 self.__loadSubscriptions() |
|
130 |
119 self.rulesChanged.emit() |
131 self.rulesChanged.emit() |
|
132 self.enabledChanged.emit(enabled) |
120 |
133 |
121 def block(self, info): |
134 def block(self, info): |
122 """ |
135 """ |
123 Public method to check, if a request should be blocked. |
136 Public method to check, if a request should be blocked. |
124 |
137 |
125 @param info request info aobject |
138 @param info request info object |
126 @type QWebEngineUrlRequestInfo |
139 @type QWebEngineUrlRequestInfo |
127 @return flag indicating to block the request |
140 @return flag indicating to block the request |
128 @rtype bool |
141 @rtype bool |
129 """ |
142 """ |
|
143 locker = QMutexLocker(self.__mutex) # __IGNORE_WARNING__ |
|
144 |
|
145 if not self.isEnabled(): |
|
146 return False |
|
147 |
130 urlString = bytes(info.requestUrl().toEncoded()).decode().lower() |
148 urlString = bytes(info.requestUrl().toEncoded()).decode().lower() |
131 urlDomain = info.requestUrl().host().lower() |
149 urlDomain = info.requestUrl().host().lower() |
132 urlScheme = info.requestUrl().scheme().lower() |
150 urlScheme = info.requestUrl().scheme().lower() |
133 refererHost = info.firstPartyUrl().host().lower() |
151 |
134 |
152 if not self.canRunOnScheme(urlScheme) or \ |
135 if not self.isEnabled() or not self.__canRunOnScheme(urlScheme): |
153 not self.__canBeBlocked(info.firstPartyUrl()): |
136 return False |
154 return False |
137 |
155 |
138 if self.isHostExcepted(urlDomain) or self.isHostExcepted(refererHost): |
|
139 return False |
|
140 |
|
141 res = False |
156 res = False |
142 |
157 blockedRule = self.__matcher.match(info, urlDomain, urlString) |
143 for subscription in self.subscriptions(): |
158 |
144 if subscription.isEnabled(): |
159 if blockedRule: |
145 if subscription.adBlockDisabledForUrl(info.requestUrl()): |
160 res = True |
146 continue |
161 if info.resourceType() == \ |
147 |
162 QWebEngineUrlRequestInfo.ResourceTypeMainFrame: |
148 blockedRule = subscription.match(info, urlDomain, urlString) |
163 url = QUrl("eric:adblock") |
149 if blockedRule: |
164 query = QUrlQuery() |
150 res = True |
165 query.addQueryItem("rule", blockedRule.filter()) |
151 if info.resourceType() == \ |
166 query.addQueryItem( |
152 QWebEngineUrlRequestInfo.ResourceTypeMainFrame: |
167 "subscription", blockedRule.subscription().title()) |
153 url = QUrl("eric:adblock") |
168 url.setQuery(query) |
154 query = QUrlQuery() |
169 info.redirect(url) |
155 query.addQueryItem("rule", blockedRule.filter()) |
170 else: |
156 query.addQueryItem( |
171 info.block(True) |
157 "subscription", blockedRule.subscription().title()) |
|
158 url.setQuery(query) |
|
159 info.redirect(url) |
|
160 res = False |
|
161 else: |
|
162 info.block(True) |
|
163 break |
|
164 |
172 |
165 return res |
173 return res |
166 |
174 |
167 def __canRunOnScheme(self, scheme): |
175 def canRunOnScheme(self, scheme): |
168 """ |
176 """ |
169 Private method to check, if AdBlock can be performed on the scheme. |
177 Public method to check, if AdBlock can be performed on the scheme. |
170 |
178 |
171 @param scheme scheme to check (string) |
179 @param scheme scheme to check |
172 @return flag indicating, that AdBlock can be performed (boolean) |
180 @type str |
|
181 @return flag indicating, that AdBlock can be performed |
|
182 @rtype bool |
173 """ |
183 """ |
174 return scheme not in ["data", "eric", "qthelp", "qrc", "file", "abp"] |
184 return scheme not in ["data", "eric", "qthelp", "qrc", "file", "abp"] |
175 |
185 |
176 def page(self): |
186 def page(self): |
177 """ |
187 """ |
178 Public method to get a reference to the page block object. |
188 Public method to get a reference to the page block object. |
179 |
189 |
180 @return reference to the page block object (AdBlockPage) |
190 @return reference to the page block object |
|
191 @rtype AdBlockPage |
181 """ |
192 """ |
182 if self.__adBlockPage is None: |
193 if self.__adBlockPage is None: |
183 from .AdBlockPage import AdBlockPage |
194 from .AdBlockPage import AdBlockPage |
184 self.__adBlockPage = AdBlockPage(self) |
195 self.__adBlockPage = AdBlockPage(self) |
185 return self.__adBlockPage |
196 return self.__adBlockPage |
186 |
197 |
187 def __customSubscriptionLocation(self): |
198 def __customSubscriptionLocation(self): |
188 """ |
199 """ |
189 Private method to generate the path for custom subscriptions. |
200 Private method to generate the path for custom subscriptions. |
190 |
201 |
191 @return URL for custom subscriptions (QUrl) |
202 @return URL for custom subscriptions |
|
203 @rtype QUrl |
192 """ |
204 """ |
193 dataDir = os.path.join(Utilities.getConfigDir(), "web_browser", |
205 dataDir = os.path.join(Utilities.getConfigDir(), "web_browser", |
194 "subscriptions") |
206 "subscriptions") |
195 if not os.path.exists(dataDir): |
207 if not os.path.exists(dataDir): |
196 os.makedirs(dataDir) |
208 os.makedirs(dataDir) |
227 |
241 |
228 def subscriptions(self): |
242 def subscriptions(self): |
229 """ |
243 """ |
230 Public method to get all subscriptions. |
244 Public method to get all subscriptions. |
231 |
245 |
232 @return list of subscriptions (list of AdBlockSubscription) |
246 @return list of subscriptions |
|
247 @rtype list of AdBlockSubscription |
233 """ |
248 """ |
234 if not self.__loaded: |
249 if not self.__loaded: |
235 self.load() |
250 self.load() |
236 |
251 |
237 return self.__subscriptions[:] |
252 return self.__subscriptions[:] |
238 |
253 |
239 def subscription(self, location): |
254 def subscription(self, location): |
240 """ |
255 """ |
241 Public method to get a subscription based on its location. |
256 Public method to get a subscription based on its location. |
242 |
257 |
243 @param location location of the subscription to search for (string) |
258 @param location location of the subscription to search for |
244 @return subscription or None (AdBlockSubscription) |
259 @type str |
|
260 @return subscription or None |
|
261 @rtype AdBlockSubscription |
245 """ |
262 """ |
246 if location != "": |
263 if location != "": |
247 for subscription in self.__subscriptions: |
264 for subscription in self.__subscriptions: |
248 if subscription.location().toString() == location: |
265 if subscription.location().toString() == location: |
249 return subscription |
266 return subscription |
408 self, |
428 self, |
409 subscription.startswith(self.__defaultSubscriptionUrlString)) |
429 subscription.startswith(self.__defaultSubscriptionUrlString)) |
410 adBlockSubscription.rulesChanged.connect(self.rulesChanged) |
430 adBlockSubscription.rulesChanged.connect(self.rulesChanged) |
411 adBlockSubscription.changed.connect(self.rulesChanged) |
431 adBlockSubscription.changed.connect(self.rulesChanged) |
412 adBlockSubscription.enabledChanged.connect(self.rulesChanged) |
432 adBlockSubscription.enabledChanged.connect(self.rulesChanged) |
|
433 adBlockSubscription.rulesEnabledChanged.connect( |
|
434 self.__updateMatcher) |
|
435 adBlockSubscription.rulesEnabledChanged.connect( |
|
436 self.__saveTimer.changeOccurred) |
413 self.__subscriptions.append(adBlockSubscription) |
437 self.__subscriptions.append(adBlockSubscription) |
414 |
438 |
415 self.__subscriptionsLoaded = True |
439 self.__subscriptionsLoaded = True |
|
440 |
|
441 self.__updateMatcher() |
416 |
442 |
417 def loadRequiredSubscription(self, location, title): |
443 def loadRequiredSubscription(self, location, title): |
418 """ |
444 """ |
419 Public method to load a subscription required by another one. |
445 Public method to load a subscription required by another one. |
420 |
446 |
421 @param location location of the required subscription (string) |
447 @param location location of the required subscription |
422 @param title title of the required subscription (string) |
448 @type str |
|
449 @param title title of the required subscription |
|
450 @type str |
423 """ |
451 """ |
424 # Step 1: check, if the subscription is in the list of subscriptions |
452 # Step 1: check, if the subscription is in the list of subscriptions |
425 urlString = "abp:subscribe?location={0}&title={1}".format( |
453 urlString = "abp:subscribe?location={0}&title={1}".format( |
426 location, title) |
454 location, title) |
427 for subscription in self.__subscriptions: |
455 for subscription in self.__subscriptions: |
468 def elementHidingRules(self, url): |
498 def elementHidingRules(self, url): |
469 """ |
499 """ |
470 Public method to get the element hiding rules. |
500 Public method to get the element hiding rules. |
471 |
501 |
472 |
502 |
473 @param url URL to get hiding rules for (QUrl) |
503 @param url URL to get hiding rules for |
474 @return element hiding rules (string) |
504 @type QUrl |
475 """ |
505 @return element hiding rules |
476 if not self.isEnabled() or not self.__canRunOnScheme(url.scheme()): |
506 @rtype str |
|
507 """ |
|
508 if not self.isEnabled() or \ |
|
509 not self.canRunOnScheme(url.scheme()) or \ |
|
510 not self.__canBeBlocked(url): |
477 return "" |
511 return "" |
478 |
512 |
479 rules = "" |
513 return self.__matcher.elementHidingRules() |
480 |
|
481 for subscription in self.__subscriptions: |
|
482 rules += subscription.elementHidingRules() |
|
483 |
|
484 if rules: |
|
485 # remove last ", |
|
486 rules = rules[:-1] |
|
487 |
|
488 return rules |
|
489 |
514 |
490 def elementHidingRulesForDomain(self, url): |
515 def elementHidingRulesForDomain(self, url): |
491 """ |
516 """ |
492 Public method to get the element hiding rules for a domain. |
517 Public method to get the element hiding rules for a domain. |
493 |
518 |
494 @param url URL to get hiding rules for (QUrl) |
519 @param url URL to get hiding rules for |
495 @return element hiding rules (string) |
520 @type QUrl |
496 """ |
521 @return element hiding rules |
497 if not self.isEnabled(): |
522 @rtype str |
|
523 """ |
|
524 if not self.isEnabled() or \ |
|
525 not self.canRunOnScheme(url.scheme()) or \ |
|
526 not self.__canBeBlocked(url): |
498 return "" |
527 return "" |
499 |
528 |
500 rules = "" |
529 return self.__matcher.elementHidingRulesForDomain(url.host()) |
501 |
|
502 for subscription in self.__subscriptions: |
|
503 if subscription.elemHideDisabledForUrl(url): |
|
504 continue |
|
505 |
|
506 rules += subscription.elementHidingRulesForDomain(url.host()) |
|
507 |
|
508 if rules: |
|
509 # remove last "," |
|
510 rules = rules[:-1] |
|
511 |
|
512 rules += "{display:none !important;}\n" |
|
513 |
|
514 return rules |
|
515 |
530 |
516 def exceptions(self): |
531 def exceptions(self): |
517 """ |
532 """ |
518 Public method to get a list of excepted hosts. |
533 Public method to get a list of excepted hosts. |
519 |
534 |
520 @return list of excepted hosts (list of string) |
535 @return list of excepted hosts |
|
536 @rtype list of str |
521 """ |
537 """ |
522 return self.__exceptedHosts |
538 return self.__exceptedHosts |
523 |
539 |
524 def setExceptions(self, hosts): |
540 def setExceptions(self, hosts): |
525 """ |
541 """ |
526 Public method to set the list of excepted hosts. |
542 Public method to set the list of excepted hosts. |
527 |
543 |
528 @param hosts list of excepted hosts (list of string) |
544 @param hosts list of excepted hosts |
|
545 @type list of str |
529 """ |
546 """ |
530 self.__exceptedHosts = [host.lower() for host in hosts] |
547 self.__exceptedHosts = [host.lower() for host in hosts] |
531 Preferences.setWebBrowser("AdBlockExceptions", self.__exceptedHosts) |
548 Preferences.setWebBrowser("AdBlockExceptions", self.__exceptedHosts) |
532 |
549 |
533 def addException(self, host): |
550 def addException(self, host): |
534 """ |
551 """ |
535 Public method to add an exception. |
552 Public method to add an exception. |
536 |
553 |
537 @param host to be excepted (string) |
554 @param host to be excepted |
|
555 @type str |
538 """ |
556 """ |
539 host = host.lower() |
557 host = host.lower() |
540 if host and host not in self.__exceptedHosts: |
558 if host and host not in self.__exceptedHosts: |
541 self.__exceptedHosts.append(host) |
559 self.__exceptedHosts.append(host) |
542 Preferences.setWebBrowser( |
560 Preferences.setWebBrowser( |
556 |
575 |
557 def isHostExcepted(self, host): |
576 def isHostExcepted(self, host): |
558 """ |
577 """ |
559 Public slot to check, if a host is excepted. |
578 Public slot to check, if a host is excepted. |
560 |
579 |
561 @param host host to check (string) |
580 @param host host to check |
562 @return flag indicating an exception (boolean) |
581 @type str |
|
582 @return flag indicating an exception |
|
583 @rtype bool |
563 """ |
584 """ |
564 host = host.lower() |
585 host = host.lower() |
565 return host in self.__exceptedHosts |
586 return host in self.__exceptedHosts |
566 |
587 |
567 def showExceptionsDialog(self): |
588 def showExceptionsDialog(self): |
568 """ |
589 """ |
569 Public method to show the AdBlock Exceptions dialog. |
590 Public method to show the AdBlock Exceptions dialog. |
570 |
591 |
571 @return reference to the exceptions dialog (AdBlockExceptionsDialog) |
592 @return reference to the exceptions dialog |
|
593 @rtype AdBlockExceptionsDialog |
572 """ |
594 """ |
573 if self.__adBlockExceptionsDialog is None: |
595 if self.__adBlockExceptionsDialog is None: |
574 from .AdBlockExceptionsDialog import AdBlockExceptionsDialog |
596 from .AdBlockExceptionsDialog import AdBlockExceptionsDialog |
575 self.__adBlockExceptionsDialog = AdBlockExceptionsDialog() |
597 self.__adBlockExceptionsDialog = AdBlockExceptionsDialog() |
576 |
598 |