src/eric7/WebBrowser/AdBlock/AdBlockManager.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
8 """ 8 """
9 9
10 import os 10 import os
11 import contextlib 11 import contextlib
12 12
13 from PyQt6.QtCore import ( 13 from PyQt6.QtCore import pyqtSignal, QObject, QUrl, QUrlQuery, QByteArray, QMutex
14 pyqtSignal, QObject, QUrl, QUrlQuery, QByteArray, QMutex
15 )
16 from PyQt6.QtWebEngineCore import QWebEngineUrlRequestInfo 14 from PyQt6.QtWebEngineCore import QWebEngineUrlRequestInfo
17 15
18 from EricWidgets import EricMessageBox 16 from EricWidgets import EricMessageBox
19 17
20 from EricUtilities.EricMutexLocker import EricMutexLocker 18 from EricUtilities.EricMutexLocker import EricMutexLocker
29 27
30 28
31 class AdBlockManager(QObject): 29 class AdBlockManager(QObject):
32 """ 30 """
33 Class implementing the AdBlock manager. 31 Class implementing the AdBlock manager.
34 32
35 @signal rulesChanged() emitted after some rule has changed 33 @signal rulesChanged() emitted after some rule has changed
36 @signal requiredSubscriptionLoaded(subscription) emitted to indicate 34 @signal requiredSubscriptionLoaded(subscription) emitted to indicate
37 loading of a required subscription is finished (AdBlockSubscription) 35 loading of a required subscription is finished (AdBlockSubscription)
38 @signal enabledChanged(enabled) emitted to indicate a change of the 36 @signal enabledChanged(enabled) emitted to indicate a change of the
39 enabled state 37 enabled state
40 """ 38 """
39
41 rulesChanged = pyqtSignal() 40 rulesChanged = pyqtSignal()
42 requiredSubscriptionLoaded = pyqtSignal(AdBlockSubscription) 41 requiredSubscriptionLoaded = pyqtSignal(AdBlockSubscription)
43 enabledChanged = pyqtSignal(bool) 42 enabledChanged = pyqtSignal(bool)
44 43
45 def __init__(self, parent=None): 44 def __init__(self, parent=None):
46 """ 45 """
47 Constructor 46 Constructor
48 47
49 @param parent reference to the parent object 48 @param parent reference to the parent object
50 @type QObject 49 @type QObject
51 """ 50 """
52 super().__init__(parent) 51 super().__init__(parent)
53 52
54 self.__loaded = False 53 self.__loaded = False
55 self.__subscriptionsLoaded = False 54 self.__subscriptionsLoaded = False
56 self.__enabled = False 55 self.__enabled = False
57 self.__adBlockDialog = None 56 self.__adBlockDialog = None
58 self.__adBlockExceptionsDialog = None 57 self.__adBlockExceptionsDialog = None
59 self.__adBlockNetwork = None 58 self.__adBlockNetwork = None
60 self.__adBlockPage = None 59 self.__adBlockPage = None
61 self.__subscriptions = [] 60 self.__subscriptions = []
62 self.__exceptedHosts = Preferences.getWebBrowser("AdBlockExceptions") 61 self.__exceptedHosts = Preferences.getWebBrowser("AdBlockExceptions")
63 self.__saveTimer = AutoSaver(self, self.save) 62 self.__saveTimer = AutoSaver(self, self.save)
64 self.__limitedEasyList = Preferences.getWebBrowser( 63 self.__limitedEasyList = Preferences.getWebBrowser("AdBlockUseLimitedEasyList")
65 "AdBlockUseLimitedEasyList") 64
66
67 self.__defaultSubscriptionUrlString = ( 65 self.__defaultSubscriptionUrlString = (
68 "abp:subscribe?location=" 66 "abp:subscribe?location="
69 "https://easylist-downloads.adblockplus.org/easylist.txt&" 67 "https://easylist-downloads.adblockplus.org/easylist.txt&"
70 "title=EasyList" 68 "title=EasyList"
71 ) 69 )
72 self.__additionalDefaultSubscriptionUrlStrings = ( 70 self.__additionalDefaultSubscriptionUrlStrings = (
73 "abp:subscribe?location=https://raw.githubusercontent.com/" 71 "abp:subscribe?location=https://raw.githubusercontent.com/"
74 "hoshsadiq/adblock-nocoin-list/master/nocoin.txt&" 72 "hoshsadiq/adblock-nocoin-list/master/nocoin.txt&"
75 "title=NoCoin", 73 "title=NoCoin",
76 ) 74 )
77 self.__customSubscriptionUrlString = ( 75 self.__customSubscriptionUrlString = bytes(
78 bytes(self.__customSubscriptionUrl().toEncoded()).decode() 76 self.__customSubscriptionUrl().toEncoded()
79 ) 77 ).decode()
80 78
81 self.__mutex = QMutex() 79 self.__mutex = QMutex()
82 self.__matcher = AdBlockMatcher(self) 80 self.__matcher = AdBlockMatcher(self)
83 81
84 self.rulesChanged.connect(self.__saveTimer.changeOccurred) 82 self.rulesChanged.connect(self.__saveTimer.changeOccurred)
85 self.rulesChanged.connect(self.__rulesChanged) 83 self.rulesChanged.connect(self.__rulesChanged)
86 84
87 self.__interceptor = AdBlockUrlInterceptor(self) 85 self.__interceptor = AdBlockUrlInterceptor(self)
88 86
89 from WebBrowser.WebBrowserWindow import WebBrowserWindow 87 from WebBrowser.WebBrowserWindow import WebBrowserWindow
90 WebBrowserWindow.networkManager().installUrlInterceptor( 88
91 self.__interceptor) 89 WebBrowserWindow.networkManager().installUrlInterceptor(self.__interceptor)
92 90
93 def __rulesChanged(self): 91 def __rulesChanged(self):
94 """ 92 """
95 Private slot handling a change of the AdBlock rules. 93 Private slot handling a change of the AdBlock rules.
96 """ 94 """
97 from WebBrowser.WebBrowserWindow import WebBrowserWindow 95 from WebBrowser.WebBrowserWindow import WebBrowserWindow
96
98 WebBrowserWindow.mainWindow().reloadUserStyleSheet() 97 WebBrowserWindow.mainWindow().reloadUserStyleSheet()
99 self.__updateMatcher() 98 self.__updateMatcher()
100 99
101 def close(self): 100 def close(self):
102 """ 101 """
103 Public method to close the open search engines manager. 102 Public method to close the open search engines manager.
104 """ 103 """
105 self.__adBlockDialog and self.__adBlockDialog.close() 104 self.__adBlockDialog and self.__adBlockDialog.close()
106 (self.__adBlockExceptionsDialog and 105 (self.__adBlockExceptionsDialog and self.__adBlockExceptionsDialog.close())
107 self.__adBlockExceptionsDialog.close()) 106
108
109 self.__saveTimer.saveIfNeccessary() 107 self.__saveTimer.saveIfNeccessary()
110 108
111 def isEnabled(self): 109 def isEnabled(self):
112 """ 110 """
113 Public method to check, if blocking ads is enabled. 111 Public method to check, if blocking ads is enabled.
114 112
115 @return flag indicating the enabled state 113 @return flag indicating the enabled state
116 @rtype bool 114 @rtype bool
117 """ 115 """
118 if not self.__loaded: 116 if not self.__loaded:
119 self.load() 117 self.load()
120 118
121 return self.__enabled 119 return self.__enabled
122 120
123 def setEnabled(self, enabled): 121 def setEnabled(self, enabled):
124 """ 122 """
125 Public slot to set the enabled state. 123 Public slot to set the enabled state.
126 124
127 @param enabled flag indicating the enabled state 125 @param enabled flag indicating the enabled state
128 @type bool 126 @type bool
129 """ 127 """
130 if self.isEnabled() == enabled: 128 if self.isEnabled() == enabled:
131 return 129 return
132 130
133 from WebBrowser.WebBrowserWindow import WebBrowserWindow 131 from WebBrowser.WebBrowserWindow import WebBrowserWindow
132
134 self.__enabled = enabled 133 self.__enabled = enabled
135 for mainWindow in WebBrowserWindow.mainWindows(): 134 for mainWindow in WebBrowserWindow.mainWindows():
136 mainWindow.adBlockIcon().setEnabled(enabled) 135 mainWindow.adBlockIcon().setEnabled(enabled)
137 if enabled: 136 if enabled:
138 self.__loadSubscriptions() 137 self.__loadSubscriptions()
139 138
140 self.rulesChanged.emit() 139 self.rulesChanged.emit()
141 self.enabledChanged.emit(enabled) 140 self.enabledChanged.emit(enabled)
142 141
143 def block(self, info): 142 def block(self, info):
144 """ 143 """
145 Public method to check, if a request should be blocked. 144 Public method to check, if a request should be blocked.
146 145
147 @param info request info object 146 @param info request info object
148 @type QWebEngineUrlRequestInfo 147 @type QWebEngineUrlRequestInfo
149 @return flag indicating to block the request 148 @return flag indicating to block the request
150 @rtype bool 149 @rtype bool
151 """ 150 """
152 with EricMutexLocker(self.__mutex): 151 with EricMutexLocker(self.__mutex):
153 if not self.isEnabled(): 152 if not self.isEnabled():
154 return False 153 return False
155 154
156 urlString = bytes(info.requestUrl().toEncoded()).decode().lower() 155 urlString = bytes(info.requestUrl().toEncoded()).decode().lower()
157 urlDomain = info.requestUrl().host().lower() 156 urlDomain = info.requestUrl().host().lower()
158 urlScheme = info.requestUrl().scheme().lower() 157 urlScheme = info.requestUrl().scheme().lower()
159 158
160 if ( 159 if not self.canRunOnScheme(urlScheme) or not self.__canBeBlocked(
161 not self.canRunOnScheme(urlScheme) or 160 info.firstPartyUrl()
162 not self.__canBeBlocked(info.firstPartyUrl())
163 ): 161 ):
164 return False 162 return False
165 163
166 res = False 164 res = False
167 blockedRule = self.__matcher.match(info, urlDomain, urlString) 165 blockedRule = self.__matcher.match(info, urlDomain, urlString)
168 166
169 if blockedRule: 167 if blockedRule:
170 res = True 168 res = True
171 if ( 169 if (
172 info.resourceType() == 170 info.resourceType()
173 QWebEngineUrlRequestInfo.ResourceType 171 == QWebEngineUrlRequestInfo.ResourceType.ResourceTypeMainFrame
174 .ResourceTypeMainFrame
175 ): 172 ):
176 url = QUrl("eric:adblock") 173 url = QUrl("eric:adblock")
177 query = QUrlQuery() 174 query = QUrlQuery()
178 query.addQueryItem("rule", blockedRule.filter()) 175 query.addQueryItem("rule", blockedRule.filter())
179 query.addQueryItem( 176 query.addQueryItem(
180 "subscription", blockedRule.subscription().title()) 177 "subscription", blockedRule.subscription().title()
178 )
181 url.setQuery(query) 179 url.setQuery(query)
182 info.redirect(url) 180 info.redirect(url)
183 else: 181 else:
184 info.block(True) 182 info.block(True)
185 183
186 return res 184 return res
187 185
188 def canRunOnScheme(self, scheme): 186 def canRunOnScheme(self, scheme):
189 """ 187 """
190 Public method to check, if AdBlock can be performed on the scheme. 188 Public method to check, if AdBlock can be performed on the scheme.
191 189
192 @param scheme scheme to check 190 @param scheme scheme to check
193 @type str 191 @type str
194 @return flag indicating, that AdBlock can be performed 192 @return flag indicating, that AdBlock can be performed
195 @rtype bool 193 @rtype bool
196 """ 194 """
197 return scheme not in ["data", "eric", "qthelp", "qrc", "file", "abp"] 195 return scheme not in ["data", "eric", "qthelp", "qrc", "file", "abp"]
198 196
199 def page(self): 197 def page(self):
200 """ 198 """
201 Public method to get a reference to the page block object. 199 Public method to get a reference to the page block object.
202 200
203 @return reference to the page block object 201 @return reference to the page block object
204 @rtype AdBlockPage 202 @rtype AdBlockPage
205 """ 203 """
206 if self.__adBlockPage is None: 204 if self.__adBlockPage is None:
207 from .AdBlockPage import AdBlockPage 205 from .AdBlockPage import AdBlockPage
206
208 self.__adBlockPage = AdBlockPage(self) 207 self.__adBlockPage = AdBlockPage(self)
209 return self.__adBlockPage 208 return self.__adBlockPage
210 209
211 def __customSubscriptionLocation(self): 210 def __customSubscriptionLocation(self):
212 """ 211 """
213 Private method to generate the path for custom subscriptions. 212 Private method to generate the path for custom subscriptions.
214 213
215 @return URL for custom subscriptions 214 @return URL for custom subscriptions
216 @rtype QUrl 215 @rtype QUrl
217 """ 216 """
218 dataDir = os.path.join(Utilities.getConfigDir(), "web_browser", 217 dataDir = os.path.join(Utilities.getConfigDir(), "web_browser", "subscriptions")
219 "subscriptions")
220 if not os.path.exists(dataDir): 218 if not os.path.exists(dataDir):
221 os.makedirs(dataDir) 219 os.makedirs(dataDir)
222 fileName = os.path.join(dataDir, "adblock_subscription_custom") 220 fileName = os.path.join(dataDir, "adblock_subscription_custom")
223 return QUrl.fromLocalFile(fileName) 221 return QUrl.fromLocalFile(fileName)
224 222
225 def __customSubscriptionUrl(self): 223 def __customSubscriptionUrl(self):
226 """ 224 """
227 Private method to generate the URL for custom subscriptions. 225 Private method to generate the URL for custom subscriptions.
228 226
229 @return URL for custom subscriptions 227 @return URL for custom subscriptions
230 @rtype QUrl 228 @rtype QUrl
231 """ 229 """
232 location = self.__customSubscriptionLocation() 230 location = self.__customSubscriptionLocation()
233 encodedUrl = bytes(location.toEncoded()).decode() 231 encodedUrl = bytes(location.toEncoded()).decode()
234 url = QUrl("abp:subscribe?location={0}&title={1}".format( 232 url = QUrl(
235 encodedUrl, self.tr("Custom Rules"))) 233 "abp:subscribe?location={0}&title={1}".format(
234 encodedUrl, self.tr("Custom Rules")
235 )
236 )
236 return url 237 return url
237 238
238 def customRules(self): 239 def customRules(self):
239 """ 240 """
240 Public method to get a subscription for custom rules. 241 Public method to get a subscription for custom rules.
241 242
242 @return subscription object for custom rules 243 @return subscription object for custom rules
243 @rtype AdBlockSubscription 244 @rtype AdBlockSubscription
244 """ 245 """
245 location = self.__customSubscriptionLocation() 246 location = self.__customSubscriptionLocation()
246 for subscription in self.__subscriptions: 247 for subscription in self.__subscriptions:
247 if subscription.location() == location: 248 if subscription.location() == location:
248 return subscription 249 return subscription
249 250
250 url = self.__customSubscriptionUrl() 251 url = self.__customSubscriptionUrl()
251 customAdBlockSubscription = AdBlockSubscription(url, True, self) 252 customAdBlockSubscription = AdBlockSubscription(url, True, self)
252 self.addSubscription(customAdBlockSubscription) 253 self.addSubscription(customAdBlockSubscription)
253 return customAdBlockSubscription 254 return customAdBlockSubscription
254 255
255 def subscriptions(self): 256 def subscriptions(self):
256 """ 257 """
257 Public method to get all subscriptions. 258 Public method to get all subscriptions.
258 259
259 @return list of subscriptions 260 @return list of subscriptions
260 @rtype list of AdBlockSubscription 261 @rtype list of AdBlockSubscription
261 """ 262 """
262 if not self.__loaded: 263 if not self.__loaded:
263 self.load() 264 self.load()
264 265
265 return self.__subscriptions[:] 266 return self.__subscriptions[:]
266 267
267 def subscription(self, location): 268 def subscription(self, location):
268 """ 269 """
269 Public method to get a subscription based on its location. 270 Public method to get a subscription based on its location.
270 271
271 @param location location of the subscription to search for 272 @param location location of the subscription to search for
272 @type str 273 @type str
273 @return subscription or None 274 @return subscription or None
274 @rtype AdBlockSubscription 275 @rtype AdBlockSubscription
275 """ 276 """
276 if location != "": 277 if location != "":
277 for subscription in self.__subscriptions: 278 for subscription in self.__subscriptions:
278 if subscription.location().toString() == location: 279 if subscription.location().toString() == location:
279 return subscription 280 return subscription
280 281
281 return None 282 return None
282 283
283 def updateAllSubscriptions(self): 284 def updateAllSubscriptions(self):
284 """ 285 """
285 Public method to update all subscriptions. 286 Public method to update all subscriptions.
286 """ 287 """
287 for subscription in self.__subscriptions: 288 for subscription in self.__subscriptions:
288 subscription.updateNow() 289 subscription.updateNow()
289 290
290 def removeSubscription(self, subscription, emitSignal=True): 291 def removeSubscription(self, subscription, emitSignal=True):
291 """ 292 """
292 Public method to remove an AdBlock subscription. 293 Public method to remove an AdBlock subscription.
293 294
294 @param subscription AdBlock subscription to be removed 295 @param subscription AdBlock subscription to be removed
295 @type AdBlockSubscription 296 @type AdBlockSubscription
296 @param emitSignal flag indicating to send a signal 297 @param emitSignal flag indicating to send a signal
297 @type bool 298 @type bool
298 """ 299 """
299 if subscription is None: 300 if subscription is None:
300 return 301 return
301 302
302 if subscription.url().toString().startswith( 303 if (
303 (self.__defaultSubscriptionUrlString, 304 subscription.url()
304 self.__customSubscriptionUrlString)): 305 .toString()
306 .startswith(
307 (
308 self.__defaultSubscriptionUrlString,
309 self.__customSubscriptionUrlString,
310 )
311 )
312 ):
305 return 313 return
306 314
307 with contextlib.suppress(ValueError): 315 with contextlib.suppress(ValueError):
308 self.__subscriptions.remove(subscription) 316 self.__subscriptions.remove(subscription)
309 rulesFileName = subscription.rulesFileName() 317 rulesFileName = subscription.rulesFileName()
310 os.unlink(rulesFileName) 318 os.unlink(rulesFileName)
311 requiresSubscriptions = self.getRequiresSubscriptions(subscription) 319 requiresSubscriptions = self.getRequiresSubscriptions(subscription)
312 for requiresSubscription in requiresSubscriptions: 320 for requiresSubscription in requiresSubscriptions:
313 self.removeSubscription(requiresSubscription, False) 321 self.removeSubscription(requiresSubscription, False)
314 if emitSignal: 322 if emitSignal:
315 self.rulesChanged.emit() 323 self.rulesChanged.emit()
316 324
317 def addSubscriptionFromUrl(self, url): 325 def addSubscriptionFromUrl(self, url):
318 """ 326 """
319 Public method to ad an AdBlock subscription given the abp URL. 327 Public method to ad an AdBlock subscription given the abp URL.
320 328
321 @param url URL to subscribe an AdBlock subscription 329 @param url URL to subscribe an AdBlock subscription
322 @type QUrl 330 @type QUrl
323 @return flag indicating success 331 @return flag indicating success
324 @rtype bool 332 @rtype bool
325 """ 333 """
326 if url.path() != "subscribe": 334 if url.path() != "subscribe":
327 return False 335 return False
328 336
329 title = QUrl.fromPercentEncoding( 337 title = QUrl.fromPercentEncoding(
330 QByteArray(QUrlQuery(url).queryItemValue("title").encode())) 338 QByteArray(QUrlQuery(url).queryItemValue("title").encode())
339 )
331 if not title: 340 if not title:
332 return False 341 return False
333 342
334 res = EricMessageBox.yesNo( 343 res = EricMessageBox.yesNo(
335 None, 344 None,
336 self.tr("Subscribe?"), 345 self.tr("Subscribe?"),
337 self.tr( 346 self.tr(
338 """<p>Subscribe to this AdBlock subscription?</p>""" 347 """<p>Subscribe to this AdBlock subscription?</p>""" """<p>{0}</p>"""
339 """<p>{0}</p>""").format(title)) 348 ).format(title),
349 )
340 if res: 350 if res:
341 from .AdBlockSubscription import AdBlockSubscription 351 from .AdBlockSubscription import AdBlockSubscription
342 from WebBrowser.WebBrowserWindow import WebBrowserWindow 352 from WebBrowser.WebBrowserWindow import WebBrowserWindow
343 353
344 dlg = WebBrowserWindow.adBlockManager().showDialog() 354 dlg = WebBrowserWindow.adBlockManager().showDialog()
345 subscription = AdBlockSubscription( 355 subscription = AdBlockSubscription(
346 url, False, 356 url, False, WebBrowserWindow.adBlockManager()
347 WebBrowserWindow.adBlockManager()) 357 )
348 WebBrowserWindow.adBlockManager().addSubscription(subscription) 358 WebBrowserWindow.adBlockManager().addSubscription(subscription)
349 dlg.addSubscription(subscription, False) 359 dlg.addSubscription(subscription, False)
350 dlg.setFocus() 360 dlg.setFocus()
351 dlg.raise_() 361 dlg.raise_()
352 362
353 return res 363 return res
354 364
355 def addSubscription(self, subscription): 365 def addSubscription(self, subscription):
356 """ 366 """
357 Public method to add an AdBlock subscription. 367 Public method to add an AdBlock subscription.
358 368
359 @param subscription AdBlock subscription to be added 369 @param subscription AdBlock subscription to be added
360 @type AdBlockSubscription 370 @type AdBlockSubscription
361 """ 371 """
362 if subscription is None: 372 if subscription is None:
363 return 373 return
364 374
365 self.__subscriptions.insert(-1, subscription) 375 self.__subscriptions.insert(-1, subscription)
366 376
367 subscription.rulesChanged.connect(self.rulesChanged) 377 subscription.rulesChanged.connect(self.rulesChanged)
368 subscription.changed.connect(self.rulesChanged) 378 subscription.changed.connect(self.rulesChanged)
369 subscription.enabledChanged.connect(self.rulesChanged) 379 subscription.enabledChanged.connect(self.rulesChanged)
370 380
371 self.rulesChanged.emit() 381 self.rulesChanged.emit()
372 382
373 def save(self): 383 def save(self):
374 """ 384 """
375 Public method to save the AdBlock subscriptions. 385 Public method to save the AdBlock subscriptions.
376 """ 386 """
377 if not self.__loaded: 387 if not self.__loaded:
378 return 388 return
379 389
380 Preferences.setWebBrowser("AdBlockEnabled", self.__enabled) 390 Preferences.setWebBrowser("AdBlockEnabled", self.__enabled)
381 if self.__subscriptionsLoaded: 391 if self.__subscriptionsLoaded:
382 subscriptions = [] 392 subscriptions = []
383 requiresSubscriptions = [] 393 requiresSubscriptions = []
384 # intermediate store for subscription requiring others 394 # intermediate store for subscription requiring others
392 subscriptions.append(urlString) 402 subscriptions.append(urlString)
393 subscription.saveRules() 403 subscription.saveRules()
394 for subscription in requiresSubscriptions: 404 for subscription in requiresSubscriptions:
395 subscriptions.insert(-1, subscription) # custom should be last 405 subscriptions.insert(-1, subscription) # custom should be last
396 Preferences.setWebBrowser("AdBlockSubscriptions", subscriptions) 406 Preferences.setWebBrowser("AdBlockSubscriptions", subscriptions)
397 407
398 def load(self): 408 def load(self):
399 """ 409 """
400 Public method to load the AdBlock subscriptions. 410 Public method to load the AdBlock subscriptions.
401 """ 411 """
402 if self.__loaded: 412 if self.__loaded:
403 return 413 return
404 414
405 self.__loaded = True 415 self.__loaded = True
406 416
407 self.__enabled = Preferences.getWebBrowser("AdBlockEnabled") 417 self.__enabled = Preferences.getWebBrowser("AdBlockEnabled")
408 if self.__enabled: 418 if self.__enabled:
409 self.__loadSubscriptions() 419 self.__loadSubscriptions()
410 420
411 def __loadSubscriptions(self): 421 def __loadSubscriptions(self):
412 """ 422 """
413 Private method to load the set of subscriptions. 423 Private method to load the set of subscriptions.
414 """ 424 """
415 if self.__subscriptionsLoaded: 425 if self.__subscriptionsLoaded:
416 return 426 return
417 427
418 subscriptions = Preferences.getWebBrowser("AdBlockSubscriptions") 428 subscriptions = Preferences.getWebBrowser("AdBlockSubscriptions")
419 if subscriptions: 429 if subscriptions:
420 for subscription in subscriptions: 430 for subscription in subscriptions:
421 if subscription.startswith(self.__customSubscriptionUrlString): 431 if subscription.startswith(self.__customSubscriptionUrlString):
422 break 432 break
423 else: 433 else:
424 subscriptions.append(self.__customSubscriptionUrlString) 434 subscriptions.append(self.__customSubscriptionUrlString)
425 else: 435 else:
426 subscriptions = ( 436 subscriptions = (
427 [self.__defaultSubscriptionUrlString] + 437 [self.__defaultSubscriptionUrlString]
428 list(self.__additionalDefaultSubscriptionUrlStrings) + 438 + list(self.__additionalDefaultSubscriptionUrlStrings)
429 [self.__customSubscriptionUrlString] 439 + [self.__customSubscriptionUrlString]
430 ) 440 )
431 for subscription in subscriptions: 441 for subscription in subscriptions:
432 url = QUrl.fromEncoded(subscription.encode("utf-8")) 442 url = QUrl.fromEncoded(subscription.encode("utf-8"))
433 adBlockSubscription = AdBlockSubscription( 443 adBlockSubscription = AdBlockSubscription(
434 url, 444 url,
435 subscription.startswith(self.__customSubscriptionUrlString), 445 subscription.startswith(self.__customSubscriptionUrlString),
436 self, 446 self,
437 subscription.startswith(self.__defaultSubscriptionUrlString)) 447 subscription.startswith(self.__defaultSubscriptionUrlString),
448 )
438 adBlockSubscription.rulesChanged.connect(self.rulesChanged) 449 adBlockSubscription.rulesChanged.connect(self.rulesChanged)
439 adBlockSubscription.changed.connect(self.rulesChanged) 450 adBlockSubscription.changed.connect(self.rulesChanged)
440 adBlockSubscription.enabledChanged.connect(self.rulesChanged) 451 adBlockSubscription.enabledChanged.connect(self.rulesChanged)
452 adBlockSubscription.rulesEnabledChanged.connect(self.__updateMatcher)
441 adBlockSubscription.rulesEnabledChanged.connect( 453 adBlockSubscription.rulesEnabledChanged.connect(
442 self.__updateMatcher) 454 self.__saveTimer.changeOccurred
443 adBlockSubscription.rulesEnabledChanged.connect( 455 )
444 self.__saveTimer.changeOccurred)
445 self.__subscriptions.append(adBlockSubscription) 456 self.__subscriptions.append(adBlockSubscription)
446 457
447 self.__subscriptionsLoaded = True 458 self.__subscriptionsLoaded = True
448 459
449 self.__updateMatcher() 460 self.__updateMatcher()
450 461
451 def loadRequiredSubscription(self, location, title): 462 def loadRequiredSubscription(self, location, title):
452 """ 463 """
453 Public method to load a subscription required by another one. 464 Public method to load a subscription required by another one.
454 465
455 @param location location of the required subscription 466 @param location location of the required subscription
456 @type str 467 @type str
457 @param title title of the required subscription 468 @param title title of the required subscription
458 @type str 469 @type str
459 """ 470 """
460 # Step 1: check, if the subscription is in the list of subscriptions 471 # Step 1: check, if the subscription is in the list of subscriptions
461 urlString = "abp:subscribe?location={0}&title={1}".format( 472 urlString = "abp:subscribe?location={0}&title={1}".format(location, title)
462 location, title)
463 for subscription in self.__subscriptions: 473 for subscription in self.__subscriptions:
464 if subscription.url().toString().startswith(urlString): 474 if subscription.url().toString().startswith(urlString):
465 # We found it! 475 # We found it!
466 return 476 return
467 477
468 # Step 2: if it is not, get it 478 # Step 2: if it is not, get it
469 url = QUrl.fromEncoded(urlString.encode("utf-8")) 479 url = QUrl.fromEncoded(urlString.encode("utf-8"))
470 adBlockSubscription = AdBlockSubscription(url, False, self) 480 adBlockSubscription = AdBlockSubscription(url, False, self)
471 self.addSubscription(adBlockSubscription) 481 self.addSubscription(adBlockSubscription)
472 self.requiredSubscriptionLoaded.emit(adBlockSubscription) 482 self.requiredSubscriptionLoaded.emit(adBlockSubscription)
473 483
474 def getRequiresSubscriptions(self, subscription): 484 def getRequiresSubscriptions(self, subscription):
475 """ 485 """
476 Public method to get a list of subscriptions, that require the given 486 Public method to get a list of subscriptions, that require the given
477 one. 487 one.
478 488
479 @param subscription subscription to check for 489 @param subscription subscription to check for
480 @type AdBlockSubscription 490 @type AdBlockSubscription
481 @return list of subscription requiring the given one 491 @return list of subscription requiring the given one
482 @rtype list of AdBlockSubscription 492 @rtype list of AdBlockSubscription
483 """ 493 """
484 subscriptions = [] 494 subscriptions = []
485 location = subscription.location().toString() 495 location = subscription.location().toString()
486 for subscription in self.__subscriptions: 496 for subscription in self.__subscriptions:
487 if subscription.requiresLocation() == location: 497 if subscription.requiresLocation() == location:
488 subscriptions.append(subscription) 498 subscriptions.append(subscription)
489 499
490 return subscriptions 500 return subscriptions
491 501
492 def showDialog(self): 502 def showDialog(self):
493 """ 503 """
494 Public slot to show the AdBlock subscription management dialog. 504 Public slot to show the AdBlock subscription management dialog.
495 505
496 @return reference to the dialog 506 @return reference to the dialog
497 @rtype AdBlockDialog 507 @rtype AdBlockDialog
498 """ 508 """
499 if self.__adBlockDialog is None: 509 if self.__adBlockDialog is None:
500 from .AdBlockDialog import AdBlockDialog 510 from .AdBlockDialog import AdBlockDialog
511
501 self.__adBlockDialog = AdBlockDialog(self) 512 self.__adBlockDialog = AdBlockDialog(self)
502 513
503 self.__adBlockDialog.show() 514 self.__adBlockDialog.show()
504 return self.__adBlockDialog 515 return self.__adBlockDialog
505 516
506 def elementHidingRules(self, url): 517 def elementHidingRules(self, url):
507 """ 518 """
508 Public method to get the element hiding rules. 519 Public method to get the element hiding rules.
509 520
510 521
511 @param url URL to get hiding rules for 522 @param url URL to get hiding rules for
512 @type QUrl 523 @type QUrl
513 @return element hiding rules 524 @return element hiding rules
514 @rtype str 525 @rtype str
515 """ 526 """
516 if ( 527 if (
517 not self.isEnabled() or 528 not self.isEnabled()
518 not self.canRunOnScheme(url.scheme()) or 529 or not self.canRunOnScheme(url.scheme())
519 not self.__canBeBlocked(url) 530 or not self.__canBeBlocked(url)
520 ): 531 ):
521 return "" 532 return ""
522 533
523 return self.__matcher.elementHidingRules() 534 return self.__matcher.elementHidingRules()
524 535
525 def elementHidingRulesForDomain(self, url): 536 def elementHidingRulesForDomain(self, url):
526 """ 537 """
527 Public method to get the element hiding rules for a domain. 538 Public method to get the element hiding rules for a domain.
528 539
529 @param url URL to get hiding rules for 540 @param url URL to get hiding rules for
530 @type QUrl 541 @type QUrl
531 @return element hiding rules 542 @return element hiding rules
532 @rtype str 543 @rtype str
533 """ 544 """
534 if ( 545 if (
535 not self.isEnabled() or 546 not self.isEnabled()
536 not self.canRunOnScheme(url.scheme()) or 547 or not self.canRunOnScheme(url.scheme())
537 not self.__canBeBlocked(url) 548 or not self.__canBeBlocked(url)
538 ): 549 ):
539 return "" 550 return ""
540 551
541 return self.__matcher.elementHidingRulesForDomain(url.host()) 552 return self.__matcher.elementHidingRulesForDomain(url.host())
542 553
543 def exceptions(self): 554 def exceptions(self):
544 """ 555 """
545 Public method to get a list of excepted hosts. 556 Public method to get a list of excepted hosts.
546 557
547 @return list of excepted hosts 558 @return list of excepted hosts
548 @rtype list of str 559 @rtype list of str
549 """ 560 """
550 return self.__exceptedHosts 561 return self.__exceptedHosts
551 562
552 def setExceptions(self, hosts): 563 def setExceptions(self, hosts):
553 """ 564 """
554 Public method to set the list of excepted hosts. 565 Public method to set the list of excepted hosts.
555 566
556 @param hosts list of excepted hosts 567 @param hosts list of excepted hosts
557 @type list of str 568 @type list of str
558 """ 569 """
559 self.__exceptedHosts = [host.lower() for host in hosts] 570 self.__exceptedHosts = [host.lower() for host in hosts]
560 Preferences.setWebBrowser("AdBlockExceptions", self.__exceptedHosts) 571 Preferences.setWebBrowser("AdBlockExceptions", self.__exceptedHosts)
561 572
562 def addException(self, host): 573 def addException(self, host):
563 """ 574 """
564 Public method to add an exception. 575 Public method to add an exception.
565 576
566 @param host to be excepted 577 @param host to be excepted
567 @type str 578 @type str
568 """ 579 """
569 host = host.lower() 580 host = host.lower()
570 if host and host not in self.__exceptedHosts: 581 if host and host not in self.__exceptedHosts:
571 self.__exceptedHosts.append(host) 582 self.__exceptedHosts.append(host)
572 Preferences.setWebBrowser( 583 Preferences.setWebBrowser("AdBlockExceptions", self.__exceptedHosts)
573 "AdBlockExceptions", self.__exceptedHosts) 584
574
575 def removeException(self, host): 585 def removeException(self, host):
576 """ 586 """
577 Public method to remove an exception. 587 Public method to remove an exception.
578 588
579 @param host to be removed from the list of exceptions 589 @param host to be removed from the list of exceptions
580 @type str 590 @type str
581 """ 591 """
582 host = host.lower() 592 host = host.lower()
583 if host in self.__exceptedHosts: 593 if host in self.__exceptedHosts:
584 self.__exceptedHosts.remove(host) 594 self.__exceptedHosts.remove(host)
585 Preferences.setWebBrowser( 595 Preferences.setWebBrowser("AdBlockExceptions", self.__exceptedHosts)
586 "AdBlockExceptions", self.__exceptedHosts) 596
587
588 def isHostExcepted(self, host): 597 def isHostExcepted(self, host):
589 """ 598 """
590 Public slot to check, if a host is excepted. 599 Public slot to check, if a host is excepted.
591 600
592 @param host host to check 601 @param host host to check
593 @type str 602 @type str
594 @return flag indicating an exception 603 @return flag indicating an exception
595 @rtype bool 604 @rtype bool
596 """ 605 """
597 host = host.lower() 606 host = host.lower()
598 return host in self.__exceptedHosts 607 return host in self.__exceptedHosts
599 608
600 def showExceptionsDialog(self): 609 def showExceptionsDialog(self):
601 """ 610 """
602 Public method to show the AdBlock Exceptions dialog. 611 Public method to show the AdBlock Exceptions dialog.
603 612
604 @return reference to the exceptions dialog 613 @return reference to the exceptions dialog
605 @rtype AdBlockExceptionsDialog 614 @rtype AdBlockExceptionsDialog
606 """ 615 """
607 if self.__adBlockExceptionsDialog is None: 616 if self.__adBlockExceptionsDialog is None:
608 from .AdBlockExceptionsDialog import AdBlockExceptionsDialog 617 from .AdBlockExceptionsDialog import AdBlockExceptionsDialog
618
609 self.__adBlockExceptionsDialog = AdBlockExceptionsDialog() 619 self.__adBlockExceptionsDialog = AdBlockExceptionsDialog()
610 620
611 self.__adBlockExceptionsDialog.load(self.__exceptedHosts) 621 self.__adBlockExceptionsDialog.load(self.__exceptedHosts)
612 self.__adBlockExceptionsDialog.show() 622 self.__adBlockExceptionsDialog.show()
613 return self.__adBlockExceptionsDialog 623 return self.__adBlockExceptionsDialog
614 624
615 def useLimitedEasyList(self): 625 def useLimitedEasyList(self):
616 """ 626 """
617 Public method to test, if limited EasyList rules shall be used. 627 Public method to test, if limited EasyList rules shall be used.
618 628
619 @return flag indicating limited EasyList rules 629 @return flag indicating limited EasyList rules
620 @rtype bool 630 @rtype bool
621 """ 631 """
622 return self.__limitedEasyList 632 return self.__limitedEasyList
623 633
624 def setUseLimitedEasyList(self, limited): 634 def setUseLimitedEasyList(self, limited):
625 """ 635 """
626 Public method to set the limited EasyList flag. 636 Public method to set the limited EasyList flag.
627 637
628 @param limited flag indicating to use limited EasyList 638 @param limited flag indicating to use limited EasyList
629 @type bool 639 @type bool
630 """ 640 """
631 self.__limitedEasyList = limited 641 self.__limitedEasyList = limited
632 642
633 for subscription in self.__subscriptions: 643 for subscription in self.__subscriptions:
634 if subscription.url().toString().startswith( 644 if (
635 self.__defaultSubscriptionUrlString): 645 subscription.url()
646 .toString()
647 .startswith(self.__defaultSubscriptionUrlString)
648 ):
636 subscription.updateNow() 649 subscription.updateNow()
637 650
638 Preferences.setWebBrowser("AdBlockUseLimitedEasyList", limited) 651 Preferences.setWebBrowser("AdBlockUseLimitedEasyList", limited)
639 652
640 def getDefaultSubscriptionUrl(self): 653 def getDefaultSubscriptionUrl(self):
641 """ 654 """
642 Public method to get the default subscription URL. 655 Public method to get the default subscription URL.
643 656
644 @return default subscription URL 657 @return default subscription URL
645 @rtype str 658 @rtype str
646 """ 659 """
647 return self.__defaultSubscriptionUrlString 660 return self.__defaultSubscriptionUrlString
648 661
649 def __updateMatcher(self): 662 def __updateMatcher(self):
650 """ 663 """
651 Private slot to update the adblock matcher. 664 Private slot to update the adblock matcher.
652 """ 665 """
653 from WebBrowser.WebBrowserWindow import WebBrowserWindow 666 from WebBrowser.WebBrowserWindow import WebBrowserWindow
654 WebBrowserWindow.networkManager().removeUrlInterceptor( 667
655 self.__interceptor) 668 WebBrowserWindow.networkManager().removeUrlInterceptor(self.__interceptor)
656 669
657 if self.__enabled: 670 if self.__enabled:
658 self.__matcher.update() 671 self.__matcher.update()
659 else: 672 else:
660 self.__matcher.clear() 673 self.__matcher.clear()
661 674
662 WebBrowserWindow.networkManager().installUrlInterceptor( 675 WebBrowserWindow.networkManager().installUrlInterceptor(self.__interceptor)
663 self.__interceptor) 676
664
665 def __canBeBlocked(self, url): 677 def __canBeBlocked(self, url):
666 """ 678 """
667 Private method to check, if the given URL could be blocked (i.e. is 679 Private method to check, if the given URL could be blocked (i.e. is
668 not whitelisted). 680 not whitelisted).
669 681
670 @param url URL to be checked 682 @param url URL to be checked
671 @type QUrl 683 @type QUrl
672 @return flag indicating that the given URL can be blocked 684 @return flag indicating that the given URL can be blocked
673 @rtype bool 685 @rtype bool
674 """ 686 """

eric ide

mercurial