WebBrowser/AdBlock/AdBlockSubscription.py

changeset 6028
859f6894eed9
parent 5389
9b1c800daff3
child 6048
82ad8ec9548c
equal deleted inserted replaced
6027:d056a536670e 6028:859f6894eed9
30 Class implementing the AdBlock subscription. 30 Class implementing the AdBlock subscription.
31 31
32 @signal changed() emitted after the subscription has changed 32 @signal changed() emitted after the subscription has changed
33 @signal rulesChanged() emitted after the subscription's rules have changed 33 @signal rulesChanged() emitted after the subscription's rules have changed
34 @signal enabledChanged(bool) emitted after the enabled state was changed 34 @signal enabledChanged(bool) emitted after the enabled state was changed
35 @signal rulesEnabledChanged() emitted after a rule enabled state was
36 changed
35 """ 37 """
36 changed = pyqtSignal() 38 changed = pyqtSignal()
37 rulesChanged = pyqtSignal() 39 rulesChanged = pyqtSignal()
38 enabledChanged = pyqtSignal(bool) 40 enabledChanged = pyqtSignal(bool)
41 rulesEnabledChanged = pyqtSignal()
39 42
40 def __init__(self, url, custom, parent=None, default=False): 43 def __init__(self, url, custom, parent=None, default=False):
41 """ 44 """
42 Constructor 45 Constructor
43 46
62 65
63 self.__updatePeriod = 0 # update period in hours, 0 = use default 66 self.__updatePeriod = 0 # update period in hours, 0 = use default
64 self.__remoteModified = QDateTime() 67 self.__remoteModified = QDateTime()
65 68
66 self.__rules = [] # list containing all AdBlock rules 69 self.__rules = [] # list containing all AdBlock rules
67
68 self.__networkExceptionRules = []
69 self.__networkBlockRules = []
70 self.__domainRestrictedCssRules = []
71 self.__elementHidingRules = ""
72 self.__documentRules = []
73 self.__elemhideRules = []
74 70
75 self.__checksumRe = re.compile( 71 self.__checksumRe = re.compile(
76 r"""^\s*!\s*checksum[\s\-:]+([\w\+\/=]+).*\n""", 72 r"""^\s*!\s*checksum[\s\-:]+([\w\+\/=]+).*\n""",
77 re.IGNORECASE | re.MULTILINE) 73 re.IGNORECASE | re.MULTILINE)
78 self.__expiresRe = re.compile( 74 self.__expiresRe = re.compile(
103 99
104 def __parseUrl(self, url): 100 def __parseUrl(self, url):
105 """ 101 """
106 Private method to parse the AdBlock URL for the subscription. 102 Private method to parse the AdBlock URL for the subscription.
107 103
108 @param url AdBlock URL for the subscription (QUrl) 104 @param url AdBlock URL for the subscription
105 @type QUrl
109 """ 106 """
110 if url.scheme() != "abp": 107 if url.scheme() != "abp":
111 return 108 return
112 109
113 if url.path() != "subscribe": 110 if url.path() != "subscribe":
140 137
141 def url(self): 138 def url(self):
142 """ 139 """
143 Public method to generate the URL for this subscription. 140 Public method to generate the URL for this subscription.
144 141
145 @return AdBlock URL for the subscription (QUrl) 142 @return AdBlock URL for the subscription
143 @rtype QUrl
146 """ 144 """
147 url = QUrl() 145 url = QUrl()
148 url.setScheme("abp") 146 url.setScheme("abp")
149 url.setPath("subscribe") 147 url.setPath("subscribe")
150 148
167 165
168 def isEnabled(self): 166 def isEnabled(self):
169 """ 167 """
170 Public method to check, if the subscription is enabled. 168 Public method to check, if the subscription is enabled.
171 169
172 @return flag indicating the enabled status (boolean) 170 @return flag indicating the enabled status
171 @rtype bool
173 """ 172 """
174 return self.__enabled 173 return self.__enabled
175 174
176 def setEnabled(self, enabled): 175 def setEnabled(self, enabled):
177 """ 176 """
178 Public method to set the enabled status. 177 Public method to set the enabled status.
179 178
180 @param enabled flag indicating the enabled status (boolean) 179 @param enabled flag indicating the enabled status
180 @type bool
181 """ 181 """
182 if self.__enabled == enabled: 182 if self.__enabled == enabled:
183 return 183 return
184 184
185 self.__enabled = enabled 185 self.__enabled = enabled
187 187
188 def title(self): 188 def title(self):
189 """ 189 """
190 Public method to get the subscription title. 190 Public method to get the subscription title.
191 191
192 @return subscription title (string) 192 @return subscription title
193 @rtype string
193 """ 194 """
194 return self.__title 195 return self.__title
195 196
196 def setTitle(self, title): 197 def setTitle(self, title):
197 """ 198 """
198 Public method to set the subscription title. 199 Public method to set the subscription title.
199 200
200 @param title subscription title (string) 201 @param title subscription title
202 @type str
201 """ 203 """
202 if self.__title == title: 204 if self.__title == title:
203 return 205 return
204 206
205 self.__title = title 207 self.__title = title
207 209
208 def location(self): 210 def location(self):
209 """ 211 """
210 Public method to get the subscription location. 212 Public method to get the subscription location.
211 213
212 @return URL of the subscription location (QUrl) 214 @return URL of the subscription location
215 @rtype QUrl
213 """ 216 """
214 return QUrl.fromEncoded(self.__location) 217 return QUrl.fromEncoded(self.__location)
215 218
216 def setLocation(self, url): 219 def setLocation(self, url):
217 """ 220 """
218 Public method to set the subscription location. 221 Public method to set the subscription location.
219 222
220 @param url URL of the subscription location (QUrl) 223 @param url URL of the subscription location
224 @type QUrl
221 """ 225 """
222 if url == self.location(): 226 if url == self.location():
223 return 227 return
224 228
225 self.__location = url.toEncoded() 229 self.__location = url.toEncoded()
228 232
229 def requiresLocation(self): 233 def requiresLocation(self):
230 """ 234 """
231 Public method to get the location of a required subscription. 235 Public method to get the location of a required subscription.
232 236
233 @return location of a required subscription (string) 237 @return location of a required subscription
238 @rtype str
234 """ 239 """
235 return self.__requiresLocation 240 return self.__requiresLocation
236 241
237 def lastUpdate(self): 242 def lastUpdate(self):
238 """ 243 """
239 Public method to get the date and time of the last update. 244 Public method to get the date and time of the last update.
240 245
241 @return date and time of the last update (QDateTime) 246 @return date and time of the last update
247 @rtype QDateTime
242 """ 248 """
243 return self.__lastUpdate 249 return self.__lastUpdate
244 250
245 def rulesFileName(self): 251 def rulesFileName(self):
246 """ 252 """
247 Public method to get the name of the rules file. 253 Public method to get the name of the rules file.
248 254
249 @return name of the rules file (string) 255 @return name of the rules file
256 @rtype str
250 """ 257 """
251 if self.location().scheme() == "file": 258 if self.location().scheme() == "file":
252 return self.location().toLocalFile() 259 return self.location().toLocalFile()
253 260
254 if self.__location.isEmpty(): 261 if self.__location.isEmpty():
320 int(day)) 327 int(day))
321 ) 328 )
322 if time: 329 if time:
323 self.__remoteModified.setTime( 330 self.__remoteModified.setTime(
324 QTime(int(hour), int(minute))) 331 QTime(int(hour), int(minute)))
325 self.__populateCache()
326 self.changed.emit() 332 self.changed.emit()
327 elif not fileName.endswith("_custom"): 333 elif not fileName.endswith("_custom"):
328 self.__lastUpdate = QDateTime() 334 self.__lastUpdate = QDateTime()
329 335
330 self.checkForUpdate() 336 self.checkForUpdate()
443 449
444 def __validateCheckSum(self, fileName): 450 def __validateCheckSum(self, fileName):
445 """ 451 """
446 Private method to check the subscription file's checksum. 452 Private method to check the subscription file's checksum.
447 453
448 @param fileName name of the file containing the subscription (string) 454 @param fileName name of the file containing the subscription
449 @return flag indicating a valid file (boolean). A file is considered 455 @type str
456 @return flag indicating a valid file. A file is considered
450 valid, if the checksum is OK, the file does not contain a 457 valid, if the checksum is OK, the file does not contain a
451 checksum (i.e. cannot be checked) or we are using the limited 458 checksum (i.e. cannot be checked) or we are using the limited
452 EasyList (because we fiddled with the original). 459 EasyList (because we fiddled with the original).
460 @rtype bool
453 """ 461 """
454 try: 462 try:
455 f = open(fileName, "r", encoding="utf-8") 463 f = open(fileName, "r", encoding="utf-8")
456 data = f.read() 464 data = f.read()
457 f.close() 465 f.close()
513 if not self.__rules or not self.__rules[0].isHeader(): 521 if not self.__rules or not self.__rules[0].isHeader():
514 textStream << "[Adblock Plus 1.1.1]\n" 522 textStream << "[Adblock Plus 1.1.1]\n"
515 for rule in self.__rules: 523 for rule in self.__rules:
516 textStream << rule.filter() << "\n" 524 textStream << rule.filter() << "\n"
517 525
518 def match(self, req, urlDomain, urlString):
519 """
520 Public method to check the subscription for a matching rule.
521
522 @param req reference to the network request (QWebEngineUrlRequestInfo)
523 @param urlDomain domain of the URL (string)
524 @param urlString URL (string)
525 @return reference to the rule object or None (AdBlockRule)
526 """
527 for rule in self.__networkExceptionRules:
528 if rule.networkMatch(req, urlDomain, urlString):
529 return None
530
531 for rule in self.__networkBlockRules:
532 if rule.networkMatch(req, urlDomain, urlString):
533 return rule
534
535 return None
536
537 def adBlockDisabledForUrl(self, url):
538 """
539 Public method to check, if AdBlock is disabled for the given URL.
540
541 @param url URL to check (QUrl)
542 @return flag indicating disabled state (boolean)
543 """
544 for rule in self.__documentRules:
545 if rule.urlMatch(url):
546 return True
547
548 return False
549
550 def elemHideDisabledForUrl(self, url):
551 """
552 Public method to check, if element hiding is disabled for the given
553 URL.
554
555 @param url URL to check (QUrl)
556 @return flag indicating disabled state (boolean)
557 """
558 if self.adBlockDisabledForUrl(url):
559 return True
560
561 for rule in self.__elemhideRules:
562 if rule.urlMatch(url):
563 return True
564
565 return False
566
567 def elementHidingRules(self):
568 """
569 Public method to get the element hiding rules.
570
571 @return element hiding rules (string)
572 """
573 return self.__elementHidingRules
574
575 def elementHidingRulesForDomain(self, domain):
576 """
577 Public method to get the element hiding rules for the given domain.
578
579 @param domain domain name (string)
580 @return element hiding rules (string)
581 """
582 rules = ""
583
584 for rule in self.__domainRestrictedCssRules:
585 if rule.matchDomain(domain):
586 rules += rule.cssSelector() + ","
587
588 return rules
589
590 def rule(self, offset): 526 def rule(self, offset):
591 """ 527 """
592 Public method to get a specific rule. 528 Public method to get a specific rule.
593 529
594 @param offset offset of the rule (integer) 530 @param offset offset of the rule
595 @return requested rule (AdBlockRule) 531 @type int
532 @return requested rule
533 @rtype AdBlockRule
596 """ 534 """
597 if offset >= len(self.__rules): 535 if offset >= len(self.__rules):
598 return None 536 return None
599 537
600 return self.__rules[offset] 538 return self.__rules[offset]
601 539
602 def allRules(self): 540 def allRules(self):
603 """ 541 """
604 Public method to get the list of rules. 542 Public method to get the list of rules.
605 543
606 @return list of rules (list of AdBlockRule) 544 @return list of rules
545 @rtype list of AdBlockRule
607 """ 546 """
608 return self.__rules[:] 547 return self.__rules[:]
609 548
610 def addRule(self, rule): 549 def addRule(self, rule):
611 """ 550 """
612 Public method to add a rule. 551 Public method to add a rule.
613 552
614 @param rule reference to the rule to add (AdBlockRule) 553 @param rule reference to the rule to add
615 @return offset of the rule (integer) 554 @type AdBlockRule
555 @return offset of the rule
556 @rtype int
616 """ 557 """
617 self.__rules.append(rule) 558 self.__rules.append(rule)
618 self.__populateCache()
619 self.rulesChanged.emit() 559 self.rulesChanged.emit()
620 560
621 return len(self.__rules) - 1 561 return len(self.__rules) - 1
622 562
623 def removeRule(self, offset): 563 def removeRule(self, offset):
624 """ 564 """
625 Public method to remove a rule given the offset. 565 Public method to remove a rule given the offset.
626 566
627 @param offset offset of the rule to remove (integer) 567 @param offset offset of the rule to remove
568 @type int
628 """ 569 """
629 if offset < 0 or offset > len(self.__rules): 570 if offset < 0 or offset > len(self.__rules):
630 return 571 return
631 572
632 del self.__rules[offset] 573 del self.__rules[offset]
633 self.__populateCache()
634 self.rulesChanged.emit() 574 self.rulesChanged.emit()
635 575
636 def replaceRule(self, rule, offset): 576 def replaceRule(self, rule, offset):
637 """ 577 """
638 Public method to replace a rule given the offset. 578 Public method to replace a rule given the offset.
639 579
640 @param rule reference to the rule to set (AdBlockRule) 580 @param rule reference to the rule to set
641 @param offset offset of the rule to remove (integer) 581 @type AdBlockRule
642 @return requested rule (AdBlockRule) 582 @param offset offset of the rule to remove
583 @type int
584 @return requested rule
585 @rtype AdBlockRule
643 """ 586 """
644 if offset >= len(self.__rules): 587 if offset >= len(self.__rules):
645 return None 588 return None
646 589
647 self.__rules[offset] = rule 590 self.__rules[offset] = rule
648 self.__populateCache()
649 self.rulesChanged.emit() 591 self.rulesChanged.emit()
650 592
651 return self.__rules[offset] 593 return self.__rules[offset]
652 594
653 def __populateCache(self):
654 """
655 Private method to populate the various rule caches.
656 """
657 self.__networkExceptionRules = []
658 self.__networkBlockRules = []
659 self.__domainRestrictedCssRules = []
660 self.__elementHidingRules = ""
661 self.__documentRules = []
662 self.__elemhideRules = []
663
664 for rule in self.__rules:
665 if not rule.isEnabled():
666 continue
667
668 if rule.isCSSRule():
669 if rule.isDomainRestricted():
670 self.__domainRestrictedCssRules.append(rule)
671 else:
672 self.__elementHidingRules += rule.cssSelector() + ","
673 elif rule.isDocument():
674 self.__documentRules.append(rule)
675 elif rule.isElementHiding():
676 self.__elemhideRules.append(rule)
677 elif rule.isException():
678 self.__networkExceptionRules.append(rule)
679 else:
680 self.__networkBlockRules.append(rule)
681
682 def canEditRules(self): 595 def canEditRules(self):
683 """ 596 """
684 Public method to check, if rules can be edited. 597 Public method to check, if rules can be edited.
685 598
686 @return flag indicating rules may be edited (boolean) 599 @return flag indicating rules may be edited
600 @rtype bool
687 """ 601 """
688 return self.__custom 602 return self.__custom
689 603
690 def canBeRemoved(self): 604 def canBeRemoved(self):
691 """ 605 """
692 Public method to check, if the subscription can be removed. 606 Public method to check, if the subscription can be removed.
693 607
694 @return flag indicating removal is allowed (boolean) 608 @return flag indicating removal is allowed
609 @rtype bool
695 """ 610 """
696 return not self.__custom and not self.__defaultSubscription 611 return not self.__custom and not self.__defaultSubscription
697 612
698 def setRuleEnabled(self, offset, enabled): 613 def setRuleEnabled(self, offset, enabled):
699 """ 614 """
700 Public method to enable a specific rule. 615 Public method to enable a specific rule.
701 616
702 @param offset offset of the rule (integer) 617 @param offset offset of the rule
703 @param enabled new enabled state (boolean) 618 @type int
704 @return reference to the changed rule (AdBlockRule) 619 @param enabled new enabled state
620 @type bool
621 @return reference to the changed rule
622 @rtype AdBlockRule
705 """ 623 """
706 if offset >= len(self.__rules): 624 if offset >= len(self.__rules):
707 return None 625 return None
708 626
709 rule = self.__rules[offset] 627 rule = self.__rules[offset]
710 rule.setEnabled(enabled) 628 rule.setEnabled(enabled)
629 self.rulesEnabledChanged.emit()
630
711 if rule.isCSSRule(): 631 if rule.isCSSRule():
712 from WebBrowser.WebBrowserWindow import WebBrowserWindow 632 from WebBrowser.WebBrowserWindow import WebBrowserWindow
713 self.__populateCache()
714 WebBrowserWindow.mainWindow().reloadUserStyleSheet() 633 WebBrowserWindow.mainWindow().reloadUserStyleSheet()
715 634
716 return rule 635 return rule

eric ide

mercurial